def test_encap(self): """ ip{v4,v6} over ip6 test encap """ p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP') p_ip4 = IP(src="1.2.3.4", dst="130.67.0.1", tos=42) p_payload = UDP(sport=1234, dport=1234) # Encapsulation # IPv6 in to IPv6 tunnel p6 = (p_ether / p_ip6 / p_payload) p6_reply = ( IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6, hlim=64) / p_ip6 / p_payload) p6_reply[1].hlim -= 1 rx = self.send_and_expect(self.pg0, p6 * 11, self.pg1) for p in rx: self.validate(p[1], p6_reply) # IPv4 in to IPv6 tunnel p4 = (p_ether / p_ip4 / p_payload) p4_reply = ( IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6, hlim=64) / p_ip4 / p_payload) p4_reply[1].ttl -= 1 rx = self.send_and_expect(self.pg0, p4 * 11, self.pg1) for p in rx: self.validate(p[1], p4_reply)
def test_decap(self): """ ip{v4,v6} over ip6 test decap """ p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP') p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4) p_payload = UDP(sport=1234, dport=1234) # Decapsulation # IPv6 tunnel to IPv4 p4 = (p_ether / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.local_ip6) / p_ip4 / p_payload) p4_reply = (p_ip4 / p_payload) p4_reply.ttl -= 1 rx = self.send_and_expect(self.pg1, p4 * 11, self.pg0) for p in rx: self.validate(p[1], p4_reply) # IPv6 tunnel to IPv6 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6) p6 = (p_ether / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.local_ip6) / p_ip6 / p_payload) p6_reply = (p_ip6 / p_payload) p6_reply.hlim = 63 rx = self.send_and_expect(self.pg1, p6 * 11, self.pg0) for p in rx: self.validate(p[1], p6_reply)
def generate_ip4_frags(self, payload_length, fragment_size): p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length) p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4) outer_ip4 = (p_ether / IP( src=self.pg1.remote_ip4, id=RandShort(), dst=self.pg0.local_ip4) / p_ip4 / p_payload) frags = fragment(outer_ip4, fragment_size) p4_reply = (p_ip4 / p_payload) p4_reply.ttl -= 1 return frags, p4_reply
def generate_ip6_frags(self, payload_length, fragment_size): p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) p_payload = UDP(sport=1234, dport=1234) / self.payload(payload_length) p_ip6 = IPv6(src="1::1", dst=self.pg0.remote_ip6) outer_ip6 = (p_ether / IPv6(src=self.pg1.remote_ip6, dst=self.pg0.local_ip6) / IPv6ExtHdrFragment() / p_ip6 / p_payload) frags = fragment6(outer_ip6, fragment_size) p6_reply = (p_ip6 / p_payload) p6_reply.hlim -= 1 return frags, p6_reply
def icmp_traceroute6(dst_addr): ans, _ = srp(Ether(src=LOCAL_MAC_ADDR, dst=NEXT_HOP_MAC) / IPv6(dst=dst_addr, hlim=(1, 30)) / ICMPv6EchoRequest(), timeout=2, filter="icmp6", iface=LOCAL_IPv6_IFACE) res = [get_local_ipv6_addr()] for snd, rcv in ans: if rcv[IPv6].src not in res: res.append(rcv[IPv6].src) return res
def test_ip6_mtu(self): """ IP6 MTU test """ # Send small packet with HBH option. Verify that router modifies it. current_mtu = self.get_mtu(self.pg1.sw_if_index) # MTU (only checked on encap) self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0]) self.assertEqual(1280, self.get_mtu(self.pg1.sw_if_index)) p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) p_ip6 = IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) hbh_mtu_option = MTURecord(mtu1=9000) p_hbh = IPv6ExtHdrHopByHop(len=0, nh=17, options=hbh_mtu_option) p_payload = UDP(sport=1234, dport=1234) p6 = p_ether / p_ip6 / p_hbh / p_payload p6.show2() p6_reply = p_ip6 / IPv6ExtHdrHopByHop( len=0, nh=17, options=MTURecord(mtu1=1280)) / p_payload p6_reply.hlim -= 1 rx = self.send_and_expect(self.pg0, p6 * 1, self.pg1) for p in rx: p.show2() self.validate(p[1], p6_reply) ''' # Should fail. Too large MTU p_icmp6 = ICMPv6PacketTooBig(mtu=1280, cksum=0x4c7a) icmp6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg0.remote_ip6, hlim=255, plen=1240) / p_icmp6 / p_ip6 / p_payload) icmp6_reply[2].hlim -= 1 n = icmp6_reply.__class__(icmp6_reply) s = bytes(icmp6_reply) icmp6_reply_str = s[0:1280] rx = self.send_and_expect(self.pg0, p6*9, self.pg0) for p in rx: self.validate_bytes(bytes(p[1]), icmp6_reply_str) ''' # Reset MTU self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [current_mtu, 0, 0, 0])
def send_packet(self, msg_type, t1=None, t2=None, iapdopt=None): if t1 is None: t1 = self.T1 if t2 is None: t2 = self.T2 if iapdopt is None: opt_ia_pd = DHCP6OptIA_PD(iaid=1, T1=t1, T2=t2) else: opt_ia_pd = DHCP6OptIA_PD(iaid=1, T1=t1, T2=t2, iapdopt=iapdopt) p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6( src=mk_ll_addr(self.pg0.remote_mac), dst=self.pg0.local_ip6_ll) / UDP(sport=547, dport=546) / msg_type(trid=self.trid) / DHCP6OptServerId(duid=self.server_duid) / DHCP6OptClientId(duid=self.client_duid) / opt_ia_pd) self.pg0.add_stream([p]) self.pg_enable_capture(self.pg_interfaces) self.pg_start()
def test_ip6_mtu(self): """ IP6 MTU test """ # # TODO: Link MTU is 216 bytes 'off'. Fix when L3 MTU patches committed # mtu_offset = 216 current_mtu = self.get_mtu(self.pg1.sw_if_index) current_mtu -= mtu_offset p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) p_ip6 = IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) p_payload = UDP(sport=1234, dport=1234) / self.payload( current_mtu - 40 - 8) p6 = p_ether / p_ip6 / p_payload p6_reply = p_ip6 / p_payload p6_reply.hlim -= 1 rx = self.send_and_expect(self.pg0, p6*9, self.pg1) for p in rx: self.validate(p[1], p6_reply) # MTU (only checked on encap) self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, 1280 + mtu_offset) self.assertEqual(1280, self.get_mtu(self.pg1.sw_if_index) - mtu_offset) # Should fail. Too large MTU p_icmp6 = ICMPv6PacketTooBig(mtu=1280, cksum=0x4c7a) icmp6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg0.remote_ip6, hlim=254, plen=1240) / p_icmp6 / p_ip6 / p_payload) icmp6_reply[2].hlim -= 1 n = icmp6_reply.__class__(str(icmp6_reply)) s = str(icmp6_reply) icmp6_reply = s[0:1280] rx = self.send_and_expect(self.pg0, p6*9, self.pg0) for p in rx: self.validate_bytes(str(p[1]), icmp6_reply) # Reset MTU self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, current_mtu)
def get_alive_clients(): if get_local_ipv6_addr() == SERVER_ADDR: return [] while True: sendp( Ether(src=LOCAL_MAC_ADDR, dst=NEXT_HOP_MAC) / IPv6(dst=SERVER_ADDR) / UDP(sport=ACCESS_CLIENT_LIST_PORT, dport=ACCESS_CLIENT_LIST_PORT), iface=LOCAL_IPv6_IFACE) recv_packets = sniff( filter= f'dst host {LOCAL_IPv6_ADDR} && port {ACCESS_CLIENT_LIST_PORT}', count=1, timeout=3, iface=LOCAL_IPv6_IFACE) if len(recv_packets) > 0: clients = parse_payload(recv_packets[0]) return [client for client in clients if client != LOCAL_IPv6_ADDR] else: print(f'server is sleeping?')
def test_ip6_mtu(self): """ IP6 MTU test """ current_mtu = self.get_mtu(self.pg1.sw_if_index) p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) p_ip6 = IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6) p_payload = UDP(sport=1234, dport=1234) / self.payload(current_mtu - 40 - 8) p6 = p_ether / p_ip6 / p_payload p6_reply = p_ip6 / p_payload p6_reply.hlim -= 1 rx = self.send_and_expect(self.pg0, p6 * 9, self.pg1) for p in rx: self.validate(p[1], p6_reply) # MTU (only checked on encap) self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0]) self.assertEqual(1280, self.get_mtu(self.pg1.sw_if_index)) # Should fail. Too large MTU p_icmp6 = ICMPv6PacketTooBig(mtu=1280, cksum=0x4c7a) icmp6_reply = (IPv6(src=self.pg0.local_ip6, dst=self.pg0.remote_ip6, hlim=255, plen=1240) / p_icmp6 / p_ip6 / p_payload) icmp6_reply[2].hlim -= 1 n = icmp6_reply.__class__(str(icmp6_reply)) s = str(icmp6_reply) icmp6_reply_str = s[0:1280] rx = self.send_and_expect(self.pg0, p6 * 9, self.pg0) for p in rx: self.validate_bytes(str(p[1]), icmp6_reply_str) # Reset MTU self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [current_mtu, 0, 0, 0])
def test_ipip4(self): """ ip{v4,v6} over ip4 test """ p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) p_ip6 = IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=42) p_ip4 = IP(src="1.2.3.4", dst="130.67.0.1", tos=42) p_payload = UDP(sport=1234, dport=1234) # IPv4 transport rv = ipip_add_tunnel(self, self.pg0.local_ip4, self.pg1.remote_ip4, tc_tos=0xFF) sw_if_index = rv.sw_if_index # Set interface up and enable IP on it self.vapi.sw_interface_set_flags(sw_if_index, 1) self.vapi.sw_interface_set_unnumbered( sw_if_index=self.pg0.sw_if_index, unnumbered_sw_if_index=sw_if_index) # Add IPv4 and IPv6 routes via tunnel interface ip4_via_tunnel = VppIpRoute( self, "130.67.0.0", 16, [ VppRoutePath( "0.0.0.0", sw_if_index, proto=DpoProto.DPO_PROTO_IP4) ], is_ip6=0) ip4_via_tunnel.add_vpp_config() ip6_via_tunnel = VppIpRoute( self, "dead::", 16, [VppRoutePath("::", sw_if_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) ip6_via_tunnel.add_vpp_config() # IPv6 in to IPv4 tunnel p6 = (p_ether / p_ip6 / p_payload) p_inner_ip6 = p_ip6 p_inner_ip6.hlim -= 1 p6_reply = (IP(src=self.pg0.local_ip4, dst=self.pg1.remote_ip4, proto='ipv6', id=0, tos=42) / p_inner_ip6 / p_payload) p6_reply.ttl -= 1 rx = self.send_and_expect(self.pg0, p6 * 10, self.pg1) for p in rx: self.validate(p[1], p6_reply) # IPv4 in to IPv4 tunnel p4 = (p_ether / p_ip4 / p_payload) p_ip4_inner = p_ip4 p_ip4_inner.ttl -= 1 p4_reply = ( IP(src=self.pg0.local_ip4, dst=self.pg1.remote_ip4, tos=42) / p_ip4_inner / p_payload) p4_reply.ttl -= 1 p4_reply.id = 0 rx = self.send_and_expect(self.pg0, p4 * 10, self.pg1) for p in rx: self.validate(p[1], p4_reply) # Decapsulation p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) # IPv4 tunnel to IPv4 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4) p4 = (p_ether / IP(src=self.pg1.remote_ip4, dst=self.pg0.local_ip4) / p_ip4 / p_payload) p4_reply = (p_ip4 / p_payload) p4_reply.ttl -= 1 rx = self.send_and_expect(self.pg1, p4 * 10, self.pg0) for p in rx: self.validate(p[1], p4_reply) err = self.statistics.get_err_counter( '/err/ipip4-input/packets decapsulated') self.assertEqual(err, 10) # IPv4 tunnel to IPv6 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6) p6 = (p_ether / IP(src=self.pg1.remote_ip4, dst=self.pg0.local_ip4) / p_ip6 / p_payload) p6_reply = (p_ip6 / p_payload) p6_reply.hlim = 63 rx = self.send_and_expect(self.pg1, p6 * 10, self.pg0) for p in rx: self.validate(p[1], p6_reply) err = self.statistics.get_err_counter( '/err/ipip4-input/packets decapsulated') self.assertEqual(err, 20) # # Fragmentation / Reassembly and Re-fragmentation # rv = self.vapi.ip_reassembly_enable_disable( sw_if_index=self.pg1.sw_if_index, enable_ip4=1) self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=1000, max_reassembly_length=1000, expire_walk_interval_ms=10000, is_ip6=0) # Send lots of fragments, verify reassembled packet frags, p4_reply = self.generate_ip4_frags(3131, 1400) f = [] for i in range(0, 1000): f.extend(frags) self.pg1.add_stream(f) self.pg_enable_capture() self.pg_start() rx = self.pg0.get_capture(1000) for p in rx: self.validate(p[1], p4_reply) err = self.statistics.get_err_counter( '/err/ipip4-input/packets decapsulated') self.assertEqual(err, 1020) f = [] r = [] for i in range(1, 90): frags, p4_reply = self.generate_ip4_frags(i * 100, 1000) f.extend(frags) r.extend(p4_reply) self.pg_enable_capture() self.pg1.add_stream(f) self.pg_start() rx = self.pg0.get_capture(89) i = 0 for p in rx: self.validate(p[1], r[i]) i += 1 # Now try with re-fragmentation # # Send fragments to tunnel head-end, for the tunnel head end # to reassemble and then refragment # self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [576, 0, 0, 0]) frags, p4_reply = self.generate_ip4_frags(3123, 1200) self.pg_enable_capture() self.pg1.add_stream(frags) self.pg_start() rx = self.pg0.get_capture(6) reass_pkt = reassemble4(rx) p4_reply.ttl -= 1 p4_reply.id = 256 self.validate(reass_pkt, p4_reply) self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [1600, 0, 0, 0]) frags, p4_reply = self.generate_ip4_frags(3123, 1200) self.pg_enable_capture() self.pg1.add_stream(frags) self.pg_start() rx = self.pg0.get_capture(2) reass_pkt = reassemble4(rx) p4_reply.ttl -= 1 p4_reply.id = 512 self.validate(reass_pkt, p4_reply)
def test_gso(self): """ GSO test """ # # Send jumbo frame with gso disabled and DF bit is set # self.create_pg_interfaces(range(2)) for i in self.pg_interfaces: i.admin_up() i.config_ip4() i.config_ip6() i.disable_ipv6_ra() i.resolve_arp() i.resolve_ndp() p4 = ( Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, flags='DF') / TCP(sport=1234, dport=1234) / Raw('\xa5' * 65200)) rxs = self.send_and_expect(self.pg0, [p4], self.pg0) for rx in rxs: self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[IP].src, self.pg0.local_ip4) self.assertEqual(rx[IP].dst, self.pg0.remote_ip4) self.assertEqual(rx[ICMP].type, 3) # "dest-unreach" self.assertEqual(rx[ICMP].code, 4) # "fragmentation-needed" # # Send jumbo frame with gso enabled and DF bit is set # input and output interfaces support GSO # self.create_pg_interfaces(range(2, 4), 1, 1460) for i in self.pg_interfaces: i.admin_up() i.config_ip4() i.config_ip6() i.disable_ipv6_ra() i.resolve_arp() i.resolve_ndp() p41 = ( Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IP(src=self.pg2.remote_ip4, dst=self.pg3.remote_ip4, flags='DF') / TCP(sport=1234, dport=1234) / Raw('\xa5' * 65200)) rxs = self.send_and_expect(self.pg2, [p41], self.pg3) for rx in rxs: self.assertEqual(rx[Ether].src, self.pg3.local_mac) self.assertEqual(rx[Ether].dst, self.pg3.remote_mac) self.assertEqual(rx[IP].src, self.pg2.remote_ip4) self.assertEqual(rx[IP].dst, self.pg3.remote_ip4) self.assertEqual(rx[IP].len, 65240) # 65200 + 20 (IP) + 20 (TCP) self.assertEqual(rx[TCP].sport, 1234) self.assertEqual(rx[TCP].dport, 1234) # # Send jumbo frame with gso enabled only on input interface # and DF bit is set. GSO packet will be chunked into gso_size # data payload # self.create_pg_interfaces(range(4, 5)) for i in self.pg_interfaces: i.admin_up() i.config_ip4() i.config_ip6() i.disable_ipv6_ra() i.resolve_arp() i.resolve_ndp() p42 = ( Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IP(src=self.pg2.remote_ip4, dst=self.pg4.remote_ip4, flags='DF') / TCP(sport=1234, dport=1234) / Raw('\xa5' * 65200)) rxs = self.send_and_expect(self.pg2, [p42], self.pg4, 45) size = 0 for rx in rxs: self.assertEqual(rx[Ether].src, self.pg4.local_mac) self.assertEqual(rx[Ether].dst, self.pg4.remote_mac) self.assertEqual(rx[IP].src, self.pg2.remote_ip4) self.assertEqual(rx[IP].dst, self.pg4.remote_ip4) self.assertEqual(rx[TCP].sport, 1234) self.assertEqual(rx[TCP].dport, 1234) size = rxs[44][TCP].seq + rxs[44][IP].len - 20 - 20 self.assertEqual(size, 65200) # # Send jumbo frame with gso enabled only on input interface # and DF bit is unset. GSO packet will be fragmented. # self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [576, 0, 0, 0]) p43 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IP(src=self.pg2.remote_ip4, dst=self.pg1.remote_ip4) / TCP(sport=1234, dport=1234) / Raw('\xa5' * 65200)) rxs = self.send_and_expect(self.pg2, [p43], self.pg1, 119) size = 0 for rx in rxs: rx.show() self.assertEqual(rx[Ether].src, self.pg1.local_mac) self.assertEqual(rx[Ether].dst, self.pg1.remote_mac) self.assertEqual(rx[IP].src, self.pg2.remote_ip4) self.assertEqual(rx[IP].dst, self.pg1.remote_ip4) size += rx[IP].len - 20 size -= 20 # TCP header self.assertEqual(size, 65200)
def test_gro(self): """GRO test""" n_packets = 124 # # Send 1500 bytes frame with gro disabled # p4 = ( Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, flags="DF") / TCP(sport=1234, dport=4321) / Raw(b"\xa5" * 1460)) rxs = self.send_and_expect(self.pg0, n_packets * p4, self.pg1) for rx in rxs: self.assertEqual(rx[Ether].src, self.pg1.local_mac) self.assertEqual(rx[Ether].dst, self.pg1.remote_mac) self.assertEqual(rx[IP].src, self.pg0.remote_ip4) self.assertEqual(rx[IP].dst, self.pg1.remote_ip4) self.assertEqual(rx[TCP].sport, 1234) self.assertEqual(rx[TCP].dport, 4321) # # Send 1500 bytes frame with gro enabled on # output interfaces support GRO # p = [] s = 0 for n in range(0, n_packets): p.append((Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg2.remote_ip4, flags="DF") / TCP(sport=1234, dport=4321, seq=s, ack=n, flags="A") / Raw(b"\xa5" * 1460))) s += 1460 rxs = self.send_and_expect(self.pg0, p, self.pg2, n_rx=2) i = 0 for rx in rxs: i += 1 self.assertEqual(rx[Ether].src, self.pg2.local_mac) self.assertEqual(rx[Ether].dst, self.pg2.remote_mac) self.assertEqual(rx[IP].src, self.pg0.remote_ip4) self.assertEqual(rx[IP].dst, self.pg2.remote_ip4) self.assertEqual(rx[IP].len, 64280) # 1460 * 44 + 40 < 65536 self.assertEqual(rx[TCP].sport, 1234) self.assertEqual(rx[TCP].dport, 4321) self.assertEqual(rx[TCP].ack, (44 * i - 1)) p4_temp = ( Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IP(src=self.pg2.remote_ip4, dst=self.pg0.remote_ip4, flags="DF") / TCP(sport=1234, dport=4321, flags="F")) rxs = self.send_and_expect(self.pg2, 100 * [p4_temp], self.pg0, n_rx=100) rx_coalesce = self.pg2.get_capture(1, timeout=1) rx0 = rx_coalesce[0] self.assertEqual(rx0[Ether].src, self.pg2.local_mac) self.assertEqual(rx0[Ether].dst, self.pg2.remote_mac) self.assertEqual(rx0[IP].src, self.pg0.remote_ip4) self.assertEqual(rx0[IP].dst, self.pg2.remote_ip4) self.assertEqual(rx0[IP].len, 52600) # 1460 * 36 + 40 self.assertEqual(rx0[TCP].sport, 1234) self.assertEqual(rx0[TCP].dport, 4321) for rx in rxs: self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[IP].src, self.pg2.remote_ip4) self.assertEqual(rx[IP].dst, self.pg0.remote_ip4) self.assertEqual(rx[IP].len, 40) self.assertEqual(rx[TCP].sport, 1234) self.assertEqual(rx[TCP].dport, 4321) # # Same test with IPv6 # p = [] s = 0 for n in range(0, 88): p.append((Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6(src=self.pg0.remote_ip6, dst=self.pg2.remote_ip6) / TCP(sport=1234, dport=4321, seq=s, ack=n, flags="A") / Raw(b"\xa5" * 1460))) s += 1460 p[-1][TCP].flags = "AP" # push to flush second packet rxs = self.send_and_expect(self.pg0, p, self.pg2, n_rx=2) i = 0 for rx in rxs: i += 1 self.assertEqual(rx[Ether].src, self.pg2.local_mac) self.assertEqual(rx[Ether].dst, self.pg2.remote_mac) self.assertEqual(rx[IPv6].src, self.pg0.remote_ip6) self.assertEqual(rx[IPv6].dst, self.pg2.remote_ip6) self.assertEqual(rx[IPv6].plen, 64260) # 1460 * 44 + 20 < 65536 self.assertEqual(rx[TCP].sport, 1234) self.assertEqual(rx[TCP].dport, 4321) self.assertEqual(rx[TCP].ack, (44 * i - 1)) # # Send a series of 1500 bytes packets each followed by a packet with a # PSH flag. Verify that GRO stops everytime a PSH flag is encountered # p = [] s = 0 for n in range(0, n_packets): p.append( (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg2.remote_ip4, flags="DF") / TCP(sport=1234, dport=4321, seq=s, ack=2 * n, flags="A") / Raw(b"\xa5" * 1460))) s += 1460 p.append(( Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg2.remote_ip4, flags="DF") / TCP(sport=1234, dport=4321, seq=s, ack=2 * n + 1, flags="AP") / Raw(b"\xa5" * 1340))) s += 1340 rxs = self.send_and_expect(self.pg0, p, self.pg2, n_rx=n_packets) i = 0 for rx in rxs: self.assertEqual(rx[Ether].src, self.pg2.local_mac) self.assertEqual(rx[Ether].dst, self.pg2.remote_mac) self.assertEqual(rx[IP].src, self.pg0.remote_ip4) self.assertEqual(rx[IP].dst, self.pg2.remote_ip4) self.assertEqual(rx[IP].len, 40 + 1460 + 1340) self.assertEqual(rx[TCP].sport, 1234) self.assertEqual(rx[TCP].dport, 4321) self.assertEqual(rx[TCP].ack, (2 * i + 1)) i += 1 # # Send a series of 1500 bytes packets each followed by a short packet # with padding. Verify that GRO removes the padding and stops on short # packets # p = [] s = 0 for n in range(0, n_packets): i = self.pg0 p.append( (Ether(src=i.remote_mac, dst=i.local_mac) / IP(src=i.remote_ip4, dst=self.pg2.remote_ip4, flags="DF") / TCP(sport=1234, dport=4321, seq=s, ack=2 * n, flags="A") / Raw(b"\xa5" * 1459))) s += 1459 p2 = (Ether(src=i.remote_mac, dst=i.local_mac) / IP( src=i.remote_ip4, dst=self.pg2.remote_ip4, flags="DF", len=41) / TCP( sport=1234, dport=4321, seq=s, ack=2 * n + 1, flags="A") / Raw(b"\xa5")) # first compute csum of pkt w/o padding to work around scapy bug p2 = Ether(bytes(p2)) p.append(p2 / Raw(b"\xa5" * 5)) # 1 byte data + 5 bytes padding s += 1 rxs = self.send_and_expect(self.pg0, p, self.pg2, n_rx=n_packets) i = 0 for rx in rxs: self.assertEqual(rx[Ether].src, self.pg2.local_mac) self.assertEqual(rx[Ether].dst, self.pg2.remote_mac) self.assertEqual(rx[IP].src, self.pg0.remote_ip4) self.assertEqual(rx[IP].dst, self.pg2.remote_ip4) self.assertEqual(rx[IP].len, 40 + 1459 + 1) self.assertEqual(rx[TCP].sport, 1234) self.assertEqual(rx[TCP].dport, 4321) self.assertEqual(rx[TCP].ack, (2 * i + 1)) i += 1
def test_mipip4(self): """ p2mp IPv4 tunnel Tests """ for itf in self.pg_interfaces: # # one underlay nh for each overlay/tunnel peer # itf.generate_remote_hosts(4) itf.configure_ipv4_neighbors() # # Create an p2mo IPIP tunnel. # - set it admin up # - assign an IP Addres # - Add a route via the tunnel # ipip_if = VppIpIpTunInterface( self, itf, itf.local_ip4, "0.0.0.0", mode=(VppEnum.vl_api_tunnel_mode_t.TUNNEL_API_MODE_MP)) ipip_if.add_vpp_config() ipip_if.admin_up() ipip_if.config_ip4() ipip_if.generate_remote_hosts(4) self.logger.info(self.vapi.cli("sh adj")) self.logger.info(self.vapi.cli("sh ip fib")) # # ensure we don't match to the tunnel if the source address # is all zeros # # tx = self.create_tunnel_stream_4o4(self.pg0, # "0.0.0.0", # itf.local_ip4, # self.pg0.local_ip4, # self.pg0.remote_ip4) # self.send_and_assert_no_replies(self.pg0, tx) # # for-each peer # for ii in range(1, 4): route_addr = "4.4.4.%d" % ii # # route traffic via the peer # route_via_tun = VppIpRoute(self, route_addr, 32, [ VppRoutePath(ipip_if._remote_hosts[ii].ip4, ipip_if.sw_if_index) ]) route_via_tun.add_vpp_config() # # Add a TEIB entry resolves the peer # teib = VppTeib(self, ipip_if, ipip_if._remote_hosts[ii].ip4, itf._remote_hosts[ii].ip4) teib.add_vpp_config() self.logger.info( self.vapi.cli("sh adj nbr ipip0 %s" % ipip_if._remote_hosts[ii].ip4)) # # Send a packet stream that is routed into the tunnel # - packets are IPIP encapped # inner = (IP(dst=route_addr, src="5.5.5.5") / UDP(sport=1234, dport=1234) / Raw(b'0x44' * 100)) tx_e = [ (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / inner) for x in range(63) ] rxs = self.send_and_expect(self.pg0, tx_e, itf) for rx in rxs: self.assertEqual(rx[IP].src, itf.local_ip4) self.assertEqual(rx[IP].dst, itf._remote_hosts[ii].ip4) tx_i = [ (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IP(src=itf._remote_hosts[ii].ip4, dst=itf.local_ip4) / IP(src=self.pg0.local_ip4, dst=self.pg0.remote_ip4) / UDP(sport=1234, dport=1234) / Raw(b'0x44' * 100)) for x in range(63) ] self.logger.info(self.vapi.cli("sh ipip tunnel-hash")) rx = self.send_and_expect(self.pg0, tx_i, self.pg0) # # delete and re-add the TEIB # teib.remove_vpp_config() self.send_and_assert_no_replies(self.pg0, tx_e) self.send_and_assert_no_replies(self.pg0, tx_i) teib.add_vpp_config() rx = self.send_and_expect(self.pg0, tx_e, itf) for rx in rxs: self.assertEqual(rx[IP].src, itf.local_ip4) self.assertEqual(rx[IP].dst, itf._remote_hosts[ii].ip4) rx = self.send_and_expect(self.pg0, tx_i, self.pg0) ipip_if.admin_down() ipip_if.unconfig_ip4()
def test_ipip4(self): """ ip{v4,v6} over ip4 test """ self.pg1.generate_remote_hosts(5) self.pg1.configure_ipv4_neighbors() e = VppEnum.vl_api_tunnel_encap_decap_flags_t d = VppEnum.vl_api_ip_dscp_t self.p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) self.p_payload = UDP(sport=1234, dport=1234) / Raw(b'X' * 100) # create a TOS byte by shifting a DSCP code point 2 bits. those 2 bits # are for the ECN. dscp = d.IP_API_DSCP_AF31 << 2 ecn = 3 dscp_ecn = d.IP_API_DSCP_AF31 << 2 | ecn # IPv4 transport that copies the DCSP from the payload tun_dscp = VppIpIpTunInterface( self, self.pg0, self.pg0.local_ip4, self.pg1.remote_hosts[0].ip4, flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP) tun_dscp.add_vpp_config() # IPv4 transport that copies the DCSP and ECN from the payload tun_dscp_ecn = VppIpIpTunInterface( self, self.pg0, self.pg0.local_ip4, self.pg1.remote_hosts[1].ip4, flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP | e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN)) tun_dscp_ecn.add_vpp_config() # IPv4 transport that copies the ECN from the payload and sets the # DF bit on encap. copies the ECN on decap tun_ecn = VppIpIpTunInterface( self, self.pg0, self.pg0.local_ip4, self.pg1.remote_hosts[2].ip4, flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN | e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_SET_DF | e.TUNNEL_API_ENCAP_DECAP_FLAG_DECAP_COPY_ECN)) tun_ecn.add_vpp_config() # IPv4 transport that sets a fixed DSCP in the encap and copies # the DF bit tun = VppIpIpTunInterface( self, self.pg0, self.pg0.local_ip4, self.pg1.remote_hosts[3].ip4, dscp=d.IP_API_DSCP_AF11, flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DF) tun.add_vpp_config() # array of all the tunnels tuns = [tun_dscp, tun_dscp_ecn, tun_ecn, tun] # addresses for prefixes routed via each tunnel a4s = ["" for i in range(len(tuns))] a6s = ["" for i in range(len(tuns))] # IP headers with each combination of DSCp/ECN tested p_ip6s = [ IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp), IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp_ecn), IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=ecn), IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=0xff) ] p_ip4s = [ IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp, flags='DF'), IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp_ecn), IP(src="1.2.3.4", dst="130.67.0.1", tos=ecn), IP(src="1.2.3.4", dst="130.67.0.1", tos=0xff) ] # Configure each tunnel for i, t in enumerate(tuns): # Set interface up and enable IP on it self.vapi.sw_interface_set_flags(t.sw_if_index, 1) self.vapi.sw_interface_set_unnumbered( sw_if_index=self.pg0.sw_if_index, unnumbered_sw_if_index=t.sw_if_index) # prefix for route / destination address for packets a4s[i] = "130.67.%d.0" % i a6s[i] = "dead:%d::" % i # Add IPv4 and IPv6 routes via tunnel interface ip4_via_tunnel = VppIpRoute(self, a4s[i], 24, [ VppRoutePath("0.0.0.0", t.sw_if_index, proto=FibPathProto.FIB_PATH_NH_PROTO_IP4) ]) ip4_via_tunnel.add_vpp_config() ip6_via_tunnel = VppIpRoute(self, a6s[i], 64, [ VppRoutePath("::", t.sw_if_index, proto=FibPathProto.FIB_PATH_NH_PROTO_IP6) ]) ip6_via_tunnel.add_vpp_config() # # Encapsulation # # tun_dscp copies only the dscp # expected TC values are thus only the DCSP value is present from the # inner exp_tcs = [dscp, dscp, 0, 0xfc] p_ip44_encaps = [ IP(src=self.pg0.local_ip4, dst=tun_dscp.dst, tos=tc) for tc in exp_tcs ] p_ip64_encaps = [ IP(src=self.pg0.local_ip4, dst=tun_dscp.dst, proto='ipv6', id=0, tos=tc) for tc in exp_tcs ] # IPv4 in to IPv4 tunnel self.verify_ip4ip4_encaps(a4s[0], p_ip4s, p_ip44_encaps) # IPv6 in to IPv4 tunnel self.verify_ip6ip4_encaps(a6s[0], p_ip6s, p_ip64_encaps) # tun_dscp_ecn copies the dscp and the ecn exp_tcs = [dscp, dscp_ecn, ecn, 0xff] p_ip44_encaps = [ IP(src=self.pg0.local_ip4, dst=tun_dscp_ecn.dst, tos=tc) for tc in exp_tcs ] p_ip64_encaps = [ IP(src=self.pg0.local_ip4, dst=tun_dscp_ecn.dst, proto='ipv6', id=0, tos=tc) for tc in exp_tcs ] self.verify_ip4ip4_encaps(a4s[1], p_ip4s, p_ip44_encaps) self.verify_ip6ip4_encaps(a6s[1], p_ip6s, p_ip64_encaps) # tun_ecn copies only the ecn and always sets DF exp_tcs = [0, ecn, ecn, ecn] p_ip44_encaps = [ IP(src=self.pg0.local_ip4, dst=tun_ecn.dst, flags='DF', tos=tc) for tc in exp_tcs ] p_ip64_encaps = [ IP(src=self.pg0.local_ip4, dst=tun_ecn.dst, flags='DF', proto='ipv6', id=0, tos=tc) for tc in exp_tcs ] self.verify_ip4ip4_encaps(a4s[2], p_ip4s, p_ip44_encaps) self.verify_ip6ip4_encaps(a6s[2], p_ip6s, p_ip64_encaps) # tun sets a fixed dscp and copies DF fixed_dscp = tun.dscp << 2 flags = ['DF', 0, 0, 0] p_ip44_encaps = [ IP(src=self.pg0.local_ip4, dst=tun.dst, flags=f, tos=fixed_dscp) for f in flags ] p_ip64_encaps = [ IP(src=self.pg0.local_ip4, dst=tun.dst, proto='ipv6', id=0, tos=fixed_dscp) for i in range(len(p_ip4s)) ] self.verify_ip4ip4_encaps(a4s[3], p_ip4s, p_ip44_encaps) self.verify_ip6ip4_encaps(a6s[3], p_ip6s, p_ip64_encaps) # # Decapsulation # n_packets_decapped = 0 self.p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) # IPv4 tunnel to IPv4 tcs = [0, dscp, dscp_ecn, ecn] # one overlay packet and all combinations of its encap p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4) p_ip4_encaps = [ IP(src=tun.dst, dst=self.pg0.local_ip4, tos=tc) for tc in tcs ] # for each encap tun will produce the same inner packet because it does # not copy up fields from the payload for p_ip4_encap in p_ip4_encaps: p4 = (self.p_ether / p_ip4_encap / p_ip4 / self.p_payload) p4_reply = (p_ip4 / self.p_payload) p4_reply.ttl -= 1 rx = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0) n_packets_decapped += N_PACKETS for p in rx: self.validate(p[1], p4_reply) self.assert_packet_checksums_valid(p) err = self.statistics.get_err_counter( '/err/ipip4-input/packets decapsulated') self.assertEqual(err, n_packets_decapped) # tun_ecn copies the ECN bits from the encap to the inner p_ip4_encaps = [ IP(src=tun_ecn.dst, dst=self.pg0.local_ip4, tos=tc) for tc in tcs ] p_ip4_replys = [p_ip4.copy() for i in range(len(p_ip4_encaps))] p_ip4_replys[2].tos = ecn p_ip4_replys[3].tos = ecn for i, p_ip4_encap in enumerate(p_ip4_encaps): p4 = (self.p_ether / p_ip4_encap / p_ip4 / self.p_payload) p4_reply = (p_ip4_replys[i] / self.p_payload) p4_reply.ttl -= 1 rx = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0) n_packets_decapped += N_PACKETS for p in rx: self.validate(p[1], p4_reply) self.assert_packet_checksums_valid(p) err = self.statistics.get_err_counter( '/err/ipip4-input/packets decapsulated') self.assertEqual(err, n_packets_decapped) # IPv4 tunnel to IPv6 # for each encap tun will produce the same inner packet because it does # not copy up fields from the payload p_ip4_encaps = [ IP(src=tun.dst, dst=self.pg0.local_ip4, tos=tc) for tc in tcs ] p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6) for p_ip4_encap in p_ip4_encaps: p6 = (self.p_ether / p_ip4_encap / p_ip6 / self.p_payload) p6_reply = (p_ip6 / self.p_payload) p6_reply.hlim = 63 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0) n_packets_decapped += N_PACKETS for p in rx: self.validate(p[1], p6_reply) self.assert_packet_checksums_valid(p) err = self.statistics.get_err_counter( '/err/ipip4-input/packets decapsulated') self.assertEqual(err, n_packets_decapped) # IPv4 tunnel to IPv6 # tun_ecn copies the ECN bits from the encap to the inner p_ip4_encaps = [ IP(src=tun_ecn.dst, dst=self.pg0.local_ip4, tos=tc) for tc in tcs ] p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6) p_ip6_replys = [p_ip6.copy() for i in range(len(p_ip4_encaps))] p_ip6_replys[2].tc = ecn p_ip6_replys[3].tc = ecn for i, p_ip4_encap in enumerate(p_ip4_encaps): p6 = (self.p_ether / p_ip4_encap / p_ip6 / self.p_payload) p6_reply = (p_ip6_replys[i] / self.p_payload) p6_reply.hlim = 63 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0) n_packets_decapped += N_PACKETS for p in rx: self.validate(p[1], p6_reply) self.assert_packet_checksums_valid(p) err = self.statistics.get_err_counter( '/err/ipip4-input/packets decapsulated') self.assertEqual(err, n_packets_decapped) # # Fragmentation / Reassembly and Re-fragmentation # rv = self.vapi.ip_reassembly_enable_disable( sw_if_index=self.pg1.sw_if_index, enable_ip4=1) self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=1000, max_reassembly_length=1000, expire_walk_interval_ms=10000, is_ip6=0) # Send lots of fragments, verify reassembled packet frags, p4_reply = self.generate_ip4_frags(3131, 1400) f = [] for i in range(0, 1000): f.extend(frags) self.pg1.add_stream(f) self.pg_enable_capture() self.pg_start() rx = self.pg0.get_capture(1000) n_packets_decapped += 1000 for p in rx: self.validate(p[1], p4_reply) err = self.statistics.get_err_counter( '/err/ipip4-input/packets decapsulated') self.assertEqual(err, n_packets_decapped) f = [] r = [] for i in range(1, 90): frags, p4_reply = self.generate_ip4_frags(i * 100, 1000) f.extend(frags) r.extend(p4_reply) self.pg_enable_capture() self.pg1.add_stream(f) self.pg_start() rx = self.pg0.get_capture(89) i = 0 for p in rx: self.validate(p[1], r[i]) i += 1 # Now try with re-fragmentation # # Send fragments to tunnel head-end, for the tunnel head end # to reassemble and then refragment # self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [576, 0, 0, 0]) frags, p4_reply = self.generate_ip4_frags(3123, 1200) self.pg_enable_capture() self.pg1.add_stream(frags) self.pg_start() rx = self.pg0.get_capture(6) reass_pkt = reassemble4(rx) p4_reply.id = 256 self.validate(reass_pkt, p4_reply) self.vapi.sw_interface_set_mtu(self.pg0.sw_if_index, [1600, 0, 0, 0]) frags, p4_reply = self.generate_ip4_frags(3123, 1200) self.pg_enable_capture() self.pg1.add_stream(frags) self.pg_start() rx = self.pg0.get_capture(2) reass_pkt = reassemble4(rx) p4_reply.id = 512 self.validate(reass_pkt, p4_reply) # send large packets through the tunnel, expect them to be fragmented self.vapi.sw_interface_set_mtu(tun_dscp.sw_if_index, [600, 0, 0, 0]) p4 = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src="1.2.3.4", dst="130.67.0.1", tos=42) / UDP(sport=1234, dport=1234) / Raw(b'Q' * 1000)) rx = self.send_and_expect(self.pg0, p4 * 15, self.pg1, 30) inners = [] for p in rx: inners.append(p[IP].payload) reass_pkt = reassemble4(inners) for p in reass_pkt: self.assert_packet_checksums_valid(p) self.assertEqual(p[IP].ttl, 63)
def test_frag(self): """ ip{v4,v6} over ip6 test frag """ p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) p_ip6 = IPv6(src="1::1", dst="DEAD::1", tc=42, nh='UDP') p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4) p_payload = UDP(sport=1234, dport=1234) # # Fragmentation / Reassembly and Re-fragmentation # rv = self.vapi.ip_reassembly_enable_disable( sw_if_index=self.pg1.sw_if_index, enable_ip6=1) self.vapi.ip_reassembly_set(timeout_ms=1000, max_reassemblies=1000, max_reassembly_length=1000, expire_walk_interval_ms=10000, is_ip6=1) # Send lots of fragments, verify reassembled packet before_cnt = self.statistics.get_err_counter( '/err/ipip6-input/packets decapsulated') frags, p6_reply = self.generate_ip6_frags(3131, 1400) f = [] for i in range(0, 1000): f.extend(frags) self.pg1.add_stream(f) self.pg_enable_capture() self.pg_start() rx = self.pg0.get_capture(1000) for p in rx: self.validate(p[1], p6_reply) cnt = self.statistics.get_err_counter( '/err/ipip6-input/packets decapsulated') self.assertEqual(cnt, before_cnt + 1000) f = [] r = [] # TODO: Check out why reassembly of atomic fragments don't work for i in range(10, 90): frags, p6_reply = self.generate_ip6_frags(i * 100, 1000) f.extend(frags) r.extend(p6_reply) self.pg_enable_capture() self.pg1.add_stream(f) self.pg_start() rx = self.pg0.get_capture(80) i = 0 for p in rx: self.validate(p[1], r[i]) i += 1 # Simple fragmentation p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0]) # IPv6 in to IPv6 tunnel p_payload = UDP(sport=1234, dport=1234) / self.payload(1300) p6 = (p_ether / p_ip6 / p_payload) p6_reply = ( IPv6(src=self.pg0.local_ip6, dst=self.pg1.remote_ip6, hlim=63) / p_ip6 / p_payload) p6_reply[1].hlim -= 1 self.pg_enable_capture() self.pg0.add_stream(p6) self.pg_start() rx = self.pg1.get_capture(2) # Scapy defragment doesn't deal well with multiple layers # of same type / Ethernet header first f = [p[1] for p in rx] reass_pkt = defragment6(f) self.validate(reass_pkt, p6_reply) # Now try with re-fragmentation # # Send large fragments to tunnel head-end, for the tunnel head end # to reassemble and then refragment out the tunnel again. # Hair-pinning # self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0]) frags, p6_reply = self.generate_ip6_hairpin_frags(8000, 1200) self.pg_enable_capture() self.pg1.add_stream(frags) self.pg_start() rx = self.pg1.get_capture(7) f = [p[1] for p in rx] reass_pkt = defragment6(f) p6_reply.id = 256 self.validate(reass_pkt, p6_reply)
def test_gso_vxlan(self): """ GSO VXLAN test """ self.logger.info(self.vapi.cli("sh int addr")) # # Send jumbo frame with gso enabled only on input interface and # create VXLAN VTEP on VPP pg0, and put vxlan_tunnel0 and pg2 # into BD. # # # enable ipv4/vxlan # self.vxlan.add_vpp_config() self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.vxlan.sw_if_index, bd_id=self.single_tunnel_bd) self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.pg2.sw_if_index, bd_id=self.single_tunnel_bd) self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index) # # IPv4/IPv4 - VXLAN # p45 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") / IP(src=self.pg2.remote_ip4, dst="172.16.3.3", flags='DF') / TCP(sport=1234, dport=1234) / Raw(b'\xa5' * 65200)) rxs = self.send_and_expect(self.pg2, 5 * [p45], self.pg0, 225) size = 0 for rx in rxs: self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[IP].src, self.pg0.local_ip4) self.assertEqual(rx[IP].dst, self.pg0.remote_ip4) self.assert_ip_checksum_valid(rx) self.assert_udp_checksum_valid(rx) self.assertEqual(rx[VXLAN].vni, 10) inner = rx[VXLAN].payload self.assertEqual(rx[IP].len - 20 - 8 - 8, len(inner)) self.assertEqual(inner[Ether].src, self.pg2.remote_mac) self.assertEqual(inner[Ether].dst, "02:fe:60:1e:a2:79") self.assertEqual(inner[IP].src, self.pg2.remote_ip4) self.assertEqual(inner[IP].dst, "172.16.3.3") self.assert_ip_checksum_valid(inner) self.assert_tcp_checksum_valid(inner) payload_len = inner[IP].len - 20 - 20 self.assertEqual(payload_len, len(inner[Raw])) size += payload_len self.assertEqual(size, 65200 * 5) # # IPv4/IPv6 - VXLAN # p65 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") / IPv6(src=self.pg2.remote_ip6, dst="fd01:3::3") / TCP(sport=1234, dport=1234) / Raw(b'\xa5' * 65200)) rxs = self.send_and_expect(self.pg2, 5 * [p65], self.pg0, 225) size = 0 for rx in rxs: self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[IP].src, self.pg0.local_ip4) self.assertEqual(rx[IP].dst, self.pg0.remote_ip4) self.assert_ip_checksum_valid(rx) self.assert_udp_checksum_valid(rx) self.assertEqual(rx[VXLAN].vni, 10) inner = rx[VXLAN].payload self.assertEqual(rx[IP].len - 20 - 8 - 8, len(inner)) self.assertEqual(inner[Ether].src, self.pg2.remote_mac) self.assertEqual(inner[Ether].dst, "02:fe:60:1e:a2:79") self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6) self.assertEqual(inner[IPv6].dst, "fd01:3::3") self.assert_tcp_checksum_valid(inner) payload_len = inner[IPv6].plen - 20 self.assertEqual(payload_len, len(inner[Raw])) size += payload_len self.assertEqual(size, 65200 * 5) # # disable ipv4/vxlan # self.vxlan.remove_vpp_config() # # enable ipv6/vxlan # self.vxlan2.add_vpp_config() self.vapi.sw_interface_set_l2_bridge( rx_sw_if_index=self.vxlan2.sw_if_index, bd_id=self.single_tunnel_bd) # # IPv6/IPv4 - VXLAN # p46 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") / IP(src=self.pg2.remote_ip4, dst="172.16.3.3", flags='DF') / TCP(sport=1234, dport=1234) / Raw(b'\xa5' * 65200)) rxs = self.send_and_expect(self.pg2, 5 * [p46], self.pg0, 225) size = 0 for rx in rxs: self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[IPv6].src, self.pg0.local_ip6) self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6) self.assert_udp_checksum_valid(rx) self.assertEqual(rx[VXLAN].vni, 10) inner = rx[VXLAN].payload self.assertEqual(rx[IPv6].plen - 8 - 8, len(inner)) self.assertEqual(inner[Ether].src, self.pg2.remote_mac) self.assertEqual(inner[Ether].dst, "02:fe:60:1e:a2:79") self.assertEqual(inner[IP].src, self.pg2.remote_ip4) self.assertEqual(inner[IP].dst, "172.16.3.3") self.assert_ip_checksum_valid(inner) self.assert_tcp_checksum_valid(inner) payload_len = inner[IP].len - 20 - 20 self.assertEqual(payload_len, len(inner[Raw])) size += payload_len self.assertEqual(size, 65200 * 5) # # IPv6/IPv6 - VXLAN # p66 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") / IPv6(src=self.pg2.remote_ip6, dst="fd01:3::3") / TCP(sport=1234, dport=1234) / Raw(b'\xa5' * 65200)) rxs = self.send_and_expect(self.pg2, 5 * [p66], self.pg0, 225) size = 0 for rx in rxs: self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[IPv6].src, self.pg0.local_ip6) self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6) self.assert_udp_checksum_valid(rx) self.assertEqual(rx[VXLAN].vni, 10) inner = rx[VXLAN].payload self.assertEqual(rx[IPv6].plen - 8 - 8, len(inner)) self.assertEqual(inner[Ether].src, self.pg2.remote_mac) self.assertEqual(inner[Ether].dst, "02:fe:60:1e:a2:79") self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6) self.assertEqual(inner[IPv6].dst, "fd01:3::3") self.assert_tcp_checksum_valid(inner) payload_len = inner[IPv6].plen - 20 self.assertEqual(payload_len, len(inner[Raw])) size += payload_len self.assertEqual(size, 65200 * 5) # # disable ipv4/vxlan # self.vxlan2.remove_vpp_config() self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index, enable_disable=0)
def test_dhcp_pd_send_solicit_receive_advertise(self): """Verify DHCPv6 PD Solicit packet and Advertise event""" self.vapi.dhcp6_clients_enable_disable(enable=1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() prefix = { "prefix": {"address": "1:2:3::", "len": 50}, "preferred_time": 60, "valid_time": 120, } prefixes = [prefix] self.vapi.dhcp6_pd_send_client_message( server_index=0xFFFFFFFF, mrc=1, msg_type=VppEnum.vl_api_dhcpv6_msg_type_t.DHCPV6_MSG_API_SOLICIT, sw_if_index=self.pg0.sw_if_index, T1=20, T2=40, prefixes=prefixes, n_prefixes=len(prefixes), ) rx_list = self.pg0.get_capture(1) self.assertEqual(len(rx_list), 1) packet = rx_list[0] self.assertEqual(packet.haslayer(IPv6), 1) self.assertEqual(packet[IPv6].haslayer(DHCP6_Solicit), 1) client_duid = packet[DHCP6OptClientId].duid trid = packet[DHCP6_Solicit].trid dst = ip6_normalize(packet[IPv6].dst) dst2 = ip6_normalize("ff02::1:2") self.assert_equal(dst, dst2) src = ip6_normalize(packet[IPv6].src) src2 = ip6_normalize(self.pg0.local_ip6_ll) self.assert_equal(src, src2) ia_pd = packet[DHCP6OptIA_PD] self.assert_equal(ia_pd.T1, 20) self.assert_equal(ia_pd.T2, 40) self.assert_equal(len(ia_pd.iapdopt), 1) prefix = ia_pd.iapdopt[0] self.assert_equal(prefix.prefix, "1:2:3::") self.assert_equal(prefix.plen, 50) self.assert_equal(prefix.preflft, 60) self.assert_equal(prefix.validlft, 120) self.vapi.want_dhcp6_pd_reply_events(enable_disable=1, pid=os.getpid()) try: ia_pd_opts = DHCP6OptIAPrefix( prefix="7:8::", plen=56, preflft=60, validlft=120 ) p = ( Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6( src=util.mk_ll_addr(self.pg0.remote_mac), dst=self.pg0.local_ip6_ll ) / UDP(sport=547, dport=546) / DHCP6_Advertise(trid=trid) / DHCP6OptServerId(duid=self.server_duid) / DHCP6OptClientId(duid=client_duid) / DHCP6OptPref(prefval=7) / DHCP6OptStatusCode(statuscode=1) / DHCP6OptIA_PD(iaid=1, T1=20, T2=40, iapdopt=ia_pd_opts) ) self.pg0.add_stream([p]) self.pg_start() ev = self.vapi.wait_for_event(1, "dhcp6_pd_reply_event") self.assert_equal(ev.preference, 7) self.assert_equal(ev.status_code, 1) self.assert_equal(ev.T1, 20) self.assert_equal(ev.T2, 40) reported_prefix = ev.prefixes[0] prefix = ia_pd_opts.getfieldval("prefix") self.assert_equal(str(reported_prefix.prefix).split("/")[0], prefix) self.assert_equal( int(str(reported_prefix.prefix).split("/")[1]), ia_pd_opts.getfieldval("plen"), ) self.assert_equal( reported_prefix.preferred_time, ia_pd_opts.getfieldval("preflft") ) self.assert_equal( reported_prefix.valid_time, ia_pd_opts.getfieldval("validlft") ) finally: self.vapi.want_dhcp6_pd_reply_events(enable_disable=0) self.vapi.dhcp6_clients_enable_disable(enable=0)
def test_ipip4(self): """ ip{v4,v6} over ip4 test """ p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) p_ip6 = IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=42) p_ip4 = IP(src="1.2.3.4", dst="130.67.0.1", tos=42) p_payload = UDP(sport=1234, dport=1234) # IPv4 transport rv = self.vapi.ipip_add_tunnel(src_address=self.pg0.local_ip4n, dst_address=self.pg1.remote_ip4n, is_ipv6=0, tc_tos=0xFF) sw_if_index = rv.sw_if_index # Set interface up and enable IP on it self.vapi.sw_interface_set_flags(sw_if_index, 1) self.vapi.sw_interface_set_unnumbered( ip_sw_if_index=self.pg0.sw_if_index, sw_if_index=sw_if_index) # Add IPv4 and IPv6 routes via tunnel interface ip4_via_tunnel = VppIpRoute( self, "130.67.0.0", 16, [ VppRoutePath( "0.0.0.0", sw_if_index, proto=DpoProto.DPO_PROTO_IP4) ], is_ip6=0) ip4_via_tunnel.add_vpp_config() ip6_via_tunnel = VppIpRoute( self, "dead::", 16, [VppRoutePath("::", sw_if_index, proto=DpoProto.DPO_PROTO_IP6)], is_ip6=1) ip6_via_tunnel.add_vpp_config() # IPv6 in to IPv4 tunnel p6 = (p_ether / p_ip6 / p_payload) p_inner_ip6 = p_ip6 p_inner_ip6.hlim -= 1 p6_reply = (IP(src=self.pg0.local_ip4, dst=self.pg1.remote_ip4, proto='ipv6', id=0, tos=42) / p_inner_ip6 / p_payload) p6_reply.ttl -= 1 rx = self.send_and_expect(self.pg0, p6 * 10, self.pg1) for p in rx: self.validate(p[1], p6_reply) # IPv4 in to IPv4 tunnel p4 = (p_ether / p_ip4 / p_payload) p_ip4_inner = p_ip4 p_ip4_inner.ttl -= 1 p4_reply = ( IP(src=self.pg0.local_ip4, dst=self.pg1.remote_ip4, tos=42) / p_ip4_inner / p_payload) p4_reply.ttl -= 1 p4_reply.id = 0 rx = self.send_and_expect(self.pg0, p4 * 10, self.pg1) for p in rx: self.validate(p[1], p4_reply) # Decapsulation p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) # IPv4 tunnel to IPv4 p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4) p4 = (p_ether / IP(src=self.pg1.remote_ip4, dst=self.pg0.local_ip4) / p_ip4 / p_payload) p4_reply = (p_ip4 / p_payload) p4_reply.ttl -= 1 rx = self.send_and_expect(self.pg1, p4 * 10, self.pg0) for p in rx: self.validate(p[1], p4_reply) # IPv4 tunnel to IPv6 p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6) p6 = (p_ether / IP(src=self.pg1.remote_ip4, dst=self.pg0.local_ip4) / p_ip6 / p_payload) p6_reply = (p_ip6 / p_payload) p6_reply.hlim = 63 rx = self.send_and_expect(self.pg1, p6 * 10, self.pg0) for p in rx: self.validate(p[1], p6_reply)
def test_gso(self): """ GSO test """ # # Send jumbo frame with gso disabled and DF bit is set # p4 = ( Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, flags='DF') / TCP(sport=1234, dport=1234) / Raw(b'\xa5' * 65200)) rxs = self.send_and_expect(self.pg0, [p4], self.pg0) for rx in rxs: self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[IP].src, self.pg0.local_ip4) self.assertEqual(rx[IP].dst, self.pg0.remote_ip4) self.assertEqual(rx[ICMP].type, 3) # "dest-unreach" self.assertEqual(rx[ICMP].code, 4) # "fragmentation-needed" # # Send checksum offload frames # p40 = ( Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IP(src=self.pg2.remote_ip4, dst=self.pg0.remote_ip4, flags='DF') / TCP(sport=1234, dport=1234) / Raw(b'\xa5' * 1460)) rxs = self.send_and_expect(self.pg2, 100 * [p40], self.pg0) for rx in rxs: self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[IP].src, self.pg2.remote_ip4) self.assertEqual(rx[IP].dst, self.pg0.remote_ip4) payload_len = rx[IP].len - 20 - 20 self.assert_ip_checksum_valid(rx) self.assert_tcp_checksum_valid(rx) self.assertEqual(payload_len, len(rx[Raw])) p60 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IPv6(src=self.pg2.remote_ip6, dst=self.pg0.remote_ip6) / TCP(sport=1234, dport=1234) / Raw(b'\xa5' * 1440)) rxs = self.send_and_expect(self.pg2, 100 * [p60], self.pg0) for rx in rxs: self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[IPv6].src, self.pg2.remote_ip6) self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6) payload_len = rx[IPv6].plen - 20 self.assert_tcp_checksum_valid(rx) self.assertEqual(payload_len, len(rx[Raw])) # # Send jumbo frame with gso enabled and DF bit is set # input and output interfaces support GSO # self.vapi.feature_gso_enable_disable(self.pg3.sw_if_index) p41 = ( Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IP(src=self.pg2.remote_ip4, dst=self.pg3.remote_ip4, flags='DF') / TCP(sport=1234, dport=1234) / Raw(b'\xa5' * 65200)) rxs = self.send_and_expect(self.pg2, 100 * [p41], self.pg3, 100) for rx in rxs: self.assertEqual(rx[Ether].src, self.pg3.local_mac) self.assertEqual(rx[Ether].dst, self.pg3.remote_mac) self.assertEqual(rx[IP].src, self.pg2.remote_ip4) self.assertEqual(rx[IP].dst, self.pg3.remote_ip4) self.assertEqual(rx[IP].len, 65240) # 65200 + 20 (IP) + 20 (TCP) self.assertEqual(rx[TCP].sport, 1234) self.assertEqual(rx[TCP].dport, 1234) # # ipv6 # p61 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IPv6(src=self.pg2.remote_ip6, dst=self.pg3.remote_ip6) / TCP(sport=1234, dport=1234) / Raw(b'\xa5' * 65200)) rxs = self.send_and_expect(self.pg2, 100 * [p61], self.pg3, 100) for rx in rxs: self.assertEqual(rx[Ether].src, self.pg3.local_mac) self.assertEqual(rx[Ether].dst, self.pg3.remote_mac) self.assertEqual(rx[IPv6].src, self.pg2.remote_ip6) self.assertEqual(rx[IPv6].dst, self.pg3.remote_ip6) self.assertEqual(rx[IPv6].plen, 65220) # 65200 + 20 (TCP) self.assertEqual(rx[TCP].sport, 1234) self.assertEqual(rx[TCP].dport, 1234) # # Send jumbo frame with gso enabled only on input interface # and DF bit is set. GSO packet will be chunked into gso_size # data payload # self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index) p42 = ( Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IP(src=self.pg2.remote_ip4, dst=self.pg0.remote_ip4, flags='DF') / TCP(sport=1234, dport=1234) / Raw(b'\xa5' * 65200)) rxs = self.send_and_expect(self.pg2, 5 * [p42], self.pg0, 225) size = 0 for rx in rxs: self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[IP].src, self.pg2.remote_ip4) self.assertEqual(rx[IP].dst, self.pg0.remote_ip4) payload_len = rx[IP].len - 20 - 20 # len - 20 (IP4) - 20 (TCP) self.assert_ip_checksum_valid(rx) self.assert_tcp_checksum_valid(rx) self.assertEqual(rx[TCP].sport, 1234) self.assertEqual(rx[TCP].dport, 1234) self.assertEqual(payload_len, len(rx[Raw])) size += payload_len self.assertEqual(size, 65200 * 5) # # ipv6 # p62 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IPv6(src=self.pg2.remote_ip6, dst=self.pg0.remote_ip6) / TCP(sport=1234, dport=1234) / Raw(b'\xa5' * 65200)) rxs = self.send_and_expect(self.pg2, 5 * [p62], self.pg0, 225) size = 0 for rx in rxs: self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[IPv6].src, self.pg2.remote_ip6) self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6) payload_len = rx[IPv6].plen - 20 self.assert_tcp_checksum_valid(rx) self.assertEqual(rx[TCP].sport, 1234) self.assertEqual(rx[TCP].dport, 1234) self.assertEqual(payload_len, len(rx[Raw])) size += payload_len self.assertEqual(size, 65200 * 5) # # Send jumbo frame with gso enabled only on input interface # and DF bit is unset. GSO packet will be fragmented. # self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [576, 0, 0, 0]) self.vapi.feature_gso_enable_disable(self.pg1.sw_if_index) p43 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IP(src=self.pg2.remote_ip4, dst=self.pg1.remote_ip4) / TCP(sport=1234, dport=1234) / Raw(b'\xa5' * 65200)) rxs = self.send_and_expect(self.pg2, 5 * [p43], self.pg1, 5 * 119) size = 0 for rx in rxs: self.assertEqual(rx[Ether].src, self.pg1.local_mac) self.assertEqual(rx[Ether].dst, self.pg1.remote_mac) self.assertEqual(rx[IP].src, self.pg2.remote_ip4) self.assertEqual(rx[IP].dst, self.pg1.remote_ip4) self.assert_ip_checksum_valid(rx) size += rx[IP].len - 20 size -= 20 * 5 # TCP header self.assertEqual(size, 65200 * 5) # # IPv6 # Send jumbo frame with gso enabled only on input interface. # ICMPv6 Packet Too Big will be sent back to sender. # self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1280, 0, 0, 0]) p63 = (Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac) / IPv6(src=self.pg2.remote_ip6, dst=self.pg1.remote_ip6) / TCP(sport=1234, dport=1234) / Raw(b'\xa5' * 65200)) rxs = self.send_and_expect(self.pg2, 5 * [p63], self.pg2, 5) for rx in rxs: self.assertEqual(rx[Ether].src, self.pg2.local_mac) self.assertEqual(rx[Ether].dst, self.pg2.remote_mac) self.assertEqual(rx[IPv6].src, self.pg2.local_ip6) self.assertEqual(rx[IPv6].dst, self.pg2.remote_ip6) self.assertEqual(rx[IPv6].plen, 1240) # MTU - IPv6 header self.assertEqual(ipv6nh[rx[IPv6].nh], "ICMPv6") self.assertEqual(rx[ICMPv6PacketTooBig].mtu, 1280) self.assertEqual(rx[IPerror6].src, self.pg2.remote_ip6) self.assertEqual(rx[IPerror6].dst, self.pg1.remote_ip6) self.assertEqual(rx[IPerror6].plen - 20, 65200) # # Send jumbo frame with gso enabled only on input interface with 9K MTU # and DF bit is unset. GSO packet will be fragmented. MSS is 8960. GSO # size will be min(MSS, 2048 - 14 - 20) vlib_buffer_t size # self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [9000, 0, 0, 0]) self.vapi.sw_interface_set_mtu(self.pg4.sw_if_index, [9000, 0, 0, 0]) p44 = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) / IP(src=self.pg4.remote_ip4, dst=self.pg1.remote_ip4) / TCP(sport=1234, dport=1234) / Raw(b'\xa5' * 65200)) rxs = self.send_and_expect(self.pg4, 5 * [p44], self.pg1, 165) size = 0 for rx in rxs: self.assertEqual(rx[Ether].src, self.pg1.local_mac) self.assertEqual(rx[Ether].dst, self.pg1.remote_mac) self.assertEqual(rx[IP].src, self.pg4.remote_ip4) self.assertEqual(rx[IP].dst, self.pg1.remote_ip4) payload_len = rx[IP].len - 20 - 20 # len - 20 (IP4) - 20 (TCP) self.assert_ip_checksum_valid(rx) self.assert_tcp_checksum_valid(rx) self.assertEqual(payload_len, len(rx[Raw])) size += payload_len self.assertEqual(size, 65200 * 5) # # IPv6 # p64 = (Ether(src=self.pg4.remote_mac, dst=self.pg4.local_mac) / IPv6(src=self.pg4.remote_ip6, dst=self.pg1.remote_ip6) / TCP(sport=1234, dport=1234) / Raw(b'\xa5' * 65200)) rxs = self.send_and_expect(self.pg4, 5 * [p64], self.pg1, 170) size = 0 for rx in rxs: self.assertEqual(rx[Ether].src, self.pg1.local_mac) self.assertEqual(rx[Ether].dst, self.pg1.remote_mac) self.assertEqual(rx[IPv6].src, self.pg4.remote_ip6) self.assertEqual(rx[IPv6].dst, self.pg1.remote_ip6) payload_len = rx[IPv6].plen - 20 self.assert_tcp_checksum_valid(rx) self.assertEqual(payload_len, len(rx[Raw])) size += payload_len self.assertEqual(size, 65200 * 5) self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index, enable_disable=0) self.vapi.feature_gso_enable_disable(self.pg1.sw_if_index, enable_disable=0)
def test_gso_ipip(self): """ GSO IPIP test """ self.logger.info(self.vapi.cli("sh int addr")) # # Send jumbo frame with gso enabled only on input interface and # create IPIP tunnel on VPP pg0. # self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index) # # enable ipip4 # self.ipip4.add_vpp_config() # Set interface up and enable IP on it self.ipip4.admin_up() self.ipip4.set_unnumbered(self.pg0.sw_if_index) # Add IPv4 routes via tunnel interface self.ip4_via_ip4_tunnel = VppIpRoute(self, "172.16.10.0", 24, [ VppRoutePath("0.0.0.0", self.ipip4.sw_if_index, proto=FibPathProto.FIB_PATH_NH_PROTO_IP4) ]) self.ip4_via_ip4_tunnel.add_vpp_config() # # IPv4/IPv4 - IPIP # p47 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") / IP(src=self.pg2.remote_ip4, dst="172.16.10.3", flags='DF') / TCP(sport=1234, dport=1234) / Raw(b'\xa5' * 65200)) rxs = self.send_and_expect(self.pg2, 5 * [p47], self.pg0, 225) size = 0 for rx in rxs: self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[IP].src, self.pg0.local_ip4) self.assertEqual(rx[IP].dst, self.pg0.remote_ip4) self.assert_ip_checksum_valid(rx) self.assertEqual(rx[IP].proto, 4) # ipencap inner = rx[IP].payload self.assertEqual(rx[IP].len - 20, len(inner)) self.assertEqual(inner[IP].src, self.pg2.remote_ip4) self.assertEqual(inner[IP].dst, "172.16.10.3") self.assert_ip_checksum_valid(inner) self.assert_tcp_checksum_valid(inner) payload_len = inner[IP].len - 20 - 20 self.assertEqual(payload_len, len(inner[Raw])) size += payload_len self.assertEqual(size, 65200 * 5) self.ip6_via_ip4_tunnel = VppIpRoute(self, "fd01:10::", 64, [ VppRoutePath("::", self.ipip4.sw_if_index, proto=FibPathProto.FIB_PATH_NH_PROTO_IP6) ]) self.ip6_via_ip4_tunnel.add_vpp_config() # # IPv4/IPv6 - IPIP # p67 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") / IPv6(src=self.pg2.remote_ip6, dst="fd01:10::3") / TCP(sport=1234, dport=1234) / Raw(b'\xa5' * 65200)) rxs = self.send_and_expect(self.pg2, 5 * [p67], self.pg0, 225) size = 0 for rx in rxs: self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[IP].src, self.pg0.local_ip4) self.assertEqual(rx[IP].dst, self.pg0.remote_ip4) self.assert_ip_checksum_valid(rx) self.assertEqual(rx[IP].proto, 41) # ipv6 inner = rx[IP].payload self.assertEqual(rx[IP].len - 20, len(inner)) self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6) self.assertEqual(inner[IPv6].dst, "fd01:10::3") self.assert_tcp_checksum_valid(inner) payload_len = inner[IPv6].plen - 20 self.assertEqual(payload_len, len(inner[Raw])) size += payload_len self.assertEqual(size, 65200 * 5) # # Send jumbo frame with gso enabled only on input interface and # create IPIP tunnel on VPP pg0. Enable gso feature node on ipip # tunnel - IPSec use case # self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index, enable_disable=0) self.vapi.feature_gso_enable_disable(self.ipip4.sw_if_index) rxs = self.send_and_expect(self.pg2, 5 * [p47], self.pg0, 225) size = 0 for rx in rxs: self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[IP].src, self.pg0.local_ip4) self.assertEqual(rx[IP].dst, self.pg0.remote_ip4) self.assert_ip_checksum_valid(rx) self.assertEqual(rx[IP].proto, 4) # ipencap inner = rx[IP].payload self.assertEqual(rx[IP].len - 20, len(inner)) self.assertEqual(inner[IP].src, self.pg2.remote_ip4) self.assertEqual(inner[IP].dst, "172.16.10.3") self.assert_ip_checksum_valid(inner) self.assert_tcp_checksum_valid(inner) payload_len = inner[IP].len - 20 - 20 self.assertEqual(payload_len, len(inner[Raw])) size += payload_len self.assertEqual(size, 65200 * 5) # # disable ipip4 # self.vapi.feature_gso_enable_disable(self.ipip4.sw_if_index, enable_disable=0) self.ip4_via_ip4_tunnel.remove_vpp_config() self.ip6_via_ip4_tunnel.remove_vpp_config() self.ipip4.remove_vpp_config() # # enable ipip6 # self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index) self.ipip6.add_vpp_config() # Set interface up and enable IP on it self.ipip6.admin_up() self.ipip6.set_unnumbered(self.pg0.sw_if_index) # Add IPv4 routes via tunnel interface self.ip4_via_ip6_tunnel = VppIpRoute(self, "172.16.10.0", 24, [ VppRoutePath("0.0.0.0", self.ipip6.sw_if_index, proto=FibPathProto.FIB_PATH_NH_PROTO_IP4) ]) self.ip4_via_ip6_tunnel.add_vpp_config() # # IPv6/IPv4 - IPIP # p48 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") / IP(src=self.pg2.remote_ip4, dst="172.16.10.3", flags='DF') / TCP(sport=1234, dport=1234) / Raw(b'\xa5' * 65200)) rxs = self.send_and_expect(self.pg2, 5 * [p48], self.pg0, 225) size = 0 for rx in rxs: self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[IPv6].src, self.pg0.local_ip6) self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6) self.assertEqual(ipv6nh[rx[IPv6].nh], "IP") inner = rx[IPv6].payload self.assertEqual(rx[IPv6].plen, len(inner)) self.assertEqual(inner[IP].src, self.pg2.remote_ip4) self.assertEqual(inner[IP].dst, "172.16.10.3") self.assert_ip_checksum_valid(inner) self.assert_tcp_checksum_valid(inner) payload_len = inner[IP].len - 20 - 20 self.assertEqual(payload_len, len(inner[Raw])) size += payload_len self.assertEqual(size, 65200 * 5) self.ip6_via_ip6_tunnel = VppIpRoute(self, "fd01:10::", 64, [ VppRoutePath("::", self.ipip6.sw_if_index, proto=FibPathProto.FIB_PATH_NH_PROTO_IP6) ]) self.ip6_via_ip6_tunnel.add_vpp_config() # # IPv6/IPv6 - IPIP # p68 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") / IPv6(src=self.pg2.remote_ip6, dst="fd01:10::3") / TCP(sport=1234, dport=1234) / Raw(b'\xa5' * 65200)) rxs = self.send_and_expect(self.pg2, 5 * [p68], self.pg0, 225) size = 0 for rx in rxs: self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[IPv6].src, self.pg0.local_ip6) self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6) self.assertEqual(ipv6nh[rx[IPv6].nh], "IPv6") inner = rx[IPv6].payload self.assertEqual(rx[IPv6].plen, len(inner)) self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6) self.assertEqual(inner[IPv6].dst, "fd01:10::3") self.assert_tcp_checksum_valid(inner) payload_len = inner[IPv6].plen - 20 self.assertEqual(payload_len, len(inner[Raw])) size += payload_len self.assertEqual(size, 65200 * 5) # # disable ipip6 # self.ip4_via_ip6_tunnel.remove_vpp_config() self.ip6_via_ip6_tunnel.remove_vpp_config() self.ipip6.remove_vpp_config() self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index, enable_disable=0)
def test_mpls(self): """ MPLS over ip{6,4} test """ tbl = VppMplsTable(self, 0) tbl.add_vpp_config() self.p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) self.p_payload = UDP(sport=1234, dport=1234) / Raw(b'X' * 100) f = FibPathProto # IPv4 transport tun4 = VppIpIpTunInterface(self, self.pg1, self.pg1.local_ip4, self.pg1.remote_ip4).add_vpp_config() tun4.admin_up() tun4.config_ip4() tun4.enable_mpls() # IPv6 transport tun6 = VppIpIpTunInterface(self, self.pg1, self.pg1.local_ip6, self.pg1.remote_ip6).add_vpp_config() tun6.admin_up() tun6.config_ip6() tun6.enable_mpls() # ip routes into the tunnels with output labels r4 = VppIpRoute(self, "1.1.1.1", 32, [ VppRoutePath( tun4.remote_ip4, tun4.sw_if_index, labels=[VppMplsLabel(44)]) ]).add_vpp_config() r6 = VppIpRoute(self, "1::1", 128, [ VppRoutePath( tun6.remote_ip6, tun6.sw_if_index, labels=[VppMplsLabel(66)]) ]).add_vpp_config() # deag MPLS routes from the tunnel r4 = VppMplsRoute( self, 44, 1, [VppRoutePath(self.pg0.remote_ip4, self.pg0.sw_if_index) ]).add_vpp_config() r6 = VppMplsRoute( self, 66, 1, [VppRoutePath(self.pg0.remote_ip6, self.pg0.sw_if_index)], eos_proto=f.FIB_PATH_NH_PROTO_IP6).add_vpp_config() # # Tunnel Encap # p4 = (self.p_ether / IP(src="2.2.2.2", dst="1.1.1.1") / self.p_payload) rxs = self.send_and_expect(self.pg0, p4 * N_PACKETS, self.pg1) for rx in rxs: self.assertEqual(rx[IP].src, self.pg1.local_ip4) self.assertEqual(rx[IP].dst, self.pg1.remote_ip4) self.assertEqual(rx[MPLS].label, 44) inner = rx[MPLS].payload self.assertEqual(inner.src, "2.2.2.2") self.assertEqual(inner.dst, "1.1.1.1") p6 = (self.p_ether / IPv6(src="2::2", dst="1::1") / self.p_payload) rxs = self.send_and_expect(self.pg0, p6 * N_PACKETS, self.pg1) for rx in rxs: self.assertEqual(rx[IPv6].src, self.pg1.local_ip6) self.assertEqual(rx[IPv6].dst, self.pg1.remote_ip6) self.assertEqual(rx[MPLS].label, 66) inner = rx[MPLS].payload self.assertEqual(inner.src, "2::2") self.assertEqual(inner.dst, "1::1") # # Tunnel Decap # p4 = (self.p_ether / IP(src=self.pg1.remote_ip4, dst=self.pg1.local_ip4) / MPLS(label=44, ttl=4) / IP(src="1.1.1.1", dst="2.2.2.2") / self.p_payload) rxs = self.send_and_expect(self.pg1, p4 * N_PACKETS, self.pg0) for rx in rxs: self.assertEqual(rx[IP].src, "1.1.1.1") self.assertEqual(rx[IP].dst, "2.2.2.2") p6 = (self.p_ether / IPv6(src=self.pg1.remote_ip6, dst=self.pg1.local_ip6) / MPLS(label=66, ttl=4) / IPv6(src="1::1", dst="2::2") / self.p_payload) rxs = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0) for rx in rxs: self.assertEqual(rx[IPv6].src, "1::1") self.assertEqual(rx[IPv6].dst, "2::2") tun4.disable_mpls() tun6.disable_mpls()
def test_ipip6(self): """ ip{v4,v6} over ip6 test """ # that's annoying self.destroy_tunnel() self.pg1.generate_remote_hosts(5) self.pg1.configure_ipv6_neighbors() e = VppEnum.vl_api_tunnel_encap_decap_flags_t d = VppEnum.vl_api_ip_dscp_t self.p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) self.p_payload = UDP(sport=1234, dport=1234) / Raw(b'X' * 100) # create a TOS byte by shifting a DSCP code point 2 bits. those 2 bits # are for the ECN. dscp = d.IP_API_DSCP_AF31 << 2 ecn = 3 dscp_ecn = d.IP_API_DSCP_AF31 << 2 | ecn # IPv4 transport that copies the DCSP from the payload tun_dscp = VppIpIpTunInterface( self, self.pg0, self.pg0.local_ip6, self.pg1.remote_hosts[0].ip6, flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP) tun_dscp.add_vpp_config() # IPv4 transport that copies the DCSP and ECN from the payload tun_dscp_ecn = VppIpIpTunInterface( self, self.pg0, self.pg0.local_ip6, self.pg1.remote_hosts[1].ip6, flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DSCP | e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN)) tun_dscp_ecn.add_vpp_config() # IPv4 transport that copies the ECN from the payload and sets the # DF bit on encap. copies the ECN on decap tun_ecn = VppIpIpTunInterface( self, self.pg0, self.pg0.local_ip6, self.pg1.remote_hosts[2].ip6, flags=(e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_ECN | e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_SET_DF | e.TUNNEL_API_ENCAP_DECAP_FLAG_DECAP_COPY_ECN)) tun_ecn.add_vpp_config() # IPv4 transport that sets a fixed DSCP in the encap and copies # the DF bit tun = VppIpIpTunInterface( self, self.pg0, self.pg0.local_ip6, self.pg1.remote_hosts[3].ip6, dscp=d.IP_API_DSCP_AF11, flags=e.TUNNEL_API_ENCAP_DECAP_FLAG_ENCAP_COPY_DF) tun.add_vpp_config() # array of all the tunnels tuns = [tun_dscp, tun_dscp_ecn, tun_ecn, tun] # addresses for prefixes routed via each tunnel a4s = ["" for i in range(len(tuns))] a6s = ["" for i in range(len(tuns))] # IP headers for inner packets with each combination of DSCp/ECN tested p_ip6s = [ IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp), IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=dscp_ecn), IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=ecn), IPv6(src="1::1", dst="DEAD::1", nh='UDP', tc=0xff) ] p_ip4s = [ IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp, flags='DF'), IP(src="1.2.3.4", dst="130.67.0.1", tos=dscp_ecn), IP(src="1.2.3.4", dst="130.67.0.1", tos=ecn), IP(src="1.2.3.4", dst="130.67.0.1", tos=0xff) ] # Configure each tunnel for i, t in enumerate(tuns): # Set interface up and enable IP on it self.vapi.sw_interface_set_flags(t.sw_if_index, 1) self.vapi.sw_interface_set_unnumbered( sw_if_index=self.pg0.sw_if_index, unnumbered_sw_if_index=t.sw_if_index) # prefix for route / destination address for packets a4s[i] = "130.67.%d.0" % i a6s[i] = "dead:%d::" % i # Add IPv4 and IPv6 routes via tunnel interface ip4_via_tunnel = VppIpRoute(self, a4s[i], 24, [ VppRoutePath("0.0.0.0", t.sw_if_index, proto=FibPathProto.FIB_PATH_NH_PROTO_IP4) ]) ip4_via_tunnel.add_vpp_config() ip6_via_tunnel = VppIpRoute(self, a6s[i], 64, [ VppRoutePath("::", t.sw_if_index, proto=FibPathProto.FIB_PATH_NH_PROTO_IP6) ]) ip6_via_tunnel.add_vpp_config() # # Encapsulation # # tun_dscp copies only the dscp # expected TC values are thus only the DCSP value is present from the # inner exp_tcs = [dscp, dscp, 0, 0xfc] p_ip6_encaps = [ IPv6(src=self.pg0.local_ip6, dst=tun_dscp.dst, tc=tc) for tc in exp_tcs ] # IPv4 in to IPv4 tunnel self.verify_ip4ip6_encaps(a4s[0], p_ip4s, p_ip6_encaps) # IPv6 in to IPv4 tunnel self.verify_ip6ip6_encaps(a6s[0], p_ip6s, p_ip6_encaps) # tun_dscp_ecn copies the dscp and the ecn exp_tcs = [dscp, dscp_ecn, ecn, 0xff] p_ip6_encaps = [ IPv6(src=self.pg0.local_ip6, dst=tun_dscp_ecn.dst, tc=tc) for tc in exp_tcs ] self.verify_ip4ip6_encaps(a4s[1], p_ip4s, p_ip6_encaps) self.verify_ip6ip6_encaps(a6s[1], p_ip6s, p_ip6_encaps) # tun_ecn copies only the ecn and always sets DF exp_tcs = [0, ecn, ecn, ecn] p_ip6_encaps = [ IPv6(src=self.pg0.local_ip6, dst=tun_ecn.dst, tc=tc) for tc in exp_tcs ] self.verify_ip4ip6_encaps(a4s[2], p_ip4s, p_ip6_encaps) self.verify_ip6ip6_encaps(a6s[2], p_ip6s, p_ip6_encaps) # tun sets a fixed dscp fixed_dscp = tun.dscp << 2 p_ip6_encaps = [ IPv6(src=self.pg0.local_ip6, dst=tun.dst, tc=fixed_dscp) for i in range(len(p_ip4s)) ] self.verify_ip4ip6_encaps(a4s[3], p_ip4s, p_ip6_encaps) self.verify_ip6ip6_encaps(a6s[3], p_ip6s, p_ip6_encaps) # # Decapsulation # n_packets_decapped = self.statistics.get_err_counter( '/err/ipip6-input/packets decapsulated') self.p_ether = Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) # IPv6 tunnel to IPv4 tcs = [0, dscp, dscp_ecn, ecn] # one overlay packet and all combinations of its encap p_ip4 = IP(src="1.2.3.4", dst=self.pg0.remote_ip4) p_ip6_encaps = [ IPv6(src=tun.dst, dst=self.pg0.local_ip6, tc=tc) for tc in tcs ] # for each encap tun will produce the same inner packet because it does # not copy up fields from the payload for p_ip6_encap in p_ip6_encaps: p6 = (self.p_ether / p_ip6_encap / p_ip4 / self.p_payload) p4_reply = (p_ip4 / self.p_payload) p4_reply.ttl -= 1 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0) n_packets_decapped += N_PACKETS for p in rx: self.validate(p[1], p4_reply) self.assert_packet_checksums_valid(p) err = self.statistics.get_err_counter( '/err/ipip6-input/packets decapsulated') self.assertEqual(err, n_packets_decapped) # tun_ecn copies the ECN bits from the encap to the inner p_ip6_encaps = [ IPv6(src=tun_ecn.dst, dst=self.pg0.local_ip6, tc=tc) for tc in tcs ] p_ip4_replys = [p_ip4.copy() for i in range(len(p_ip6_encaps))] p_ip4_replys[2].tos = ecn p_ip4_replys[3].tos = ecn for i, p_ip6_encap in enumerate(p_ip6_encaps): p6 = (self.p_ether / p_ip6_encap / p_ip4 / self.p_payload) p4_reply = (p_ip4_replys[i] / self.p_payload) p4_reply.ttl -= 1 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0) n_packets_decapped += N_PACKETS for p in rx: self.validate(p[1], p4_reply) self.assert_packet_checksums_valid(p) err = self.statistics.get_err_counter( '/err/ipip6-input/packets decapsulated') self.assertEqual(err, n_packets_decapped) # IPv6 tunnel to IPv6 # for each encap tun will produce the same inner packet because it does # not copy up fields from the payload p_ip6_encaps = [ IPv6(src=tun.dst, dst=self.pg0.local_ip6, tc=tc) for tc in tcs ] p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6) for p_ip6_encap in p_ip6_encaps: p6 = (self.p_ether / p_ip6_encap / p_ip6 / self.p_payload) p6_reply = (p_ip6 / self.p_payload) p6_reply.hlim = 63 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0) n_packets_decapped += N_PACKETS for p in rx: self.validate(p[1], p6_reply) self.assert_packet_checksums_valid(p) err = self.statistics.get_err_counter( '/err/ipip6-input/packets decapsulated') self.assertEqual(err, n_packets_decapped) # IPv6 tunnel to IPv6 # tun_ecn copies the ECN bits from the encap to the inner p_ip6_encaps = [ IPv6(src=tun_ecn.dst, dst=self.pg0.local_ip6, tc=tc) for tc in tcs ] p_ip6 = IPv6(src="1:2:3::4", dst=self.pg0.remote_ip6) p_ip6_replys = [p_ip6.copy() for i in range(len(p_ip6_encaps))] p_ip6_replys[2].tc = ecn p_ip6_replys[3].tc = ecn for i, p_ip6_encap in enumerate(p_ip6_encaps): p6 = (self.p_ether / p_ip6_encap / p_ip6 / self.p_payload) p6_reply = (p_ip6_replys[i] / self.p_payload) p6_reply.hlim = 63 rx = self.send_and_expect(self.pg1, p6 * N_PACKETS, self.pg0) n_packets_decapped += N_PACKETS for p in rx: self.validate(p[1], p6_reply) self.assert_packet_checksums_valid(p) err = self.statistics.get_err_counter( '/err/ipip6-input/packets decapsulated') self.assertEqual(err, n_packets_decapped)
def test_gso_ipsec(self): """ GSO IPSEC test """ # # Send jumbo frame with gso enabled only on input interface and # create IPIP tunnel on VPP pg0. # # # enable ipip4 # self.ipip4.add_vpp_config() self.vapi.feature_gso_enable_disable( sw_if_index=self.ipip4.sw_if_index, enable_disable=1) # Add IPv4 routes via tunnel interface self.ip4_via_ip4_tunnel = VppIpRoute(self, "172.16.10.0", 24, [ VppRoutePath("0.0.0.0", self.ipip4.sw_if_index, proto=FibPathProto.FIB_PATH_NH_PROTO_IP4) ]) self.ip4_via_ip4_tunnel.add_vpp_config() # IPSec config self.ipv4_params = IPsecIPv4Params() self.encryption_type = ESP config_tun_params(self.ipv4_params, self.encryption_type, self.ipip4) self.tun_sa_in_v4 = VppIpsecSA( self, self.ipv4_params.vpp_tun_sa_id, self.ipv4_params.vpp_tun_spi, self.ipv4_params.auth_algo_vpp_id, self.ipv4_params.auth_key, self.ipv4_params.crypt_algo_vpp_id, self.ipv4_params.crypt_key, VppEnum.vl_api_ipsec_proto_t.IPSEC_API_PROTO_ESP) self.tun_sa_in_v4.add_vpp_config() self.tun_sa_out_v4 = VppIpsecSA( self, self.ipv4_params.scapy_tun_sa_id, self.ipv4_params.scapy_tun_spi, self.ipv4_params.auth_algo_vpp_id, self.ipv4_params.auth_key, self.ipv4_params.crypt_algo_vpp_id, self.ipv4_params.crypt_key, VppEnum.vl_api_ipsec_proto_t.IPSEC_API_PROTO_ESP) self.tun_sa_out_v4.add_vpp_config() self.tun_protect_v4 = VppIpsecTunProtect(self, self.ipip4, self.tun_sa_out_v4, [self.tun_sa_in_v4]) self.tun_protect_v4.add_vpp_config() # Set interface up and enable IP on it self.ipip4.admin_up() self.ipip4.set_unnumbered(self.pg0.sw_if_index) # # IPv4/IPv4 - IPSEC # ipsec44 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") / IP(src=self.pg2.remote_ip4, dst="172.16.10.3", flags='DF') / TCP(sport=1234, dport=1234) / Raw(b'\xa5' * 65200)) rxs = self.send_and_expect(self.pg2, [ipsec44], self.pg0, 45) size = 0 for rx in rxs: self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[IP].src, self.pg0.local_ip4) self.assertEqual(rx[IP].dst, self.pg0.remote_ip4) self.assertEqual(rx[IP].proto, 50) # ESP self.assertEqual(rx[ESP].spi, self.ipv4_params.scapy_tun_spi) inner = self.ipv4_params.vpp_tun_sa.decrypt(rx[IP]) self.assertEqual(inner[IP].src, self.pg2.remote_ip4) self.assertEqual(inner[IP].dst, "172.16.10.3") size += inner[IP].len - 20 - 20 self.assertEqual(size, 65200) self.ip6_via_ip4_tunnel = VppIpRoute(self, "fd01:10::", 64, [ VppRoutePath("::", self.ipip4.sw_if_index, proto=FibPathProto.FIB_PATH_NH_PROTO_IP6) ]) self.ip6_via_ip4_tunnel.add_vpp_config() # # IPv4/IPv6 - IPSEC # ipsec46 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") / IPv6(src=self.pg2.remote_ip6, dst="fd01:10::3") / TCP(sport=1234, dport=1234) / Raw(b'\xa5' * 65200)) rxs = self.send_and_expect(self.pg2, [ipsec46], self.pg0, 45) size = 0 for rx in rxs: self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[IP].src, self.pg0.local_ip4) self.assertEqual(rx[IP].dst, self.pg0.remote_ip4) self.assertEqual(rx[IP].proto, 50) # ESP self.assertEqual(rx[ESP].spi, self.ipv4_params.scapy_tun_spi) inner = self.ipv4_params.vpp_tun_sa.decrypt(rx[IP]) self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6) self.assertEqual(inner[IPv6].dst, "fd01:10::3") size += inner[IPv6].plen - 20 self.assertEqual(size, 65200) # disable IPSec self.tun_protect_v4.remove_vpp_config() self.tun_sa_in_v4.remove_vpp_config() self.tun_sa_out_v4.remove_vpp_config() # # disable ipip4 # self.vapi.feature_gso_enable_disable(self.ipip4.sw_if_index, enable_disable=0) self.ip4_via_ip4_tunnel.remove_vpp_config() self.ip6_via_ip4_tunnel.remove_vpp_config() self.ipip4.remove_vpp_config() # # enable ipip6 # self.ipip6.add_vpp_config() self.vapi.feature_gso_enable_disable(self.ipip6.sw_if_index, enable_disable=1) # Set interface up and enable IP on it self.ipip6.admin_up() self.ipip6.set_unnumbered(self.pg0.sw_if_index) # Add IPv4 routes via tunnel interface self.ip4_via_ip6_tunnel = VppIpRoute(self, "172.16.10.0", 24, [ VppRoutePath("0.0.0.0", self.ipip6.sw_if_index, proto=FibPathProto.FIB_PATH_NH_PROTO_IP4) ]) self.ip4_via_ip6_tunnel.add_vpp_config() # IPSec config self.ipv6_params = IPsecIPv6Params() self.encryption_type = ESP config_tun_params(self.ipv6_params, self.encryption_type, self.ipip6) self.tun_sa_in_v6 = VppIpsecSA( self, self.ipv6_params.vpp_tun_sa_id, self.ipv6_params.vpp_tun_spi, self.ipv6_params.auth_algo_vpp_id, self.ipv6_params.auth_key, self.ipv6_params.crypt_algo_vpp_id, self.ipv6_params.crypt_key, VppEnum.vl_api_ipsec_proto_t.IPSEC_API_PROTO_ESP) self.tun_sa_in_v6.add_vpp_config() self.tun_sa_out_v6 = VppIpsecSA( self, self.ipv6_params.scapy_tun_sa_id, self.ipv6_params.scapy_tun_spi, self.ipv6_params.auth_algo_vpp_id, self.ipv6_params.auth_key, self.ipv6_params.crypt_algo_vpp_id, self.ipv6_params.crypt_key, VppEnum.vl_api_ipsec_proto_t.IPSEC_API_PROTO_ESP) self.tun_sa_out_v6.add_vpp_config() self.tun_protect_v6 = VppIpsecTunProtect(self, self.ipip6, self.tun_sa_out_v6, [self.tun_sa_in_v6]) self.tun_protect_v6.add_vpp_config() # # IPv6/IPv4 - IPSEC # ipsec64 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") / IP(src=self.pg2.remote_ip4, dst="172.16.10.3", flags='DF') / TCP(sport=1234, dport=1234) / Raw(b'\xa5' * 65200)) rxs = self.send_and_expect(self.pg2, [ipsec64], self.pg0, 45) size = 0 for rx in rxs: self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[IPv6].src, self.pg0.local_ip6) self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6) self.assertEqual(ipv6nh[rx[IPv6].nh], "ESP Header") self.assertEqual(rx[ESP].spi, self.ipv6_params.scapy_tun_spi) inner = self.ipv6_params.vpp_tun_sa.decrypt(rx[IPv6]) self.assertEqual(inner[IP].src, self.pg2.remote_ip4) self.assertEqual(inner[IP].dst, "172.16.10.3") size += inner[IP].len - 20 - 20 self.assertEqual(size, 65200) self.ip6_via_ip6_tunnel = VppIpRoute(self, "fd01:10::", 64, [ VppRoutePath("::", self.ipip6.sw_if_index, proto=FibPathProto.FIB_PATH_NH_PROTO_IP6) ]) self.ip6_via_ip6_tunnel.add_vpp_config() # # IPv6/IPv6 - IPSEC # ipsec66 = (Ether(src=self.pg2.remote_mac, dst="02:fe:60:1e:a2:79") / IPv6(src=self.pg2.remote_ip6, dst="fd01:10::3") / TCP(sport=1234, dport=1234) / Raw(b'\xa5' * 65200)) rxs = self.send_and_expect(self.pg2, [ipsec66], self.pg0, 45) size = 0 for rx in rxs: self.assertEqual(rx[Ether].src, self.pg0.local_mac) self.assertEqual(rx[Ether].dst, self.pg0.remote_mac) self.assertEqual(rx[IPv6].src, self.pg0.local_ip6) self.assertEqual(rx[IPv6].dst, self.pg0.remote_ip6) self.assertEqual(ipv6nh[rx[IPv6].nh], "ESP Header") self.assertEqual(rx[ESP].spi, self.ipv6_params.scapy_tun_spi) inner = self.ipv6_params.vpp_tun_sa.decrypt(rx[IPv6]) self.assertEqual(inner[IPv6].src, self.pg2.remote_ip6) self.assertEqual(inner[IPv6].dst, "fd01:10::3") size += inner[IPv6].plen - 20 self.assertEqual(size, 65200) # disable IPSec self.tun_protect_v6.remove_vpp_config() self.tun_sa_in_v6.remove_vpp_config() self.tun_sa_out_v6.remove_vpp_config() # # disable ipip6 # self.ip4_via_ip6_tunnel.remove_vpp_config() self.ip6_via_ip6_tunnel.remove_vpp_config() self.ipip6.remove_vpp_config() self.vapi.feature_gso_enable_disable(self.pg0.sw_if_index, enable_disable=0)
def run(self): instance = ByteBlower.InstanceGet() assert isinstance(instance, ByteBlower) # Connect to the server self.server = instance.ServerAdd(self.server_address) # create and configure the port. self.port = self.server.PortCreate(self.server_interface) # configure the MAC address on the port port_layer2_config = self.port.Layer2EthIISet() port_layer2_config.MacSet(self.port_mac_address) # configure the IP addressing on the port port_layer3_config = self.port.Layer3IPv6Set() if (type(self.port_ip_address) is str and self.port_ip_address.lower() == 'dhcp'): # DHCP is configured on the DHCP protocol dhcp_protocol = port_layer3_config.ProtocolDhcpGet() dhcp_protocol.Perform() elif (type(self.port_ip_address) is str and self.port_ip_address.lower() == 'slaac'): # wait for stateless autoconfiguration to complete port_layer3_config.StatelessAutoconfiguration() else: # Static addressing address = self.port_ip_address[0] prefixlength = self.port_ip_address[1] ip = "{}/{}".format(address, prefixlength) port_layer3_config.IpManualAdd(ip) print("Created port", self.port.DescriptionGet()) # Connect to the meetingpoint self.meetingpoint = instance.MeetingPointAdd(self.meetingpoint_address) # If no WirelessEndpoint UUID was given, search an available one. if self.wireless_endpoint_uuid is None: self.wireless_endpoint_uuid = self.select_wireless_endpoint_uuid() # Get the WirelessEndpoint device self.wireless_endpoint = self.meetingpoint.DeviceGet( self.wireless_endpoint_uuid) print("Using wireless endpoint", self.wireless_endpoint.DescriptionGet()) # Now we have the correct information to start configuring the flow. # The ByteBlower port will transmit frames to the wireless endpoint, # This means we need to create a 'stream' on the ByteBlower port # and a Trigger on the WirelessEndpoint stream = self.port.TxStreamAdd() stream.InterFrameGapSet(self.interframe_gap_nanoseconds) stream.NumberOfFramesSet(self.number_of_frames) # a stream needs to send some data, so lets create a frame # For the frame, we need: # - The source MAC address (MAC address of the ByteBlower port # in our case) # - The destination MAC address. This can be the MAC address of the # WirelessEndpoint, a router, ... This will resolved later on. # - The source IP address (The IP address of the ByteBlower port) # - The destination IP address (The IP address of the WirelessEndpoint) # - The source and destination UDP ports (we configured this on top of # this script) # - a payload to transmit. port_mac = self.port.Layer2EthIIGet().MacGet() port_layer3_config = self.port.Layer3IPv6Get() ipv6_addresses = port_layer3_config.IpLinkLocalGet() if self.port_ip_address == "dhcp": ipv6_addresses = port_layer3_config.IpDhcpGet() elif self.port_ip_address == "slaac": ipv6_addresses = port_layer3_config.IpStatelessGet() elif isinstance(self.port_ip_address, list): ipv6_addresses = port_layer3_config.IpManualGet() port_ipv6 = None for ipv6_address in ipv6_addresses: port_ipv6 = ipv6_address.split("/")[0] # destination MAC must be resolved, since we do not know whether the WE # is available on the local LAN destination_mac = None wireless_endpoint_ipv6 = None all_we_addresses = self.select_wireless_endpoint_addresses() for address in all_we_addresses: wireless_endpoint_ipv6 = address.split('/')[0] try: destination_mac = port_layer3_config.Resolve( wireless_endpoint_ipv6) break except: pass payload = 'a' * (self.frame_size - 42) from scapy.layers.inet6 import UDP, IPv6, Ether from scapy.all import Raw udp_payload = Raw(payload.encode('ascii', 'strict')) udp_header = UDP(dport=self.udp_dstport, sport=self.udp_srcport) ip_header = IPv6(src=port_ipv6, dst=wireless_endpoint_ipv6) eth_header = Ether(src=port_mac, dst=destination_mac) scapy_frame = eth_header / ip_header / udp_header / udp_payload frame_content = bytearray(bytes(scapy_frame)) # The ByteBlower API expects an 'str' as input for the # frame.BytesSet() method, we need to convert the bytearray hexbytes = ''.join((format(b, "02x") for b in frame_content)) frame = stream.FrameAdd() frame.BytesSet(hexbytes) # The trigger on the WirelessEndpoint counts received frames # We need # - the source UDP port # - the destination UDP port # - the originating IP address # - the duration of the session. This can be calculated from the # stream settings as # interframegap (nanoseconds/frame) * number of frames (frames) # some fixed rollout can be added too trigger = self.wireless_endpoint.RxTriggerBasicAdd() # Add 2 seconds of rollout, so frames in transit can be counted too duration_ns = self.interframe_gap_nanoseconds * self.number_of_frames duration_ns += 2000000000 trigger.DurationSet(duration_ns) trigger.FilterUdpSourcePortSet(self.udp_srcport) trigger.FilterUdpDestinationPortSet(self.udp_dstport) trigger.FilterSourceAddressSet(port_ipv6) # Now all configuration is made print(stream.DescriptionGet()) print(trigger.DescriptionGet()) # Make sure we are the only users for the wireless endpoint self.wireless_endpoint.Lock(True) # Upload the configuration to the wireless endpoint self.wireless_endpoint.Prepare() from time import sleep # POSIX timestamp in nanoseconds when the wireless endpoint will start starttime_posix = self.wireless_endpoint.Start() # Current POSIX timestamp on the meetingpoint current_time_posix = self.meetingpoint.TimestampGet() time_to_wait_ns = starttime_posix - current_time_posix # Wait 200 ms longer, to make sure the wireless endpoint has started. time_to_wait_ns += 200000000 print("Waiting for", time_to_wait_ns / 1000000000.0, "to start the port") sleep(time_to_wait_ns / 1000000000.0) print("Port will transmit for", duration_ns / 1000000000.0, "seconds") self.port.Start() print("Waiting for the test to finish") sleep(duration_ns / 1000000000.0) # get the results from the wireless endpoint self.wireless_endpoint.ResultGet() self.wireless_endpoint.Lock(False) tx_result = stream.ResultGet() tx_result.Refresh() rx_result = trigger.ResultGet() rx_result.Refresh() print("Transmitted", tx_result.PacketCountGet(), "packets") print("Received ", rx_result.PacketCountGet(), "packets") return { 'tx': tx_result.PacketCountGet(), 'rx': rx_result.PacketCountGet() }
def test_dhcp_pd_send_solicit_receive_advertise(self): """ Verify DHCPv6 PD Solicit packet and Advertise envent """ self.vapi.dhcp6_clients_enable_disable() self.pg_enable_capture(self.pg_interfaces) self.pg_start() prefix_bin = '\00\01\00\02\00\03' + '\00' * 10 prefix = {'prefix': prefix_bin, 'prefix_length': 50, 'preferred_time': 60, 'valid_time': 120} self.vapi.dhcp6_pd_send_client_message(1, self.pg0.sw_if_index, T1=20, T2=40, prefixes=[prefix]) rx_list = self.pg0.get_capture(1) self.assertEqual(len(rx_list), 1) packet = rx_list[0] self.assertTrue(packet.haslayer(IPv6)) self.assertTrue(packet[IPv6].haslayer(DHCP6_Solicit)) client_duid = packet[DHCP6OptClientId].duid trid = packet[DHCP6_Solicit].trid dst = ip6_normalize(packet[IPv6].dst) dst2 = ip6_normalize("ff02::1:2") self.assert_equal(dst, dst2) src = ip6_normalize(packet[IPv6].src) src2 = ip6_normalize(self.pg0.local_ip6_ll) self.assert_equal(src, src2) ia_pd = packet[DHCP6OptIA_PD] self.assert_equal(ia_pd.T1, 20) self.assert_equal(ia_pd.T2, 40) self.assert_equal(len(ia_pd.iapdopt), 1) prefix = ia_pd.iapdopt[0] self.assert_equal(prefix.prefix, '1:2:3::') self.assert_equal(prefix.plen, 50) self.assert_equal(prefix.preflft, 60) self.assert_equal(prefix.validlft, 120) self.vapi.want_dhcp6_pd_reply_events() try: ia_pd_opts = DHCP6OptIAPrefix(prefix='7:8::', plen=56, preflft=60, validlft=120) p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6(src=mk_ll_addr(self.pg0.remote_mac), dst=self.pg0.local_ip6_ll) / UDP(sport=547, dport=546) / DHCP6_Advertise(trid=trid) / DHCP6OptServerId(duid=self.server_duid) / DHCP6OptClientId(duid=client_duid) / DHCP6OptPref(prefval=7) / DHCP6OptStatusCode(statuscode=1) / DHCP6OptIA_PD(iaid=1, T1=20, T2=40, iapdopt=ia_pd_opts) ) self.pg0.add_stream([p]) self.pg_start() ev = self.vapi.wait_for_event(1, "dhcp6_pd_reply_event") self.assert_equal(ev.preference, 7) self.assert_equal(ev.status_code, 1) self.assert_equal(ev.T1, 20) self.assert_equal(ev.T2, 40) reported_prefix = ev.prefixes[0] prefix = inet_pton(AF_INET6, ia_pd_opts.getfieldval("prefix")) self.assert_equal(reported_prefix.prefix, prefix) self.assert_equal(reported_prefix.prefix_length, ia_pd_opts.getfieldval("plen")) self.assert_equal(reported_prefix.preferred_time, ia_pd_opts.getfieldval("preflft")) self.assert_equal(reported_prefix.valid_time, ia_pd_opts.getfieldval("validlft")) finally: self.vapi.want_dhcp6_pd_reply_events(enable_disable=0)
def test_ip4_mtu(self): """ IP4 MTU test """ p_ether = Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) p_ip4 = IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, flags='DF') current_mtu = self.get_mtu(self.pg1.sw_if_index) p_payload = UDP(sport=1234, dport=1234) / self.payload(current_mtu - 20 - 8) p4 = p_ether / p_ip4 / p_payload p4_reply = p_ip4 / p_payload p4_reply.ttl -= 1 rx = self.send_and_expect(self.pg0, p4 * 11, self.pg1) for p in rx: self.validate(p[1], p4_reply) # MTU self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [576, 0, 0, 0]) self.assertEqual(576, self.get_mtu(self.pg1.sw_if_index)) # Should fail. Too large MTU p_icmp4 = ICMP(type='dest-unreach', code='fragmentation-needed', nexthopmtu=576, chksum=0x2dbb) icmp4_reply = (IP(src=self.pg0.local_ip4, dst=self.pg0.remote_ip4, ttl=254, len=576, id=0) / p_icmp4 / p_ip4 / p_payload) icmp4_reply[1].ttl -= 1 n = icmp4_reply.__class__(str(icmp4_reply)) s = str(icmp4_reply) icmp4_reply = s[0:576] rx = self.send_and_expect(self.pg0, p4 * 11, self.pg0) for p in rx: # p.show2() # n.show2() self.validate_bytes(str(p[1]), icmp4_reply) # Now with DF off. Expect fragments. # First go with 1500 byte packets. p_payload = UDP(sport=1234, dport=1234) / self.payload(1500 - 20 - 8) p4 = p_ether / p_ip4 / p_payload p4.flags = 0 p4_reply = p_ip4 / p_payload p4_reply.ttl = 62 # check this p4_reply.flags = 0 p4_reply.id = 256 self.pg_enable_capture() self.pg0.add_stream(p4 * 1) self.pg_start() rx = self.pg1.get_capture(3) reass_pkt = reassemble(rx) self.validate(reass_pkt, p4_reply) ''' # Now what happens with a 9K frame p_payload = UDP(sport=1234, dport=1234) / self.payload( current_mtu - 20 - 8) p4 = p_ether / p_ip4 / p_payload p4.flags = 0 p4_reply = p_ip4 / p_payload p4_reply.ttl = 62 # check this p4_reply.flags = 0 p4_reply.id = 512 self.pg_enable_capture() self.pg0.add_stream(p4*1) self.pg_start() rx = self.pg1.get_capture(16) reass_pkt = reassemble(rx) reass_pkt.show2() p4_reply.show2() self.validate(reass_pkt, p4_reply) ''' # Reset MTU self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [current_mtu, 0, 0, 0])
def test_dhcp_ia_na_send_solicit_receive_advertise(self): """ Verify DHCPv6 IA NA Solicit packet and Advertise envent """ self.vapi.dhcp6_clients_enable_disable() self.pg_enable_capture(self.pg_interfaces) self.pg_start() address_bin = '\00\01\00\02\00\03' + '\00' * 8 + '\00\05' address = {'address': address_bin, 'preferred_time': 60, 'valid_time': 120} self.vapi.dhcp6_send_client_message(1, self.pg0.sw_if_index, T1=20, T2=40, addresses=[address]) rx_list = self.pg0.get_capture(1) self.assertEqual(len(rx_list), 1) packet = rx_list[0] self.assertTrue(packet.haslayer(IPv6)) self.assertTrue(packet[IPv6].haslayer(DHCP6_Solicit)) client_duid = packet[DHCP6OptClientId].duid trid = packet[DHCP6_Solicit].trid dst = ip6_normalize(packet[IPv6].dst) dst2 = ip6_normalize("ff02::1:2") self.assert_equal(dst, dst2) src = ip6_normalize(packet[IPv6].src) src2 = ip6_normalize(self.pg0.local_ip6_ll) self.assert_equal(src, src2) ia_na = packet[DHCP6OptIA_NA] self.assert_equal(ia_na.T1, 20) self.assert_equal(ia_na.T2, 40) self.assert_equal(len(ia_na.ianaopts), 1) address = ia_na.ianaopts[0] self.assert_equal(address.addr, '1:2:3::5') self.assert_equal(address.preflft, 60) self.assert_equal(address.validlft, 120) self.vapi.want_dhcp6_reply_events() try: ia_na_opts = DHCP6OptIAAddress(addr='7:8::2', preflft=60, validlft=120) p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6(src=mk_ll_addr(self.pg0.remote_mac), dst=self.pg0.local_ip6_ll) / UDP(sport=547, dport=546) / DHCP6_Advertise(trid=trid) / DHCP6OptServerId(duid=self.server_duid) / DHCP6OptClientId(duid=client_duid) / DHCP6OptPref(prefval=7) / DHCP6OptStatusCode(statuscode=1) / DHCP6OptIA_NA(iaid=1, T1=20, T2=40, ianaopts=ia_na_opts) ) self.pg0.add_stream([p]) self.pg_start() ev = self.vapi.wait_for_event(1, "dhcp6_reply_event") self.assert_equal(ev.preference, 7) self.assert_equal(ev.status_code, 1) self.assert_equal(ev.T1, 20) self.assert_equal(ev.T2, 40) reported_address = ev.addresses[0] address = inet_pton(AF_INET6, ia_na_opts.getfieldval("addr")) self.assert_equal(reported_address.address, address) self.assert_equal(reported_address.preferred_time, ia_na_opts.getfieldval("preflft")) self.assert_equal(reported_address.valid_time, ia_na_opts.getfieldval("validlft")) finally: self.vapi.want_dhcp6_reply_events(enable_disable=0)
def test_dhcp_ia_na_send_solicit_receive_advertise(self): """Verify DHCPv6 IA NA Solicit packet and Advertise event""" self.vapi.dhcp6_clients_enable_disable(enable=1) self.pg_enable_capture(self.pg_interfaces) self.pg_start() address = {"address": "1:2:3::5", "preferred_time": 60, "valid_time": 120} self.vapi.dhcp6_send_client_message( server_index=0xFFFFFFFF, mrc=1, msg_type=VppEnum.vl_api_dhcpv6_msg_type_t.DHCPV6_MSG_API_SOLICIT, sw_if_index=self.pg0.sw_if_index, T1=20, T2=40, addresses=[address], n_addresses=len([address]), ) rx_list = self.pg0.get_capture(1) self.assertEqual(len(rx_list), 1) packet = rx_list[0] self.assertEqual(packet.haslayer(IPv6), 1) self.assertEqual(packet[IPv6].haslayer(DHCP6_Solicit), 1) client_duid = packet[DHCP6OptClientId].duid trid = packet[DHCP6_Solicit].trid dst = ip6_normalize(packet[IPv6].dst) dst2 = ip6_normalize("ff02::1:2") self.assert_equal(dst, dst2) src = ip6_normalize(packet[IPv6].src) src2 = ip6_normalize(self.pg0.local_ip6_ll) self.assert_equal(src, src2) ia_na = packet[DHCP6OptIA_NA] self.assert_equal(ia_na.T1, 20) self.assert_equal(ia_na.T2, 40) self.assert_equal(len(ia_na.ianaopts), 1) address = ia_na.ianaopts[0] self.assert_equal(address.addr, "1:2:3::5") self.assert_equal(address.preflft, 60) self.assert_equal(address.validlft, 120) self.vapi.want_dhcp6_reply_events(enable_disable=1, pid=os.getpid()) try: ia_na_opts = DHCP6OptIAAddress(addr="7:8::2", preflft=60, validlft=120) p = ( Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6( src=util.mk_ll_addr(self.pg0.remote_mac), dst=self.pg0.local_ip6_ll ) / UDP(sport=547, dport=546) / DHCP6_Advertise(trid=trid) / DHCP6OptServerId(duid=self.server_duid) / DHCP6OptClientId(duid=client_duid) / DHCP6OptPref(prefval=7) / DHCP6OptStatusCode(statuscode=1) / DHCP6OptIA_NA(iaid=1, T1=20, T2=40, ianaopts=ia_na_opts) ) self.pg0.add_stream([p]) self.pg_start() ev = self.vapi.wait_for_event(1, "dhcp6_reply_event") self.assert_equal(ev.preference, 7) self.assert_equal(ev.status_code, 1) self.assert_equal(ev.T1, 20) self.assert_equal(ev.T2, 40) reported_address = ev.addresses[0] address = ia_na_opts.getfieldval("addr") self.assert_equal(str(reported_address.address), address) self.assert_equal( reported_address.preferred_time, ia_na_opts.getfieldval("preflft") ) self.assert_equal( reported_address.valid_time, ia_na_opts.getfieldval("validlft") ) finally: self.vapi.want_dhcp6_reply_events(enable_disable=0) self.vapi.dhcp6_clients_enable_disable(enable=0)
def run(self): byteblower_instance = ByteBlower.InstanceGet() print("Connecting to ByteBlower server %s..." % self.server_address) self.server = byteblower_instance.ServerAdd(self.server_address) # Create the port which will be the HTTP server (port_1) print("Creating TX port") self.port_1 = self.provision_port(self.port_1_config) print("Creating RX port") # Create the port which will be the HTTP client (port_2) self.port_2 = self.provision_port(self.port_2_config) # now create the stream. # A stream transmits frames on the port on which it is created. stream = self.port_1.TxStreamAdd() # set the number of frames to transmit stream.NumberOfFramesSet(self.number_of_frames) # set the speed of the transmission stream.InterFrameGapSet(self.interframegap_ns) # Since a stream transmits frames, we need to tell the stream which # frames we want to transmit frame = stream.FrameAdd() # collect the frame header info. We need to provide the # Layer2 (ethernet) and Layer3 (IPv4) addresses. src_ip = self.port_1_config['ip_address'] src_mac = self.port_1.Layer2EthIIGet().MacGet() dst_ip = self.port_2_config['ip_address'] # the destination MAC is the MAC address of the destination port if # the destination port is in the same subnet as the source port, # otherwise it will be the MAC address of the gateway. # ByteBlower has a function to resolve the correct MAC address in # the Layer3 configuration object dst_mac = self.port_1.Layer3IPv6Get().Resolve(dst_ip) frame_size = 512 udp_src = 4096 udp_dest = 4096 payload = 'a' * (frame_size - 42) from scapy.layers.inet6 import UDP, IPv6, Ether from scapy.all import Raw udp_payload = Raw(payload.encode('ascii', 'strict')) udp_header = UDP(dport=udp_dest, sport=udp_src) ip_header = IPv6(src=src_ip, dst=dst_ip) eth_header = Ether(src=src_mac, dst=dst_mac) scapy_frame = eth_header / ip_header / udp_header / udp_payload frame_content = bytearray(bytes(scapy_frame)) # The ByteBlower API expects an 'str' as input for the # frame.BytesSet() method, we need to convert the bytearray hex_bytes = ''.join((format(b, "02x") for b in frame_content)) frame.BytesSet(hex_bytes) # Create a trigger. A trigger is an object which receives data. # The Basic trigger just count packets trigger = self.port_2.RxTriggerBasicAdd() # Every trigger needs to know on which frames it will work. # The default filter is no filter, so it will analyze every frame, # which is not what we want here. # We will filter on the destination IP and the destination UDP port bpf_filter = "ip6 dst {} and udp port {}".format(dst_ip, udp_dest) trigger.FilterSet(bpf_filter) # print the configuration, this makes it easy to review what we have # done until now print("Current ByteBlower configuration:") print("port1:", self.port_1.DescriptionGet()) print("port2:", self.port_2.DescriptionGet()) # Start the traffic and clear the trigger. # Triggers are active as soon they are created, so we may want to clear # the data it already has collected. print("Starting traffic") trigger.ResultClear() stream_history = stream.ResultHistoryGet() trigger_history = trigger.ResultHistoryGet() duration_ns = self.interframegap_ns * self.number_of_frames duration_s = duration_ns / 1000000000 + 1 stream.Start() # duration_s is a float, so we need to cast it to an integer first for iteration in range(1, int(duration_s)): # sleep one second sleep(1) # Refresh the history, the ByteBlower server will create interval # and cumulative results every second (by default). # The Refresh method will synchronize the server data with # the client. stream_history.Refresh() trigger_history.Refresh() last_interval_tx = stream_history.IntervalLatestGet() last_interval_rx = trigger_history.IntervalLatestGet() print("Sent {TX} frames, received {RX} frames".format( TX=last_interval_tx.PacketCountGet(), RX=last_interval_rx.PacketCountGet())) print("Done sending traffic (time elapsed)") # Waiting for a second after the stream is finished. # This has the advantage that frames that were transmitted but not # received yet, can be processed by the server print("Waiting for a second") sleep(1) # During the test itself we queried the interval counters, there are # also cumulative counters. The last cumulative counter available in # the history is also available as the Result stream_result = stream.ResultGet() trigger_result = trigger.ResultGet() stream_result.Refresh() print("Stream result:", stream_result.DescriptionGet()) trigger_result.Refresh() print("Trigger result:", trigger_result.DescriptionGet()) tx_frames = stream_result.PacketCountGet() rx_frames = trigger_result.PacketCountGet() print("Sent {TX} frames, received {RX} frames".format(TX=tx_frames, RX=rx_frames)) return [tx_frames, rx_frames]