def create_dhcp_discover_relayed_packet(self): my_chaddr = ''.join( [chr(int(octet, 16)) for octet in self.client_mac.split(':')]) # Relay modifies the DHCPDISCOVER message in the following ways: # 1.) Increments the hops count in the DHCP header # 2.) Updates the gateway IP address in hte BOOTP header (if it is 0.0.0.0) # 3.) Replaces the source IP with the IP of the interface which the relay # received the broadcast DHCPDISCOVER message on # 4.) Replaces the destination IP with the IP address of the DHCP server # each message is being forwarded to # Here, the actual destination MAC should be the MAC of the leaf the relay # forwards through and the destination IP should be the IP of the DHCP server # the relay is forwarding to. We don't need to confirm these, so we'll # just mask them off later # # TODO: In IP layer, DHCP relay also replaces source IP with IP of interface on # which it received the broadcast DHCPDISCOVER from client. This appears to # be loopback. We could pull from minigraph and check here. ether = scapy.Ether(dst=self.BROADCAST_MAC, src=self.uplink_mac, type=0x0800) ip = scapy.IP(src=self.DEFAULT_ROUTE_IP, dst=self.BROADCAST_IP, len=328, ttl=64) udp = scapy.UDP(sport=self.DHCP_SERVER_PORT, dport=self.DHCP_SERVER_PORT, len=308) bootp = scapy.BOOTP(op=1, htype=1, hlen=6, hops=1, xid=0, secs=0, flags=0x8000, ciaddr=self.DEFAULT_ROUTE_IP, yiaddr=self.DEFAULT_ROUTE_IP, siaddr=self.DEFAULT_ROUTE_IP, giaddr=self.relay_iface_ip if not self.dual_tor else self.switch_loopback_ip, chaddr=my_chaddr) bootp /= scapy.DHCP( options=[('message-type', 'discover'), ('relay_agent_Information', self.option82), ('end')]) # If our bootp layer is too small, pad it pad_bytes = self.DHCP_PKT_BOOTP_MIN_LEN - len(bootp) if pad_bytes > 0: bootp /= scapy.PADDING('\x00' * pad_bytes) pkt = ether / ip / udp / bootp return pkt
def runSendReceiveTest(self, pkt2send, src_port, destination_ports): """ @summary Send packet and verify it is received/not received on the expected ports """ testutils.send_packet(self, src_port, pkt2send) (index, rcv_pkt, received) = self.receivePacketOnPorts(destination_ports) self.tests_total += 1 if not received: return False scapy_pkt = scapy.Ether(rcv_pkt) if scapy.IP not in scapy_pkt: return False if self.expected_dst_mac and scapy_pkt.dst != self.expected_dst_mac: return False if scapy_pkt[scapy.IP].src != self.session_src_ip: return False if scapy_pkt[scapy.IP].dst != self.session_dst_ip: return False if scapy_pkt[scapy.IP].ttl != self.session_ttl: return False # TODO: Fanout modifies DSCP. TOS value is olways 0. #if (scapy_pkt[scapy.IP].tos >> 2) != self.session_dscp: # return False payload = str(scapy_pkt[scapy.GRE].payload)[22:] inner_pkt = scapy.Ether(payload) return dataplane.match_exp_pkt(pkt2send, inner_pkt)
def greFilter(self, pkt_str): ''' @summaty: Filter GRE packets ''' try: pkt = scapy.Ether(pkt_str) if scapy.IP not in pkt: return False return pkt[scapy.IP].proto == self.GRE_PROTOCOL_NUMBER except: return False
def create_dhcp_ack_relayed_packet(self): my_chaddr = ''.join( [chr(int(octet, 16)) for octet in self.client_mac.split(':')]) # Relay modifies the DHCPACK message in the following ways: # 1.) Replaces the source MAC with the MAC of the interface it received it on # 2.) Replaces the destination MAC with boradcast (ff:ff:ff:ff:ff:ff) # 3.) Replaces the source IP with the IP of the interface which the relay # received it on # 4.) Replaces the destination IP with broadcast (255.255.255.255) # 5.) Replaces the destination port with the DHCP client port (68) ether = scapy.Ether(dst=self.BROADCAST_MAC, src=self.relay_iface_mac, type=0x0800) ip = scapy.IP(src=self.relay_iface_ip, dst=self.BROADCAST_IP, len=290, ttl=64) udp = scapy.UDP(sport=self.DHCP_SERVER_PORT, dport=self.DHCP_CLIENT_PORT, len=262) bootp = scapy.BOOTP(op=2, htype=1, hlen=6, hops=0, xid=0, secs=0, flags=0x8000, ciaddr=self.DEFAULT_ROUTE_IP, yiaddr=self.client_ip, siaddr=self.server_ip, giaddr=self.relay_iface_ip if not self.dual_tor else self.switch_loopback_ip, chaddr=my_chaddr) bootp /= scapy.DHCP(options=[( 'message-type', 'ack'), ('server_id', self.server_ip), ( 'lease_time', self.LEASE_TIME), ('subnet_mask', self.client_subnet), ('end')]) # TODO: Need to add this to the packet creation functions in PTF code first! # If our bootp layer is too small, pad it #pad_bytes = self.DHCP_PKT_BOOTP_MIN_LEN - len(bootp) #if pad_bytes > 0: # bootp /= scapy.PADDING('\x00' * pad_bytes) pkt = ether / ip / udp / bootp return pkt
def create_dhcp_discover_relayed_packet(self): my_chaddr = ''.join([ chr(int(octet, 16)) for octet in self.client_iface_mac.split(':') ]) # Relay modifies the DHCPDISCOVER message in the following ways: # 1.) Increments the hops count in the DHCP header # 2.) Updates the gateway IP address in hte BOOTP header (if it is 0.0.0.0) # 3.) Replaces the source IP with the IP of the interface which the relay # received the broadcast DHCPDISCOVER message on # 4.) Replaces the destination IP with the IP address of the DHCP server # each message is being forwarded to # Here, the actual destination MAC should be the MAC of the leaf the relay # forwards through and the destination IP should be the IP of the DHCP server # the relay is forwarding to. We don't need to confirm these, so we'll # just mask them off later # # TODO: Relay also replaces source IP with IP of interface on which it received the # broadcast DHCPDISCOVER from client. This appears to be loopback. # We could pull from minigraph and check here. pkt = scapy.Ether(dst=self.BROADCAST_MAC, src=self.relay_iface_mac, type=0x0800) pkt /= scapy.IP(src=self.DEFAULT_ROUTE_IP, dst=self.BROADCAST_IP, len=328, ttl=64) pkt /= scapy.UDP(sport=self.DHCP_SERVER_PORT, dport=self.DHCP_SERVER_PORT, len=308) pkt /= scapy.BOOTP(op=1, htype=1, hlen=6, hops=1, xid=0, secs=0, flags=0x8000, ciaddr=self.DEFAULT_ROUTE_IP, yiaddr=self.DEFAULT_ROUTE_IP, siaddr=self.DEFAULT_ROUTE_IP, giaddr=self.relay_iface_ip, chaddr=my_chaddr) pkt /= scapy.DHCP(options=[( 'message-type', 'discover'), ('relay_agent_Information', self.relay_agent_info), ('end')]) # The isc-dhcp-relay adds 44 bytes of padding to our discover packet pkt /= scapy.PADDING('\x00' * 44) return pkt
def fc_packet(pause_dur=65535, source_mac='00:11:22:33:44:55'): if pause_dur < 0 or pause_dur > 65535: return None eth_hdr = scapy.Ether(dst='01:80:c2:00:00:01', src=source_mac, type=0x8808) opcode = '\x00\x01' classtime = binascii.unhexlify(format(pause_dur, '04x')) pad = '\x00' * 42 payload = opcode + classtime + pad pkt = eth_hdr / payload return pkt
def create_dhcp_request_relayed_packet(self): my_chaddr = ''.join( [chr(int(octet, 16)) for octet in self.client_mac.split(':')]) # Here, the actual destination MAC should be the MAC of the leaf the relay # forwards through and the destination IP should be the IP of the DHCP server # the relay is forwarding to. We don't need to confirm these, so we'll # just mask them off later # # TODO: In IP layer, DHCP relay also replaces source IP with IP of interface on # which it received the broadcast DHCPREQUEST from client. This appears to # be loopback. We could pull from minigraph and check here. ether = scapy.Ether(dst=self.BROADCAST_MAC, src=self.uplink_mac, type=0x0800) ip = scapy.IP(src=self.DEFAULT_ROUTE_IP, dst=self.BROADCAST_IP, len=336, ttl=64) udp = scapy.UDP(sport=self.DHCP_SERVER_PORT, dport=self.DHCP_SERVER_PORT, len=316) bootp = scapy.BOOTP(op=1, htype=1, hlen=6, hops=1, xid=0, secs=0, flags=0x8000, ciaddr=self.DEFAULT_ROUTE_IP, yiaddr=self.DEFAULT_ROUTE_IP, siaddr=self.DEFAULT_ROUTE_IP, giaddr=self.relay_iface_ip if not self.dual_tor else self.switch_loopback_ip, chaddr=my_chaddr) bootp /= scapy.DHCP(options=[( 'message-type', 'request'), ( 'requested_addr', self.client_ip), ( 'server_id', self.server_ip), ('relay_agent_Information', self.option82), ('end')]) # If our bootp layer is too small, pad it pad_bytes = self.DHCP_PKT_BOOTP_MIN_LEN - len(bootp) if pad_bytes > 0: bootp /= scapy.PADDING('\x00' * pad_bytes) pkt = ether / ip / udp / bootp return pkt
def simple_eth_packet(pktlen=60, eth_dst="00:01:02:03:04:05", eth_src="00:06:07:08:09:0a", vlan_vid=0, vlan_pcp=0): pkt = scapy.Ether(dst=eth_dst, src=eth_src) if vlan_vid or vlan_pcp: pktlen += 4 pkt /= scapy.Dot1Q(vlan=vlan_vid, prio=vlan_pcp) pkt[scapy.Dot1Q:1].type = DEFAULT_FDB_ETHERNET_TYPE else: pkt.type = DEFAULT_FDB_ETHERNET_TYPE pkt = pkt / ("0" * (pktlen - len(pkt))) return pkt
def createDhcpRequestRelayedPacket(self, dutMac): """ Helper function that creates DHCP Request packet destined to DUT Args: dutMac(str): MAC address of DUT Returns: packet: DHCP Request packet """ ether = scapy.Ether(dst=dutMac, src=self.DHCP_RELAY["mac"], type=0x0800) ip = scapy.IP(src=self.DHCP_RELAY["loopback"], dst=self.DHCP_SERVER["ip"], len=328, ttl=64) udp = scapy.UDP(sport=self.DHCP_SERVER["port"], dport=self.DHCP_SERVER["port"], len=308) bootp = scapy.BOOTP(op=1, htype=1, hlen=6, hops=1, xid=0, secs=0, flags=0x8000, ciaddr=str(INADDR_ANY), yiaddr=str(INADDR_ANY), siaddr=str(INADDR_ANY), giaddr=self.DHCP_RELAY["ip"], chaddr=''.join([ chr(int(octet, 16)) for octet in self.DHCP_CLIENT["mac"].split(':') ])) bootp /= scapy.DHCP( options=[("message-type", "request"), ("requested_addr", self.DHCP_CLIENT["ip"] ), ("server_id", self.DHCP_SERVER["ip"]), ("end")]) pad_bytes = self.DHCP_PKT_BOOTP_MIN_LEN - len(bootp) if pad_bytes > 0: bootp /= scapy.PADDING("\x00" * pad_bytes) pkt = ether / ip / udp / bootp return pkt
def gre_filter(self, pkt_str): """ Filters GRE packets. Keyword arguments: pkt_str -- the packet being filtered in string format """ try: pkt = scapy.Ether(pkt_str) if scapy.IP not in pkt: return False return pkt[scapy.IP].proto == self.IP_PROTO_GRE except: return False
def create_dhcp_request_relayed_packet(self): my_chaddr = ''.join([ chr(int(octet, 16)) for octet in self.client_iface_mac.split(':') ]) # Here, the actual destination MAC should be the MAC of the leaf the relay # forwards through and the destination IP should be the IP of the DHCP server # the relay is forwarding to. We don't need to confirm these, so we'll # just mask them off later # # TODO: Relay also replaces source IP with IP of interface on which it received the # broadcast DHCPDISCOVER from client. This appears to be loopback. # We could pull from minigraph and check here. pkt = scapy.Ether(dst=self.BROADCAST_MAC, src=self.relay_iface_mac, type=0x0800) pkt /= scapy.IP(src=self.DEFAULT_ROUTE_IP, dst=self.BROADCAST_IP, len=328, ttl=64) pkt /= scapy.UDP(sport=self.DHCP_SERVER_PORT, dport=self.DHCP_SERVER_PORT, len=308) pkt /= scapy.BOOTP(op=1, htype=1, hlen=6, hops=1, xid=0, secs=0, flags=0x8000, ciaddr=self.DEFAULT_ROUTE_IP, yiaddr=self.DEFAULT_ROUTE_IP, siaddr=self.DEFAULT_ROUTE_IP, giaddr=self.relay_iface_ip, chaddr=my_chaddr) pkt /= scapy.DHCP(options=[( 'message-type', 'request'), ('requested_addr', self.client_ip), ('server_id', self.server_ip), ('relay_agent_Information', self.relay_agent_info), ('end')]) # The isc-dhcp-relay adds 32 bytes of padding to our request pkt /= scapy.PADDING('\x00' * 32) return pkt
def _send_and_check_mirror_packets(self, setup, mirror_session, ptfadapter, duthost, mirror_packet): expected_mirror_packet = self._get_expected_mirror_packet( mirror_session, setup, duthost, mirror_packet) ptfadapter.dataplane.flush() testutils.send(ptfadapter, self._get_src_port(setup), mirror_packet) _, received_packet = testutils.verify_packet_any_port( ptfadapter, expected_mirror_packet, ports=[self._get_monitor_port(setup, mirror_session, duthost)]) logging.info("received: %s", packet.Ether(received_packet).summary()) inner_packet = self._extract_mirror_payload(received_packet, len(mirror_packet)) logging.info("inner_packet: %s", inner_packet.summary()) logging.info("expected_packet: %s", mirror_packet.summary()) pytest_assert( Mask(inner_packet).pkt_match(mirror_packet), "Mirror payload does not match received packet")
def _extract_mirror_payload(self, encapsulated_packet, payload_size): pytest_assert(len(encapsulated_packet) >= self.OUTER_HEADER_SIZE, "Incomplete packet, expected at least {} header bytes".format(self.OUTER_HEADER_SIZE)) inner_frame = encapsulated_packet[-payload_size:] return packet.Ether(inner_frame)
def runTest(self): pass_cnt = 0 tos = self.dscp << 2 tos_bg = self.dscp_bg << 2 if self.debug: # remove previous debug files files = glob.glob("/tmp/pfc_pause_{}*".format(self.dscp)) for file in files: os.remove(file) current_time = datetime.datetime.now().strftime( "%Y-%m-%d_%H:%M:%S") log_file = open( "/tmp/pfc_pause_{}_{}".format(self.dscp, current_time), "w") """ If DUT needs to learn MAC addresses """ if not self.dut_has_mac: pkt = simple_udp_packet(eth_dst=self.mac_dst, eth_src=self.mac_src, ip_src=self.ip_src, ip_dst=self.ip_dst) send_packet(self, self.port_src, pkt, 5) pkt = simple_udp_packet(eth_dst=self.mac_src, eth_src=self.mac_dst, ip_src=self.ip_dst, ip_dst=self.ip_src) send_packet(self, self.port_dst, pkt, 5) for x in range(self.pkt_count): sport = random.randint(0, 65535) dport = random.randint(0, 65535) pkt = simple_udp_packet(eth_dst=self.mac_dst, eth_src=self.mac_src, ip_src=self.ip_src, ip_dst=self.ip_dst, ip_tos=tos, udp_sport=sport, udp_dport=dport, ip_ttl=64) pkt_bg = simple_udp_packet(eth_dst=self.mac_dst, eth_src=self.mac_src, ip_src=self.ip_src, ip_dst=self.ip_dst, ip_tos=tos_bg, udp_sport=sport, udp_dport=dport, ip_ttl=64) exp_pkt = simple_udp_packet(ip_src=self.ip_src, ip_dst=self.ip_dst, ip_tos=tos_bg, udp_sport=sport, udp_dport=dport, ip_ttl=63) masked_exp_pkt = Mask(exp_pkt) masked_exp_pkt.set_do_not_care_scapy(scapy.Ether, "src") masked_exp_pkt.set_do_not_care_scapy(scapy.Ether, "dst") masked_exp_pkt.set_do_not_care_scapy(scapy.IP, "ttl") masked_exp_pkt.set_do_not_care_scapy(scapy.IP, "chksum") masked_exp_pkt.set_do_not_care_scapy(scapy.IP, "tos") send_packet(self, self.port_src, pkt, 1) send_packet(self, self.port_src, pkt_bg, 1) pkts = capture_matched_packets(self, masked_exp_pkt, self.port_dst) if self.debug: for i, pkt in enumerate(pkts): dump_msg = "Iteration {}:\n Pkt num {}:\n Hex dump: {}\n\n".format( x, i, sc.utils.hexstr(pkt)) log_file.write(dump_msg) time.sleep(self.pkt_intvl) """ If the queue is paused, we should only receive the background packet """ if self.queue_paused: pass_cnt += int( len(pkts) == 1 and scapy.Ether(pkts[0])[scapy.IP].tos == tos_bg) else: pass_cnt += int(len(pkts) == 2) if self.debug: log_file.close() print "Passes: %d / %d" % (pass_cnt, self.pkt_count)
def send_and_verify(self, dst_ip, expected_ports, src_port, triple_encap = False): ''' @summary: This function builds encap packet, send and verify their arrival. @dst_ip: the destination ip for the inner IP header @expected_ports: list of ports that a packet can arrived from @src_port: the physical port that the packet will be sent from @triple_encap: True to send triple encapsulated packet ''' #setting parameters src_mac = self.dataplane.get_mac(0, 0) dst_mac = '00:11:22:33:44:55' inner_src_ip = '2.2.2.2' router_mac = self.test_params['router_mac'] dscp_in = random.randint(0, 32) tos_in = dscp_in << 2 dscp_out = random.randint(0, 32) tos_out = dscp_out << 2 if ("pipe" == self.test_params['dscp_mode']): exp_tos = tos_in elif("uniform" == self.test_params['dscp_mode']): exp_tos = tos_out else: print("ERROR: no dscp is configured") exit() default_packet_len = 100 default_packet_add_header_len = 114 #building the packets and the expected packets if (not triple_encap): #for the double encap packet we will use IP header with TCP header without mac inner_pkt = simple_ip_only_packet(ip_dst=dst_ip, ip_src=inner_src_ip, ip_ttl=64, ip_tos=tos_in) #after the decap process the retuning packet will be normal tcp packet, The TTL is taked from the inner layer and redused by one exp_pkt = simple_tcp_packet(pktlen=default_packet_add_header_len, eth_dst=dst_mac, eth_src=router_mac, ip_dst=dst_ip, ip_src=inner_src_ip, ip_tos=exp_tos, ip_ttl=63) else: #Building triple encap packet with SCAPY, because there is no PTF function for it, I use the defualt values for the TCP header tcp_hdr = scapy.TCP(sport=1234, dport=80, flags="S", chksum=0) inner_pkt2 = scapy.IP(src='4.4.4.4', dst='3.3.3.3', tos=0, ttl=64, id=1, ihl=None) / tcp_hdr inner_pkt = scapy.IP(src=inner_src_ip, dst=dst_ip, tos=tos_in, ttl=64, id=1, ihl=None,proto=4) / inner_pkt2 inner_pkt = inner_pkt/("".join([chr(x) for x in xrange(default_packet_len - len(inner_pkt))])) #The expected packet is also built by scapy, and the TTL is taked from the inner layer and redused by one exp_pkt = scapy.Ether(dst=dst_mac, src=router_mac)/inner_pkt exp_pkt['IP'].tos = exp_tos #this parameter is taken by the decap rule configuration exp_pkt['IP'].ttl = 63 pkt = simple_ipv4ip_packet( eth_dst=router_mac, eth_src=src_mac, ip_src='1.1.1.1', ip_dst=self.test_params['lo_ip'], ip_tos=tos_out, ip_ttl=random.randint(2, 63), inner_frame=inner_pkt) #send and verify the return packets masked_exp_pkt = Mask(exp_pkt) masked_exp_pkt.set_do_not_care_scapy(scapy.Ether, "dst") masked_exp_pkt.set_do_not_care_scapy(scapy.Ether, "src") send_packet(self, src_port, pkt) logging.info(".....Sending packet from port" + str(src_port) + " to " + dst_ip + ", Triple_encap: " + str(triple_encap)) (matched, received) = verify_packet_any_port(self, masked_exp_pkt, expected_ports) assert received return (matched, received)
def send_and_check_mirror_packets(self, setup, mirror_session, ptfadapter, duthost, mirror_packet, src_port=None, dest_ports=None, expect_recv=True, valid_across_namespace=True): expected_mirror_packet = self._get_expected_mirror_packet( mirror_session, setup, duthost, mirror_packet) if not src_port: src_port = self._get_random_src_port(setup) if not dest_ports: dest_ports = [ self._get_monitor_port(setup, mirror_session, duthost) ] # In Below logic idea is to send traffic in such a way so that mirror traffic # will need to go across namespaces and within namespace. If source and mirror destination # namespace are different then traffic mirror will go across namespace via (backend asic) # else via same namespace(asic) src_port_namespace = self._get_port_namespace(setup, int(src_port)) dest_ports_namespace = self._get_port_namespace( setup, int(dest_ports[0])) src_port_set = set() # Some of test scenario are not valid across namespaces so test will explicltly pass # valid_across_namespace as False (default is True) if valid_across_namespace == True or src_port_namespace == dest_ports_namespace: src_port_set.add(src_port) # To verify same namespace mirroring we will add destination port also to the Source Port Set if src_port_namespace != dest_ports_namespace: src_port_set.add(dest_ports[0]) # Loop through Source Port Set and send traffic on each source port of the set for src_port in src_port_set: ptfadapter.dataplane.flush() testutils.send(ptfadapter, src_port, mirror_packet) if expect_recv: _, received_packet = testutils.verify_packet_any_port( ptfadapter, expected_mirror_packet, ports=dest_ports) logging.info("Received packet: %s", packet.Ether(received_packet).summary()) inner_packet = self._extract_mirror_payload( received_packet, len(mirror_packet)) logging.info("Received inner packet: %s", inner_packet.summary()) inner_packet = Mask(inner_packet) # For egress mirroring, we expect the DUT to have modified the packet # before forwarding it. Specifically: # # - In L2 the SMAC and DMAC will change. # - In L3 the TTL and checksum will change. # # We know what the TTL and SMAC should be after going through the pipeline, # but DMAC and checksum are trickier. For now, update the TTL and SMAC, and # mask off the DMAC and IP Checksum to verify the packet contents. if self.mirror_type() == "egress": mirror_packet[packet.IP].ttl -= 1 mirror_packet[packet.Ether].src = setup["router_mac"] inner_packet.set_do_not_care_scapy(packet.Ether, "dst") inner_packet.set_do_not_care_scapy(packet.IP, "chksum") logging.info("Expected inner packet: %s", mirror_packet.summary()) pytest_assert(inner_packet.pkt_match(mirror_packet), "Mirror payload does not match received packet") else: testutils.verify_no_packet_any(ptfadapter, expected_mirror_packet, dest_ports)
def create_encap_packet(self, dst_ip, outer_pkt='ipv4', triple_encap=False): """Creates an IPv4/IPv6 encapsulated packet in @outer_pkt packet @param dst_ip: Destination IP for inner packet. Depending @dst_ip IPv4 or IPv6 packet will be created @param outer_pkt: Outer packet type to encapsulate inner packet in (ipv4/ipv6) @param triple_encap: Whether to build triple encapsulated packet @return: built packet and expected packet to match after decapsulation""" src_mac = self.dataplane.get_mac(0, 0) dst_mac = '00:11:22:33:44:55' router_mac = self.test_params['router_mac'] dscp_in = random.randint(0, 32) # TC for IPv6, ToS for IPv4 tc_in = tos_in = dscp_in << 2 dscp_out = random.randint(0, 32) tc_out = tos_out = dscp_out << 2 if ("pipe" == self.test_params['dscp_mode']): exp_tc = exp_tos = tc_in elif ("uniform" == self.test_params['dscp_mode']): exp_tc = exp_tos = tc_out else: print("ERROR: no dscp is configured") exit() if ipaddress.ip_address(unicode(dst_ip)).version == 6: inner_src_ip = self.DEFAULT_INNER_V6_PKT_SRC_IP # build inner packet, if triple_encap is True inner_pkt would be double encapsulated inner_pkt = self.create_ipv6_inner_pkt_only( inner_src_ip, dst_ip, tos_in, triple_encap) # build expected packet based on inner packet # set the correct L2 fields exp_pkt = scapy.Ether(dst=dst_mac, src=router_mac) / inner_pkt # set expected TC value exp_pkt['IPv6'].tc = exp_tc # decrement TTL exp_pkt['IPv6'].hlim -= 1 else: inner_src_ip = self.DEFAULT_INNER_V4_PKT_SRC_IP # build inner packet, if triple_encap is True inner_pkt would be double encapsulated inner_pkt = self.create_ipv4_inner_pkt_only( inner_src_ip, dst_ip, tos_in, triple_encap) # build expected packet based on inner packet # set the correct L2 fields exp_pkt = scapy.Ether(dst=dst_mac, src=router_mac) / inner_pkt # set expected ToS value exp_pkt['IP'].tos = exp_tos # decrement TTL exp_pkt['IP'].ttl -= 1 if outer_pkt == 'ipv4': pkt = simple_ipv4ip_packet(eth_dst=router_mac, eth_src=src_mac, ip_src='1.1.1.1', ip_dst=self.test_params['lo_ip'], ip_tos=tos_out, ip_ttl=random.randint(2, 63), inner_frame=inner_pkt) elif outer_pkt == 'ipv6': pkt = simple_ipv6ip_packet(eth_dst=router_mac, eth_src=src_mac, ipv6_src='1::1', ipv6_dst=self.test_params['lo_ipv6'], ipv6_tc=tc_out, ipv6_hlim=random.randint(2, 63), inner_frame=inner_pkt) else: raise Exception("ERROR: invalid outer packet type ", outer_pkt) return pkt, exp_pkt
def runTest(self): pass_cnt = 0 tos = self.dscp << 2 tos_bg = self.dscp_bg << 2 """ If DUT needs to learn MAC addresses """ if not self.dut_has_mac: pkt = simple_udp_packet(eth_dst=self.mac_dst, eth_src=self.mac_src, ip_src=self.ip_src, ip_dst=self.ip_dst) send_packet(self, self.port_src, pkt, 5) pkt = simple_udp_packet(eth_dst=self.mac_src, eth_src=self.mac_dst, ip_src=self.ip_dst, ip_dst=self.ip_src) send_packet(self, self.port_dst, pkt, 5) for x in range(self.pkt_count): sport = random.randint(0, 65535) dport = random.randint(0, 65535) pkt = simple_udp_packet(eth_dst=self.mac_dst, eth_src=self.mac_src, ip_src=self.ip_src, ip_dst=self.ip_dst, ip_tos=tos, udp_sport=sport, udp_dport=dport, ip_ttl=64) pkt_bg = simple_udp_packet(eth_dst=self.mac_dst, eth_src=self.mac_src, ip_src=self.ip_src, ip_dst=self.ip_dst, ip_tos=tos_bg, udp_sport=sport, udp_dport=dport, ip_ttl=64) exp_pkt = simple_udp_packet(ip_src=self.ip_src, ip_dst=self.ip_dst, ip_tos=tos_bg, udp_sport=sport, udp_dport=dport, ip_ttl=63) masked_exp_pkt = Mask(exp_pkt) masked_exp_pkt.set_do_not_care_scapy(scapy.Ether, "src") masked_exp_pkt.set_do_not_care_scapy(scapy.Ether, "dst") masked_exp_pkt.set_do_not_care_scapy(scapy.IP, "ttl") masked_exp_pkt.set_do_not_care_scapy(scapy.IP, "chksum") masked_exp_pkt.set_do_not_care_scapy(scapy.IP, "tos") send_packet(self, self.port_src, pkt, 1) send_packet(self, self.port_src, pkt_bg, 1) pkts = capture_matched_packets(self, masked_exp_pkt, self.port_dst) time.sleep(self.pkt_intvl) """ If the queue is paused, we should only receive the background packet """ if self.queue_paused: pass_cnt += int( len(pkts) == 1 and scapy.Ether(pkts[0])[scapy.IP].tos == tos_bg) else: pass_cnt += int(len(pkts) == 2) print "Passes: %d / %d" % (pass_cnt, self.pkt_count)
def test_encap(self, ptf_port, vni, ptf_addr, destination, nhs, test_ecn=False, vlan=0): rv = True try: pkt_len = self.DEFAULT_PKT_LEN if 'vlan' != 0: tagged = True pkt_len += 4 else: tagged = False options = {'ip_ecn': 0} options_v6 = {'ipv6_ecn': 0} if test_ecn: ecn = random.randint(0, 3) options = {'ip_ecn': ecn} options_v6 = {'ipv6_ecn': ecn} # ECMP support, assume it is a string of comma seperated list of addresses. returned_ip_addresses = {} check_ecmp = False for host_address in nhs: check_ecmp = True # This will ensure that every nh is used atleast once. for i in range(self.packet_count): tcp_sport = get_incremental_value('tcp_sport') valid_combination = True if isinstance(ip_address(destination), ipaddress.IPv4Address) and isinstance( ip_address(ptf_addr), ipaddress.IPv4Address): pkt_opts = { "pktlen": pkt_len, "eth_dst": self.dut_mac, "eth_src": self.ptf_mac_addrs['eth%d' % ptf_port], "ip_dst": destination, "ip_src": ptf_addr, "ip_id": 105, "ip_ttl": 64, "tcp_sport": tcp_sport, "tcp_dport": VARS['tcp_dport'] } pkt_opts.update(options) pkt = simple_tcp_packet(**pkt_opts) pkt_opts['ip_ttl'] = 63 pkt_opts['eth_src'] = self.dut_mac exp_pkt = simple_tcp_packet(**pkt_opts) elif isinstance(ip_address(destination), ipaddress.IPv6Address) and isinstance( ip_address(ptf_addr), ipaddress.IPv6Address): pkt_opts = { "pktlen": pkt_len, "eth_dst": self.dut_mac, "eth_src": self.ptf_mac_addrs['eth%d' % ptf_port], "ipv6_dst": destination, "ipv6_src": ptf_addr, "ipv6_hlim": 64, "tcp_sport": tcp_sport, "tcp_dport": VARS['tcp_dport'] } pkt_opts.update(options_v6) pkt = simple_tcpv6_packet(**pkt_opts) pkt_opts['ipv6_hlim'] = 63 pkt_opts['eth_src'] = self.dut_mac exp_pkt = simple_tcpv6_packet(**pkt_opts) else: valid_combination = False udp_sport = 1234 # Use entropy_hash(pkt), it will be ignored in the test later. udp_dport = self.vxlan_port if isinstance(ip_address(host_address), ipaddress.IPv4Address): encap_pkt = simple_vxlan_packet( eth_src=self.dut_mac, eth_dst=self.random_mac, ip_id=0, ip_src=self.loopback_ipv4, ip_dst=host_address, ip_ttl=128, udp_sport=udp_sport, udp_dport=udp_dport, with_udp_chksum=False, vxlan_vni=vni, inner_frame=exp_pkt, **options) encap_pkt[scapy.IP].flags = 0x2 elif isinstance(ip_address(host_address), ipaddress.IPv6Address): encap_pkt = simple_vxlanv6_packet( eth_src=self.dut_mac, eth_dst=self.random_mac, ipv6_src=self.loopback_ipv6, ipv6_dst=host_address, udp_sport=udp_sport, udp_dport=udp_dport, with_udp_chksum=False, vxlan_vni=vni, inner_frame=exp_pkt, **options_v6) send_packet(self, ptf_port, str(pkt)) masked_exp_pkt = Mask(encap_pkt) masked_exp_pkt.set_do_not_care_scapy(scapy.Ether, "src") masked_exp_pkt.set_do_not_care_scapy(scapy.Ether, "dst") if isinstance(ip_address(host_address), ipaddress.IPv4Address): masked_exp_pkt.set_do_not_care_scapy(scapy.IP, "ttl") masked_exp_pkt.set_do_not_care_scapy( scapy.IP, "chksum") masked_exp_pkt.set_do_not_care_scapy(scapy.IP, "dst") else: masked_exp_pkt.set_do_not_care_scapy( scapy.IPv6, "hlim") masked_exp_pkt.set_do_not_care_scapy( scapy.IPv6, "chksum") masked_exp_pkt.set_do_not_care_scapy(scapy.IPv6, "dst") masked_exp_pkt.set_do_not_care_scapy(scapy.UDP, "sport") masked_exp_pkt.set_do_not_care_scapy(scapy.UDP, "chksum") logger.info("Sending packet from port " + str(ptf_port) + " to " + destination) if self.expect_encap_success: _, received_pkt = verify_packet_any_port( self, masked_exp_pkt, self.t2_ports) scapy_pkt = scapy.Ether(received_pkt) # Store every destination that was received. if isinstance(ip_address(host_address), ipaddress.IPv6Address): dest_ip = scapy_pkt['IPv6'].dst else: dest_ip = scapy_pkt['IP'].dst try: returned_ip_addresses[ dest_ip] = returned_ip_addresses[dest_ip] + 1 except KeyError: returned_ip_addresses[dest_ip] = 1 else: check_ecmp = False logger.info("Verifying no packet") verify_no_packet_any(self, masked_exp_pkt, self.t2_ports) # Verify ECMP: if check_ecmp: self.verify_all_addresses_used_equally(nhs, returned_ip_addresses) pkt.load = '0' * 60 + str(len(self.packets)) self.packets.append((ptf_port, str(pkt).encode("base64"))) finally: logger.info("")
def create_encap_packet(self, dst_ip, outer_pkt='ipv4', triple_encap=False, outer_ttl=None, inner_ttl=None): """Creates an IPv4/IPv6 encapsulated packet in @outer_pkt packet @param dst_ip: Destination IP for inner packet. Depending @dst_ip IPv4 or IPv6 packet will be created @param outer_pkt: Outer packet type to encapsulate inner packet in (ipv4/ipv6) @param triple_encap: Whether to build triple encapsulated packet @outer_ttl: TTL for the outer layer @inner_ttl: TTL for the inner layer @return: built packet and expected packet to match after decapsulation """ src_mac = self.dataplane.get_mac(0, 0) dst_mac = '00:11:22:33:44:55' router_mac = self.test_params['router_mac'] # Set DSCP value for the inner layer dscp_in = self.DSCP_RANGE[self.dscp_in_idx] self.dscp_in_idx = (self.dscp_in_idx + 1) % len( self.DSCP_RANGE) # Next packet will use a different DSCP # TC for IPv6, ToS for IPv4 tc_in = tos_in = dscp_in << 2 # Set DSCP value for the outer layer dscp_out = self.DSCP_RANGE[self.dscp_out_idx] self.dscp_out_idx = (self.dscp_out_idx + 1) % len( self.DSCP_RANGE) # Next packet will use a different DSCP # TC for IPv6, ToS for IPv4 tc_out = tos_out = dscp_out << 2 if "pipe" == self.test_params['dscp_mode']: exp_tc = exp_tos = tc_in elif "uniform" == self.test_params['dscp_mode']: exp_tc = exp_tos = tc_out else: print("ERROR: no dscp is configured") exit() # Set TTL value for the outer layer if outer_ttl is None: outer_ttl = self.TTL_RANGE[self.ttl_out_idx] self.ttl_out_idx = (self.ttl_out_idx + 1) % len( self.TTL_RANGE) # Next packet will use a different TTL # Set TTL value for the inner layer if inner_ttl is None: inner_ttl = self.TTL_RANGE[self.ttl_in_idx] self.ttl_in_idx = (self.ttl_in_idx + 1) % len( self.TTL_RANGE) # Next packet will use a different TTL if "pipe" == self.test_params['ttl_mode']: exp_ttl = inner_ttl - 1 elif "uniform" == self.test_params["ttl_mode"]: exp_ttl = outer_ttl - 1 else: print("ERROR: unexpected ttl_mode is configured") exit() if ipaddress.ip_address(unicode(dst_ip)).version == 6: inner_src_ip = self.DEFAULT_INNER_V6_PKT_SRC_IP # build inner packet, if triple_encap is True inner_pkt would be double encapsulated inner_pkt = self.create_ipv6_inner_pkt_only(inner_src_ip, dst_ip, tos_in, triple_encap, hlim=inner_ttl) # build expected packet based on inner packet # set the correct L2 fields exp_pkt = scapy.Ether(dst=dst_mac, src=router_mac) / inner_pkt # set expected TC value exp_pkt['IPv6'].tc = exp_tc # decrement TTL exp_pkt['IPv6'].hlim = exp_ttl else: inner_src_ip = self.DEFAULT_INNER_V4_PKT_SRC_IP # build inner packet, if triple_encap is True inner_pkt would be double encapsulated inner_pkt = self.create_ipv4_inner_pkt_only(inner_src_ip, dst_ip, tos_in, triple_encap, ttl=inner_ttl) # build expected packet based on inner packet # set the correct L2 fields exp_pkt = scapy.Ether(dst=dst_mac, src=router_mac) / inner_pkt # set expected ToS value exp_pkt['IP'].tos = exp_tos # decrement TTL exp_pkt['IP'].ttl = exp_ttl if outer_pkt == 'ipv4': pkt = simple_ipv4ip_packet(eth_dst=router_mac, eth_src=src_mac, ip_src='1.1.1.1', ip_dst=self.test_params['lo_ip'], ip_tos=tos_out, ip_ttl=outer_ttl, inner_frame=inner_pkt) elif outer_pkt == 'ipv6': pkt = simple_ipv6ip_packet(eth_dst=router_mac, eth_src=src_mac, ipv6_src='1::1', ipv6_dst=self.test_params['lo_ipv6'], ipv6_tc=tc_out, ipv6_hlim=outer_ttl, inner_frame=inner_pkt) else: raise Exception("ERROR: invalid outer packet type ", outer_pkt) return pkt, exp_pkt
def icmp_filter(pkt_str): try: pkt = scapy.Ether(pkt_str) return (scapy.ICMP in pkt) except: return False