def create_packet_header_IPv6_SRH_L2(self, srcaddr, sidlist, segleft, vlan=0): """Create packet header: L2 encapsulated in SRv6: IPv6 header with SRH, L2 :param int srcaddr: IPv6 source address :param list sidlist: segment list of outer IPv6 SRH :param int segleft: segments-left field of outer IPv6 SRH :param vlan: L2 vlan; if vlan!=0 then add 802.1q header IPv6 source address is set to srcaddr IPv6 destination address is set to sidlist[segleft] """ eth = Ether(src='00:11:22:33:44:55', dst='00:55:44:33:22:11') etype = 0x8137 # IPX if vlan: # add 802.1q layer eth /= Dot1Q(vlan=vlan, type=etype) else: eth.type = etype p = IPv6(src=srcaddr, dst=sidlist[segleft]) / \ IPv6ExtHdrSegmentRouting(addresses=sidlist, segleft=segleft, nh=59) / \ eth return p
def create_stream(self, src_if=None, dst_if=None, packets=None, size=None, ip_ver='v4'): """Create a packet stream to tickle the plugin :param VppInterface src_if: Source interface for packet stream :param VppInterface src_if: Dst interface for packet stream """ if src_if is None: src_if = self.pg1 if dst_if is None: dst_if = self.pg2 self.pkts = [] if packets is None: packets = random.randint(1, self.max_number_of_packets) pkt_size = size for p in range(0, packets): if size is None: pkt_size = random.choice(self.pg_if_packet_sizes) info = self.create_packet_info(src_if, dst_if) payload = self.info_to_payload(info) p = Ether(src=src_if.remote_mac, dst=src_if.local_mac) if ip_ver == 'v4': p /= IP(src=src_if.remote_ip4, dst=dst_if.remote_ip4) else: p /= IPv6(src=src_if.remote_ip6, dst=dst_if.remote_ip6) p /= UDP(sport=1234, dport=4321) p /= Raw(payload) info.data = p.copy() self.extend_packet(p, pkt_size) self.pkts.append(p)
def test_from_frame(self): e = Ether(src='00:01:02:03:04:05', dst='AA:BB:CC:DD:EE:FF') e.add_payload("thisisapayload") frame = str(e) vx = VXLAN(frame=frame, vni=123) self.assertEqual(vx.vni, 123) self.assertEqual(str(vx), "\x08\x00\x00\x00\x00\x00\x7b\x00" + frame)
def send_frame(self, frame_body): PACKET = Ether() PACKET.length = 64 PACKET.dst = self.dst PACKET.src = self.getHwAddr(self.interface) if self.stag: # WARNING: September/2016: This should be 0x88a8, but the Intel 10G # hardware I am currently using does not support receiving a TPID of # 0x88a8. So, I send double CTAGs, and I usually set this to 0x8100. # (NOTE: The Intel hardware can send a TPID of 0x88a8) PACKET.type = 0x8100 if self.ctag: PACKET/=Dot1Q(type=0x8100,vlan=int(self.stag)) PACKET/=Dot1Q(type=self.etype,vlan=int(self.ctag)) else: PACKET/=Dot1Q(type=self.etype,vlan=int(self.stag)) else: if self.ctag: PACKET.type = 0x8100 PACKET/=Dot1Q(type=self.etype,vlan=int(self.ctag)) else: PACKET.type = self.etype # PACKET/=Dot1Q(type=self.etype, vlan=int(self.ctag)) PACKET/=SlowProtocolsSubtype()/FlagsBytes()/OAMPDU() PACKET/=frame_body PACKET/=EndOfPDU() if (self.verbose == True): PACKET.show() print '###[ Frame Length %d (before padding) ]###' % len(PACKET) if (self.hexdump == True): print hexdump(PACKET) if (self.dryrun != True): sendp(PACKET, iface=self.interface, verbose=self.verbose) time.sleep(self.sleep) return PACKET
def test_from_packet(self): e = Ether(src='00:01:02:03:04:05', dst='AA:BB:CC:DD:EE:FF') e.add_payload("thisisapayload") frame = str(e) packet = "\x08\x00\x00\x00\x00\x00\x7c\x00" + frame vx = VXLAN(packet=packet) self.assertEqual(vx.vni, 124) self.assertEqual(str(vx.frame), frame) self.assertEqual(str(vx), packet) self.assertEqual(vx.src_mac, "00:01:02:03:04:05") self.assertEqual(vx.dst_mac, "AA:BB:CC:DD:EE:FF")
def create_packet_header_L2(self, vlan=0): """Create packet header: L2 header :param vlan: if vlan!=0 then add 802.1q header """ # Note: the dst addr ('00:55:44:33:22:11') is used in # the compare function compare_rx_tx_packet_T_Encaps_L2 # to detect presence of L2 in SRH payload p = Ether(src='00:11:22:33:44:55', dst='00:55:44:33:22:11') etype = 0x8137 # IPX if vlan: # add 802.1q layer p /= Dot1Q(vlan=vlan, type=etype) else: p.type = etype return p
def create_stream(self, src_if, dst_if, packet_header, packet_sizes, count): """Create SRv6 input packet stream for defined interface. :param VppInterface src_if: Interface to create packet stream for :param VppInterface dst_if: destination interface of packet stream :param packet_header: Layer3 scapy packet headers, L2 is added when not provided, Raw(payload) with packet_info is added :param list packet_sizes: packet stream pckt sizes,sequentially applied to packets in stream have :param int count: number of packets in packet stream :return: list of packets """ self.logger.info("Creating packets") pkts = [] for i in range(0, count-1): payload_info = self.create_packet_info(src_if, dst_if) self.logger.debug( "Creating packet with index %d" % (payload_info.index)) payload = self.info_to_payload(payload_info) # add L2 header if not yet provided in packet_header if packet_header.getlayer(0).name == 'Ethernet': p = (packet_header / Raw(payload)) else: p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) / packet_header / Raw(payload)) size = packet_sizes[i % len(packet_sizes)] self.logger.debug("Packet size %d" % (size)) self.extend_packet(p, size) # we need to store the packet with the automatic fields computed # read back the dumped packet (with str()) # to force computing these fields # probably other ways are possible p = Ether(scapy.compat.raw(p)) payload_info.data = p.copy() self.logger.debug(ppp("Created packet:", p)) pkts.append(p) self.logger.info("Done creating packets") return pkts
def on_pkt_rx (self, pkt): scapy_pkt = Ether(pkt['binary']) if not 'ICMP' in scapy_pkt: return None #scapy_pkt.show2() ip = scapy_pkt['IP'] icmp = scapy_pkt['ICMP'] dt = pkt['ts'] - self.start_ts if icmp.type == 0: # echo reply return self.port.ok('Reply from {0}: bytes={1}, time={2:.2f}ms, TTL={3}'.format(ip.src, len(pkt['binary']), dt * 1000, ip.ttl)) # unreachable elif icmp.type == 3: return self.port.ok('Reply from {0}: Destination host unreachable'.format(icmp.src)) else: scapy_pkt.show2() return self.port.err('unknown ICMP reply')
def cpu_port_handler(self, packet, psock): eth = Ether(packet) if not self.running: raise Exception('stop') if not eth.haslayer(bgp.BGPUpdate): # Release the packet. psock.send(packet) return #log("Get BGP update packet: {}".format(eth.summary()), "yellow") update = eth[bgp.BGPUpdate] # Flag to determine whether this packet should be stopped. quarantine = False drop = False quarantine_key = None while True: # Check if this path_attr ends at a different AS compared to # known for this prefix, and if so, quarantine this BGP update packet. p = [ path_attr for path_attr in update.path_attr if path_attr.type_code == AS_PATH ] if len(p) > 0: s = [ path.segment_value for path in p[0].attribute.segments if path.segment_type == AS_SEQUENCE ] if len(s) > 0: # Get the destination AS in each sequence. Assert that they are all the same. dest = [seq[-1] for seq in s] assert (all(d == dest[0] for d in dest)) if dest[0] in self.blocked_as: log( "Dropping packet announcing blocked AS {}.".format( dest[0]), "red") drop = True break if dest[0] != 0: for dest_prefix in [ nlri.prefix for nlri in update.nlri ]: #print("Announcement for prefix {}:".format(dest_prefix)) #print(s) if dest_prefix.split('.')[0] == 9: continue # TODO: this skips the internal network. Should be fixed with CIDR below. if (dest[0], dest_prefix.split('.')[0] ) in self.quarantined: drop = True # Ignore this packet that's advertising a quarantined route. elif dest_prefix in self.routing_table and self.routing_table[ dest_prefix] != dest[0]: log( "Delay AS {} announcing prefix {}.".format( dest[0], dest_prefix), "red") # Ideally, we should look through all of the updates and notify all the # ASes being targeted in a single update. For now though, we only notify # the first, and similarly unblock the AS when this is done. # Hardcode the prefix to /8. This needs modification on the P4 side to support # proper CIDR. quarantine_key = (dest[0], dest_prefix.split('.')[0]) if not quarantine_key in self.allowed: quarantine = True break else: log("Route {}: {}".format(dest_prefix, s[0])) self.routing_table[dest_prefix] = dest[0] if not update.haslayer( bgp.BGPHeader) or not update[bgp.BGPHeader].haslayer( bgp.BGPUpdate): break else: # next update update = update[bgp.BGPHeader][bgp.BGPUpdate] if drop: pass # blackhole elif not quarantine: psock.send(packet) elif not quarantine_key in self.quarantined: self.quarantined[quarantine_key] = int( time.time()) + _QUARANTINE_EXPIRATION_SEC (gap, prefix) = quarantine_key self.add_slice(prefix, gap)
async def run_test(dut): tb = TB(dut) await tb.init() tb.log.info("test UDP RX packet") payload = bytes([x % 256 for x in range(256)]) eth = Ether(src='5a:51:52:53:54:55', dst='02:00:00:00:00:00') ip = IP(src='192.168.1.100', dst='192.168.1.128') udp = UDP(sport=5678, dport=1234) test_pkt = eth / ip / udp / payload test_frame = XgmiiFrame.from_payload(test_pkt.build()) await tb.qsfp_0_0_source.send(test_frame) tb.log.info("receive ARP request") rx_frame = await tb.qsfp_0_0_sink.recv() rx_pkt = Ether(bytes(rx_frame.get_payload())) tb.log.info("RX packet: %s", repr(rx_pkt)) assert rx_pkt.dst == 'ff:ff:ff:ff:ff:ff' assert rx_pkt.src == test_pkt.dst assert rx_pkt[ARP].hwtype == 1 assert rx_pkt[ARP].ptype == 0x0800 assert rx_pkt[ARP].hwlen == 6 assert rx_pkt[ARP].plen == 4 assert rx_pkt[ARP].op == 1 assert rx_pkt[ARP].hwsrc == test_pkt.dst assert rx_pkt[ARP].psrc == test_pkt[IP].dst assert rx_pkt[ARP].hwdst == '00:00:00:00:00:00' assert rx_pkt[ARP].pdst == test_pkt[IP].src tb.log.info("send ARP response") eth = Ether(src=test_pkt.src, dst=test_pkt.dst) arp = ARP(hwtype=1, ptype=0x0800, hwlen=6, plen=4, op=2, hwsrc=test_pkt.src, psrc=test_pkt[IP].src, hwdst=test_pkt.dst, pdst=test_pkt[IP].dst) resp_pkt = eth / arp resp_frame = XgmiiFrame.from_payload(resp_pkt.build()) await tb.qsfp_0_0_source.send(resp_frame) tb.log.info("receive UDP packet") rx_frame = await tb.qsfp_0_0_sink.recv() rx_pkt = Ether(bytes(rx_frame.get_payload())) tb.log.info("RX packet: %s", repr(rx_pkt)) assert rx_pkt.dst == test_pkt.src assert rx_pkt.src == test_pkt.dst assert rx_pkt[IP].dst == test_pkt[IP].src assert rx_pkt[IP].src == test_pkt[IP].dst assert rx_pkt[UDP].dport == test_pkt[UDP].sport assert rx_pkt[UDP].sport == test_pkt[UDP].dport assert rx_pkt[UDP].payload == test_pkt[UDP].payload await RisingEdge(dut.clk) await RisingEdge(dut.clk)
def test_gbp(self): """ Group Based Policy """ nat_table = VppIpTable(self, 20) nat_table.add_vpp_config() nat_table = VppIpTable(self, 20, is_ip6=True) nat_table.add_vpp_config() # # Bridge Domains # self.vapi.bridge_domain_add_del(1, flood=1, uu_flood=1, forward=1, learn=0, arp_term=1, is_add=1) self.vapi.bridge_domain_add_del(2, flood=1, uu_flood=1, forward=1, learn=0, arp_term=1, is_add=1) self.vapi.bridge_domain_add_del(20, flood=1, uu_flood=1, forward=1, learn=0, arp_term=1, is_add=1) # # 3 EPGs, 2 of which share a BD. # 2 NAT EPGs, one for floating-IP subnets, the other for internet # epgs = [ VppGbpEndpointGroup(self, 220, 0, 1, self.pg4, self.loop0, "10.0.0.128", "2001:10::128"), VppGbpEndpointGroup(self, 221, 0, 1, self.pg5, self.loop0, "10.0.1.128", "2001:10:1::128"), VppGbpEndpointGroup(self, 222, 0, 2, self.pg6, self.loop1, "10.0.2.128", "2001:10:2::128"), VppGbpEndpointGroup(self, 333, 20, 20, self.pg7, self.loop2, "11.0.0.128", "3001::128"), VppGbpEndpointGroup(self, 444, 20, 20, self.pg8, self.loop2, "11.0.0.129", "3001::129") ] recircs = [ VppGbpRecirc(self, epgs[0], self.loop3), VppGbpRecirc(self, epgs[1], self.loop4), VppGbpRecirc(self, epgs[2], self.loop5), VppGbpRecirc(self, epgs[3], self.loop6, is_ext=True), VppGbpRecirc(self, epgs[4], self.loop8, is_ext=True) ] epg_nat = epgs[3] recirc_nat = recircs[3] # # 4 end-points, 2 in the same subnet, 3 in the same BD # eps = [ VppGbpEndpoint(self, self.pg0, epgs[0], recircs[0], "10.0.0.1", "11.0.0.1", "2001:10::1", "3001::1"), VppGbpEndpoint(self, self.pg1, epgs[0], recircs[0], "10.0.0.2", "11.0.0.2", "2001:10::2", "3001::2"), VppGbpEndpoint(self, self.pg2, epgs[1], recircs[1], "10.0.1.1", "11.0.0.3", "2001:10:1::1", "3001::3"), VppGbpEndpoint(self, self.pg3, epgs[2], recircs[2], "10.0.2.1", "11.0.0.4", "2001:10:2::1", "3001::4") ] # # Config related to each of the EPGs # for epg in epgs: # IP config on the BVI interfaces if epg != epgs[1] and epg != epgs[4]: epg.bvi.set_table_ip4(epg.rd) epg.bvi.set_table_ip6(epg.rd) # The BVIs are NAT inside interfaces self.vapi.nat44_interface_add_del_feature(epg.bvi.sw_if_index, is_inside=1, is_add=1) self.vapi.nat66_add_del_interface(epg.bvi.sw_if_index, is_inside=1, is_add=1) self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index, epg.bvi_ip4_n, 32) self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index, epg.bvi_ip6_n, 128, is_ipv6=True) # EPG uplink interfaces in the BD epg.uplink.set_table_ip4(epg.rd) epg.uplink.set_table_ip6(epg.rd) self.vapi.sw_interface_set_l2_bridge(epg.uplink.sw_if_index, epg.bd) # add the BD ARP termination entry for BVI IP self.vapi.bd_ip_mac_add_del(bd_id=epg.bd, mac=mactobinary(self.router_mac), ip=epg.bvi_ip4_n, is_ipv6=0, is_add=1) self.vapi.bd_ip_mac_add_del(bd_id=epg.bd, mac=mactobinary(self.router_mac), ip=epg.bvi_ip6_n, is_ipv6=1, is_add=1) # epg[1] shares the same BVI to epg[0] if epg != epgs[1] and epg != epgs[4]: # BVI in BD self.vapi.sw_interface_set_l2_bridge( epg.bvi.sw_if_index, epg.bd, port_type=L2_PORT_TYPE.BVI) # BVI L2 FIB entry self.vapi.l2fib_add_del(self.router_mac, epg.bd, epg.bvi.sw_if_index, is_add=1, bvi_mac=1) # EPG in VPP epg.add_vpp_config() for recirc in recircs: # EPG's ingress recirculation interface maps to its RD recirc.recirc.set_table_ip4(recirc.epg.rd) recirc.recirc.set_table_ip6(recirc.epg.rd) # in the bridge to allow DVR. L2 emulation to punt to L3 self.vapi.sw_interface_set_l2_bridge(recirc.recirc.sw_if_index, recirc.epg.bd) self.vapi.sw_interface_set_l2_emulation(recirc.recirc.sw_if_index) self.vapi.nat44_interface_add_del_feature( recirc.recirc.sw_if_index, is_inside=0, is_add=1) self.vapi.nat66_add_del_interface(recirc.recirc.sw_if_index, is_inside=0, is_add=1) recirc.add_vpp_config() ep_routes = [] ep_arps = [] for ep in eps: self.pg_enable_capture(self.pg_interfaces) self.pg_start() # # routes to the endpoints. We need these since there are no # adj-fibs due to the fact the the BVI address has /32 and # the subnet is not attached. # for (ip, fip) in zip(ep.ips, ep.fips): r = VppIpRoute(self, ip.address, ip.length, [ VppRoutePath(ip.address, ep.epg.bvi.sw_if_index, proto=ip.dpo_proto) ], is_ip6=ip.is_ip6) r.add_vpp_config() ep_routes.append(r) # # ARP entries for the endpoints # a = VppNeighbor(self, ep.epg.bvi.sw_if_index, ep.itf.remote_mac, ip.address, af=ip.af) a.add_vpp_config() ep_arps.append(a) # add the BD ARP termination entry self.vapi.bd_ip_mac_add_del(bd_id=ep.epg.bd, mac=ep.bin_mac, ip=ip.bytes, is_ipv6=ip.is_ip6, is_add=1) # Add static mappings for each EP from the 10/8 to 11/8 network if ip.af == AF_INET: self.vapi.nat44_add_del_static_mapping(ip.bytes, fip.bytes, vrf_id=0, addr_only=1) else: self.vapi.nat66_add_del_static_mapping(ip.bytes, fip.bytes, vrf_id=0) # add each EP itf to the its BD self.vapi.sw_interface_set_l2_bridge(ep.itf.sw_if_index, ep.epg.bd) # L2 FIB entry self.vapi.l2fib_add_del(ep.mac, ep.epg.bd, ep.itf.sw_if_index, is_add=1) # VPP EP create ... ep.add_vpp_config() self.logger.info(self.vapi.cli("sh gbp endpoint")) # ... results in a Gratuitous ARP/ND on the EPG's uplink rx = ep.epg.uplink.get_capture(len(ep.ips), timeout=0.2) for ii, ip in enumerate(ep.ips): p = rx[ii] if ip.is_ip6: self.assertTrue(p.haslayer(ICMPv6ND_NA)) self.assertEqual(p[ICMPv6ND_NA].tgt, ip.address) else: self.assertTrue(p.haslayer(ARP)) self.assertEqual(p[ARP].psrc, ip.address) self.assertEqual(p[ARP].pdst, ip.address) # add the BD ARP termination entry for floating IP for fip in ep.fips: self.vapi.bd_ip_mac_add_del(bd_id=epg_nat.bd, mac=ep.bin_mac, ip=fip.bytes, is_ipv6=fip.is_ip6, is_add=1) # floating IPs route via EPG recirc r = VppIpRoute(self, fip.address, fip.length, [ VppRoutePath(fip.address, ep.recirc.recirc.sw_if_index, is_dvr=1, proto=fip.dpo_proto) ], table_id=20, is_ip6=fip.is_ip6) r.add_vpp_config() ep_routes.append(r) # L2 FIB entries in the NAT EPG BD to bridge the packets from # the outside direct to the internal EPG self.vapi.l2fib_add_del(ep.mac, epg_nat.bd, ep.recirc.recirc.sw_if_index, is_add=1) # # ARP packets for unknown IP are flooded # pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(op="who-has", hwdst="ff:ff:ff:ff:ff:ff", hwsrc=self.pg0.remote_mac, pdst=epgs[0].bvi_ip4, psrc="10.0.0.88")) self.send_and_expect(self.pg0, [pkt_arp], self.pg0) # # ARP/ND packets get a response # pkt_arp = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(op="who-has", hwdst="ff:ff:ff:ff:ff:ff", hwsrc=self.pg0.remote_mac, pdst=epgs[0].bvi_ip4, psrc=eps[0].ip4.address)) self.send_and_expect(self.pg0, [pkt_arp], self.pg0) nsma = in6_getnsma(inet_pton(AF_INET6, eps[0].ip6.address)) d = inet_ntop(AF_INET6, nsma) pkt_nd = (Ether(dst=in6_getnsmac(nsma)) / IPv6(dst=d, src=eps[0].ip6.address) / ICMPv6ND_NS(tgt=epgs[0].bvi_ip6) / ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)) self.send_and_expect(self.pg0, [pkt_nd], self.pg0) # # broadcast packets are flooded # pkt_bcast = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / IP(src=eps[0].ip4.address, dst="232.1.1.1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.vapi.cli("clear trace") self.pg0.add_stream(pkt_bcast) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rxd = eps[1].itf.get_capture(1) self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst) rxd = epgs[0].uplink.get_capture(1) self.assertEqual(rxd[0][Ether].dst, pkt_bcast[Ether].dst) # # packets to non-local L3 destinations dropped # pkt_intra_epg_220_ip4 = ( Ether(src=self.pg0.remote_mac, dst=self.router_mac) / IP(src=eps[0].ip4.address, dst="10.0.0.99") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pkt_inter_epg_222_ip4 = ( Ether(src=self.pg0.remote_mac, dst=self.router_mac) / IP(src=eps[0].ip4.address, dst="10.0.1.99") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_assert_no_replies(self.pg0, pkt_intra_epg_220_ip4 * 65) pkt_inter_epg_222_ip6 = ( Ether(src=self.pg0.remote_mac, dst=self.router_mac) / IPv6(src=eps[0].ip6.address, dst="2001:10::99") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_222_ip6 * 65) # # Add the subnet routes # s41 = VppGbpSubnet(self, 0, "10.0.0.0", 24) s42 = VppGbpSubnet(self, 0, "10.0.1.0", 24) s43 = VppGbpSubnet(self, 0, "10.0.2.0", 24) s41.add_vpp_config() s42.add_vpp_config() s43.add_vpp_config() s61 = VppGbpSubnet(self, 0, "2001:10::1", 64) s62 = VppGbpSubnet(self, 0, "2001:10:1::1", 64) s63 = VppGbpSubnet(self, 0, "2001:10:2::1", 64) s61.add_vpp_config() s62.add_vpp_config() s63.add_vpp_config() self.send_and_expect_bridged(self.pg0, pkt_intra_epg_220_ip4 * 65, self.pg4) self.send_and_expect_bridged(self.pg3, pkt_inter_epg_222_ip4 * 65, self.pg6) self.send_and_expect_bridged6(self.pg3, pkt_inter_epg_222_ip6 * 65, self.pg6) self.logger.info(self.vapi.cli("sh ip fib 11.0.0.2")) self.logger.info(self.vapi.cli("sh gbp endpoint-group")) self.logger.info(self.vapi.cli("sh gbp endpoint")) self.logger.info(self.vapi.cli("sh gbp recirc")) self.logger.info(self.vapi.cli("sh int")) self.logger.info(self.vapi.cli("sh int addr")) self.logger.info(self.vapi.cli("sh int feat loop6")) self.logger.info(self.vapi.cli("sh vlib graph ip4-gbp-src-classify")) self.logger.info(self.vapi.cli("sh int feat loop3")) # # Packet destined to unknown unicast is sent on the epg uplink ... # pkt_intra_epg_220_to_uplink = ( Ether(src=self.pg0.remote_mac, dst="00:00:00:33:44:55") / IP(src=eps[0].ip4.address, dst="10.0.0.99") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect_bridged(self.pg0, pkt_intra_epg_220_to_uplink * 65, self.pg4) # ... and nowhere else self.pg1.get_capture(0, timeout=0.1) self.pg1.assert_nothing_captured(remark="Flood onto other VMS") pkt_intra_epg_221_to_uplink = ( Ether(src=self.pg2.remote_mac, dst="00:00:00:33:44:66") / IP(src=eps[0].ip4.address, dst="10.0.0.99") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect_bridged(self.pg2, pkt_intra_epg_221_to_uplink * 65, self.pg5) # # Packets from the uplink are forwarded in the absence of a contract # pkt_intra_epg_220_from_uplink = ( Ether(src="00:00:00:33:44:55", dst=self.pg0.remote_mac) / IP(src=eps[0].ip4.address, dst="10.0.0.99") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect_bridged(self.pg4, pkt_intra_epg_220_from_uplink * 65, self.pg0) # # in the absence of policy, endpoints in the same EPG # can communicate # pkt_intra_epg = ( Ether(src=self.pg0.remote_mac, dst=self.pg1.remote_mac) / IP(src=eps[0].ip4.address, dst=eps[1].ip4.address) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect_bridged(self.pg0, pkt_intra_epg * 65, self.pg1) # # in the abscense of policy, endpoints in the different EPG # cannot communicate # pkt_inter_epg_220_to_221 = ( Ether(src=self.pg0.remote_mac, dst=self.pg2.remote_mac) / IP(src=eps[0].ip4.address, dst=eps[2].ip4.address) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pkt_inter_epg_221_to_220 = ( Ether(src=self.pg2.remote_mac, dst=self.pg0.remote_mac) / IP(src=eps[2].ip4.address, dst=eps[0].ip4.address) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pkt_inter_epg_220_to_222 = ( Ether(src=self.pg0.remote_mac, dst=self.router_mac) / IP(src=eps[0].ip4.address, dst=eps[3].ip4.address) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_220_to_221 * 65) self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_220_to_222 * 65) # # A uni-directional contract from EPG 220 -> 221 # acl = VppGbpAcl(self) rule = acl.create_rule(permit_deny=1, proto=17) rule2 = acl.create_rule(is_ipv6=1, permit_deny=1, proto=17) acl_index = acl.add_vpp_config([rule, rule2]) c1 = VppGbpContract(self, 220, 221, acl_index) c1.add_vpp_config() self.send_and_expect_bridged(self.pg0, pkt_inter_epg_220_to_221 * 65, self.pg2) self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_220_to_222 * 65) # # contract for the return direction # c2 = VppGbpContract(self, 221, 220, acl_index) c2.add_vpp_config() self.send_and_expect_bridged(self.pg0, pkt_inter_epg_220_to_221 * 65, self.pg2) self.send_and_expect_bridged(self.pg2, pkt_inter_epg_221_to_220 * 65, self.pg0) # # check that inter group is still disabled for the groups # not in the contract. # self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_220_to_222 * 65) # # A uni-directional contract from EPG 220 -> 222 'L3 routed' # c3 = VppGbpContract(self, 220, 222, acl_index) c3.add_vpp_config() self.logger.info(self.vapi.cli("sh gbp contract")) self.send_and_expect_routed(self.pg0, pkt_inter_epg_220_to_222 * 65, self.pg3, self.router_mac) # # remove both contracts, traffic stops in both directions # c2.remove_vpp_config() c1.remove_vpp_config() c3.remove_vpp_config() acl.remove_vpp_config() self.send_and_assert_no_replies(self.pg2, pkt_inter_epg_221_to_220 * 65) self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_220_to_221 * 65) self.send_and_expect_bridged(self.pg0, pkt_intra_epg * 65, self.pg1) # # EPs to the outside world # # in the EP's RD an external subnet via the NAT EPG's recirc se1 = VppGbpSubnet(self, 0, "0.0.0.0", 0, is_internal=False, sw_if_index=recirc_nat.recirc.sw_if_index, epg=epg_nat.epg) se1.add_vpp_config() se2 = VppGbpSubnet(self, 0, "11.0.0.0", 8, is_internal=False, sw_if_index=recirc_nat.recirc.sw_if_index, epg=epg_nat.epg) se2.add_vpp_config() se16 = VppGbpSubnet(self, 0, "::", 0, is_internal=False, sw_if_index=recirc_nat.recirc.sw_if_index, epg=epg_nat.epg) se16.add_vpp_config() # in the NAT RD an external subnet via the NAT EPG's uplink se3 = VppGbpSubnet(self, 20, "0.0.0.0", 0, is_internal=False, sw_if_index=epg_nat.uplink.sw_if_index, epg=epg_nat.epg) se36 = VppGbpSubnet(self, 20, "::", 0, is_internal=False, sw_if_index=epg_nat.uplink.sw_if_index, epg=epg_nat.epg) se4 = VppGbpSubnet(self, 20, "11.0.0.0", 8, is_internal=False, sw_if_index=epg_nat.uplink.sw_if_index, epg=epg_nat.epg) se3.add_vpp_config() se36.add_vpp_config() se4.add_vpp_config() self.logger.info(self.vapi.cli("sh ip fib 0.0.0.0/0")) self.logger.info(self.vapi.cli("sh ip fib 11.0.0.1")) self.logger.info(self.vapi.cli("sh ip6 fib ::/0")) self.logger.info(self.vapi.cli("sh ip6 fib %s" % eps[0].fip6)) # # From an EP to an outside addess: IN2OUT # pkt_inter_epg_220_to_global = ( Ether(src=self.pg0.remote_mac, dst=self.router_mac) / IP(src=eps[0].ip4.address, dst="1.1.1.1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) # no policy yet self.send_and_assert_no_replies(self.pg0, pkt_inter_epg_220_to_global * 65) acl2 = VppGbpAcl(self) rule = acl2.create_rule(permit_deny=1, proto=17, sport_from=1234, sport_to=1234, dport_from=1234, dport_to=1234) rule2 = acl2.create_rule(is_ipv6=1, permit_deny=1, proto=17, sport_from=1234, sport_to=1234, dport_from=1234, dport_to=1234) acl_index2 = acl2.add_vpp_config([rule, rule2]) c4 = VppGbpContract(self, 220, 333, acl_index2) c4.add_vpp_config() self.send_and_expect_natted(self.pg0, pkt_inter_epg_220_to_global * 65, self.pg7, eps[0].fip4.address) pkt_inter_epg_220_to_global = ( Ether(src=self.pg0.remote_mac, dst=self.router_mac) / IPv6(src=eps[0].ip6.address, dst="6001::1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect_natted6(self.pg0, pkt_inter_epg_220_to_global * 65, self.pg7, eps[0].fip6.address) # # From a global address to an EP: OUT2IN # pkt_inter_epg_220_from_global = ( Ether(src=self.router_mac, dst=self.pg0.remote_mac) / IP(dst=eps[0].fip4.address, src="1.1.1.1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_assert_no_replies(self.pg7, pkt_inter_epg_220_from_global * 65) c5 = VppGbpContract(self, 333, 220, acl_index2) c5.add_vpp_config() self.send_and_expect_unnatted(self.pg7, pkt_inter_epg_220_from_global * 65, eps[0].itf, eps[0].ip4.address) pkt_inter_epg_220_from_global = ( Ether(src=self.router_mac, dst=self.pg0.remote_mac) / IPv6(dst=eps[0].fip6.address, src="6001::1") / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect_unnatted6(self.pg7, pkt_inter_epg_220_from_global * 65, eps[0].itf, eps[0].ip6.address) # # From a local VM to another local VM using resp. public addresses: # IN2OUT2IN # pkt_intra_epg_220_global = ( Ether(src=self.pg0.remote_mac, dst=self.router_mac) / IP(src=eps[0].ip4.address, dst=eps[1].fip4.address) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect_double_natted(eps[0].itf, pkt_intra_epg_220_global * 65, eps[1].itf, eps[0].fip4.address, eps[1].ip4.address) pkt_intra_epg_220_global = ( Ether(src=self.pg0.remote_mac, dst=self.router_mac) / IPv6(src=eps[0].ip6.address, dst=eps[1].fip6.address) / UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) self.send_and_expect_double_natted6(eps[0].itf, pkt_intra_epg_220_global * 65, eps[1].itf, eps[0].fip6.address, eps[1].ip6.address) # # cleanup # for ep in eps: # del static mappings for each EP from the 10/8 to 11/8 network self.vapi.nat44_add_del_static_mapping(ep.ip4.bytes, ep.fip4.bytes, vrf_id=0, addr_only=1, is_add=0) self.vapi.nat66_add_del_static_mapping(ep.ip6.bytes, ep.fip6.bytes, vrf_id=0, is_add=0) for epg in epgs: # IP config on the BVI interfaces self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index, epg.bvi_ip4_n, 32, is_add=0) self.vapi.sw_interface_add_del_address(epg.bvi.sw_if_index, epg.bvi_ip6_n, 128, is_add=0, is_ipv6=True) self.logger.info(self.vapi.cli("sh int addr")) epg.uplink.set_table_ip4(0) epg.uplink.set_table_ip6(0) if epg != epgs[0] and epg != epgs[3]: epg.bvi.set_table_ip4(0) epg.bvi.set_table_ip6(0) self.vapi.nat44_interface_add_del_feature(epg.bvi.sw_if_index, is_inside=1, is_add=0) self.vapi.nat66_add_del_interface(epg.bvi.sw_if_index, is_inside=1, is_add=0) for recirc in recircs: recirc.recirc.set_table_ip4(0) recirc.recirc.set_table_ip6(0) self.vapi.nat44_interface_add_del_feature( recirc.recirc.sw_if_index, is_inside=0, is_add=0) self.vapi.nat66_add_del_interface(recirc.recirc.sw_if_index, is_inside=0, is_add=0)
def test_dhcp_proxy(self): """ DHCPv4 Proxy """ # # Verify no response to DHCP request without DHCP config # p_disc_vrf0 = ( Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / IP(src="0.0.0.0", dst="255.255.255.255") / UDP(sport=DHCP4_CLIENT_PORT, dport=DHCP4_SERVER_PORT) / BOOTP(op=1) / DHCP(options=[('message-type', 'discover'), ('end')])) pkts_disc_vrf0 = [p_disc_vrf0] p_disc_vrf1 = ( Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg3.remote_mac) / IP(src="0.0.0.0", dst="255.255.255.255") / UDP(sport=DHCP4_CLIENT_PORT, dport=DHCP4_SERVER_PORT) / BOOTP(op=1) / DHCP(options=[('message-type', 'discover'), ('end')])) pkts_disc_vrf1 = [p_disc_vrf0] self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0, "DHCP with no configuration") self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1, "DHCP with no configuration") # # Enable DHCP proxy in VRF 0 # server_addr = self.pg0.remote_ip4n src_addr = self.pg0.local_ip4n self.vapi.dhcp_proxy_config(server_addr, src_addr, rx_table_id=0) # # Discover packets from the client are dropped because there is no # IP address configured on the client facing interface # self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0, "Discover DHCP no relay address") # # Inject a response from the server # dropped, because there is no IP addrees on the # client interfce to fill in the option. # p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / BOOTP(op=1) / DHCP(options=[('message-type', 'offer'), ('end')])) pkts = [p] self.send_and_assert_no_replies(self.pg2, pkts, "Offer DHCP no relay address") # # configure an IP address on the client facing interface # self.pg2.config_ip4() # # Try again with a discover packet # Rx'd packet should be to the server address and from the configured # source address # UDP source ports are unchanged # we've no option 82 config so that should be absent # self.pg2.add_stream(pkts_disc_vrf0) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(1) rx = rx[0] option_82 = self.verify_relayed_dhcp_discover(rx, self.pg0, src_intf=self.pg2) # # Create an DHCP offer reply from the server with a correctly formatted # option 82. i.e. send back what we just captured # The offer, sent mcast to the client, still has option 82. # p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / BOOTP(op=1) / DHCP(options=[('message-type', 'offer'), ('relay_agent_Information', option_82), ('end')])) pkts = [p] self.pg0.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(1) rx = rx[0] self.verify_dhcp_offer(rx, self.pg2) # # Bogus Option 82: # # 1. not our IP address = not checked by VPP? so offer is replayed # to client bad_ip = option_82[0:8] + chr(33) + option_82[9:] p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / BOOTP(op=1) / DHCP(options=[('message-type', 'offer'), ('relay_agent_Information', bad_ip), ('end')])) pkts = [p] self.send_and_assert_no_replies(self.pg0, pkts, "DHCP offer option 82 bad address") # 2. Not a sw_if_index VPP knows bad_if_index = option_82[0:2] + chr(33) + option_82[3:] p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / BOOTP(op=1) / DHCP(options=[('message-type', 'offer'), ('relay_agent_Information', bad_if_index), ('end')])) pkts = [p] self.send_and_assert_no_replies(self.pg0, pkts, "DHCP offer option 82 bad if index") # # Send a DHCP request in VRF 1. should be dropped. # self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1, "DHCP with no configuration VRF 1") # # Delete the DHCP config in VRF 0 # Should now drop requests. # self.vapi.dhcp_proxy_config(server_addr, src_addr, rx_table_id=0, is_add=0) self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0, "DHCP config removed VRF 0") self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1, "DHCP config removed VRF 1") # # Add DHCP config for VRF 1 # server_addr = self.pg1.remote_ip4n src_addr = self.pg1.local_ip4n self.vapi.dhcp_proxy_config(server_addr, src_addr, rx_table_id=1, server_table_id=1) # # Confim DHCP requests ok in VRF 1. # - dropped on IP config on client interface # self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1, "DHCP config removed VRF 1") # # configure an IP address on the client facing interface # self.pg3.config_ip4() self.pg3.add_stream(pkts_disc_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) rx = rx[0] self.verify_relayed_dhcp_discover(rx, self.pg1, src_intf=self.pg3) # # Add VSS config # table=1, fib=id=1, oui=4 self.vapi.dhcp_proxy_set_vss(1, 1, 4) self.pg3.add_stream(pkts_disc_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) rx = rx[0] self.verify_relayed_dhcp_discover(rx, self.pg1, src_intf=self.pg3, fib_id=1, oui=4) # # Add a second DHCP server in VRF 1 # expect clients messages to be relay to both configured servers # self.pg1.generate_remote_hosts(2) server_addr2 = socket.inet_pton(AF_INET, self.pg1.remote_hosts[1].ip4) self.vapi.dhcp_proxy_config(server_addr2, src_addr, rx_table_id=1, server_table_id=1, is_add=1) # # We'll need an ARP entry for the server to send it packets # arp_entry = VppNeighbor(self, self.pg1.sw_if_index, self.pg1.remote_hosts[1].mac, self.pg1.remote_hosts[1].ip4) arp_entry.add_vpp_config() # # Send a discover from the client. expect two relayed messages # The frist packet is sent to the second server # We're not enforcing that here, it's just the way it is. # self.pg3.add_stream(pkts_disc_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(2) option_82 = self.verify_relayed_dhcp_discover( rx[0], self.pg1, src_intf=self.pg3, dst_mac=self.pg1.remote_hosts[1].mac, dst_ip=self.pg1.remote_hosts[1].ip4, fib_id=1, oui=4) self.verify_relayed_dhcp_discover(rx[1], self.pg1, src_intf=self.pg3, fib_id=1, oui=4) # # Send both packets back. Client gets both. # p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IP(src=self.pg1.remote_ip4, dst=self.pg1.local_ip4) / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / BOOTP(op=1) / DHCP(options=[('message-type', 'offer'), ('relay_agent_Information', option_82), ('end')])) p2 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IP(src=self.pg1.remote_hosts[1].ip4, dst=self.pg1.local_ip4) / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / BOOTP(op=1) / DHCP(options=[('message-type', 'offer'), ('relay_agent_Information', option_82), ('end')])) pkts = [p1, p2] self.pg1.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg3.get_capture(2) self.verify_dhcp_offer(rx[0], self.pg3, fib_id=1, oui=4) self.verify_dhcp_offer(rx[1], self.pg3, fib_id=1, oui=4) # # Ensure offers from non-servers are dropeed # p2 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IP(src="8.8.8.8", dst=self.pg1.local_ip4) / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_SERVER_PORT) / BOOTP(op=1) / DHCP(options=[('message-type', 'offer'), ('relay_agent_Information', option_82), ('end')])) self.send_and_assert_no_replies(self.pg1, p2, "DHCP offer from non-server") # # Ensure only the discover is sent to multiple servers # p_req_vrf1 = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg3.remote_mac) / IP(src="0.0.0.0", dst="255.255.255.255") / UDP(sport=DHCP4_CLIENT_PORT, dport=DHCP4_SERVER_PORT) / BOOTP(op=1) / DHCP(options=[('message-type', 'request'), ('end')])) self.pg3.add_stream(p_req_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) # # Remove the second DHCP server # self.vapi.dhcp_proxy_config(server_addr2, src_addr, rx_table_id=1, server_table_id=1, is_add=0) # # Test we can still relay with the first # self.pg3.add_stream(pkts_disc_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) rx = rx[0] self.verify_relayed_dhcp_discover(rx, self.pg1, src_intf=self.pg3, fib_id=1, oui=4) # # Remove the VSS config # relayed DHCP has default vlaues in the option. # self.vapi.dhcp_proxy_set_vss(1, 1, 4, is_add=0) self.pg3.add_stream(pkts_disc_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) rx = rx[0] self.verify_relayed_dhcp_discover(rx, self.pg1, src_intf=self.pg3) # # remove DHCP config to cleanup # self.vapi.dhcp_proxy_config(server_addr, src_addr, rx_table_id=1, server_table_id=1, is_add=0) self.send_and_assert_no_replies(self.pg2, pkts_disc_vrf0, "DHCP cleanup VRF 0") self.send_and_assert_no_replies(self.pg3, pkts_disc_vrf1, "DHCP cleanup VRF 1") self.pg2.unconfig_ip4() self.pg3.unconfig_ip4()
def test_qos_ip(self): """ QoS Mark/Record IP """ # # for table 1 map the n=0xff possible values of input QoS mark, # n to 1-n # output = [chr(0)] * 256 for i in range(0, 255): output[i] = chr(255 - i) os = ''.join(output) rows = [{ 'outputs': os }, { 'outputs': os }, { 'outputs': os }, { 'outputs': os }] self.vapi.qos_egress_map_update(1, rows) # # For table 2 (and up) use the value n for everything # output = [chr(2)] * 256 os = ''.join(output) rows = [{ 'outputs': os }, { 'outputs': os }, { 'outputs': os }, { 'outputs': os }] self.vapi.qos_egress_map_update(2, rows) output = [chr(3)] * 256 os = ''.join(output) rows = [{ 'outputs': os }, { 'outputs': os }, { 'outputs': os }, { 'outputs': os }] self.vapi.qos_egress_map_update(3, rows) output = [chr(4)] * 256 os = ''.join(output) rows = [{ 'outputs': os }, { 'outputs': os }, { 'outputs': os }, { 'outputs': os }] self.vapi.qos_egress_map_update(4, rows) self.vapi.qos_egress_map_update(5, rows) self.vapi.qos_egress_map_update(6, rows) self.vapi.qos_egress_map_update(7, rows) self.logger.info(self.vapi.cli("sh qos eg map")) # # Bind interface pgN to table n # self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.IP, 1, 1) self.vapi.qos_mark_enable_disable(self.pg2.sw_if_index, QOS_SOURCE.IP, 2, 1) self.vapi.qos_mark_enable_disable(self.pg3.sw_if_index, QOS_SOURCE.IP, 3, 1) self.vapi.qos_mark_enable_disable(self.pg4.sw_if_index, QOS_SOURCE.IP, 4, 1) # # packets ingress on Pg0 # p_v4 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, tos=1) / UDP(sport=1234, dport=1234) / Raw(chr(100) * 65)) p_v6 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6, tc=1) / UDP(sport=1234, dport=1234) / Raw(chr(100) * 65)) # # Since we have not yet enabled the recording of the input QoS # from the input iP header, the egress packet's ToS will be unchanged # rx = self.send_and_expect(self.pg0, p_v4 * 65, self.pg1) for p in rx: self.assertEqual(p[IP].tos, 1) rx = self.send_and_expect(self.pg0, p_v6 * 65, self.pg1) for p in rx: self.assertEqual(p[IPv6].tc, 1) # # Enable QoS recrding on IP input for pg0 # self.vapi.qos_record_enable_disable(self.pg0.sw_if_index, QOS_SOURCE.IP, 1) # # send the same packets, this time expect the input TOS of 1 # to be mapped to pg1's egress value of 254 # rx = self.send_and_expect(self.pg0, p_v4 * 65, self.pg1) for p in rx: self.assertEqual(p[IP].tos, 254) rx = self.send_and_expect(self.pg0, p_v6 * 65, self.pg1) for p in rx: self.assertEqual(p[IPv6].tc, 254) # # different input ToS to test the mapping # p_v4[IP].tos = 127 rx = self.send_and_expect(self.pg0, p_v4 * 65, self.pg1) for p in rx: self.assertEqual(p[IP].tos, 128) p_v6[IPv6].tc = 127 rx = self.send_and_expect(self.pg0, p_v6 * 65, self.pg1) for p in rx: self.assertEqual(p[IPv6].tc, 128) p_v4[IP].tos = 254 rx = self.send_and_expect(self.pg0, p_v4 * 65, self.pg1) for p in rx: self.assertEqual(p[IP].tos, 1) p_v6[IPv6].tc = 254 rx = self.send_and_expect(self.pg0, p_v6 * 65, self.pg1) for p in rx: self.assertEqual(p[IPv6].tc, 1) # # send packets out the other interfaces to test the maps are # correctly applied # p_v4[IP].dst = self.pg2.remote_ip4 rx = self.send_and_expect(self.pg0, p_v4 * 65, self.pg2) for p in rx: self.assertEqual(p[IP].tos, 2) p_v4[IP].dst = self.pg3.remote_ip4 rx = self.send_and_expect(self.pg0, p_v4 * 65, self.pg3) for p in rx: self.assertEqual(p[IP].tos, 3) p_v6[IPv6].dst = self.pg3.remote_ip6 rx = self.send_and_expect(self.pg0, p_v6 * 65, self.pg3) for p in rx: self.assertEqual(p[IPv6].tc, 3) # # remove the map on pg2 and pg3, now expect an unchanged IP tos # self.vapi.qos_mark_enable_disable(self.pg2.sw_if_index, QOS_SOURCE.IP, 2, 0) self.vapi.qos_mark_enable_disable(self.pg3.sw_if_index, QOS_SOURCE.IP, 3, 0) self.logger.info(self.vapi.cli("sh int feat pg2")) p_v4[IP].dst = self.pg2.remote_ip4 rx = self.send_and_expect(self.pg0, p_v4 * 65, self.pg2) for p in rx: self.assertEqual(p[IP].tos, 254) p_v4[IP].dst = self.pg3.remote_ip4 rx = self.send_and_expect(self.pg0, p_v4 * 65, self.pg3) for p in rx: self.assertEqual(p[IP].tos, 254) # # still mapping out of pg1 # p_v4[IP].dst = self.pg1.remote_ip4 rx = self.send_and_expect(self.pg0, p_v4 * 65, self.pg1) for p in rx: self.assertEqual(p[IP].tos, 1) # # disable the input recording on pg0 # self.vapi.qos_record_enable_disable(self.pg0.sw_if_index, QOS_SOURCE.IP, 0) # # back to an unchanged TOS value # rx = self.send_and_expect(self.pg0, p_v4 * 65, self.pg1) for p in rx: self.assertEqual(p[IP].tos, 254) # # disable the egress map on pg1 and pg4 # self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.IP, 1, 0) self.vapi.qos_mark_enable_disable(self.pg4.sw_if_index, QOS_SOURCE.IP, 4, 0) # # unchanged Tos on pg1 # rx = self.send_and_expect(self.pg0, p_v4 * 65, self.pg1) for p in rx: self.assertEqual(p[IP].tos, 254) # # clean-up the masp # self.vapi.qos_egress_map_delete(1) self.vapi.qos_egress_map_delete(4) self.vapi.qos_egress_map_delete(2) self.vapi.qos_egress_map_delete(3) self.vapi.qos_egress_map_delete(5) self.vapi.qos_egress_map_delete(6) self.vapi.qos_egress_map_delete(7)
def test_qos_mpls(self): """ QoS Mark/Record MPLS """ # # 255 QoS for all input values # from_ext = 7 from_ip = 6 from_mpls = 5 from_vlan = 4 output = [chr(from_ext)] * 256 os1 = ''.join(output) output = [chr(from_vlan)] * 256 os2 = ''.join(output) output = [chr(from_mpls)] * 256 os3 = ''.join(output) output = [chr(from_ip)] * 256 os4 = ''.join(output) rows = [{ 'outputs': os1 }, { 'outputs': os2 }, { 'outputs': os3 }, { 'outputs': os4 }] self.vapi.qos_egress_map_update(1, rows) # # a route with 1 MPLS label # route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32, [ VppRoutePath( self.pg1.remote_ip4, self.pg1.sw_if_index, labels=[32]) ]) route_10_0_0_1.add_vpp_config() # # a route with 3 MPLS labels # route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32, [ VppRoutePath( self.pg1.remote_ip4, self.pg1.sw_if_index, labels=[63, 33, 34]) ]) route_10_0_0_3.add_vpp_config() # # enable IP QoS recording on the input Pg0 and MPLS egress marking # on Pg1 # self.vapi.qos_record_enable_disable(self.pg0.sw_if_index, QOS_SOURCE.IP, 1) self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.MPLS, 1, 1) # # packet that will get one label added and 3 labels added resp. # p_1 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst="10.0.0.1", tos=1) / UDP(sport=1234, dport=1234) / Raw(chr(100) * 65)) p_3 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst="10.0.0.3", tos=1) / UDP(sport=1234, dport=1234) / Raw(chr(100) * 65)) rx = self.send_and_expect(self.pg0, p_1 * 65, self.pg1) # # only 3 bits of ToS value in MPLS make sure tos is correct # and the label and EOS bit have not been corrupted # for p in rx: self.assertEqual(p[MPLS].cos, from_ip) self.assertEqual(p[MPLS].label, 32) self.assertEqual(p[MPLS].s, 1) rx = self.send_and_expect(self.pg0, p_3 * 65, self.pg1) for p in rx: self.assertEqual(p[MPLS].cos, from_ip) self.assertEqual(p[MPLS].label, 63) self.assertEqual(p[MPLS].s, 0) h = p[MPLS].payload self.assertEqual(h[MPLS].cos, from_ip) self.assertEqual(h[MPLS].label, 33) self.assertEqual(h[MPLS].s, 0) h = h[MPLS].payload self.assertEqual(h[MPLS].cos, from_ip) self.assertEqual(h[MPLS].label, 34) self.assertEqual(h[MPLS].s, 1) # # enable MPLS QoS recording on the input Pg0 and IP egress marking # on Pg1 # self.vapi.qos_record_enable_disable(self.pg0.sw_if_index, QOS_SOURCE.MPLS, 1) self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.IP, 1, 1) # # MPLS x-connect - COS according to pg1 map # route_32_eos = VppMplsRoute(self, 32, 1, [ VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index, labels=[VppMplsLabel(33)]) ]) route_32_eos.add_vpp_config() p_m1 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / MPLS(label=32, cos=3, ttl=2) / IP(src=self.pg0.remote_ip4, dst="10.0.0.1", tos=1) / UDP(sport=1234, dport=1234) / Raw(chr(100) * 65)) rx = self.send_and_expect(self.pg0, p_m1 * 65, self.pg1) for p in rx: self.assertEqual(p[MPLS].cos, from_mpls) self.assertEqual(p[MPLS].label, 33) self.assertEqual(p[MPLS].s, 1) # # MPLS deag - COS is copied from MPLS to IP # route_33_eos = VppMplsRoute( self, 33, 1, [VppRoutePath("0.0.0.0", 0xffffffff, nh_table_id=0)]) route_33_eos.add_vpp_config() route_10_0_0_4 = VppIpRoute( self, "10.0.0.4", 32, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)]) route_10_0_0_4.add_vpp_config() p_m2 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / MPLS(label=33, ttl=2, cos=3) / IP(src=self.pg0.remote_ip4, dst="10.0.0.4", tos=1) / UDP(sport=1234, dport=1234) / Raw(chr(100) * 65)) rx = self.send_and_expect(self.pg0, p_m2 * 65, self.pg1) for p in rx: self.assertEqual(p[IP].tos, from_mpls) # # cleanup # self.vapi.qos_record_enable_disable(self.pg0.sw_if_index, QOS_SOURCE.IP, 0) self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.MPLS, 1, 0) self.vapi.qos_record_enable_disable(self.pg0.sw_if_index, QOS_SOURCE.MPLS, 0) self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.IP, 1, 0) self.vapi.qos_egress_map_delete(1)
def test_dvr(self): """Distributed Virtual Router""" # # A packet destined to an IP address that is L2 bridged via # a non-tag interface # ip_non_tag_bridged = "10.10.10.10" ip_tag_bridged = "10.10.10.11" any_src_addr = "1.1.1.1" pkt_no_tag = ( Ether(src=self.pg0.remote_mac, dst=self.loop0.local_mac) / IP(src=any_src_addr, dst=ip_non_tag_bridged) / UDP(sport=1234, dport=1234) / Raw(b"\xa5" * 100)) pkt_tag = (Ether(src=self.pg0.remote_mac, dst=self.loop0.local_mac) / IP(src=any_src_addr, dst=ip_tag_bridged) / UDP(sport=1234, dport=1234) / Raw(b"\xa5" * 100)) # # Two sub-interfaces so we can test VLAN tag push/pop # sub_if_on_pg2 = VppDot1QSubint(self, self.pg2, 92) sub_if_on_pg3 = VppDot1QSubint(self, self.pg3, 93) sub_if_on_pg2.admin_up() sub_if_on_pg3.admin_up() # # Put all the interfaces into a new bridge domain # self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg0.sw_if_index, bd_id=1) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg1.sw_if_index, bd_id=1) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=sub_if_on_pg2.sw_if_index, bd_id=1) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=sub_if_on_pg3.sw_if_index, bd_id=1) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.loop0.sw_if_index, bd_id=1, port_type=L2_PORT_TYPE.BVI) self.vapi.l2_interface_vlan_tag_rewrite( sw_if_index=sub_if_on_pg2.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1, push_dot1q=92, ) self.vapi.l2_interface_vlan_tag_rewrite( sw_if_index=sub_if_on_pg3.sw_if_index, vtr_op=L2_VTR_OP.L2_POP_1, push_dot1q=93, ) # # Add routes to bridge the traffic via a tagged an nontagged interface # route_no_tag = VppIpRoute( self, ip_non_tag_bridged, 32, [ VppRoutePath("0.0.0.0", self.pg1.sw_if_index, type=FibPathType.FIB_PATH_TYPE_DVR) ], ) route_no_tag.add_vpp_config() # # Inject the packet that arrives and leaves on a non-tagged interface # Since it's 'bridged' expect that the MAC headed is unchanged. # rx = self.send_and_expect(self.pg0, pkt_no_tag * NUM_PKTS, self.pg1) self.assert_same_mac_addr(pkt_no_tag, rx) self.assert_has_no_tag(rx) # # Add routes to bridge the traffic via a tagged interface # route_with_tag = VppIpRoute( self, ip_tag_bridged, 32, [ VppRoutePath( "0.0.0.0", sub_if_on_pg3.sw_if_index, type=FibPathType.FIB_PATH_TYPE_DVR, ) ], ) route_with_tag.add_vpp_config() # # Inject the packet that arrives non-tag and leaves on a tagged # interface # rx = self.send_and_expect(self.pg0, pkt_tag * NUM_PKTS, self.pg3) self.assert_same_mac_addr(pkt_tag, rx) self.assert_has_vlan_tag(93, rx) # # Tag to tag # pkt_tag_to_tag = ( Ether(src=self.pg2.remote_mac, dst=self.loop0.local_mac) / Dot1Q(vlan=92) / IP(src=any_src_addr, dst=ip_tag_bridged) / UDP(sport=1234, dport=1234) / Raw(b"\xa5" * 100)) rx = self.send_and_expect(self.pg2, pkt_tag_to_tag * NUM_PKTS, self.pg3) self.assert_same_mac_addr(pkt_tag_to_tag, rx) self.assert_has_vlan_tag(93, rx) # # Tag to non-Tag # pkt_tag_to_non_tag = ( Ether(src=self.pg2.remote_mac, dst=self.loop0.local_mac) / Dot1Q(vlan=92) / IP(src=any_src_addr, dst=ip_non_tag_bridged) / UDP(sport=1234, dport=1234) / Raw(b"\xa5" * 100)) rx = self.send_and_expect(self.pg2, pkt_tag_to_non_tag * NUM_PKTS, self.pg1) self.assert_same_mac_addr(pkt_tag_to_tag, rx) self.assert_has_no_tag(rx) # # Add an output L3 ACL that will block the traffic # rule_1 = AclRule( is_permit=0, proto=17, ports=1234, src_prefix=IPv4Network((any_src_addr, 32)), dst_prefix=IPv4Network((ip_non_tag_bridged, 32)), ) acl = VppAcl(self, rules=[rule_1]) acl.add_vpp_config() # # Apply the ACL on the output interface # acl_if1 = VppAclInterface(self, sw_if_index=self.pg1.sw_if_index, n_input=0, acls=[acl]) acl_if1.add_vpp_config() # # Send packet's that should match the ACL and be dropped # rx = self.send_and_assert_no_replies(self.pg2, pkt_tag_to_non_tag * NUM_PKTS) # # cleanup # acl_if1.remove_vpp_config() acl.remove_vpp_config() self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg0.sw_if_index, bd_id=1, enable=0) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg1.sw_if_index, bd_id=1, enable=0) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=sub_if_on_pg2.sw_if_index, bd_id=1, enable=0) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=sub_if_on_pg3.sw_if_index, bd_id=1, enable=0) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.loop0.sw_if_index, bd_id=1, port_type=L2_PORT_TYPE.BVI, enable=0, ) # # Do a FIB dump to make sure the paths are correctly reported as DVR # routes = self.vapi.ip_route_dump(0) for r in routes: if ip_tag_bridged == str(r.route.prefix.network_address): self.assertEqual(r.route.paths[0].sw_if_index, sub_if_on_pg3.sw_if_index) self.assertEqual(r.route.paths[0].type, FibPathType.FIB_PATH_TYPE_DVR) if ip_non_tag_bridged == str(r.route.prefix.network_address): self.assertEqual(r.route.paths[0].sw_if_index, self.pg1.sw_if_index) self.assertEqual(r.route.paths[0].type, FibPathType.FIB_PATH_TYPE_DVR) # # the explicit route delete is require so it happens before # the sbu-interface delete. subinterface delete is required # because that object type does not use the object registry # route_no_tag.remove_vpp_config() route_with_tag.remove_vpp_config() sub_if_on_pg3.remove_vpp_config() sub_if_on_pg2.remove_vpp_config()
def gen_pkts(self, sw_intf, src, dst, count=1, payload_size=100): return [ Ether(dst=self.omac) / IP(src="1.1.1.1", dst="1.1.1.2") / UDP(sport=1144, dport=2233) / Raw('X' * payload_size) for i in range(count) ]
def test_svs4(self): """ Source VRF Select IP4 """ # # packets destined out of the 3 non-default table interfaces # pkts_0 = [(Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src="1.1.1.1", dst=self.pg1.remote_ip4) / UDP(sport=1234, dport=1234) / Raw(b'\xa5' * 100)), (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src="2.2.2.2", dst=self.pg2.remote_ip4) / UDP(sport=1234, dport=1234) / Raw(b'\xa5' * 100)), (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src="3.3.3.3", dst=self.pg3.remote_ip4) / UDP(sport=1234, dport=1234) / Raw(b'\xa5' * 100))] pkts_1 = [(Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IP(src="1.1.1.1", dst=self.pg1.remote_ip4) / UDP(sport=1234, dport=1234) / Raw(b'\xa5' * 100)), (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IP(src="2.2.2.2", dst=self.pg2.remote_ip4) / UDP(sport=1234, dport=1234) / Raw(b'\xa5' * 100)), (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IP(src="3.3.3.3", dst=self.pg3.remote_ip4) / UDP(sport=1234, dport=1234) / Raw(b'\xa5' * 100))] # # before adding the SVS config all these packets are dropped when # ingressing on pg0 since pg0 is in the default table # for p in pkts_0: self.send_and_assert_no_replies(self.pg0, p * 1) # # Add table 1001 & 1002 into which we'll add the routes # determining the source VRF selection # table_ids = [101, 102] for table_id in table_ids: self.vapi.svs_table_add_del( VppEnum.vl_api_address_family_t.ADDRESS_IP4, table_id) # # map X.0.0.0/8 to each SVS table for lookup in table X # for i in range(1, 4): self.vapi.svs_route_add_del(table_id, "%d.0.0.0/8" % i, i) # # Enable SVS on pg0/pg1 using table 1001/1002 # self.vapi.svs_enable_disable( VppEnum.vl_api_address_family_t.ADDRESS_IP4, table_ids[0], self.pg0.sw_if_index) self.vapi.svs_enable_disable( VppEnum.vl_api_address_family_t.ADDRESS_IP4, table_ids[1], self.pg1.sw_if_index) # # now all the packets should be delivered out the respective interface # self.send_and_expect(self.pg0, pkts_0[0] * NUM_PKTS, self.pg1) self.send_and_expect(self.pg0, pkts_0[1] * NUM_PKTS, self.pg2) self.send_and_expect(self.pg0, pkts_0[2] * NUM_PKTS, self.pg3) self.send_and_expect(self.pg1, pkts_1[0] * NUM_PKTS, self.pg1) self.send_and_expect(self.pg1, pkts_1[1] * NUM_PKTS, self.pg2) self.send_and_expect(self.pg1, pkts_1[2] * NUM_PKTS, self.pg3) # # check that if the SVS lookup does not match a route the packet # is forwarded using the interface's routing table # p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg0.remote_ip4) / UDP(sport=1234, dport=1234) / Raw(b'\xa5' * 100)) self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg0) p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IP(src=self.pg1.remote_ip4, dst=self.pg1.remote_ip4) / UDP(sport=1234, dport=1234) / Raw(b'\xa5' * 100)) self.send_and_expect(self.pg1, p * NUM_PKTS, self.pg1) # # dump the SVS configs # ss = self.vapi.svs_dump() self.assertEqual(ss[0].table_id, table_ids[0]) self.assertEqual(ss[0].sw_if_index, self.pg0.sw_if_index) self.assertEqual(ss[0].af, VppEnum.vl_api_address_family_t.ADDRESS_IP4) self.assertEqual(ss[1].table_id, table_ids[1]) self.assertEqual(ss[1].sw_if_index, self.pg1.sw_if_index) self.assertEqual(ss[1].af, VppEnum.vl_api_address_family_t.ADDRESS_IP4) # # cleanup # self.vapi.svs_enable_disable( VppEnum.vl_api_address_family_t.ADDRESS_IP4, table_ids[0], self.pg0.sw_if_index, is_enable=0) self.vapi.svs_enable_disable( VppEnum.vl_api_address_family_t.ADDRESS_IP4, table_ids[1], self.pg1.sw_if_index, is_enable=0) for table_id in table_ids: for i in range(1, 4): self.vapi.svs_route_add_del(table_id, "%d.0.0.0/8" % i, 0, is_add=0) self.vapi.svs_table_add_del( VppEnum.vl_api_address_family_t.ADDRESS_IP4, table_id, is_add=0)
async def run_test(dut, idle_inserter=None, backpressure_inserter=None): tb = TB(dut) await tb.reset() tb.set_idle_generator(idle_inserter) tb.set_backpressure_generator(backpressure_inserter) local_mac = 'DA:D1:D2:D3:D4:D5' local_ip = '192.168.1.101' gateway_ip = '192.168.1.1' subnet_mask = '255.255.255.0' dut.local_mac.value = int.from_bytes(mac2str(local_mac), 'big') dut.local_ip.value = atol(local_ip) dut.gateway_ip.value = atol(gateway_ip) dut.subnet_mask.value = atol(subnet_mask) for k in range(10): await RisingEdge(dut.clk) tb.log.info("test ARP request") eth = Ether(src='5A:51:52:53:54:55', dst='FF:FF:FF:FF:FF:FF') arp = ARP(hwtype=1, ptype=0x0800, hwlen=6, plen=4, op=1, hwsrc='5A:51:52:53:54:55', psrc='192.168.1.100', hwdst='00:00:00:00:00:00', pdst='192.168.1.101') test_pkt = eth / arp await tb.send(test_pkt) rx_pkt = await tb.recv() tb.log.info("RX packet: %s", repr(rx_pkt)) assert rx_pkt[Ether].dst.casefold() == test_pkt[Ether].src.casefold() assert rx_pkt[Ether].src.casefold() == local_mac.casefold() assert rx_pkt[Ether].type == test_pkt[Ether].type assert rx_pkt[ARP].hwtype == test_pkt[Ether].hwtype assert rx_pkt[ARP].ptype == test_pkt[Ether].ptype assert rx_pkt[ARP].hwlen == test_pkt[Ether].hwlen assert rx_pkt[ARP].plen == test_pkt[Ether].plen assert rx_pkt[ARP].op == 2 assert rx_pkt[ARP].hwsrc.casefold() == local_mac.casefold() assert rx_pkt[ARP].psrc == local_ip assert rx_pkt[ARP].hwdst.casefold() == test_pkt[ARP].hwsrc.casefold() assert rx_pkt[ARP].pdst == test_pkt[ARP].psrc tb.log.info("Cached read") await tb.arp_req_source.send(ArpReqTransaction(ip=atol('192.168.1.100'))) resp = await tb.arp_resp_sink.recv() tb.log.info("Read value: %s", resp) assert not resp.error assert resp.mac == int.from_bytes(mac2str(test_pkt[Ether].src), 'big') tb.log.info("Uncached read, inside subnet") await tb.arp_req_source.send(ArpReqTransaction(ip=atol('192.168.1.102'))) # wait for ARP request rx_pkt = await tb.recv() tb.log.info("RX packet: %s", repr(rx_pkt)) assert rx_pkt[Ether].dst.casefold() == "ff:ff:ff:ff:ff:ff".casefold() assert rx_pkt[Ether].src.casefold() == local_mac.casefold() assert rx_pkt[Ether].type == 0x0806 assert rx_pkt[ARP].hwtype == 0x0001 assert rx_pkt[ARP].ptype == 0x0800 assert rx_pkt[ARP].hwlen == 6 assert rx_pkt[ARP].plen == 4 assert rx_pkt[ARP].op == 1 assert rx_pkt[ARP].hwsrc.casefold() == local_mac.casefold() assert rx_pkt[ARP].psrc == local_ip assert rx_pkt[ARP].hwdst.casefold() == "00:00:00:00:00:00".casefold() assert rx_pkt[ARP].pdst == '192.168.1.102' # generate response eth = Ether(src='6A:61:62:63:64:65', dst=local_mac) arp = ARP(hwtype=1, ptype=0x0800, hwlen=6, plen=4, op=2, hwsrc='6A:61:62:63:64:65', psrc='192.168.1.102', hwdst=local_mac, pdst=local_ip) test_pkt = eth / arp await tb.send(test_pkt) resp = await tb.arp_resp_sink.recv() tb.log.info("Read value: %s", resp) assert not resp.error assert resp.mac == int.from_bytes(mac2str(test_pkt[Ether].src), 'big') tb.log.info("Uncached read, outside of subnet") await tb.arp_req_source.send(ArpReqTransaction(ip=atol('8.8.8.8'))) # wait for ARP request rx_pkt = await tb.recv() tb.log.info("RX packet: %s", repr(rx_pkt)) assert rx_pkt[Ether].dst.casefold() == "ff:ff:ff:ff:ff:ff".casefold() assert rx_pkt[Ether].src.casefold() == local_mac.casefold() assert rx_pkt[Ether].type == 0x0806 assert rx_pkt[ARP].hwtype == 0x0001 assert rx_pkt[ARP].ptype == 0x0800 assert rx_pkt[ARP].hwlen == 6 assert rx_pkt[ARP].plen == 4 assert rx_pkt[ARP].op == 1 assert rx_pkt[ARP].hwsrc.casefold() == local_mac.casefold() assert rx_pkt[ARP].psrc == local_ip assert rx_pkt[ARP].hwdst.casefold() == "00:00:00:00:00:00".casefold() assert rx_pkt[ARP].pdst == gateway_ip # generate response eth = Ether(src='AA:BB:CC:DD:EE:FF', dst=local_mac) arp = ARP(hwtype=1, ptype=0x0800, hwlen=6, plen=4, op=2, hwsrc='AA:BB:CC:DD:EE:FF', psrc='192.168.1.1', hwdst=local_mac, pdst=local_ip) test_pkt = eth / arp await tb.send(test_pkt) resp = await tb.arp_resp_sink.recv() tb.log.info("Read value: %s", resp) assert not resp.error assert resp.mac == int.from_bytes(mac2str(test_pkt[Ether].src), 'big') tb.log.info("Uncached read, timeout") await tb.arp_req_source.send(ArpReqTransaction(ip=atol('192.168.1.103'))) # wait for ARP request for k in range(4): rx_pkt = await tb.recv() tb.log.info("RX packet: %s", repr(rx_pkt)) assert rx_pkt[Ether].dst.casefold() == "ff:ff:ff:ff:ff:ff".casefold() assert rx_pkt[Ether].src.casefold() == local_mac.casefold() assert rx_pkt[Ether].type == 0x0806 assert rx_pkt[ARP].hwtype == 0x0001 assert rx_pkt[ARP].ptype == 0x0800 assert rx_pkt[ARP].hwlen == 6 assert rx_pkt[ARP].plen == 4 assert rx_pkt[ARP].op == 1 assert rx_pkt[ARP].hwsrc.casefold() == local_mac.casefold() assert rx_pkt[ARP].psrc == local_ip assert rx_pkt[ARP].hwdst.casefold() == "00:00:00:00:00:00".casefold() assert rx_pkt[ARP].pdst == '192.168.1.103' resp = await tb.arp_resp_sink.recv() tb.log.info("Read value: %s", resp) assert resp.error tb.log.info("Broadcast") await tb.arp_req_source.send(ArpReqTransaction(ip=atol('192.168.1.255'))) resp = await tb.arp_resp_sink.recv() tb.log.info("Read value: %s", resp) assert not resp.error assert resp.mac == int.from_bytes(mac2str('FF:FF:FF:FF:FF:FF'), 'big') await tb.arp_req_source.send(ArpReqTransaction(ip=atol('255.255.255.255'))) resp = await tb.arp_resp_sink.recv() tb.log.info("Read value: %s", resp) assert not resp.error assert resp.mac == int.from_bytes(mac2str('FF:FF:FF:FF:FF:FF'), 'big') assert tb.header_sink.empty() assert tb.payload_sink.empty() await RisingEdge(dut.clk) await RisingEdge(dut.clk)
def test_tra_anti_replay(self, count=1): """ ipsec v4 transport anti-reply test """ p = self.params[socket.AF_INET] use_esn = p.vpp_tra_sa.use_esn # fire in a packet with seq number 1 pkt = (Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac) / p.scapy_tra_sa.encrypt(IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(), seq_num=1)) recv_pkts = self.send_and_expect(self.tra_if, [pkt], self.tra_if) # now move the window over to 235 pkt = (Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac) / p.scapy_tra_sa.encrypt(IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(), seq_num=235)) recv_pkts = self.send_and_expect(self.tra_if, [pkt], self.tra_if) # replayed packets are dropped self.send_and_assert_no_replies(self.tra_if, pkt * 3) self.assert_packet_counter_equal( '/err/%s/SA replayed packet' % self.tra4_decrypt_node_name, 3) # the window size is 64 packets # in window are still accepted pkt = (Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac) / p.scapy_tra_sa.encrypt(IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(), seq_num=172)) recv_pkts = self.send_and_expect(self.tra_if, [pkt], self.tra_if) # a packet that does not decrypt does not move the window forward bogus_sa = SecurityAssociation(self.encryption_type, p.vpp_tra_spi) pkt = (Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac) / bogus_sa.encrypt(IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(), seq_num=350)) self.send_and_assert_no_replies(self.tra_if, pkt * 17) self.assert_packet_counter_equal( '/err/%s/Integrity check failed' % self.tra4_decrypt_node_name, 17) # which we can determine since this packet is still in the window pkt = (Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac) / p.scapy_tra_sa.encrypt(IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(), seq_num=234)) self.send_and_expect(self.tra_if, [pkt], self.tra_if) # out of window are dropped pkt = (Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac) / p.scapy_tra_sa.encrypt(IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(), seq_num=17)) self.send_and_assert_no_replies(self.tra_if, pkt * 17) if use_esn: # an out of window error with ESN looks like a high sequence # wrap. but since it isn't then the verify will fail. self.assert_packet_counter_equal( '/err/%s/Integrity check failed' % self.tra4_decrypt_node_name, 34) else: self.assert_packet_counter_equal( '/err/%s/SA replayed packet' % self.tra4_decrypt_node_name, 20) # valid packet moves the window over to 236 pkt = (Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac) / p.scapy_tra_sa.encrypt(IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(), seq_num=236)) rx = self.send_and_expect(self.tra_if, [pkt], self.tra_if) decrypted = p.vpp_tra_sa.decrypt(rx[0][IP]) # move VPP's SA to just before the seq-number wrap self.vapi.cli("test ipsec sa %d seq 0xffffffff" % p.scapy_tra_sa_id) # then fire in a packet that VPP should drop because it causes the # seq number to wrap unless we're using extended. pkt = (Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac) / p.scapy_tra_sa.encrypt(IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(), seq_num=237)) if use_esn: rx = self.send_and_expect(self.tra_if, [pkt], self.tra_if) # in order to decrpyt the high order number needs to wrap p.vpp_tra_sa.seq_num = 0x100000000 decrypted = p.vpp_tra_sa.decrypt(rx[0][IP]) # send packets with high bits set p.scapy_tra_sa.seq_num = 0x100000005 pkt = ( Ether(src=self.tra_if.remote_mac, dst=self.tra_if.local_mac) / p.scapy_tra_sa.encrypt(IP(src=self.tra_if.remote_ip4, dst=self.tra_if.local_ip4) / ICMP(), seq_num=0x100000005)) rx = self.send_and_expect(self.tra_if, [pkt], self.tra_if) # in order to decrpyt the high order number needs to wrap decrypted = p.vpp_tra_sa.decrypt(rx[0][IP]) else: self.send_and_assert_no_replies(self.tra_if, [pkt]) self.assert_packet_counter_equal( '/err/%s/sequence number cycled' % self.tra4_encrypt_node_name, 1) # move the security-associations seq number on to the last we used self.vapi.cli("test ipsec sa %d seq 0x15f" % p.scapy_tra_sa_id) p.scapy_tra_sa.seq_num = 351 p.vpp_tra_sa.seq_num = 351
def gen_pkts(self, sw_intf, src, dst, count=1): return [ Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) / IP(src=src, dst=dst) / ICMP() / self.payload for i in range(count) ]
def gen_pkts(self, sw_intf, src, dst, count=1, payload_size=54): return [ Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) / IP(src=src, dst=dst) / ICMP() / Raw('X' * payload_size) for i in range(count) ]
def test_static(self): """ 1:1 NAT66 test """ flags = self.config_flags.NAT_IS_INSIDE self.vapi.nat66_add_del_interface(is_add=1, flags=flags, sw_if_index=self.pg0.sw_if_index) self.vapi.nat66_add_del_interface(is_add=1, sw_if_index=self.pg1.sw_if_index) self.vapi.nat66_add_del_static_mapping( local_ip_address=self.pg0.remote_ip6, external_ip_address=self.nat_addr, is_add=1) # in2out pkts = [] p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) / TCP()) pkts.append(p) p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) / UDP()) pkts.append(p) p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) / ICMPv6EchoRequest()) pkts.append(p) p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) / GRE() / IP() / TCP()) pkts.append(p) self.pg0.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() capture = self.pg1.get_capture(len(pkts)) for packet in capture: try: self.assertEqual(packet[IPv6].src, self.nat_addr) self.assertEqual(packet[IPv6].dst, self.pg1.remote_ip6) self.assert_packet_checksums_valid(packet) except: self.logger.error(ppp("Unexpected or invalid packet:", packet)) raise # out2in pkts = [] p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) / TCP()) pkts.append(p) p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) / UDP()) pkts.append(p) p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) / ICMPv6EchoReply()) pkts.append(p) p = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(src=self.pg1.remote_ip6, dst=self.nat_addr) / GRE() / IP() / TCP()) pkts.append(p) self.pg1.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() capture = self.pg0.get_capture(len(pkts)) for packet in capture: try: self.assertEqual(packet[IPv6].src, self.pg1.remote_ip6) self.assertEqual(packet[IPv6].dst, self.pg0.remote_ip6) self.assert_packet_checksums_valid(packet) except: self.logger.error(ppp("Unexpected or invalid packet:", packet)) raise sm = self.vapi.nat66_static_mapping_dump() self.assertEqual(len(sm), 1) self.assertEqual(sm[0].total_pkts, 8)
async def run_test(dut, payload_lengths=None, payload_data=None, idle_inserter=None, backpressure_inserter=None): tb = TB(dut) await tb.reset() tb.set_idle_generator(idle_inserter) tb.set_backpressure_generator(backpressure_inserter) test_pkts = [] test_frames = [] ip_id = 1 for payload in [payload_data(x) for x in payload_lengths()]: eth = Ether(src='5A:51:52:53:54:55', dst='DA:D1:D2:D3:D4:D5') ip = IP(src='192.168.1.100', dst='192.168.1.101', id=ip_id) udp = UDP(sport=1234, dport=4321) test_pkt = eth / ip / udp / payload ip_id = (ip_id + 1) & 0xffff # don't compute checksum test_pkts.append(test_pkt.copy()) test_frame = AxiStreamFrame(test_pkt.build()) test_frames.append(test_frame) await tb.source.send(test_frame) await tb.cmd_source.send( CsumCmdTransaction(csum_enable=0, csum_start=34, csum_offset=40, csum_init=0)) # inline partial checksum test_pkts.append(test_pkt.copy()) pkt = test_pkt.copy() partial_csum = scapy.utils.checksum(bytes(pkt[UDP])) pkt[UDP].chksum = partial_csum test_frame = AxiStreamFrame(pkt.build()) test_frames.append(test_frame) await tb.source.send(test_frame) await tb.cmd_source.send( CsumCmdTransaction(csum_enable=1, csum_start=34, csum_offset=40, csum_init=0)) # partial checksum in command test_pkts.append(test_pkt.copy()) pkt = test_pkt.copy() partial_csum = scapy.utils.checksum(bytes(pkt[UDP])) pkt[UDP].chksum = 0 test_frame = AxiStreamFrame(pkt.build()) test_frames.append(test_frame) await tb.source.send(test_frame) await tb.cmd_source.send( CsumCmdTransaction(csum_enable=1, csum_start=34, csum_offset=40, csum_init=partial_csum)) for test_pkt, test_frame in zip(test_pkts, test_frames): rx_frame = await tb.sink.recv() rx_pkt = Ether(bytes(rx_frame)) tb.log.info("RX packet: %s", repr(rx_pkt)) check_pkt = Ether(test_pkt.build()) tb.log.info("RX packet UDP checksum: 0x%04x (expected 0x%04x)", rx_pkt[UDP].chksum, check_pkt[UDP].chksum) assert check_pkt == rx_pkt assert tb.sink.empty() await RisingEdge(dut.clk) await RisingEdge(dut.clk)
ip_dst_count = Counter() ip_src_size = Counter() ip_dst_size = Counter() tcp_src_count = Counter() tcp_dst_count = Counter() tcp_src_size = Counter() tcp_dst_size = Counter() for block in rdr: # print(repr(block)) if isinstance(block, EnhancedPacket): assert block.interface.link_type == 1 # must be ethernet! decoded = Ether(block.packet_data) # print(repr(Ether(block.packet_data))[:400] + '...') _pl1 = decoded.payload if isinstance(_pl1, IP): ip_src_count[_pl1.src] += 1 ip_dst_count[_pl1.dst] += 1 ip_src_size[_pl1.src] += block.packet_len ip_dst_size[_pl1.dst] += block.packet_len _pl2 = _pl1.payload if isinstance(_pl2, TCP): _src = '{0}:{1}'.format(_pl1.dst, _pl2.dport) _dst = '{0}:{1}'.format(_pl1.src, _pl2.sport) tcp_src_count[_src] += 1 tcp_dst_count[_dst] += 1
def create_stream(self, src_ip_if, dst_ip_if, reverse, packet_sizes, is_ip6, expect_blocked, expect_established, add_extension_header): pkts = [] rules = [] permit_rules = [] permit_and_reflect_rules = [] total_packet_count = 8 for i in range(0, total_packet_count): modulo = (i // 2) % 2 can_reflect_this_packet = (modulo == 0) is_permit = i % 2 remote_dst_index = i % len(dst_ip_if.remote_hosts) remote_dst_host = dst_ip_if.remote_hosts[remote_dst_index] if is_permit == 1: info = self.create_packet_info(src_ip_if, dst_ip_if) payload = self.info_to_payload(info) else: to_be_blocked = False if (expect_blocked and not expect_established): to_be_blocked = True if (not can_reflect_this_packet): to_be_blocked = True if to_be_blocked: payload = "to be blocked" else: info = self.create_packet_info(src_ip_if, dst_ip_if) payload = self.info_to_payload(info) if reverse: dst_mac = 'de:ad:00:00:00:00' src_mac = remote_dst_host._mac dst_ip6 = src_ip_if.remote_ip6 src_ip6 = remote_dst_host.ip6 dst_ip4 = src_ip_if.remote_ip4 src_ip4 = remote_dst_host.ip4 dst_l4 = 1234 + i src_l4 = 4321 + i else: dst_mac = src_ip_if.local_mac src_mac = src_ip_if.remote_mac src_ip6 = src_ip_if.remote_ip6 dst_ip6 = remote_dst_host.ip6 src_ip4 = src_ip_if.remote_ip4 dst_ip4 = remote_dst_host.ip4 src_l4 = 1234 + i dst_l4 = 4321 + i # default ULP should be something we do not use in tests ulp_l4 = TCP(sport=src_l4, dport=dst_l4) # potentially a chain of protocols leading to ULP ulp = ulp_l4 if can_reflect_this_packet: if is_ip6: ulp_l4 = UDP(sport=src_l4, dport=dst_l4) if add_extension_header: # prepend some extension headers ulp = (IPv6ExtHdrRouting() / IPv6ExtHdrRouting() / IPv6ExtHdrFragment(offset=0, m=1) / ulp_l4) # uncomment below to test invalid ones # ulp = IPv6ExtHdrRouting(len = 200) / ulp_l4 else: ulp = ulp_l4 p = (Ether(dst=dst_mac, src=src_mac) / IPv6(src=src_ip6, dst=dst_ip6) / ulp / Raw(payload)) else: ulp_l4 = UDP(sport=src_l4, dport=dst_l4) # IPv4 does not allow extension headers, # but we rather make it a first fragment flags = 1 if add_extension_header else 0 ulp = ulp_l4 p = (Ether(dst=dst_mac, src=src_mac) / IP(src=src_ip4, dst=dst_ip4, frag=0, flags=flags) / ulp / Raw(payload)) elif modulo == 1: if is_ip6: ulp_l4 = ICMPv6Unknown(type=128 + (i % 2), code=i % 2) ulp = ulp_l4 p = (Ether(dst=dst_mac, src=src_mac) / IPv6(src=src_ip6, dst=dst_ip6) / ulp / Raw(payload)) else: ulp_l4 = ICMP(type=8 + (i % 2), code=i % 2) ulp = ulp_l4 p = (Ether(dst=dst_mac, src=src_mac) / IP(src=src_ip4, dst=dst_ip4) / ulp / Raw(payload)) if i % 2 == 1: info.data = p.copy() size = packet_sizes[(i // 2) % len(packet_sizes)] self.extend_packet(p, size) pkts.append(p) rule_family = AF_INET6 if p.haslayer(IPv6) else AF_INET rule_prefix_len = 128 if p.haslayer(IPv6) else 32 rule_l3_layer = IPv6 if p.haslayer(IPv6) else IP if p.haslayer(UDP): rule_l4_sport = p[UDP].sport rule_l4_dport = p[UDP].dport else: if p.haslayer(ICMP): rule_l4_sport = p[ICMP].type rule_l4_dport = p[ICMP].code else: rule_l4_sport = p[ICMPv6Unknown].type rule_l4_dport = p[ICMPv6Unknown].code if p.haslayer(IPv6): rule_l4_proto = ulp_l4.overload_fields[IPv6]['nh'] else: rule_l4_proto = p[IP].proto new_rule = { 'is_permit': is_permit, 'is_ipv6': p.haslayer(IPv6), 'src_ip_addr': inet_pton(rule_family, p[rule_l3_layer].src), 'src_ip_prefix_len': rule_prefix_len, 'dst_ip_addr': inet_pton(rule_family, p[rule_l3_layer].dst), 'dst_ip_prefix_len': rule_prefix_len, 'srcport_or_icmptype_first': rule_l4_sport, 'srcport_or_icmptype_last': rule_l4_sport, 'dstport_or_icmpcode_first': rule_l4_dport, 'dstport_or_icmpcode_last': rule_l4_dport, 'proto': rule_l4_proto, } rules.append(new_rule) new_rule_permit = new_rule.copy() new_rule_permit['is_permit'] = 1 permit_rules.append(new_rule_permit) new_rule_permit_and_reflect = new_rule.copy() if can_reflect_this_packet: new_rule_permit_and_reflect['is_permit'] = 2 else: new_rule_permit_and_reflect['is_permit'] = is_permit permit_and_reflect_rules.append(new_rule_permit_and_reflect) return { 'stream': pkts, 'rules': rules, 'permit_rules': permit_rules, 'permit_and_reflect_rules': permit_and_reflect_rules }
def test_arp_duplicates(self): """ ARP Duplicates""" # # Generate some hosts on the LAN # self.pg1.generate_remote_hosts(3) # # Add host 1 on pg1 and pg2 # arp_pg1 = VppNeighbor(self, self.pg1.sw_if_index, self.pg1.remote_hosts[1].mac, self.pg1.remote_hosts[1].ip4) arp_pg1.add_vpp_config() arp_pg2 = VppNeighbor(self, self.pg2.sw_if_index, self.pg2.remote_mac, self.pg1.remote_hosts[1].ip4) arp_pg2.add_vpp_config() # # IP packet destined for pg1 remote host arrives on pg1 again. # p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[1].ip4) / UDP(sport=1234, dport=1234) / Raw()) self.pg0.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx1 = self.pg1.get_capture(1) self.verify_ip(rx1[0], self.pg1.local_mac, self.pg1.remote_hosts[1].mac, self.pg0.remote_ip4, self.pg1.remote_hosts[1].ip4) # # remove the duplicate on pg1 # packet stream shoud generate ARPs out of pg1 # arp_pg1.remove_vpp_config() self.pg0.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx1 = self.pg1.get_capture(1) self.verify_arp_req(rx1[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1.remote_hosts[1].ip4) # # Add it back # arp_pg1.add_vpp_config() self.pg0.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx1 = self.pg1.get_capture(1) self.verify_ip(rx1[0], self.pg1.local_mac, self.pg1.remote_hosts[1].mac, self.pg0.remote_ip4, self.pg1.remote_hosts[1].ip4)
def test_qos_vlan(self): """QoS mark/record VLAN """ # # QoS for all input values # output = [chr(0)] * 256 for i in range(0, 255): output[i] = chr(255 - i) os = ''.join(output) rows = [{ 'outputs': os }, { 'outputs': os }, { 'outputs': os }, { 'outputs': os }] self.vapi.qos_egress_map_update(1, rows) sub_if = VppDot1QSubint(self, self.pg0, 11) sub_if.admin_up() sub_if.config_ip4() sub_if.resolve_arp() sub_if.config_ip6() sub_if.resolve_ndp() # # enable VLAN QoS recording/marking on the input Pg0 subinterface and # self.vapi.qos_record_enable_disable(sub_if.sw_if_index, QOS_SOURCE.VLAN, 1) self.vapi.qos_mark_enable_disable(sub_if.sw_if_index, QOS_SOURCE.VLAN, 1, 1) # # IP marking/recording on pg1 # self.vapi.qos_record_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.IP, 1) self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.IP, 1, 1) # # a routes to/from sub-interface # route_10_0_0_1 = VppIpRoute( self, "10.0.0.1", 32, [VppRoutePath(sub_if.remote_ip4, sub_if.sw_if_index)]) route_10_0_0_1.add_vpp_config() route_10_0_0_2 = VppIpRoute( self, "10.0.0.2", 32, [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)]) route_10_0_0_2.add_vpp_config() route_2001_1 = VppIpRoute( self, "2001::1", 128, [ VppRoutePath(sub_if.remote_ip6, sub_if.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ], is_ip6=1) route_2001_1.add_vpp_config() route_2001_2 = VppIpRoute( self, "2001::2", 128, [ VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ], is_ip6=1) route_2001_2.add_vpp_config() p_v1 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / Dot1Q(vlan=11, prio=1) / IP(src="1.1.1.1", dst="10.0.0.2", tos=1) / UDP(sport=1234, dport=1234) / Raw(chr(100) * 65)) p_v2 = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IP(src="1.1.1.1", dst="10.0.0.1", tos=1) / UDP(sport=1234, dport=1234) / Raw(chr(100) * 65)) rx = self.send_and_expect(self.pg1, p_v2 * 65, self.pg0) for p in rx: self.assertEqual(p[Dot1Q].prio, 6) rx = self.send_and_expect(self.pg0, p_v1 * 65, self.pg1) for p in rx: self.assertEqual(p[IP].tos, 254) p_v1 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / Dot1Q(vlan=11, prio=2) / IPv6(src="2001::1", dst="2001::2", tc=1) / UDP(sport=1234, dport=1234) / Raw(chr(100) * 65)) p_v2 = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IPv6(src="3001::1", dst="2001::1", tc=1) / UDP(sport=1234, dport=1234) / Raw(chr(100) * 65)) rx = self.send_and_expect(self.pg1, p_v2 * 65, self.pg0) for p in rx: self.assertEqual(p[Dot1Q].prio, 6) rx = self.send_and_expect(self.pg0, p_v1 * 65, self.pg1) for p in rx: self.assertEqual(p[IPv6].tc, 253) # # cleanup # sub_if.unconfig_ip4() sub_if.unconfig_ip6() self.vapi.qos_record_enable_disable(sub_if.sw_if_index, QOS_SOURCE.VLAN, 0) self.vapi.qos_mark_enable_disable(sub_if.sw_if_index, QOS_SOURCE.VLAN, 1, 0) self.vapi.qos_record_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.IP, 0) self.vapi.qos_mark_enable_disable(self.pg1.sw_if_index, QOS_SOURCE.IP, 1, 0)
def test_arp(self): """ ARP """ # # Generate some hosts on the LAN # self.pg1.generate_remote_hosts(11) # # Send IP traffic to one of these unresolved hosts. # expect the generation of an ARP request # p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4) / UDP(sport=1234, dport=1234) / Raw()) self.pg0.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_arp_req(rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[1].ip4) # # And a dynamic ARP entry for host 1 # dyn_arp = VppNeighbor(self, self.pg1.sw_if_index, self.pg1.remote_hosts[1].mac, self.pg1.remote_hosts[1].ip4) dyn_arp.add_vpp_config() # # now we expect IP traffic forwarded # dyn_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[1].ip4) / UDP(sport=1234, dport=1234) / Raw()) self.pg0.add_stream(dyn_p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_ip(rx[0], self.pg1.local_mac, self.pg1.remote_hosts[1].mac, self.pg0.remote_ip4, self.pg1._remote_hosts[1].ip4) # # And a Static ARP entry for host 2 # static_arp = VppNeighbor(self, self.pg1.sw_if_index, self.pg1.remote_hosts[2].mac, self.pg1.remote_hosts[2].ip4, is_static=1) static_arp.add_vpp_config() static_p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[2].ip4) / UDP(sport=1234, dport=1234) / Raw()) self.pg0.add_stream(static_p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_ip(rx[0], self.pg1.local_mac, self.pg1.remote_hosts[2].mac, self.pg0.remote_ip4, self.pg1._remote_hosts[2].ip4) # # flap the link. dynamic ARPs get flush, statics don't # self.pg1.admin_down() self.pg1.admin_up() self.pg0.add_stream(static_p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_ip(rx[0], self.pg1.local_mac, self.pg1.remote_hosts[2].mac, self.pg0.remote_ip4, self.pg1._remote_hosts[2].ip4) self.pg0.add_stream(dyn_p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_arp_req(rx[0], self.pg1.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[1].ip4) # # Send an ARP request from one of the so-far unlearned remote hosts # p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1._remote_hosts[3].mac) / ARP(op="who-has", hwsrc=self.pg1._remote_hosts[3].mac, pdst=self.pg1.local_ip4, psrc=self.pg1._remote_hosts[3].ip4)) self.pg1.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_arp_resp(rx[0], self.pg1.local_mac, self.pg1._remote_hosts[3].mac, self.pg1.local_ip4, self.pg1._remote_hosts[3].ip4) # # VPP should have learned the mapping for the remote host # self.assertTrue(find_nbr(self, self.pg1.sw_if_index, self.pg1._remote_hosts[3].ip4)) # # Fire in an ARP request before the interface becomes IP enabled # self.pg2.generate_remote_hosts(4) p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(op="who-has", hwsrc=self.pg2.remote_mac, pdst=self.pg1.local_ip4, psrc=self.pg2.remote_hosts[3].ip4)) pt = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / Dot1Q(vlan=0) / ARP(op="who-has", hwsrc=self.pg2.remote_mac, pdst=self.pg1.local_ip4, psrc=self.pg2.remote_hosts[3].ip4)) self.send_and_assert_no_replies(self.pg2, p, "interface not IP enabled") # # Make pg2 un-numbered to pg1 # self.pg2.set_unnumbered(self.pg1.sw_if_index) # # We should respond to ARP requests for the unnumbered to address # once an attached route to the source is known # self.send_and_assert_no_replies( self.pg2, p, "ARP req for unnumbered address - no source") attached_host = VppIpRoute(self, self.pg2.remote_hosts[3].ip4, 32, [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)]) attached_host.add_vpp_config() self.pg2.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(1) self.verify_arp_resp(rx[0], self.pg2.local_mac, self.pg2.remote_mac, self.pg1.local_ip4, self.pg2.remote_hosts[3].ip4) self.pg2.add_stream(pt) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(1) self.verify_arp_resp(rx[0], self.pg2.local_mac, self.pg2.remote_mac, self.pg1.local_ip4, self.pg2.remote_hosts[3].ip4) # # A neighbor entry that has no associated FIB-entry # arp_no_fib = VppNeighbor(self, self.pg1.sw_if_index, self.pg1.remote_hosts[4].mac, self.pg1.remote_hosts[4].ip4, is_no_fib_entry=1) arp_no_fib.add_vpp_config() # # check we have the neighbor, but no route # self.assertTrue(find_nbr(self, self.pg1.sw_if_index, self.pg1._remote_hosts[4].ip4)) self.assertFalse(find_route(self, self.pg1._remote_hosts[4].ip4, 32)) # # pg2 is unnumbered to pg1, so we can form adjacencies out of pg2 # from within pg1's subnet # arp_unnum = VppNeighbor(self, self.pg2.sw_if_index, self.pg1.remote_hosts[5].mac, self.pg1.remote_hosts[5].ip4) arp_unnum.add_vpp_config() p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[5].ip4) / UDP(sport=1234, dport=1234) / Raw()) self.pg0.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(1) self.verify_ip(rx[0], self.pg2.local_mac, self.pg1.remote_hosts[5].mac, self.pg0.remote_ip4, self.pg1._remote_hosts[5].ip4) # # ARP requests from hosts in pg1's subnet sent on pg2 are replied to # with the unnumbered interface's address as the source # p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(op="who-has", hwsrc=self.pg2.remote_mac, pdst=self.pg1.local_ip4, psrc=self.pg1.remote_hosts[6].ip4)) self.pg2.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(1) self.verify_arp_resp(rx[0], self.pg2.local_mac, self.pg2.remote_mac, self.pg1.local_ip4, self.pg1.remote_hosts[6].ip4) # # An attached host route out of pg2 for an undiscovered hosts generates # an ARP request with the unnumbered address as the source # att_unnum = VppIpRoute(self, self.pg1.remote_hosts[7].ip4, 32, [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)]) att_unnum.add_vpp_config() p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg1._remote_hosts[7].ip4) / UDP(sport=1234, dport=1234) / Raw()) self.pg0.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(1) self.verify_arp_req(rx[0], self.pg2.local_mac, self.pg1.local_ip4, self.pg1._remote_hosts[7].ip4) p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(op="who-has", hwsrc=self.pg2.remote_mac, pdst=self.pg1.local_ip4, psrc=self.pg1.remote_hosts[7].ip4)) self.pg2.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(1) self.verify_arp_resp(rx[0], self.pg2.local_mac, self.pg2.remote_mac, self.pg1.local_ip4, self.pg1.remote_hosts[7].ip4) # # An attached host route as yet unresolved out of pg2 for an # undiscovered host, an ARP requests begets a response. # att_unnum1 = VppIpRoute(self, self.pg1.remote_hosts[8].ip4, 32, [VppRoutePath("0.0.0.0", self.pg2.sw_if_index)]) att_unnum1.add_vpp_config() p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(op="who-has", hwsrc=self.pg2.remote_mac, pdst=self.pg1.local_ip4, psrc=self.pg1.remote_hosts[8].ip4)) self.pg2.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(1) self.verify_arp_resp(rx[0], self.pg2.local_mac, self.pg2.remote_mac, self.pg1.local_ip4, self.pg1.remote_hosts[8].ip4) # # Send an ARP request from one of the so-far unlearned remote hosts # with a VLAN0 tag # p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1._remote_hosts[9].mac) / Dot1Q(vlan=0) / ARP(op="who-has", hwsrc=self.pg1._remote_hosts[9].mac, pdst=self.pg1.local_ip4, psrc=self.pg1._remote_hosts[9].ip4)) self.pg1.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_arp_resp(rx[0], self.pg1.local_mac, self.pg1._remote_hosts[9].mac, self.pg1.local_ip4, self.pg1._remote_hosts[9].ip4) # # Add a hierachy of routes for a host in the sub-net. # Should still get an ARP resp since the cover is attached # p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg1.remote_mac) / ARP(op="who-has", hwsrc=self.pg1.remote_mac, pdst=self.pg1.local_ip4, psrc=self.pg1.remote_hosts[10].ip4)) r1 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 30, [VppRoutePath(self.pg1.remote_hosts[10].ip4, self.pg1.sw_if_index)]) r1.add_vpp_config() self.pg1.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_arp_resp(rx[0], self.pg1.local_mac, self.pg1.remote_mac, self.pg1.local_ip4, self.pg1.remote_hosts[10].ip4) r2 = VppIpRoute(self, self.pg1.remote_hosts[10].ip4, 32, [VppRoutePath(self.pg1.remote_hosts[10].ip4, self.pg1.sw_if_index)]) r2.add_vpp_config() self.pg1.add_stream(p) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_arp_resp(rx[0], self.pg1.local_mac, self.pg1.remote_mac, self.pg1.local_ip4, self.pg1.remote_hosts[10].ip4) # # add an ARP entry that's not on the sub-net and so whose # adj-fib fails the refinement check. then send an ARP request # from that source # a1 = VppNeighbor(self, self.pg0.sw_if_index, self.pg0.remote_mac, "100.100.100.50") a1.add_vpp_config() p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(op="who-has", hwsrc=self.pg0.remote_mac, psrc="100.100.100.50", pdst=self.pg0.remote_ip4)) self.send_and_assert_no_replies(self.pg0, p, "ARP req for from failed adj-fib") # # ERROR Cases # 1 - don't respond to ARP request for address not within the # interface's sub-net # 1b - nor within the unnumbered subnet # 1c - nor within the subnet of a different interface # p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(op="who-has", hwsrc=self.pg0.remote_mac, pdst="10.10.10.3", psrc=self.pg0.remote_ip4)) self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local destination") self.assertFalse(find_nbr(self, self.pg0.sw_if_index, "10.10.10.3")) p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(op="who-has", hwsrc=self.pg2.remote_mac, pdst="10.10.10.3", psrc=self.pg1.remote_hosts[7].ip4)) self.send_and_assert_no_replies( self.pg0, p, "ARP req for non-local destination - unnum") p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(op="who-has", hwsrc=self.pg0.remote_mac, pdst=self.pg1.local_ip4, psrc=self.pg1.remote_ip4)) self.send_and_assert_no_replies(self.pg0, p, "ARP req diff sub-net") self.assertFalse(find_nbr(self, self.pg0.sw_if_index, self.pg1.remote_ip4)) # # 2 - don't respond to ARP request from an address not within the # interface's sub-net # 2b - to a prxied address # 2c - not within a differents interface's sub-net p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(op="who-has", hwsrc=self.pg0.remote_mac, psrc="10.10.10.3", pdst=self.pg0.local_ip4)) self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source") p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg2.remote_mac) / ARP(op="who-has", hwsrc=self.pg2.remote_mac, psrc="10.10.10.3", pdst=self.pg0.local_ip4)) self.send_and_assert_no_replies( self.pg0, p, "ARP req for non-local source - unnum") p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(op="who-has", hwsrc=self.pg0.remote_mac, psrc=self.pg1.remote_ip4, pdst=self.pg0.local_ip4)) self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source 2c") # # 3 - don't respond to ARP request from an address that belongs to # the router # p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(op="who-has", hwsrc=self.pg0.remote_mac, psrc=self.pg0.local_ip4, pdst=self.pg0.local_ip4)) self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source") # # 4 - don't respond to ARP requests that has mac source different # from ARP request HW source # the router # p = (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.pg0.remote_mac) / ARP(op="who-has", hwsrc="00:00:00:DE:AD:BE", psrc=self.pg0.remote_ip4, pdst=self.pg0.local_ip4)) self.send_and_assert_no_replies(self.pg0, p, "ARP req for non-local source") # # cleanup # dyn_arp.remove_vpp_config() static_arp.remove_vpp_config() self.pg2.unset_unnumbered(self.pg1.sw_if_index) # need this to flush the adj-fibs self.pg2.unset_unnumbered(self.pg1.sw_if_index) self.pg2.admin_down() self.pg1.admin_down()
def test_dhcp_client(self): """ DHCP Client""" hostname = 'universal-dp' self.pg_enable_capture(self.pg_interfaces) # # Configure DHCP client on PG2 and capture the discover sent # self.vapi.dhcp_client(self.pg2.sw_if_index, hostname) rx = self.pg2.get_capture(1) self.verify_orig_dhcp_discover(rx[0], self.pg2, hostname) # # Sned back on offer, expect the request # p_offer = (Ether(dst=self.pg2.local_mac, src=self.pg2.remote_mac) / IP(src=self.pg2.remote_ip4, dst="255.255.255.255") / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) / BOOTP(op=1, yiaddr=self.pg2.local_ip4) / DHCP(options=[('message-type', 'offer'), ('server_id', self.pg2.remote_ip4), ('end')])) self.pg2.add_stream(p_offer) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(1) self.verify_orig_dhcp_request(rx[0], self.pg2, hostname, self.pg2.local_ip4) # # Send an acknowloedgement # p_ack = (Ether(dst=self.pg2.local_mac, src=self.pg2.remote_mac) / IP(src=self.pg2.remote_ip4, dst="255.255.255.255") / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) / BOOTP(op=1, yiaddr=self.pg2.local_ip4) / DHCP(options=[('message-type', 'ack'), ('subnet_mask', "255.255.255.0"), ('router', self.pg2.remote_ip4), ('server_id', self.pg2.remote_ip4), ('lease_time', 43200), ('end')])) self.pg2.add_stream(p_ack) self.pg_enable_capture(self.pg_interfaces) self.pg_start() # # We'll get an ARP request for the router address # rx = self.pg2.get_capture(1) self.assertEqual(rx[0][ARP].pdst, self.pg2.remote_ip4) self.pg_enable_capture(self.pg_interfaces) # # At the end of this procedure there should be a connected route # in the FIB # self.assertTrue(find_route(self, self.pg2.local_ip4, 24)) self.assertTrue(find_route(self, self.pg2.local_ip4, 32)) # remove the left over ARP entry self.vapi.ip_neighbor_add_del(self.pg2.sw_if_index, mactobinary(self.pg2.remote_mac), self.pg2.remote_ip4, is_add=0) # # remove the DHCP config # self.vapi.dhcp_client(self.pg2.sw_if_index, hostname, is_add=0) # # and now the route should be gone # self.assertFalse(find_route(self, self.pg2.local_ip4, 32)) self.assertFalse(find_route(self, self.pg2.local_ip4, 24)) # # Start the procedure again. this time have VPP send the client-ID # self.pg2.admin_down() self.sleep(1) self.pg2.admin_up() self.vapi.dhcp_client(self.pg2.sw_if_index, hostname, client_id=self.pg2.local_mac) rx = self.pg2.get_capture(1) self.verify_orig_dhcp_discover(rx[0], self.pg2, hostname, self.pg2.local_mac) self.pg2.add_stream(p_offer) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(1) self.verify_orig_dhcp_request(rx[0], self.pg2, hostname, self.pg2.local_ip4) # # unicast the ack to the offered address # p_ack = (Ether(dst=self.pg2.local_mac, src=self.pg2.remote_mac) / IP(src=self.pg2.remote_ip4, dst=self.pg2.local_ip4) / UDP(sport=DHCP4_SERVER_PORT, dport=DHCP4_CLIENT_PORT) / BOOTP(op=1, yiaddr=self.pg2.local_ip4) / DHCP(options=[('message-type', 'ack'), ('subnet_mask', "255.255.255.0"), ('router', self.pg2.remote_ip4), ('server_id', self.pg2.remote_ip4), ('lease_time', 43200), ('end')])) self.pg2.add_stream(p_ack) self.pg_enable_capture(self.pg_interfaces) self.pg_start() # # At the end of this procedure there should be a connected route # in the FIB # self.assertTrue(find_route(self, self.pg2.local_ip4, 32)) self.assertTrue(find_route(self, self.pg2.local_ip4, 24)) # # remove the DHCP config # self.vapi.dhcp_client(self.pg2.sw_if_index, hostname, is_add=0) self.assertFalse(find_route(self, self.pg2.local_ip4, 32)) self.assertFalse(find_route(self, self.pg2.local_ip4, 24))
def test_proxy_mirror_arp(self): """ Interface Mirror Proxy ARP """ # # When VPP has an interface whose address is also applied to a TAP # interface on the host, then VPP's TAP interface will be unnumbered # to the 'real' interface and do proxy ARP from the host. # the curious aspect of this setup is that ARP requests from the host # will come from the VPP's own address. # self.pg0.generate_remote_hosts(2) arp_req_from_me = (Ether(src=self.pg2.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(op="who-has", hwsrc=self.pg2.remote_mac, pdst=self.pg0.remote_hosts[1].ip4, psrc=self.pg0.local_ip4)) # # Configure Proxy ARP for the subnet on PG0addresses on pg0 # self.vapi.proxy_arp_add_del(self.pg0._local_ip4n_subnet, self.pg0._local_ip4n_bcast) # Make pg2 un-numbered to pg0 # self.pg2.set_unnumbered(self.pg0.sw_if_index) # # Enable pg2 for proxy ARP # self.pg2.set_proxy_arp() # # Send the ARP request with an originating address that # is VPP's own address # self.pg2.add_stream(arp_req_from_me) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(1) self.verify_arp_resp(rx[0], self.pg2.local_mac, self.pg2.remote_mac, self.pg0.remote_hosts[1].ip4, self.pg0.local_ip4) # # validate we have not learned an ARP entry as a result of this # self.assertFalse(find_nbr(self, self.pg2.sw_if_index, self.pg0.local_ip4)) # # cleanup # self.pg2.set_proxy_arp(0) self.vapi.proxy_arp_add_del(self.pg0._local_ip4n_subnet, self.pg0._local_ip4n_bcast, is_add=0)
def test_dhcp6_proxy(self): """ DHCPv6 Proxy""" # # Verify no response to DHCP request without DHCP config # dhcp_solicit_dst = "ff02::1:2" dhcp_solicit_src_vrf0 = mk_ll_addr(self.pg2.remote_mac) dhcp_solicit_src_vrf1 = mk_ll_addr(self.pg3.remote_mac) server_addr_vrf0 = self.pg0.remote_ip6n src_addr_vrf0 = self.pg0.local_ip6n server_addr_vrf1 = self.pg1.remote_ip6n src_addr_vrf1 = self.pg1.local_ip6n dmac = in6_getnsmac(inet_pton(socket.AF_INET6, dhcp_solicit_dst)) p_solicit_vrf0 = ( Ether(dst=dmac, src=self.pg2.remote_mac) / IPv6(src=dhcp_solicit_src_vrf0, dst=dhcp_solicit_dst) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_CLIENT_PORT) / DHCP6_Solicit()) p_solicit_vrf1 = ( Ether(dst=dmac, src=self.pg3.remote_mac) / IPv6(src=dhcp_solicit_src_vrf1, dst=dhcp_solicit_dst) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_CLIENT_PORT) / DHCP6_Solicit()) self.send_and_assert_no_replies(self.pg2, p_solicit_vrf0, "DHCP with no configuration") self.send_and_assert_no_replies(self.pg3, p_solicit_vrf1, "DHCP with no configuration") # # DHCPv6 config in VRF 0. # Packets still dropped because the client facing interface has no # IPv6 config # self.vapi.dhcp_proxy_config(server_addr_vrf0, src_addr_vrf0, rx_table_id=0, server_table_id=0, is_ipv6=1) self.send_and_assert_no_replies(self.pg2, p_solicit_vrf0, "DHCP with no configuration") self.send_and_assert_no_replies(self.pg3, p_solicit_vrf1, "DHCP with no configuration") # # configure an IP address on the client facing interface # self.pg2.config_ip6() # # Now the DHCP requests are relayed to the server # self.pg2.add_stream(p_solicit_vrf0) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(1) self.verify_dhcp6_solicit(rx[0], self.pg0, dhcp_solicit_src_vrf0, self.pg2.remote_mac) # # Exception cases for rejected relay responses # # 1 - not a relay reply p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / DHCP6_Advertise()) self.send_and_assert_no_replies(self.pg2, p_adv_vrf0, "DHCP6 not a relay reply") # 2 - no relay message option p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / DHCP6_RelayReply() / DHCP6_Advertise()) self.send_and_assert_no_replies(self.pg2, p_adv_vrf0, "DHCP not a relay message") # 3 - no circuit ID p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / DHCP6_RelayReply() / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise()) self.send_and_assert_no_replies(self.pg2, p_adv_vrf0, "DHCP6 no circuit ID") # 4 - wrong circuit ID p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / DHCP6_RelayReply() / DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x05') / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise()) self.send_and_assert_no_replies(self.pg2, p_adv_vrf0, "DHCP6 wrong circuit ID") # # Send the relay response (the advertisement) # - no peer address p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / DHCP6_RelayReply() / DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x03') / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise(trid=1) / DHCP6OptStatusCode(statuscode=0)) pkts_adv_vrf0 = [p_adv_vrf0] self.pg0.add_stream(pkts_adv_vrf0) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(1) self.verify_dhcp6_advert(rx[0], self.pg2, "::") # # Send the relay response (the advertisement) # - with peer address p_adv_vrf0 = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf0) / DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x03') / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise(trid=1) / DHCP6OptStatusCode(statuscode=0)) pkts_adv_vrf0 = [p_adv_vrf0] self.pg0.add_stream(pkts_adv_vrf0) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(1) self.verify_dhcp6_advert(rx[0], self.pg2, dhcp_solicit_src_vrf0) # # Add all the config for VRF 1 # self.vapi.dhcp_proxy_config(server_addr_vrf1, src_addr_vrf1, rx_table_id=1, server_table_id=1, is_ipv6=1) self.pg3.config_ip6() # # VRF 1 solicit # self.pg3.add_stream(p_solicit_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_dhcp6_solicit(rx[0], self.pg1, dhcp_solicit_src_vrf1, self.pg3.remote_mac) # # VRF 1 Advert # p_adv_vrf1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(dst=self.pg1.local_ip6, src=self.pg1.remote_ip6) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) / DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise(trid=1) / DHCP6OptStatusCode(statuscode=0)) pkts_adv_vrf1 = [p_adv_vrf1] self.pg1.add_stream(pkts_adv_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg3.get_capture(1) self.verify_dhcp6_advert(rx[0], self.pg3, dhcp_solicit_src_vrf1) # # Add VSS config # table=1, fib=id=1, oui=4 self.vapi.dhcp_proxy_set_vss(1, 1, 4, is_ip6=1) self.pg3.add_stream(p_solicit_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_dhcp6_solicit(rx[0], self.pg1, dhcp_solicit_src_vrf1, self.pg3.remote_mac, fib_id=1, oui=4) # # Remove the VSS config # relayed DHCP has default vlaues in the option. # self.vapi.dhcp_proxy_set_vss(1, 1, 4, is_ip6=1, is_add=0) self.pg3.add_stream(p_solicit_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_dhcp6_solicit(rx[0], self.pg1, dhcp_solicit_src_vrf1, self.pg3.remote_mac) # # Add a second DHCP server in VRF 1 # expect clients messages to be relay to both configured servers # self.pg1.generate_remote_hosts(2) server_addr2 = socket.inet_pton(AF_INET6, self.pg1.remote_hosts[1].ip6) self.vapi.dhcp_proxy_config(server_addr2, src_addr_vrf1, rx_table_id=1, server_table_id=1, is_ipv6=1) # # We'll need an ND entry for the server to send it packets # nd_entry = VppNeighbor(self, self.pg1.sw_if_index, self.pg1.remote_hosts[1].mac, self.pg1.remote_hosts[1].ip6, af=AF_INET6) nd_entry.add_vpp_config() # # Send a discover from the client. expect two relayed messages # The frist packet is sent to the second server # We're not enforcing that here, it's just the way it is. # self.pg3.add_stream(p_solicit_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(2) self.verify_dhcp6_solicit(rx[0], self.pg1, dhcp_solicit_src_vrf1, self.pg3.remote_mac) self.verify_dhcp6_solicit(rx[1], self.pg1, dhcp_solicit_src_vrf1, self.pg3.remote_mac, dst_mac=self.pg1.remote_hosts[1].mac, dst_ip=self.pg1.remote_hosts[1].ip6) # # Send both packets back. Client gets both. # p1 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac) / IPv6(dst=self.pg1.local_ip6, src=self.pg1.remote_ip6) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) / DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise(trid=1) / DHCP6OptStatusCode(statuscode=0)) p2 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_hosts[1].mac) / IPv6(dst=self.pg1.local_ip6, src=self.pg1._remote_hosts[1].ip6) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) / DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise(trid=1) / DHCP6OptStatusCode(statuscode=0)) pkts = [p1, p2] self.pg1.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg3.get_capture(2) self.verify_dhcp6_advert(rx[0], self.pg3, dhcp_solicit_src_vrf1) self.verify_dhcp6_advert(rx[1], self.pg3, dhcp_solicit_src_vrf1) # # Ensure only solicit messages are duplicated # p_request_vrf1 = ( Ether(dst=dmac, src=self.pg3.remote_mac) / IPv6(src=dhcp_solicit_src_vrf1, dst=dhcp_solicit_dst) / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_CLIENT_PORT) / DHCP6_Request()) self.pg3.add_stream(p_request_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) # # Test we drop DHCP packets from addresses that are not configured as # DHCP servers # p2 = (Ether(dst=self.pg1.local_mac, src=self.pg1.remote_hosts[1].mac) / IPv6(dst=self.pg1.local_ip6, src="3001::1") / UDP(sport=DHCP6_SERVER_PORT, dport=DHCP6_SERVER_PORT) / DHCP6_RelayReply(peeraddr=dhcp_solicit_src_vrf1) / DHCP6OptIfaceId(optlen=4, ifaceid='\x00\x00\x00\x04') / DHCP6OptRelayMsg(optlen=0) / DHCP6_Advertise(trid=1) / DHCP6OptStatusCode(statuscode=0)) self.send_and_assert_no_replies(self.pg1, p2, "DHCP6 not from server") # # Remove the second DHCP server # self.vapi.dhcp_proxy_config(server_addr2, src_addr_vrf1, rx_table_id=1, server_table_id=1, is_ipv6=1, is_add=0) # # Test we can still relay with the first # self.pg3.add_stream(p_solicit_vrf1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_dhcp6_solicit(rx[0], self.pg1, dhcp_solicit_src_vrf1, self.pg3.remote_mac) # # Cleanup # self.vapi.dhcp_proxy_config(server_addr_vrf1, src_addr_vrf1, rx_table_id=1, server_table_id=1, is_ipv6=1, is_add=0) self.vapi.dhcp_proxy_config(server_addr_vrf0, src_addr_vrf0, rx_table_id=0, server_table_id=0, is_ipv6=1, is_add=0) # duplicate delete self.vapi.dhcp_proxy_config(server_addr_vrf0, src_addr_vrf0, rx_table_id=0, server_table_id=0, is_ipv6=1, is_add=0) self.pg2.unconfig_ip6() self.pg3.unconfig_ip6()
def test_proxy_arp(self): """ Proxy ARP """ self.pg1.generate_remote_hosts(2) # # Proxy ARP rewquest packets for each interface # arp_req_pg0 = (Ether(src=self.pg0.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(op="who-has", hwsrc=self.pg0.remote_mac, pdst="10.10.10.3", psrc=self.pg0.remote_ip4)) arp_req_pg0_tagged = (Ether(src=self.pg0.remote_mac, dst="ff:ff:ff:ff:ff:ff") / Dot1Q(vlan=0) / ARP(op="who-has", hwsrc=self.pg0.remote_mac, pdst="10.10.10.3", psrc=self.pg0.remote_ip4)) arp_req_pg1 = (Ether(src=self.pg1.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(op="who-has", hwsrc=self.pg1.remote_mac, pdst="10.10.10.3", psrc=self.pg1.remote_ip4)) arp_req_pg2 = (Ether(src=self.pg2.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(op="who-has", hwsrc=self.pg2.remote_mac, pdst="10.10.10.3", psrc=self.pg1.remote_hosts[1].ip4)) arp_req_pg3 = (Ether(src=self.pg3.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(op="who-has", hwsrc=self.pg3.remote_mac, pdst="10.10.10.3", psrc=self.pg3.remote_ip4)) # # Configure Proxy ARP for 10.10.10.0 -> 10.10.10.124 # self.vapi.proxy_arp_add_del(inet_pton(AF_INET, "10.10.10.2"), inet_pton(AF_INET, "10.10.10.124")) # # No responses are sent when the interfaces are not enabled for proxy # ARP # self.send_and_assert_no_replies(self.pg0, arp_req_pg0, "ARP req from unconfigured interface") self.send_and_assert_no_replies(self.pg2, arp_req_pg2, "ARP req from unconfigured interface") # # Make pg2 un-numbered to pg1 # still won't reply. # self.pg2.set_unnumbered(self.pg1.sw_if_index) self.send_and_assert_no_replies(self.pg2, arp_req_pg2, "ARP req from unnumbered interface") # # Enable each interface to reply to proxy ARPs # for i in self.pg_interfaces: i.set_proxy_arp() # # Now each of the interfaces should reply to a request to a proxied # address # self.pg0.add_stream(arp_req_pg0) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(1) self.verify_arp_resp(rx[0], self.pg0.local_mac, self.pg0.remote_mac, "10.10.10.3", self.pg0.remote_ip4) self.pg0.add_stream(arp_req_pg0_tagged) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg0.get_capture(1) self.verify_arp_resp(rx[0], self.pg0.local_mac, self.pg0.remote_mac, "10.10.10.3", self.pg0.remote_ip4) self.pg1.add_stream(arp_req_pg1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg1.get_capture(1) self.verify_arp_resp(rx[0], self.pg1.local_mac, self.pg1.remote_mac, "10.10.10.3", self.pg1.remote_ip4) self.pg2.add_stream(arp_req_pg2) self.pg_enable_capture(self.pg_interfaces) self.pg_start() rx = self.pg2.get_capture(1) self.verify_arp_resp(rx[0], self.pg2.local_mac, self.pg2.remote_mac, "10.10.10.3", self.pg1.remote_hosts[1].ip4) # # A request for an address out of the configured range # arp_req_pg1_hi = (Ether(src=self.pg1.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(op="who-has", hwsrc=self.pg1.remote_mac, pdst="10.10.10.125", psrc=self.pg1.remote_ip4)) self.send_and_assert_no_replies(self.pg1, arp_req_pg1_hi, "ARP req out of range HI") arp_req_pg1_low = (Ether(src=self.pg1.remote_mac, dst="ff:ff:ff:ff:ff:ff") / ARP(op="who-has", hwsrc=self.pg1.remote_mac, pdst="10.10.10.1", psrc=self.pg1.remote_ip4)) self.send_and_assert_no_replies(self.pg1, arp_req_pg1_low, "ARP req out of range Low") # # Request for an address in the proxy range but from an interface # in a different VRF # self.send_and_assert_no_replies(self.pg3, arp_req_pg3, "ARP req from different VRF") # # Disable Each interface for proxy ARP # - expect none to respond # for i in self.pg_interfaces: i.set_proxy_arp(0) self.send_and_assert_no_replies(self.pg0, arp_req_pg0, "ARP req from disable") self.send_and_assert_no_replies(self.pg1, arp_req_pg1, "ARP req from disable") self.send_and_assert_no_replies(self.pg2, arp_req_pg2, "ARP req from disable") # # clean up on interface 2 # self.pg2.unset_unnumbered(self.pg1.sw_if_index)
def _get_gw_mac_address_v4(self, ip: IPAddress, vlan: str = "") -> str: try: gw_ip = ipaddress.ip_address(ip.address) self.logger.debug( "sending arp via egress: %s", self.config.non_nat_arp_egress_port, ) eth_mac_src = get_if_hwaddr(self.config.non_nat_arp_egress_port) psrc = "0.0.0.0" egress_port_ip = get_if_addr(self.config.non_nat_arp_egress_port) if egress_port_ip: psrc = egress_port_ip pkt = Ether(dst=ETHER_BROADCAST, src=eth_mac_src) if vlan.isdigit(): pkt /= Dot1Q(vlan=int(vlan)) pkt /= ARP(op="who-has", pdst=gw_ip, hwsrc=eth_mac_src, psrc=psrc) self.logger.debug("ARP Req pkt %s", pkt.show(dump=True)) res = srp1( pkt, type=ETH_P_ALL, iface=self.config.non_nat_arp_egress_port, timeout=1, verbose=0, nofilter=1, promisc=0, ) if res is not None: self.logger.debug("ARP Res pkt %s", res.show(dump=True)) if str(res[ARP].psrc) != str(gw_ip): self.logger.warning( "Unexpected IP in ARP response. expected: %s pkt: %s", str(gw_ip), res.show(dump=True), ) return "" if vlan.isdigit(): if Dot1Q in res and str(res[Dot1Q].vlan) == vlan: mac = res[ARP].hwsrc else: self.logger.warning( "Unexpected vlan in ARP response. expected: %s pkt: %s", vlan, res.show(dump=True), ) return "" else: mac = res[ARP].hwsrc return mac else: self.logger.debug("Got Null response") return "" except Scapy_Exception as ex: self.logger.warning("Error in probing Mac address: err %s", ex) return "" except ValueError: self.logger.warning( "Invalid GW Ip address: [%s] or vlan %s", str(ip), vlan, ) return ""
def create_stream(self, mac_type, ip_type, packet_count, src_if, dst_if, traffic, is_ip6, tags=PERMIT_TAGS): # exact MAC and exact IP # exact MAC and subnet of IPs # exact MAC and wildcard IP # wildcard MAC and exact IP # wildcard MAC and subnet of IPs # wildcard MAC and wildcard IP # OUI restricted MAC and exact IP # OUI restricted MAC and subnet of IPs # OUI restricted MAC and wildcard IP packets = [] macip_rules = [] acl_rules = [] ip_permit = "" mac_permit = "" dst_mac = "" mac_rule = "00:00:00:00:00:00" mac_mask = "00:00:00:00:00:00" for p in range(0, packet_count): remote_dst_index = p % len(dst_if.remote_hosts) remote_dst_host = dst_if.remote_hosts[remote_dst_index] dst_port = 1234 + p src_port = 4321 + p is_permit = self.PERMIT if p % 3 == 0 else self.DENY denyMAC = True if not is_permit and p % 3 == 1 else False denyIP = True if not is_permit and p % 3 == 2 else False if not is_permit and ip_type == self.WILD_IP: denyMAC = True if not is_permit and mac_type == self.WILD_MAC: denyIP = True if traffic == self.BRIDGED: if is_permit: src_mac = remote_dst_host._mac dst_mac = 'de:ad:00:00:00:00' src_ip4 = remote_dst_host.ip4 dst_ip4 = src_if.remote_ip4 src_ip6 = remote_dst_host.ip6 dst_ip6 = src_if.remote_ip6 ip_permit = src_ip6 if is_ip6 else src_ip4 mac_permit = src_mac if denyMAC: mac = src_mac.split(':') mac[0] = format(int(mac[0], 16)+1, "02x") src_mac = ":".join(mac) if is_ip6: src_ip6 = ip_permit else: src_ip4 = ip_permit if denyIP: if ip_type != self.WILD_IP: src_mac = mac_permit src_ip4 = remote_dst_host.ip4 dst_ip4 = src_if.remote_ip4 src_ip6 = remote_dst_host.ip6 dst_ip6 = src_if.remote_ip6 else: if is_permit: src_mac = remote_dst_host._mac dst_mac = src_if.local_mac src_ip4 = src_if.remote_ip4 dst_ip4 = remote_dst_host.ip4 src_ip6 = src_if.remote_ip6 dst_ip6 = remote_dst_host.ip6 ip_permit = src_ip6 if is_ip6 else src_ip4 mac_permit = src_mac if denyMAC: mac = src_mac.split(':') mac[0] = format(int(mac[0], 16) + 1, "02x") src_mac = ":".join(mac) if is_ip6: src_ip6 = ip_permit else: src_ip4 = ip_permit if denyIP: src_mac = remote_dst_host._mac if ip_type != self.WILD_IP: src_mac = mac_permit src_ip4 = remote_dst_host.ip4 dst_ip4 = src_if.remote_ip4 src_ip6 = remote_dst_host.ip6 dst_ip6 = src_if.remote_ip6 if is_permit: info = self.create_packet_info(src_if, dst_if) payload = self.info_to_payload(info) else: payload = "to be blocked" if mac_type == self.WILD_MAC: mac = src_mac.split(':') for i in range(1, 5): mac[i] = format(random.randint(0, 255), "02x") src_mac = ":".join(mac) # create packet packet = Ether(src=src_mac, dst=dst_mac) ip_rule = src_ip6 if is_ip6 else src_ip4 if is_ip6: if ip_type != self.EXACT_IP: sub_ip = list(unpack('<16B', inet_pton(AF_INET6, ip_rule))) if ip_type == self.WILD_IP: sub_ip[0] = random.randint(240, 254) sub_ip[1] = random.randint(230, 239) sub_ip[14] = random.randint(100, 199) sub_ip[15] = random.randint(200, 255) elif ip_type == self.SUBNET_IP: if denyIP: sub_ip[2] = int(sub_ip[2]) + 1 sub_ip[14] = random.randint(100, 199) sub_ip[15] = random.randint(200, 255) packed_src_ip6 = b''.join( [scapy.compat.chb(x) for x in sub_ip]) src_ip6 = inet_ntop(AF_INET6, packed_src_ip6) packet /= IPv6(src=src_ip6, dst=dst_ip6) else: if ip_type != self.EXACT_IP: sub_ip = ip_rule.split('.') if ip_type == self.WILD_IP: sub_ip[0] = random.randint(1, 49) sub_ip[1] = random.randint(50, 99) sub_ip[2] = random.randint(100, 199) sub_ip[3] = random.randint(200, 255) elif ip_type == self.SUBNET_IP: if denyIP: sub_ip[1] = int(sub_ip[1])+1 sub_ip[2] = random.randint(100, 199) sub_ip[3] = random.randint(200, 255) src_ip4 = '.'.join(['{!s}'.format(x) for x in sub_ip]) packet /= IP(src=src_ip4, dst=dst_ip4, frag=0, flags=0) packet /= UDP(sport=src_port, dport=dst_port)/Raw(payload) packet[Raw].load += b" mac:%s" % scapy.compat.raw(src_mac) size = self.pg_if_packet_sizes[p % len(self.pg_if_packet_sizes)] if isinstance(src_if, VppSubInterface): size = size + 4 if isinstance(src_if, VppDot1QSubint): if src_if is self.subifs[0]: if tags == self.PERMIT_TAGS: packet = src_if.add_dot1q_layer(packet, 10) else: packet = src_if.add_dot1q_layer(packet, 11) else: if tags == self.PERMIT_TAGS: packet = src_if.add_dot1q_layer(packet, 30) else: packet = src_if.add_dot1q_layer(packet, 33) elif isinstance(src_if, VppDot1ADSubint): if src_if is self.subifs[1]: if tags == self.PERMIT_TAGS: packet = src_if.add_dot1ad_layer(packet, 300, 400) else: packet = src_if.add_dot1ad_layer(packet, 333, 444) else: if tags == self.PERMIT_TAGS: packet = src_if.add_dot1ad_layer(packet, 600, 700) else: packet = src_if.add_dot1ad_layer(packet, 666, 777) self.extend_packet(packet, size) packets.append(packet) # create suitable MACIP rule if mac_type == self.EXACT_MAC: mac_rule = src_mac mac_mask = "ff:ff:ff:ff:ff:ff" elif mac_type == self.WILD_MAC: mac_rule = "00:00:00:00:00:00" mac_mask = "00:00:00:00:00:00" elif mac_type == self.OUI_MAC: mac = src_mac.split(':') mac[3] = mac[4] = mac[5] = '00' mac_rule = ":".join(mac) mac_mask = "ff:ff:ff:00:00:00" if is_ip6: if ip_type == self.WILD_IP: ip = "0::0" else: ip = src_ip6 if ip_type == self.SUBNET_IP: sub_ip = list(unpack('<16B', inet_pton(AF_INET6, ip))) for i in range(8, 16): sub_ip[i] = 0 packed_ip = b''.join( [scapy.compat.chb(x) for x in sub_ip]) ip = inet_ntop(AF_INET6, packed_ip) else: if ip_type == self.WILD_IP: ip = "0.0.0.0" else: ip = src_ip4 if ip_type == self.SUBNET_IP: sub_ip = ip.split('.') sub_ip[2] = sub_ip[3] = '0' ip = ".".join(sub_ip) prefix_len = 128 if is_ip6 else 32 if ip_type == self.WILD_IP: prefix_len = 0 elif ip_type == self.SUBNET_IP: prefix_len = 64 if is_ip6 else 16 ip_rule = inet_pton(AF_INET6 if is_ip6 else AF_INET, ip) # create suitable ACL rule if is_permit: rule_l4_sport = packet[UDP].sport rule_l4_dport = packet[UDP].dport rule_family = AF_INET6 if packet.haslayer(IPv6) else AF_INET rule_prefix_len = 128 if packet.haslayer(IPv6) else 32 rule_l3_layer = IPv6 if packet.haslayer(IPv6) else IP if packet.haslayer(IPv6): rule_l4_proto = packet[UDP].overload_fields[IPv6]['nh'] else: rule_l4_proto = packet[IP].proto acl_rule = { 'is_permit': is_permit, 'is_ipv6': is_ip6, 'src_ip_addr': inet_pton(rule_family, packet[rule_l3_layer].src), 'src_ip_prefix_len': rule_prefix_len, 'dst_ip_addr': inet_pton(rule_family, packet[rule_l3_layer].dst), 'dst_ip_prefix_len': rule_prefix_len, 'srcport_or_icmptype_first': rule_l4_sport, 'srcport_or_icmptype_last': rule_l4_sport, 'dstport_or_icmpcode_first': rule_l4_dport, 'dstport_or_icmpcode_last': rule_l4_dport, 'proto': rule_l4_proto} acl_rules.append(acl_rule) if mac_type == self.WILD_MAC and ip_type == self.WILD_IP and p > 0: continue if is_permit: macip_rule = ({ 'is_permit': is_permit, 'is_ipv6': is_ip6, 'src_ip_addr': ip_rule, 'src_ip_prefix_len': prefix_len, 'src_mac': binascii.unhexlify(mac_rule.replace(':', '')), 'src_mac_mask': binascii.unhexlify( mac_mask.replace(':', ''))}) macip_rules.append(macip_rule) # deny all other packets if not (mac_type == self.WILD_MAC and ip_type == self.WILD_IP): macip_rule = ({'is_permit': 0, 'is_ipv6': is_ip6, 'src_ip_addr': "", 'src_ip_prefix_len': 0, 'src_mac': "", 'src_mac_mask': ""}) macip_rules.append(macip_rule) acl_rule = {'is_permit': 0, 'is_ipv6': is_ip6} acl_rules.append(acl_rule) return {'stream': packets, 'macip_rules': macip_rules, 'acl_rules': acl_rules}
def gen_pkts6(self, sw_intf, src, dst, count=1, payload_size=100): return [ Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) / IPv6(src=src, dst=dst) / UDP(sport=1166, dport=2233) / Raw(b'X' * payload_size) for i in range(count) ]
async def run_test_nic(dut): tb = TB(dut) await tb.init() tb.log.info("Init driver") await tb.driver.init_dev(tb.dev.functions[0].pcie_id) await tb.driver.interfaces[0].open() # await driver.interfaces[1].open() # enable queues tb.log.info("Enable queues") await tb.rc.mem_write_dword(tb.driver.interfaces[0].ports[0].hw_addr+mqnic.MQNIC_PORT_REG_SCHED_ENABLE, 0x00000001) for k in range(tb.driver.interfaces[0].tx_queue_count): await tb.rc.mem_write_dword(tb.driver.interfaces[0].ports[0].schedulers[0].hw_addr+4*k, 0x00000003) # wait for all writes to complete await tb.rc.mem_read(tb.driver.hw_addr, 4) tb.log.info("Init complete") tb.log.info("Send and receive single packet") data = bytearray([x % 256 for x in range(1024)]) await tb.driver.interfaces[0].start_xmit(data, 0) pkt = await tb.qsfp0_mac.tx.recv() tb.log.info("Packet: %s", pkt) await tb.qsfp0_mac.rx.send(pkt) pkt = await tb.driver.interfaces[0].recv() tb.log.info("Packet: %s", pkt) assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff # await tb.driver.interfaces[1].start_xmit(data, 0) # pkt = await tb.qsfp1_mac.tx.recv() # tb.log.info("Packet: %s", pkt) # await tb.qsfp1_mac.rx.send(pkt) # pkt = await tb.driver.interfaces[1].recv() # tb.log.info("Packet: %s", pkt) # assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff tb.log.info("RX and TX checksum tests") payload = bytes([x % 256 for x in range(256)]) eth = Ether(src='5A:51:52:53:54:55', dst='DA:D1:D2:D3:D4:D5') ip = IP(src='192.168.1.100', dst='192.168.1.101') udp = UDP(sport=1, dport=2) test_pkt = eth / ip / udp / payload test_pkt2 = test_pkt.copy() test_pkt2[UDP].chksum = scapy.utils.checksum(bytes(test_pkt2[UDP])) await tb.driver.interfaces[0].start_xmit(test_pkt2.build(), 0, 34, 6) pkt = await tb.qsfp0_mac.tx.recv() tb.log.info("Packet: %s", pkt) await tb.qsfp0_mac.rx.send(pkt) pkt = await tb.driver.interfaces[0].recv() tb.log.info("Packet: %s", pkt) assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff assert Ether(pkt.data).build() == test_pkt.build() tb.log.info("Multiple small packets") count = 64 pkts = [bytearray([(x+k) % 256 for x in range(60)]) for k in range(count)] tb.loopback_enable = True for p in pkts: await tb.driver.interfaces[0].start_xmit(p, 0) for k in range(count): pkt = await tb.driver.interfaces[0].recv() tb.log.info("Packet: %s", pkt) assert pkt.data == pkts[k] assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff tb.loopback_enable = False tb.log.info("Multiple large packets") count = 64 pkts = [bytearray([(x+k) % 256 for x in range(1514)]) for k in range(count)] tb.loopback_enable = True for p in pkts: await tb.driver.interfaces[0].start_xmit(p, 0) for k in range(count): pkt = await tb.driver.interfaces[0].recv() tb.log.info("Packet: %s", pkt) assert pkt.data == pkts[k] assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff tb.loopback_enable = False tb.log.info("Jumbo frames") count = 64 pkts = [bytearray([(x+k) % 256 for x in range(9014)]) for k in range(count)] tb.loopback_enable = True for p in pkts: await tb.driver.interfaces[0].start_xmit(p, 0) for k in range(count): pkt = await tb.driver.interfaces[0].recv() tb.log.info("Packet: %s", pkt) assert pkt.data == pkts[k] assert pkt.rx_checksum == ~scapy.utils.checksum(bytes(pkt.data[14:])) & 0xffff tb.loopback_enable = False await RisingEdge(dut.clk_250mhz) await RisingEdge(dut.clk_250mhz)
def create_stream(self, src_if, packet_sizes, traffic_type=0, ipv6=0, proto=-1, ports=0, fragments=False, pkt_raw=True, etype=-1): """ Create input packet stream for defined interface using hosts or deleted_hosts list. :param object src_if: Interface to create packet stream for. :param list packet_sizes: List of required packet sizes. :param traffic_type: 1: ICMP packet, 2: IPv6 with EH, 0: otherwise. :return: Stream of packets. """ pkts = [] if self.flows.__contains__(src_if): src_hosts = self.hosts_by_pg_idx[src_if.sw_if_index] for dst_if in self.flows[src_if]: dst_hosts = self.hosts_by_pg_idx[dst_if.sw_if_index] n_int = len(dst_hosts) * len(src_hosts) for i in range(0, n_int): dst_host = dst_hosts[i / len(src_hosts)] src_host = src_hosts[i % len(src_hosts)] pkt_info = self.create_packet_info(src_if, dst_if) if ipv6 == 1: pkt_info.ip = 1 elif ipv6 == 0: pkt_info.ip = 0 else: pkt_info.ip = random.choice([0, 1]) if proto == -1: pkt_info.proto = random.choice(self.proto[self.IP]) else: pkt_info.proto = proto payload = self.info_to_payload(pkt_info) p = Ether(dst=dst_host.mac, src=src_host.mac) if etype > 0: p = Ether(dst=dst_host.mac, src=src_host.mac, type=etype) if pkt_info.ip: p /= IPv6(dst=dst_host.ip6, src=src_host.ip6) if fragments: p /= IPv6ExtHdrFragment(offset=64, m=1) else: if fragments: p /= IP(src=src_host.ip4, dst=dst_host.ip4, flags=1, frag=64) else: p /= IP(src=src_host.ip4, dst=dst_host.ip4) if traffic_type == self.ICMP: if pkt_info.ip: p /= ICMPv6EchoRequest(type=self.icmp6_type, code=self.icmp6_code) else: p /= ICMP(type=self.icmp4_type, code=self.icmp4_code) else: p /= self.create_upper_layer(i, pkt_info.proto, ports) if pkt_raw: p /= Raw(payload) pkt_info.data = p.copy() if pkt_raw: size = random.choice(packet_sizes) self.extend_packet(p, size) pkts.append(p) return pkts
def test_fif6(self): """ Fragments in fragments (6o6) """ # TODO this should be ideally in setUpClass, but then we hit a bug # with VppIpRoute incorrectly reporting it's present when it's not # so we need to manually remove the vpp config, thus we cannot have # it shared for multiple test cases self.tun_ip6 = "1002::1" self.gre6 = VppGre6Interface(self, self.src_if.local_ip6, self.tun_ip6) self.gre6.add_vpp_config() self.gre6.admin_up() self.gre6.config_ip6() self.vapi.ip_reassembly_enable_disable( sw_if_index=self.gre6.sw_if_index, enable_ip6=True) self.route6 = VppIpRoute(self, self.tun_ip6, 128, [ VppRoutePath(self.src_if.remote_ip6, self.src_if.sw_if_index, proto=DpoProto.DPO_PROTO_IP6) ], is_ip6=1) self.route6.add_vpp_config() self.reset_packet_infos() for i in range(test_packet_count): info = self.create_packet_info(self.src_if, self.dst_if) payload = self.info_to_payload(info) # Ethernet header here is only for size calculation, thus it # doesn't matter how it's initialized. This is to ensure that # reassembled packet is not > 9000 bytes, so that it's not dropped p = (Ether() / IPv6(src=self.src_if.remote_ip6, dst=self.dst_if.remote_ip6) / UDP(sport=1234, dport=5678) / Raw(payload)) size = self.packet_sizes[(i // 2) % len(self.packet_sizes)] self.extend_packet(p, size, self.padding) info.data = p[IPv6] # use only IPv6 part, without ethernet header fragments = [ x for _, i in self._packet_infos.iteritems() for x in fragment_rfc8200(i.data, i.index, 400) ] encapped_fragments = \ [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) / IPv6(src=self.tun_ip6, dst=self.src_if.local_ip6) / GRE() / p for p in fragments] fragmented_encapped_fragments = \ [x for p in encapped_fragments for x in ( fragment_rfc8200( p, 2 * len(self._packet_infos) + p[IPv6ExtHdrFragment].id, 200) if IPv6ExtHdrFragment in p else [p] ) ] self.src_if.add_stream(fragmented_encapped_fragments) self.pg_enable_capture(self.pg_interfaces) self.pg_start() self.src_if.assert_nothing_captured() packets = self.dst_if.get_capture(len(self._packet_infos)) self.verify_capture(packets, IPv6) # TODO remove gre vpp config by hand until VppIpRoute gets fixed # so that it's query_vpp_config() works as it should self.gre6.remove_vpp_config()
def test_fif4(self): """ Fragments in fragments (4o4) """ # TODO this should be ideally in setUpClass, but then we hit a bug # with VppIpRoute incorrectly reporting it's present when it's not # so we need to manually remove the vpp config, thus we cannot have # it shared for multiple test cases self.tun_ip4 = "1.1.1.2" self.gre4 = VppGreInterface(self, self.src_if.local_ip4, self.tun_ip4) self.gre4.add_vpp_config() self.gre4.admin_up() self.gre4.config_ip4() self.vapi.ip_reassembly_enable_disable( sw_if_index=self.gre4.sw_if_index, enable_ip4=True) self.route4 = VppIpRoute( self, self.tun_ip4, 32, [VppRoutePath(self.src_if.remote_ip4, self.src_if.sw_if_index)]) self.route4.add_vpp_config() self.reset_packet_infos() for i in range(test_packet_count): info = self.create_packet_info(self.src_if, self.dst_if) payload = self.info_to_payload(info) # Ethernet header here is only for size calculation, thus it # doesn't matter how it's initialized. This is to ensure that # reassembled packet is not > 9000 bytes, so that it's not dropped p = (Ether() / IP( id=i, src=self.src_if.remote_ip4, dst=self.dst_if.remote_ip4) / UDP(sport=1234, dport=5678) / Raw(payload)) size = self.packet_sizes[(i // 2) % len(self.packet_sizes)] self.extend_packet(p, size, self.padding) info.data = p[IP] # use only IP part, without ethernet header fragments = [ x for _, p in self._packet_infos.iteritems() for x in fragment_rfc791(p.data, 400) ] encapped_fragments = \ [Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) / IP(src=self.tun_ip4, dst=self.src_if.local_ip4) / GRE() / p for p in fragments] fragmented_encapped_fragments = \ [x for p in encapped_fragments for x in fragment_rfc791(p, 200)] self.src_if.add_stream(fragmented_encapped_fragments) self.pg_enable_capture(self.pg_interfaces) self.pg_start() self.src_if.assert_nothing_captured() packets = self.dst_if.get_capture(len(self._packet_infos)) self.verify_capture(packets, IP) # TODO remove gre vpp config by hand until VppIpRoute gets fixed # so that it's query_vpp_config() works as it should self.gre4.remove_vpp_config() self.logger.debug(self.vapi.ppcli("show interface"))
async def run_test_offsets(dut, payload_lengths=None, payload_data=None, idle_inserter=None, backpressure_inserter=None): tb = TB(dut) await tb.reset() tb.set_idle_generator(idle_inserter) tb.set_backpressure_generator(backpressure_inserter) test_pkts = [] test_frames = [] check_frames = [] ip_id = 1 for payload in [payload_data(x) for x in payload_lengths()]: eth = Ether(src='5A:51:52:53:54:55', dst='DA:D1:D2:D3:D4:D5') test_pkt = eth / payload ip_id = (ip_id + 1) & 0xffff for start in range(0, min(len(payload) + 14, 32)): offset = 0 test_pkts.append(test_pkt.copy()) test_frame = AxiStreamFrame(test_pkt.build()) test_frames.append(test_frame) await tb.source.send(test_frame) await tb.cmd_source.send( CsumCmdTransaction(csum_enable=1, csum_start=start, csum_offset=offset, csum_init=0)) csum = scapy.utils.checksum(bytes(test_pkt)[start:]) check_frame = bytearray(test_frame.tdata) struct.pack_into('>H', check_frame, offset, csum) check_frames.append(check_frame) for offset in range(0, min(len(payload) + 14, 32) - 1): start = 0 test_pkts.append(test_pkt.copy()) test_frame = AxiStreamFrame(test_pkt.build()) test_frames.append(test_frame) await tb.source.send(test_frame) await tb.cmd_source.send( CsumCmdTransaction(csum_enable=1, csum_start=start, csum_offset=offset, csum_init=0)) csum = scapy.utils.checksum(bytes(test_pkt)[start:]) check_frame = bytearray(test_frame.tdata) struct.pack_into('>H', check_frame, offset, csum) check_frames.append(check_frame) for test_pkt, test_frame, check_frame in zip(test_pkts, test_frames, check_frames): rx_frame = await tb.sink.recv() rx_pkt = Ether(bytes(rx_frame)) tb.log.info("RX packet: %s", repr(rx_pkt)) assert rx_frame.tdata == check_frame assert tb.sink.empty() await RisingEdge(dut.clk) await RisingEdge(dut.clk)