X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=test%2Ftest_ip6.py;h=35061b0b53c5085dff398ef18b02cc262e45e39c;hb=097fa66b9;hp=21d8025d583f13c9f5e52c1e8daedd850dbc4eb2;hpb=744902e306c5a1f00bf13bbe344c6616cc816f0e;p=vpp.git diff --git a/test/test_ip6.py b/test/test_ip6.py index 21d8025d583..35061b0b53c 100644 --- a/test/test_ip6.py +++ b/test/test_ip6.py @@ -1,37 +1,42 @@ #!/usr/bin/env python -import unittest import socket +import unittest + +from parameterized import parameterized +import scapy.compat +import scapy.layers.inet6 as inet6 +from scapy.contrib.mpls import MPLS +from scapy.layers.inet6 import IPv6, ICMPv6ND_NS, ICMPv6ND_RS, \ + ICMPv6ND_RA, ICMPv6NDOptMTU, ICMPv6NDOptSrcLLAddr, ICMPv6NDOptPrefixInfo, \ + ICMPv6ND_NA, ICMPv6NDOptDstLLAddr, ICMPv6DestUnreach, icmp6types, \ + ICMPv6TimeExceeded, ICMPv6EchoRequest, ICMPv6EchoReply, IPv6ExtHdrHopByHop +from scapy.layers.l2 import Ether, Dot1Q +from scapy.packet import Raw +from scapy.utils import inet_pton, inet_ntop +from scapy.utils6 import in6_getnsma, in6_getnsmac, in6_ptop, in6_islladdr, \ + in6_mactoifaceid +from six import moves from framework import VppTestCase, VppTestRunner -from util import ppp, ip6_normalize -from vpp_sub_interface import VppSubInterface, VppDot1QSubint -from vpp_pg_interface import is_ipv6_misc +from util import ppp, ip6_normalize, mk_ll_addr +from vpp_ip import DpoProto from vpp_ip_route import VppIpRoute, VppRoutePath, find_route, VppIpMRoute, \ VppMRoutePath, MRouteItfFlags, MRouteEntryFlags, VppMplsIpBind, \ - VppMplsRoute, DpoProto, VppMplsTable + VppMplsRoute, VppMplsTable, VppIpTable, FibPathType from vpp_neighbor import find_nbr, VppNeighbor - -from scapy.packet import Raw -from scapy.layers.l2 import Ether, Dot1Q -from scapy.layers.inet6 import IPv6, UDP, TCP, ICMPv6ND_NS, ICMPv6ND_RS, \ - ICMPv6ND_RA, ICMPv6NDOptSrcLLAddr, getmacbyip6, ICMPv6MRD_Solicitation, \ - ICMPv6NDOptMTU, ICMPv6NDOptSrcLLAddr, ICMPv6NDOptPrefixInfo, \ - ICMPv6ND_NA, ICMPv6NDOptDstLLAddr, ICMPv6DestUnreach, icmp6types, \ - ICMPv6TimeExceeded -from scapy.utils6 import in6_getnsma, in6_getnsmac, in6_ptop, in6_islladdr, \ - in6_mactoifaceid, in6_ismaddr -from scapy.utils import inet_pton, inet_ntop -from scapy.contrib.mpls import MPLS - +from vpp_pg_interface import is_ipv6_misc +from vpp_sub_interface import VppSubInterface, VppDot1QSubint +from ipaddress import IPv6Network, IPv4Network, IPv6Address AF_INET6 = socket.AF_INET6 +try: + text_type = unicode +except NameError: + text_type = str -def mk_ll_addr(mac): - euid = in6_mactoifaceid(mac) - addr = "fe80::" + euid - return addr +NUM_PKTS = 67 class TestIPv6ND(VppTestCase): @@ -73,7 +78,8 @@ class TestIPv6ND(VppTestCase): in6_ptop(dst_ip)) # and come from the target address - self.assertEqual(in6_ptop(rx[IPv6].src), in6_ptop(tgt_ip)) + self.assertEqual( + in6_ptop(rx[IPv6].src), in6_ptop(tgt_ip)) # Dest link-layer options should have the router's MAC dll = rx[ICMPv6NDOptDstLLAddr] @@ -91,14 +97,16 @@ class TestIPv6ND(VppTestCase): # the rx'd NS should be addressed to an mcast address # derived from the target address - self.assertEqual(in6_ptop(rx[IPv6].dst), in6_ptop(dst_ip)) + self.assertEqual( + in6_ptop(rx[IPv6].dst), in6_ptop(dst_ip)) # expect the tgt IP in the NS header ns = rx[ICMPv6ND_NS] self.assertEqual(in6_ptop(ns.tgt), in6_ptop(tgt_ip)) # packet is from the router's local address - self.assertEqual(in6_ptop(rx[IPv6].src), intf.local_ip6) + self.assertEqual( + in6_ptop(rx[IPv6].src), intf.local_ip6) # Src link-layer options should have the router's MAC sll = rx[ICMPv6NDOptSrcLLAddr] @@ -155,6 +163,10 @@ class TestIPv6(TestIPv6ND): def setUpClass(cls): super(TestIPv6, cls).setUpClass() + @classmethod + def tearDownClass(cls): + super(TestIPv6, cls).tearDownClass() + def setUp(self): """ Perform test setup before test case. @@ -172,7 +184,6 @@ class TestIPv6(TestIPv6ND): :ivar list interfaces: pg interfaces and subinterfaces. :ivar dict flows: IPv4 packet flows in test. - :ivar list pg_if_packet_sizes: packet sizes in test. *TODO:* Create AD sub interface """ @@ -195,8 +206,7 @@ class TestIPv6(TestIPv6ND): self.flows[self.pg2.sub_if] = [self.pg0, self.pg1.sub_if] # packet sizes - self.pg_if_packet_sizes = [64, 512, 1518, 9018] - self.sub_if_packet_sizes = [64, 512, 1518 + 4, 9018 + 4] + self.pg_if_packet_sizes = [64, 1500, 9020] self.interfaces = list(self.pg_interfaces) self.interfaces.extend(self.sub_interfaces) @@ -207,9 +217,6 @@ class TestIPv6(TestIPv6ND): i.config_ip6() i.resolve_ndp() - # config 2M FIB entries - self.config_fib_entries(200) - def tearDown(self): """Run standard test teardown and log ``show ip6 neighbors``.""" for i in self.interfaces: @@ -224,53 +231,46 @@ class TestIPv6(TestIPv6ND): self.logger.info(self.vapi.cli("show ip6 neighbors")) # info(self.vapi.cli("show ip6 fib")) # many entries - def config_fib_entries(self, count): - """For each interface add to the FIB table *count* routes to - "fd02::1/128" destination with interface's local address as next-hop - address. - - :param int count: Number of FIB entries. + def modify_packet(self, src_if, packet_size, pkt): + """Add load, set destination IP and extend packet to required packet + size for defined interface. - - *TODO:* check if the next-hop address shouldn't be remote address - instead of local address. + :param VppInterface src_if: Interface to create packet for. + :param int packet_size: Required packet size. + :param Scapy pkt: Packet to be modified. """ - n_int = len(self.interfaces) - percent = 0 - counter = 0.0 - dest_addr = inet_pton(AF_INET6, "fd02::1") - dest_addr_len = 128 - for i in self.interfaces: - next_hop_address = i.local_ip6n - for j in range(count / n_int): - self.vapi.ip_add_del_route( - dest_addr, dest_addr_len, next_hop_address, is_ipv6=1) - counter += 1 - if counter / count * 100 > percent: - self.logger.info("Configure %d FIB entries .. %d%% done" % - (count, percent)) - percent += 1 - - def create_stream(self, src_if, packet_sizes): + dst_if_idx = packet_size / 10 % 2 + dst_if = self.flows[src_if][dst_if_idx] + info = self.create_packet_info(src_if, dst_if) + payload = self.info_to_payload(info) + p = pkt / Raw(payload) + p[IPv6].dst = dst_if.remote_ip6 + info.data = p.copy() + if isinstance(src_if, VppSubInterface): + p = src_if.add_dot1_layer(p) + self.extend_packet(p, packet_size) + + return p + + def create_stream(self, src_if): """Create input packet stream for defined interface. :param VppInterface src_if: Interface to create packet stream for. - :param list packet_sizes: Required packet sizes. """ - pkts = [] - for i in range(0, 257): - dst_if = self.flows[src_if][i % 2] - info = self.create_packet_info(src_if, dst_if) - payload = self.info_to_payload(info) - p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) / - IPv6(src=src_if.remote_ip6, dst=dst_if.remote_ip6) / - UDP(sport=1234, dport=1234) / - Raw(payload)) - info.data = p.copy() - if isinstance(src_if, VppSubInterface): - p = src_if.add_dot1_layer(p) - size = packet_sizes[(i // 2) % len(packet_sizes)] - self.extend_packet(p, size) - pkts.append(p) + hdr_ext = 4 if isinstance(src_if, VppSubInterface) else 0 + pkt_tmpl = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) / + IPv6(src=src_if.remote_ip6) / + inet6.UDP(sport=1234, dport=1234)) + + pkts = [self.modify_packet(src_if, i, pkt_tmpl) + for i in moves.range(self.pg_if_packet_sizes[0], + self.pg_if_packet_sizes[1], 10)] + pkts_b = [self.modify_packet(src_if, i, pkt_tmpl) + for i in moves.range(self.pg_if_packet_sizes[1] + hdr_ext, + self.pg_if_packet_sizes[2] + hdr_ext, + 50)] + pkts.extend(pkts_b) + return pkts def verify_capture(self, dst_if, capture): @@ -295,8 +295,8 @@ class TestIPv6(TestIPv6ND): self.assertTrue(Dot1Q not in packet) try: ip = packet[IPv6] - udp = packet[UDP] - payload_info = self.payload_to_info(str(packet[Raw])) + udp = packet[inet6.UDP] + payload_info = self.payload_to_info(packet[Raw]) packet_index = payload_info.index self.assertEqual(payload_info.dst, dst_sw_if_index) self.logger.debug( @@ -310,10 +310,14 @@ class TestIPv6(TestIPv6ND): self.assertEqual(packet_index, next_info.index) saved_packet = next_info.data # Check standard fields - self.assertEqual(ip.src, saved_packet[IPv6].src) - self.assertEqual(ip.dst, saved_packet[IPv6].dst) - self.assertEqual(udp.sport, saved_packet[UDP].sport) - self.assertEqual(udp.dport, saved_packet[UDP].dport) + self.assertEqual( + ip.src, saved_packet[IPv6].src) + self.assertEqual( + ip.dst, saved_packet[IPv6].dst) + self.assertEqual( + udp.sport, saved_packet[inet6.UDP].sport) + self.assertEqual( + udp.dport, saved_packet[inet6.UDP].dport) except: self.logger.error(ppp("Unexpected or invalid packet:", packet)) raise @@ -324,6 +328,24 @@ class TestIPv6(TestIPv6ND): "Interface %s: Packet expected from interface %s " "didn't arrive" % (dst_if.name, i.name)) + def test_next_header_anomaly(self): + """ IPv6 next header anomaly test + + Test scenario: + - ipv6 next header field = Fragment Header (44) + - next header is ICMPv6 Echo Request + - wait for reassembly + """ + pkt = (Ether(src=self.pg0.local_mac, dst=self.pg0.remote_mac) / + IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6, nh=44) / + ICMPv6EchoRequest()) + + self.pg0.add_stream(pkt) + self.pg_start() + + # wait for reassembly + self.sleep(10) + def test_fib(self): """ IPv6 FIB test @@ -333,11 +355,11 @@ class TestIPv6(TestIPv6ND): - Send and verify received packets on each interface. """ - pkts = self.create_stream(self.pg0, self.pg_if_packet_sizes) + pkts = self.create_stream(self.pg0) self.pg0.add_stream(pkts) for i in self.sub_interfaces: - pkts = self.create_stream(i, self.sub_if_packet_sizes) + pkts = self.create_stream(i) i.parent.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) @@ -368,7 +390,8 @@ class TestIPv6(TestIPv6ND): p = (Ether(dst=in6_getnsmac(nsma)) / IPv6(dst=d, src="2002::2") / ICMPv6ND_NS(tgt=self.pg0.local_ip6) / - ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)) + ICMPv6NDOptSrcLLAddr( + lladdr=self.pg0.remote_mac)) pkts = [p] self.send_and_assert_no_replies( @@ -386,7 +409,8 @@ class TestIPv6(TestIPv6ND): p = (Ether(dst=in6_getnsmac(nsma)) / IPv6(dst=d, src=self.pg0.remote_ip6) / ICMPv6ND_NS(tgt=self.pg0.local_ip6) / - ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)) + ICMPv6NDOptSrcLLAddr( + lladdr=self.pg0.remote_mac)) pkts = [p] self.send_and_assert_no_replies( @@ -402,7 +426,8 @@ class TestIPv6(TestIPv6ND): p = (Ether(dst=in6_getnsmac(nsma)) / IPv6(dst=d, src=self.pg0.remote_ip6) / ICMPv6ND_NS(tgt="fd::ffff") / - ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)) + ICMPv6NDOptSrcLLAddr( + lladdr=self.pg0.remote_mac)) pkts = [p] self.send_and_assert_no_replies(self.pg0, pkts, @@ -416,7 +441,6 @@ class TestIPv6(TestIPv6ND): self.pg0.sw_if_index, self.pg0.remote_hosts[2].mac, self.pg0.remote_hosts[2].ip6, - af=AF_INET6, is_no_fib_entry=1) nd_entry.add_vpp_config() @@ -425,21 +449,21 @@ class TestIPv6(TestIPv6ND): # self.assertTrue(find_nbr(self, self.pg0.sw_if_index, - self.pg0._remote_hosts[2].ip6, - inet=AF_INET6)) + self.pg0._remote_hosts[2].ip6)) self.assertFalse(find_route(self, self.pg0._remote_hosts[2].ip6, - 128, - inet=AF_INET6)) + 128)) # # send an NS from a link local address to the interface's global # address # p = (Ether(dst=in6_getnsmac(nsma), src=self.pg0.remote_mac) / - IPv6(dst=d, src=self.pg0._remote_hosts[2].ip6_ll) / + IPv6( + dst=d, src=self.pg0._remote_hosts[2].ip6_ll) / ICMPv6ND_NS(tgt=self.pg0.local_ip6) / - ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)) + ICMPv6NDOptSrcLLAddr( + lladdr=self.pg0.remote_mac)) self.send_and_expect_na(self.pg0, p, "NS from link-local", @@ -452,20 +476,20 @@ class TestIPv6(TestIPv6ND): # self.assertTrue(find_nbr(self, self.pg0.sw_if_index, - self.pg0._remote_hosts[2].ip6_ll, - inet=AF_INET6)) + self.pg0._remote_hosts[2].ip6_ll)) self.assertFalse(find_route(self, self.pg0._remote_hosts[2].ip6_ll, - 128, - inet=AF_INET6)) + 128)) # # An NS to the router's own Link-local # p = (Ether(dst=in6_getnsmac(nsma), src=self.pg0.remote_mac) / - IPv6(dst=d, src=self.pg0._remote_hosts[3].ip6_ll) / + IPv6( + dst=d, src=self.pg0._remote_hosts[3].ip6_ll) / ICMPv6ND_NS(tgt=self.pg0.local_ip6_ll) / - ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)) + ICMPv6NDOptSrcLLAddr( + lladdr=self.pg0.remote_mac)) self.send_and_expect_na(self.pg0, p, "NS to/from link-local", @@ -478,12 +502,10 @@ class TestIPv6(TestIPv6ND): # self.assertTrue(find_nbr(self, self.pg0.sw_if_index, - self.pg0._remote_hosts[3].ip6_ll, - inet=AF_INET6)) + self.pg0._remote_hosts[3].ip6_ll)) self.assertFalse(find_route(self, self.pg0._remote_hosts[3].ip6_ll, - 128, - inet=AF_INET6)) + 128)) def test_ns_duplicates(self): """ ND Duplicates""" @@ -499,14 +521,12 @@ class TestIPv6(TestIPv6ND): ns_pg1 = VppNeighbor(self, self.pg1.sw_if_index, self.pg1.remote_hosts[1].mac, - self.pg1.remote_hosts[1].ip6, - af=AF_INET6) + self.pg1.remote_hosts[1].ip6) ns_pg1.add_vpp_config() ns_pg2 = VppNeighbor(self, self.pg2.sw_if_index, self.pg2.remote_mac, - self.pg1.remote_hosts[1].ip6, - af=AF_INET6) + self.pg1.remote_hosts[1].ip6) ns_pg2.add_vpp_config() # @@ -516,7 +536,7 @@ class TestIPv6(TestIPv6ND): src=self.pg0.remote_mac) / IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_hosts[1].ip6) / - UDP(sport=1234, dport=1234) / + inet6.UDP(sport=1234, dport=1234) / Raw()) self.pg0.add_stream(p) @@ -533,7 +553,7 @@ class TestIPv6(TestIPv6ND): # # remove the duplicate on pg1 - # packet stream shoud generate NSs out of pg1 + # packet stream should generate NSs out of pg1 # ns_pg1.remove_vpp_config() @@ -587,7 +607,8 @@ class TestIPv6(TestIPv6ND): if not pi_opt: # the RA should not contain prefix information - self.assertFalse(ra.haslayer(ICMPv6NDOptPrefixInfo)) + self.assertFalse(ra.haslayer( + ICMPv6NDOptPrefixInfo)) else: raos = rx.getlayer(ICMPv6NDOptPrefixInfo, 1) @@ -595,15 +616,17 @@ class TestIPv6(TestIPv6ND): # decipher how to decode. this 1st layer of option always returns # nested classes, so a direct obj1=obj2 comparison always fails. # however, the getlayer(.., 2) does give one instnace. - # so we cheat here and construct a new opt instnace for comparison - rd = ICMPv6NDOptPrefixInfo(prefixlen=raos.prefixlen, - prefix=raos.prefix, - L=raos.L, - A=raos.A) + # so we cheat here and construct a new opt instance for comparison + rd = ICMPv6NDOptPrefixInfo( + prefixlen=raos.prefixlen, + prefix=raos.prefix, + L=raos.L, + A=raos.A) if type(pi_opt) is list: for ii in range(len(pi_opt)): self.assertEqual(pi_opt[ii], rd) - rd = rx.getlayer(ICMPv6NDOptPrefixInfo, ii+2) + rd = rx.getlayer( + ICMPv6NDOptPrefixInfo, ii + 2) else: self.assertEqual(pi_opt, raos) @@ -640,7 +663,8 @@ class TestIPv6(TestIPv6ND): # - expect an RA in return # p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IPv6(dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / + IPv6( + dst=self.pg0.local_ip6, src=self.pg0.remote_ip6) / ICMPv6ND_RS()) pkts = [p] self.send_and_expect_ra(self.pg0, pkts, "Genuine RS") @@ -651,7 +675,8 @@ class TestIPv6(TestIPv6ND): self.send_and_assert_no_replies(self.pg0, pkts, "RA rate limited") # - # When we reconfiure the IPv6 RA config, we reset the RA rate limiting, + # When we reconfigure the IPv6 RA config, + # we reset the RA rate limiting, # so we need to do this before each test below so as not to drop # packets for rate limiting reasons. Test this works here. # @@ -663,7 +688,8 @@ class TestIPv6(TestIPv6ND): # self.pg0.ip6_ra_config(send_unicast=1) p = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / - IPv6(dst=self.pg0.local_ip6, src="2002::ffff") / + IPv6(dst=self.pg0.local_ip6, + src="2002::ffff") / ICMPv6ND_RS()) pkts = [p] self.send_and_assert_no_replies(self.pg0, pkts, @@ -717,16 +743,17 @@ class TestIPv6(TestIPv6ND): # # Configure The RA to announce the links prefix # - self.pg0.ip6_ra_prefix(self.pg0.local_ip6n, + self.pg0.ip6_ra_prefix(self.pg0.local_ip6, self.pg0.local_ip6_prefix_len) # # RAs should now contain the prefix information option # - opt = ICMPv6NDOptPrefixInfo(prefixlen=self.pg0.local_ip6_prefix_len, - prefix=self.pg0.local_ip6, - L=1, - A=1) + opt = ICMPv6NDOptPrefixInfo( + prefixlen=self.pg0.local_ip6_prefix_len, + prefix=self.pg0.local_ip6, + L=1, + A=1) self.pg0.ip6_ra_config(send_unicast=1) ll = mk_ll_addr(self.pg0.remote_mac) @@ -742,14 +769,15 @@ class TestIPv6(TestIPv6ND): # Change the prefix info to not off-link # L-flag is clear # - self.pg0.ip6_ra_prefix(self.pg0.local_ip6n, + self.pg0.ip6_ra_prefix(self.pg0.local_ip6, self.pg0.local_ip6_prefix_len, off_link=1) - opt = ICMPv6NDOptPrefixInfo(prefixlen=self.pg0.local_ip6_prefix_len, - prefix=self.pg0.local_ip6, - L=0, - A=1) + opt = ICMPv6NDOptPrefixInfo( + prefixlen=self.pg0.local_ip6_prefix_len, + prefix=self.pg0.local_ip6, + L=0, + A=1) self.pg0.ip6_ra_config(send_unicast=1) self.send_and_expect_ra(self.pg0, p, @@ -761,15 +789,16 @@ class TestIPv6(TestIPv6ND): # Change the prefix info to not off-link, no-autoconfig # L and A flag are clear in the advert # - self.pg0.ip6_ra_prefix(self.pg0.local_ip6n, + self.pg0.ip6_ra_prefix(self.pg0.local_ip6, self.pg0.local_ip6_prefix_len, off_link=1, no_autoconfig=1) - opt = ICMPv6NDOptPrefixInfo(prefixlen=self.pg0.local_ip6_prefix_len, - prefix=self.pg0.local_ip6, - L=0, - A=0) + opt = ICMPv6NDOptPrefixInfo( + prefixlen=self.pg0.local_ip6_prefix_len, + prefix=self.pg0.local_ip6, + L=0, + A=0) self.pg0.ip6_ra_config(send_unicast=1) self.send_and_expect_ra(self.pg0, p, @@ -781,13 +810,14 @@ class TestIPv6(TestIPv6ND): # Change the flag settings back to the defaults # L and A flag are set in the advert # - self.pg0.ip6_ra_prefix(self.pg0.local_ip6n, + self.pg0.ip6_ra_prefix(self.pg0.local_ip6, self.pg0.local_ip6_prefix_len) - opt = ICMPv6NDOptPrefixInfo(prefixlen=self.pg0.local_ip6_prefix_len, - prefix=self.pg0.local_ip6, - L=1, - A=1) + opt = ICMPv6NDOptPrefixInfo( + prefixlen=self.pg0.local_ip6_prefix_len, + prefix=self.pg0.local_ip6, + L=1, + A=1) self.pg0.ip6_ra_config(send_unicast=1) self.send_and_expect_ra(self.pg0, p, @@ -799,15 +829,16 @@ class TestIPv6(TestIPv6ND): # Change the prefix info to not off-link, no-autoconfig # L and A flag are clear in the advert # - self.pg0.ip6_ra_prefix(self.pg0.local_ip6n, + self.pg0.ip6_ra_prefix(self.pg0.local_ip6, self.pg0.local_ip6_prefix_len, off_link=1, no_autoconfig=1) - opt = ICMPv6NDOptPrefixInfo(prefixlen=self.pg0.local_ip6_prefix_len, - prefix=self.pg0.local_ip6, - L=0, - A=0) + opt = ICMPv6NDOptPrefixInfo( + prefixlen=self.pg0.local_ip6_prefix_len, + prefix=self.pg0.local_ip6, + L=0, + A=0) self.pg0.ip6_ra_config(send_unicast=1) self.send_and_expect_ra(self.pg0, p, @@ -816,17 +847,18 @@ class TestIPv6(TestIPv6ND): opt=opt) # - # Use the reset to defults option to revert to defaults + # Use the reset to defaults option to revert to defaults # L and A flag are clear in the advert # - self.pg0.ip6_ra_prefix(self.pg0.local_ip6n, + self.pg0.ip6_ra_prefix(self.pg0.local_ip6, self.pg0.local_ip6_prefix_len, use_default=1) - opt = ICMPv6NDOptPrefixInfo(prefixlen=self.pg0.local_ip6_prefix_len, - prefix=self.pg0.local_ip6, - L=1, - A=1) + opt = ICMPv6NDOptPrefixInfo( + prefixlen=self.pg0.local_ip6_prefix_len, + prefix=self.pg0.local_ip6, + L=1, + A=1) self.pg0.ip6_ra_config(send_unicast=1) self.send_and_expect_ra(self.pg0, p, @@ -837,19 +869,21 @@ class TestIPv6(TestIPv6ND): # # Advertise Another prefix. With no L-flag/A-flag # - self.pg0.ip6_ra_prefix(self.pg1.local_ip6n, + self.pg0.ip6_ra_prefix(self.pg1.local_ip6, self.pg1.local_ip6_prefix_len, off_link=1, no_autoconfig=1) - opt = [ICMPv6NDOptPrefixInfo(prefixlen=self.pg0.local_ip6_prefix_len, - prefix=self.pg0.local_ip6, - L=1, - A=1), - ICMPv6NDOptPrefixInfo(prefixlen=self.pg1.local_ip6_prefix_len, - prefix=self.pg1.local_ip6, - L=0, - A=0)] + opt = [ICMPv6NDOptPrefixInfo( + prefixlen=self.pg0.local_ip6_prefix_len, + prefix=self.pg0.local_ip6, + L=1, + A=1), + ICMPv6NDOptPrefixInfo( + prefixlen=self.pg1.local_ip6_prefix_len, + prefix=self.pg1.local_ip6, + L=0, + A=0)] self.pg0.ip6_ra_config(send_unicast=1) ll = mk_ll_addr(self.pg0.remote_mac) @@ -862,17 +896,18 @@ class TestIPv6(TestIPv6ND): opt=opt) # - # Remove the first refix-info - expect the second is still in the + # Remove the first prefix-info - expect the second is still in the # advert # - self.pg0.ip6_ra_prefix(self.pg0.local_ip6n, + self.pg0.ip6_ra_prefix(self.pg0.local_ip6, self.pg0.local_ip6_prefix_len, is_no=1) - opt = ICMPv6NDOptPrefixInfo(prefixlen=self.pg1.local_ip6_prefix_len, - prefix=self.pg1.local_ip6, - L=0, - A=0) + opt = ICMPv6NDOptPrefixInfo( + prefixlen=self.pg1.local_ip6_prefix_len, + prefix=self.pg1.local_ip6, + L=0, + A=0) self.pg0.ip6_ra_config(send_unicast=1) self.send_and_expect_ra(self.pg0, p, @@ -881,9 +916,9 @@ class TestIPv6(TestIPv6ND): opt=opt) # - # Remove the second prefix-info - expect no prefix-info i nthe adverts + # Remove the second prefix-info - expect no prefix-info in the adverts # - self.pg0.ip6_ra_prefix(self.pg1.local_ip6n, + self.pg0.ip6_ra_prefix(self.pg1.local_ip6, self.pg1.local_ip6_prefix_len, is_no=1) @@ -898,6 +933,79 @@ class TestIPv6(TestIPv6ND): self.pg0.ip6_ra_config(no=1, suppress=1, send_unicast=0) +class TestICMPv6Echo(VppTestCase): + """ ICMPv6 Echo Test Case """ + + @classmethod + def setUpClass(cls): + super(TestICMPv6Echo, cls).setUpClass() + + @classmethod + def tearDownClass(cls): + super(TestICMPv6Echo, cls).tearDownClass() + + def setUp(self): + super(TestICMPv6Echo, self).setUp() + + # create 1 pg interface + self.create_pg_interfaces(range(1)) + + for i in self.pg_interfaces: + i.admin_up() + i.config_ip6() + i.resolve_ndp() + + def tearDown(self): + super(TestICMPv6Echo, self).tearDown() + for i in self.pg_interfaces: + i.unconfig_ip6() + i.ip6_disable() + i.admin_down() + + def test_icmpv6_echo(self): + """ VPP replies to ICMPv6 Echo Request + + Test scenario: + + - Receive ICMPv6 Echo Request message on pg0 interface. + - Check outgoing ICMPv6 Echo Reply message on pg0 interface. + """ + + icmpv6_id = 0xb + icmpv6_seq = 5 + icmpv6_data = b'\x0a' * 18 + p_echo_request = (Ether(src=self.pg0.remote_mac, + dst=self.pg0.local_mac) / + IPv6(src=self.pg0.remote_ip6, + dst=self.pg0.local_ip6) / + ICMPv6EchoRequest( + id=icmpv6_id, + seq=icmpv6_seq, + data=icmpv6_data)) + + self.pg0.add_stream(p_echo_request) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() + + rx = self.pg0.get_capture(1) + rx = rx[0] + ether = rx[Ether] + ipv6 = rx[IPv6] + icmpv6 = rx[ICMPv6EchoReply] + + self.assertEqual(ether.src, self.pg0.local_mac) + self.assertEqual(ether.dst, self.pg0.remote_mac) + + self.assertEqual(ipv6.src, self.pg0.local_ip6) + self.assertEqual(ipv6.dst, self.pg0.remote_ip6) + + self.assertEqual( + icmp6types[icmpv6.type], "Echo Reply") + self.assertEqual(icmpv6.id, icmpv6_id) + self.assertEqual(icmpv6.seq, icmpv6_seq) + self.assertEqual(icmpv6.data, icmpv6_data) + + class TestIPv6RD(TestIPv6ND): """ IPv6 Router Discovery Test Case """ @@ -905,6 +1013,10 @@ class TestIPv6RD(TestIPv6ND): def setUpClass(cls): super(TestIPv6RD, cls).setUpClass() + @classmethod + def tearDownClass(cls): + super(TestIPv6RD, cls).tearDownClass() + def setUp(self): super(TestIPv6RD, self).setUp() @@ -935,24 +1047,30 @@ class TestIPv6RD(TestIPv6ND): rx_list = self.pg1.get_capture(count, timeout=3) self.assertEqual(len(rx_list), count) for packet in rx_list: - self.assertTrue(packet.haslayer(IPv6)) - self.assertTrue(packet[IPv6].haslayer(ICMPv6ND_RS)) + self.assertEqual(packet.haslayer(IPv6), 1) + self.assertEqual(packet[IPv6].haslayer( + ICMPv6ND_RS), 1) dst = ip6_normalize(packet[IPv6].dst) dst2 = ip6_normalize("ff02::2") self.assert_equal(dst, dst2) src = ip6_normalize(packet[IPv6].src) src2 = ip6_normalize(self.pg1.local_ip6_ll) self.assert_equal(src, src2) - self.assertTrue(packet[ICMPv6ND_RS].haslayer(ICMPv6NDOptSrcLLAddr)) - self.assert_equal(packet[ICMPv6NDOptSrcLLAddr].lladdr, - self.pg1.local_mac) + self.assertTrue( + bool(packet[ICMPv6ND_RS].haslayer( + ICMPv6NDOptSrcLLAddr))) + self.assert_equal( + packet[ICMPv6NDOptSrcLLAddr].lladdr, + self.pg1.local_mac) def verify_prefix_info(self, reported_prefix, prefix_option): - prefix = socket.inet_pton(socket.AF_INET6, - prefix_option.getfieldval("prefix")) - self.assert_equal(reported_prefix.dst_address, prefix) - self.assert_equal(reported_prefix.dst_address_length, - prefix_option.getfieldval("prefixlen")) + prefix = IPv6Network( + text_type(prefix_option.getfieldval("prefix") + + "/" + + text_type(prefix_option.getfieldval("prefixlen"))), + strict=False) + self.assert_equal(reported_prefix.prefix.network_address, + prefix.network_address) L = prefix_option.getfieldval("L") A = prefix_option.getfieldval("A") option_flags = (L << 7) | (A << 6) @@ -1016,6 +1134,10 @@ class TestIPv6RDControlPlane(TestIPv6ND): def setUpClass(cls): super(TestIPv6RDControlPlane, cls).setUpClass() + @classmethod + def tearDownClass(cls): + super(TestIPv6RDControlPlane, cls).tearDownClass() + def setUp(self): super(TestIPv6RDControlPlane, self).setUp() @@ -1048,12 +1170,12 @@ class TestIPv6RDControlPlane(TestIPv6ND): def get_default_routes(fib): list = [] for entry in fib: - if entry.address_length == 0: - for path in entry.path: + if entry.route.prefix.prefixlen == 0: + for path in entry.route.paths: if path.sw_if_index != 0xFFFFFFFF: defaut_route = {} defaut_route['sw_if_index'] = path.sw_if_index - defaut_route['next_hop'] = path.next_hop + defaut_route['next_hop'] = path.nh.address.ip6 list.append(defaut_route) return list @@ -1061,27 +1183,28 @@ class TestIPv6RDControlPlane(TestIPv6ND): def get_interface_addresses(fib, pg): list = [] for entry in fib: - if entry.address_length == 128: - path = entry.path[0] + if entry.route.prefix.prefixlen == 128: + path = entry.route.paths[0] if path.sw_if_index == pg.sw_if_index: - list.append(entry.address) + list.append(str(entry.route.prefix.network_address)) return list def test_all(self): """ Test handling of SLAAC addresses and default routes """ - fib = self.vapi.ip6_fib_dump() + fib = self.vapi.ip_route_dump(0, True) default_routes = self.get_default_routes(fib) initial_addresses = set(self.get_interface_addresses(fib, self.pg0)) self.assertEqual(default_routes, []) - router_address = self.pg0.remote_ip6n_ll + router_address = IPv6Address(text_type(self.pg0.remote_ip6_ll)) self.vapi.ip6_nd_address_autoconfig(self.pg0.sw_if_index, 1, 1) self.sleep(0.1) # send RA - packet = (self.create_ra_packet(self.pg0) / ICMPv6NDOptPrefixInfo( + packet = (self.create_ra_packet( + self.pg0) / ICMPv6NDOptPrefixInfo( prefix="1::", prefixlen=64, validlifetime=2, @@ -1101,14 +1224,15 @@ class TestIPv6RDControlPlane(TestIPv6ND): self.sleep(0.1) - fib = self.vapi.ip6_fib_dump() + fib = self.vapi.ip_route_dump(0, True) # check FIB for new address addresses = set(self.get_interface_addresses(fib, self.pg0)) new_addresses = addresses.difference(initial_addresses) self.assertEqual(len(new_addresses), 1) - prefix = list(new_addresses)[0][:8] + '\0\0\0\0\0\0\0\0' - self.assertEqual(inet_ntop(AF_INET6, prefix), '1::') + prefix = IPv6Network(text_type("%s/%d" % (list(new_addresses)[0], 20)), + strict=False) + self.assertEqual(prefix, IPv6Network(text_type('1::/20'))) # check FIB for new default route default_routes = self.get_default_routes(fib) @@ -1125,7 +1249,7 @@ class TestIPv6RDControlPlane(TestIPv6ND): self.sleep(0.1) # check that default route is deleted - fib = self.vapi.ip6_fib_dump() + fib = self.vapi.ip_route_dump(0, True) default_routes = self.get_default_routes(fib) self.assertEqual(len(default_routes), 0) @@ -1139,7 +1263,7 @@ class TestIPv6RDControlPlane(TestIPv6ND): self.sleep(0.1) # check FIB for new default route - fib = self.vapi.ip6_fib_dump() + fib = self.vapi.ip_route_dump(0, True) default_routes = self.get_default_routes(fib) self.assertEqual(len(default_routes), 1) dr = default_routes[0] @@ -1154,7 +1278,7 @@ class TestIPv6RDControlPlane(TestIPv6ND): self.sleep(0.1) # check that default route still exists - fib = self.vapi.ip6_fib_dump() + fib = self.vapi.ip_route_dump(0, True) default_routes = self.get_default_routes(fib) self.assertEqual(len(default_routes), 1) dr = default_routes[0] @@ -1164,21 +1288,23 @@ class TestIPv6RDControlPlane(TestIPv6ND): self.sleep(1) # check that default route is deleted - fib = self.vapi.ip6_fib_dump() + fib = self.vapi.ip_route_dump(0, True) default_routes = self.get_default_routes(fib) self.assertEqual(len(default_routes), 0) # check FIB still contains the SLAAC address addresses = set(self.get_interface_addresses(fib, self.pg0)) new_addresses = addresses.difference(initial_addresses) + self.assertEqual(len(new_addresses), 1) - prefix = list(new_addresses)[0][:8] + '\0\0\0\0\0\0\0\0' - self.assertEqual(inet_ntop(AF_INET6, prefix), '1::') + prefix = IPv6Network(text_type("%s/%d" % (list(new_addresses)[0], 20)), + strict=False) + self.assertEqual(prefix, IPv6Network(text_type('1::/20'))) self.sleep(1) # check that SLAAC address is deleted - fib = self.vapi.ip6_fib_dump() + fib = self.vapi.ip_route_dump(0, True) addresses = set(self.get_interface_addresses(fib, self.pg0)) new_addresses = addresses.difference(initial_addresses) self.assertEqual(len(new_addresses), 0) @@ -1187,6 +1313,14 @@ class TestIPv6RDControlPlane(TestIPv6ND): class IPv6NDProxyTest(TestIPv6ND): """ IPv6 ND ProxyTest Case """ + @classmethod + def setUpClass(cls): + super(IPv6NDProxyTest, cls).setUpClass() + + @classmethod + def tearDownClass(cls): + super(IPv6NDProxyTest, cls).tearDownClass() + def setUp(self): super(IPv6NDProxyTest, self).setUp() @@ -1221,18 +1355,20 @@ class IPv6NDProxyTest(TestIPv6ND): # on the link that has the prefix configured # ns_pg1 = (Ether(dst=in6_getnsmac(nsma), src=self.pg1.remote_mac) / - IPv6(dst=d, src=self.pg0._remote_hosts[2].ip6) / + IPv6(dst=d, + src=self.pg0._remote_hosts[2].ip6) / ICMPv6ND_NS(tgt=self.pg0.local_ip6) / - ICMPv6NDOptSrcLLAddr(lladdr=self.pg0._remote_hosts[2].mac)) + ICMPv6NDOptSrcLLAddr( + lladdr=self.pg0._remote_hosts[2].mac)) self.send_and_assert_no_replies(self.pg1, ns_pg1, "Off link NS") # # Add proxy support for the host # - self.vapi.ip6_nd_proxy( - inet_pton(AF_INET6, self.pg0._remote_hosts[2].ip6), - self.pg1.sw_if_index) + self.vapi.ip6nd_proxy_add_del( + ip=inet_pton(AF_INET6, self.pg0._remote_hosts[2].ip6), + sw_if_index=self.pg1.sw_if_index) # # try that NS again. this time we expect an NA back @@ -1247,8 +1383,7 @@ class IPv6NDProxyTest(TestIPv6ND): # self.assertTrue(find_nbr(self, self.pg1.sw_if_index, - self.pg0._remote_hosts[2].ip6, - inet=AF_INET6)) + self.pg0._remote_hosts[2].ip6)) # # ... and we can route traffic to it @@ -1256,7 +1391,7 @@ class IPv6NDProxyTest(TestIPv6ND): t = (Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac) / IPv6(dst=self.pg0._remote_hosts[2].ip6, src=self.pg0.remote_ip6) / - UDP(sport=10000, dport=20000) / + inet6.UDP(sport=10000, dport=20000) / Raw('\xa5' * 100)) self.pg0.add_stream(t) @@ -1268,16 +1403,20 @@ class IPv6NDProxyTest(TestIPv6ND): self.assertEqual(rx[Ether].dst, self.pg0._remote_hosts[2].mac) self.assertEqual(rx[Ether].src, self.pg1.local_mac) - self.assertEqual(rx[IPv6].src, t[IPv6].src) - self.assertEqual(rx[IPv6].dst, t[IPv6].dst) + self.assertEqual(rx[IPv6].src, + t[IPv6].src) + self.assertEqual(rx[IPv6].dst, + t[IPv6].dst) # # Test we proxy for the host on the main interface # ns_pg0 = (Ether(dst=in6_getnsmac(nsma), src=self.pg0.remote_mac) / IPv6(dst=d, src=self.pg0.remote_ip6) / - ICMPv6ND_NS(tgt=self.pg0._remote_hosts[2].ip6) / - ICMPv6NDOptSrcLLAddr(lladdr=self.pg0.remote_mac)) + ICMPv6ND_NS( + tgt=self.pg0._remote_hosts[2].ip6) / + ICMPv6NDOptSrcLLAddr( + lladdr=self.pg0.remote_mac)) self.send_and_expect_na(self.pg0, ns_pg0, "NS to proxy entry on main", @@ -1288,13 +1427,15 @@ class IPv6NDProxyTest(TestIPv6ND): # Setup and resolve proxy for another host on another interface # ns_pg2 = (Ether(dst=in6_getnsmac(nsma), src=self.pg2.remote_mac) / - IPv6(dst=d, src=self.pg0._remote_hosts[3].ip6) / + IPv6(dst=d, + src=self.pg0._remote_hosts[3].ip6) / ICMPv6ND_NS(tgt=self.pg0.local_ip6) / - ICMPv6NDOptSrcLLAddr(lladdr=self.pg0._remote_hosts[2].mac)) + ICMPv6NDOptSrcLLAddr( + lladdr=self.pg0._remote_hosts[2].mac)) - self.vapi.ip6_nd_proxy( - inet_pton(AF_INET6, self.pg0._remote_hosts[3].ip6), - self.pg2.sw_if_index) + self.vapi.ip6nd_proxy_add_del( + ip=inet_pton(AF_INET6, self.pg0._remote_hosts[3].ip6), + sw_if_index=self.pg2.sw_if_index) self.send_and_expect_na(self.pg2, ns_pg2, "NS to proxy entry other interface", @@ -1303,8 +1444,7 @@ class IPv6NDProxyTest(TestIPv6ND): self.assertTrue(find_nbr(self, self.pg2.sw_if_index, - self.pg0._remote_hosts[3].ip6, - inet=AF_INET6)) + self.pg0._remote_hosts[3].ip6)) # # hosts can communicate. pg2->pg1 @@ -1313,7 +1453,7 @@ class IPv6NDProxyTest(TestIPv6ND): src=self.pg0.remote_hosts[3].mac) / IPv6(dst=self.pg0._remote_hosts[2].ip6, src=self.pg0._remote_hosts[3].ip6) / - UDP(sport=10000, dport=20000) / + inet6.UDP(sport=10000, dport=20000) / Raw('\xa5' * 100)) self.pg2.add_stream(t2) @@ -1325,29 +1465,27 @@ class IPv6NDProxyTest(TestIPv6ND): self.assertEqual(rx[Ether].dst, self.pg0._remote_hosts[2].mac) self.assertEqual(rx[Ether].src, self.pg1.local_mac) - self.assertEqual(rx[IPv6].src, t2[IPv6].src) - self.assertEqual(rx[IPv6].dst, t2[IPv6].dst) + self.assertEqual(rx[IPv6].src, + t2[IPv6].src) + self.assertEqual(rx[IPv6].dst, + t2[IPv6].dst) # # remove the proxy configs # - self.vapi.ip6_nd_proxy( - inet_pton(AF_INET6, self.pg0._remote_hosts[2].ip6), - self.pg1.sw_if_index, - is_del=1) - self.vapi.ip6_nd_proxy( - inet_pton(AF_INET6, self.pg0._remote_hosts[3].ip6), - self.pg2.sw_if_index, - is_del=1) + self.vapi.ip6nd_proxy_add_del( + ip=inet_pton(AF_INET6, self.pg0._remote_hosts[2].ip6), + sw_if_index=self.pg1.sw_if_index, is_del=1) + self.vapi.ip6nd_proxy_add_del( + ip=inet_pton(AF_INET6, self.pg0._remote_hosts[3].ip6), + sw_if_index=self.pg2.sw_if_index, is_del=1) self.assertFalse(find_nbr(self, self.pg2.sw_if_index, - self.pg0._remote_hosts[3].ip6, - inet=AF_INET6)) + self.pg0._remote_hosts[3].ip6)) self.assertFalse(find_nbr(self, self.pg1.sw_if_index, - self.pg0._remote_hosts[2].ip6, - inet=AF_INET6)) + self.pg0._remote_hosts[2].ip6)) # # no longer proxy-ing... @@ -1372,6 +1510,14 @@ class IPv6NDProxyTest(TestIPv6ND): class TestIPNull(VppTestCase): """ IPv6 routes via NULL """ + @classmethod + def setUpClass(cls): + super(TestIPNull, cls).setUpClass() + + @classmethod + def tearDownClass(cls): + super(TestIPNull, cls).tearDownClass() + def setUp(self): super(TestIPNull, self).setUp() @@ -1395,13 +1541,16 @@ class TestIPNull(VppTestCase): p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6(src=self.pg0.remote_ip6, dst="2001::1") / - UDP(sport=1234, dport=1234) / + inet6.UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) # # A route via IP NULL that will reply with ICMP unreachables # - ip_unreach = VppIpRoute(self, "2001::", 64, [], is_unreach=1, is_ip6=1) + ip_unreach = VppIpRoute( + self, "2001::", 64, + [VppRoutePath("::", 0xffffffff, + type=FibPathType.FIB_PATH_TYPE_ICMP_UNREACH)]) ip_unreach.add_vpp_config() self.pg0.add_stream(p) @@ -1421,8 +1570,10 @@ class TestIPNull(VppTestCase): # # A route via IP NULL that will reply with ICMP prohibited # - ip_prohibit = VppIpRoute(self, "2001::1", 128, [], - is_prohibit=1, is_ip6=1) + ip_prohibit = VppIpRoute( + self, "2001::1", 128, + [VppRoutePath("::", 0xffffffff, + type=FibPathType.FIB_PATH_TYPE_ICMP_PROHIBIT)]) ip_prohibit.add_vpp_config() self.pg0.add_stream(p) @@ -1440,13 +1591,21 @@ class TestIPNull(VppTestCase): class TestIPDisabled(VppTestCase): """ IPv6 disabled """ + @classmethod + def setUpClass(cls): + super(TestIPDisabled, cls).setUpClass() + + @classmethod + def tearDownClass(cls): + super(TestIPDisabled, cls).tearDownClass() + def setUp(self): super(TestIPDisabled, self).setUp() # create 2 pg interfaces self.create_pg_interfaces(range(2)) - # PG0 is IP enalbed + # PG0 is IP enabled self.pg0.admin_up() self.pg0.config_ip6() self.pg0.resolve_ndp() @@ -1475,19 +1634,18 @@ class TestIPDisabled(VppTestCase): [VppMRoutePath(self.pg1.sw_if_index, MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT), VppMRoutePath(self.pg0.sw_if_index, - MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)], - is_ip6=1) + MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)]) route_ff_01.add_vpp_config() pu = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IPv6(src="2001::1", dst=self.pg0.remote_ip6) / - UDP(sport=1234, dport=1234) / + inet6.UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pm = (Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac) / IPv6(src="2001::1", dst="ffef::1") / - UDP(sport=1234, dport=1234) / + inet6.UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) # @@ -1529,6 +1687,14 @@ class TestIPDisabled(VppTestCase): class TestIP6LoadBalance(VppTestCase): """ IPv6 Load-Balancing """ + @classmethod + def setUpClass(cls): + super(TestIP6LoadBalance, cls).setUpClass() + + @classmethod + def tearDownClass(cls): + super(TestIP6LoadBalance, cls).tearDownClass() + def setUp(self): super(TestIP6LoadBalance, self).setUp() @@ -1550,20 +1716,20 @@ class TestIP6LoadBalance(VppTestCase): i.disable_mpls() super(TestIP6LoadBalance, self).tearDown() - def send_and_expect_load_balancing(self, input, pkts, outputs): + def pg_send(self, input, pkts): self.vapi.cli("clear trace") input.add_stream(pkts) self.pg_enable_capture(self.pg_interfaces) self.pg_start() + + def send_and_expect_load_balancing(self, input, pkts, outputs): + self.pg_send(input, pkts) for oo in outputs: rx = oo._get_capture(1) self.assertNotEqual(0, len(rx)) def send_and_expect_one_itf(self, input, pkts, itf): - self.vapi.cli("clear trace") - input.add_stream(pkts) - self.pg_enable_capture(self.pg_interfaces) - self.pg_start() + self.pg_send(input, pkts) rx = itf.get_capture(len(pkts)) def test_ip6_load_balance(self): @@ -1587,10 +1753,11 @@ class TestIP6LoadBalance(VppTestCase): src_ip_pkts = [] src_mpls_pkts = [] - for ii in range(65): - port_ip_hdr = (IPv6(dst="3000::1", src="3000:1::1") / - UDP(sport=1234, dport=1234 + ii) / - Raw('\xa5' * 100)) + for ii in range(NUM_PKTS): + port_ip_hdr = ( + IPv6(dst="3000::1", src="3000:1::1") / + inet6.UDP(sport=1234, dport=1234 + ii) / + Raw('\xa5' * 100)) port_ip_pkts.append((Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / port_ip_hdr)) @@ -1609,9 +1776,10 @@ class TestIP6LoadBalance(VppTestCase): MPLS(label=14, ttl=2) / MPLS(label=999, ttl=2) / port_ip_hdr)) - src_ip_hdr = (IPv6(dst="3000::1", src="3000:1::%d" % ii) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) + src_ip_hdr = ( + IPv6(dst="3000::1", src="3000:1::%d" % ii) / + inet6.UDP(sport=1234, dport=1234) / + Raw('\xa5' * 100)) src_ip_pkts.append((Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / src_ip_hdr)) @@ -1621,16 +1789,13 @@ class TestIP6LoadBalance(VppTestCase): src_ip_hdr)) # - # A route for the IP pacekts + # A route for the IP packets # route_3000_1 = VppIpRoute(self, "3000::1", 128, [VppRoutePath(self.pg1.remote_ip6, - self.pg1.sw_if_index, - proto=DpoProto.DPO_PROTO_IP6), + self.pg1.sw_if_index), VppRoutePath(self.pg2.remote_ip6, - self.pg2.sw_if_index, - proto=DpoProto.DPO_PROTO_IP6)], - is_ip6=1) + self.pg2.sw_if_index)]) route_3000_1.add_vpp_config() # @@ -1645,12 +1810,10 @@ class TestIP6LoadBalance(VppTestCase): route_67 = VppMplsRoute(self, 67, 0, [VppRoutePath(self.pg1.remote_ip6, self.pg1.sw_if_index, - labels=[67], - proto=DpoProto.DPO_PROTO_IP6), + labels=[67]), VppRoutePath(self.pg2.remote_ip6, self.pg2.sw_if_index, - labels=[67], - proto=DpoProto.DPO_PROTO_IP6)]) + labels=[67])]) route_67.add_vpp_config() # @@ -1659,7 +1822,7 @@ class TestIP6LoadBalance(VppTestCase): # src,dst # We are not going to ensure equal amounts of packets across each link, # since the hash algorithm is statistical and therefore this can never - # be guaranteed. But wuth 64 different packets we do expect some + # be guaranteed. But with 64 different packets we do expect some # balancing. So instead just ensure there is traffic on each link. # self.send_and_expect_load_balancing(self.pg0, port_ip_pkts, @@ -1675,7 +1838,7 @@ class TestIP6LoadBalance(VppTestCase): # # The packets with Entropy label in should not load-balance, - # since the Entorpy value is fixed. + # since the Entropy value is fixed. # self.send_and_expect_one_itf(self.pg0, port_ent_pkts, self.pg1) @@ -1684,7 +1847,8 @@ class TestIP6LoadBalance(VppTestCase): # - now only the stream with differing source address will # load-balance # - self.vapi.set_ip_flow_hash(0, is_ip6=1, src=1, dst=1, sport=0, dport=0) + self.vapi.set_ip_flow_hash(vrf_id=0, src=1, dst=1, sport=0, dport=0, + is_ipv6=1) self.send_and_expect_load_balancing(self.pg0, src_ip_pkts, [self.pg1, self.pg2]) @@ -1695,7 +1859,8 @@ class TestIP6LoadBalance(VppTestCase): # # change the flow hash config back to defaults # - self.vapi.set_ip_flow_hash(0, is_ip6=1, src=1, dst=1, sport=1, dport=1) + self.vapi.set_ip_flow_hash(vrf_id=0, src=1, dst=1, sport=1, dport=1, + is_ipv6=1) # # Recursive prefixes @@ -1708,33 +1873,30 @@ class TestIP6LoadBalance(VppTestCase): for ii in range(257): port_pkts.append((Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IPv6(dst="4000::1", src="4000:1::1") / - UDP(sport=1234, dport=1234 + ii) / + IPv6(dst="4000::1", + src="4000:1::1") / + inet6.UDP(sport=1234, + dport=1234 + ii) / Raw('\xa5' * 100))) src_pkts.append((Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IPv6(dst="4000::1", src="4000:1::%d" % ii) / - UDP(sport=1234, dport=1234) / + IPv6(dst="4000::1", + src="4000:1::%d" % ii) / + inet6.UDP(sport=1234, dport=1234) / Raw('\xa5' * 100))) route_3000_2 = VppIpRoute(self, "3000::2", 128, [VppRoutePath(self.pg3.remote_ip6, - self.pg3.sw_if_index, - proto=DpoProto.DPO_PROTO_IP6), + self.pg3.sw_if_index), VppRoutePath(self.pg4.remote_ip6, - self.pg4.sw_if_index, - proto=DpoProto.DPO_PROTO_IP6)], - is_ip6=1) + self.pg4.sw_if_index)]) route_3000_2.add_vpp_config() route_4000_1 = VppIpRoute(self, "4000::1", 128, [VppRoutePath("3000::1", - 0xffffffff, - proto=DpoProto.DPO_PROTO_IP6), + 0xffffffff), VppRoutePath("3000::2", - 0xffffffff, - proto=DpoProto.DPO_PROTO_IP6)], - is_ip6=1) + 0xffffffff)]) route_4000_1.add_vpp_config() # @@ -1757,22 +1919,20 @@ class TestIP6LoadBalance(VppTestCase): for ii in range(257): port_pkts.append((Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IPv6(dst="6000::1", src="6000:1::1") / - UDP(sport=1234, dport=1234 + ii) / + IPv6(dst="6000::1", + src="6000:1::1") / + inet6.UDP(sport=1234, + dport=1234 + ii) / Raw('\xa5' * 100))) route_5000_2 = VppIpRoute(self, "5000::2", 128, [VppRoutePath(self.pg3.remote_ip6, - self.pg3.sw_if_index, - proto=DpoProto.DPO_PROTO_IP6)], - is_ip6=1) + self.pg3.sw_if_index)]) route_5000_2.add_vpp_config() route_6000_1 = VppIpRoute(self, "6000::1", 128, [VppRoutePath("5000::2", - 0xffffffff, - proto=DpoProto.DPO_PROTO_IP6)], - is_ip6=1) + 0xffffffff)]) route_6000_1.add_vpp_config() # @@ -1785,10 +1945,18 @@ class TestIP6LoadBalance(VppTestCase): class TestIP6Punt(VppTestCase): """ IPv6 Punt Police/Redirect """ + @classmethod + def setUpClass(cls): + super(TestIP6Punt, cls).setUpClass() + + @classmethod + def tearDownClass(cls): + super(TestIP6Punt, cls).tearDownClass() + def setUp(self): super(TestIP6Punt, self).setUp() - self.create_pg_interfaces(range(2)) + self.create_pg_interfaces(range(4)) for i in self.pg_interfaces: i.admin_up() @@ -1806,8 +1974,9 @@ class TestIP6Punt(VppTestCase): p = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / - IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) / - TCP(sport=1234, dport=1234) / + IPv6(src=self.pg0.remote_ip6, + dst=self.pg0.local_ip6) / + inet6.TCP(sport=1234, dport=1234) / Raw('\xa5' * 100)) pkts = p * 1025 @@ -1815,19 +1984,17 @@ class TestIP6Punt(VppTestCase): # # Configure a punt redirect via pg1. # - nh_addr = inet_pton(AF_INET6, - self.pg1.remote_ip6) + nh_addr = self.pg1.remote_ip6 self.vapi.ip_punt_redirect(self.pg0.sw_if_index, self.pg1.sw_if_index, - nh_addr, - is_ip6=1) + nh_addr) self.send_and_expect(self.pg0, pkts, self.pg1) # # add a policer # - policer = self.vapi.policer_add_del("ip6-punt", 400, 0, 10, 0, + policer = self.vapi.policer_add_del(b"ip6-punt", 400, 0, 10, 0, rate_type=1) self.vapi.ip_punt_police(policer.policer_index, is_ip6=1) @@ -1837,18 +2004,18 @@ class TestIP6Punt(VppTestCase): self.pg_start() # - # the number of packet recieved should be greater than 0, + # the number of packet received should be greater than 0, # but not equal to the number sent, since some were policed # rx = self.pg1._get_capture(1) - self.assertTrue(len(rx) > 0) - self.assertTrue(len(rx) < len(pkts)) + self.assertGreater(len(rx), 0) + self.assertLess(len(rx), len(pkts)) # - # remove the poilcer. back to full rx + # remove the policer. back to full rx # self.vapi.ip_punt_police(policer.policer_index, is_add=0, is_ip6=1) - self.vapi.policer_add_del("ip6-punt", 400, 0, 10, 0, + self.vapi.policer_add_del(b"ip6-punt", 400, 0, 10, 0, rate_type=1, is_add=0) self.send_and_expect(self.pg0, pkts, self.pg1) @@ -1858,8 +2025,7 @@ class TestIP6Punt(VppTestCase): self.vapi.ip_punt_redirect(self.pg0.sw_if_index, self.pg1.sw_if_index, nh_addr, - is_add=0, - is_ip6=1) + is_add=0) self.send_and_assert_no_replies(self.pg0, pkts, "IP no punt config") @@ -1868,24 +2034,65 @@ class TestIP6Punt(VppTestCase): # self.vapi.ip_punt_redirect(0xffffffff, self.pg1.sw_if_index, - nh_addr, - is_ip6=1) + nh_addr) self.send_and_expect(self.pg0, pkts, self.pg1) self.vapi.ip_punt_redirect(0xffffffff, self.pg1.sw_if_index, nh_addr, - is_add=0, - is_ip6=1) + is_add=0) + def test_ip_punt_dump(self): + """ IP6 punt redirect dump""" -class TestIP6Input(VppTestCase): - """ IPv6 Input Exceptions """ + # + # Configure a punt redirects + # + nh_addr = self.pg3.remote_ip6 + self.vapi.ip_punt_redirect(self.pg0.sw_if_index, + self.pg3.sw_if_index, + nh_addr) + self.vapi.ip_punt_redirect(self.pg1.sw_if_index, + self.pg3.sw_if_index, + nh_addr) + self.vapi.ip_punt_redirect(self.pg2.sw_if_index, + self.pg3.sw_if_index, + '0::0') + + # + # Dump pg0 punt redirects + # + punts = self.vapi.ip_punt_redirect_dump(self.pg0.sw_if_index, + is_ipv6=1) + for p in punts: + self.assertEqual(p.punt.rx_sw_if_index, self.pg0.sw_if_index) + + # + # Dump punt redirects for all interfaces + # + punts = self.vapi.ip_punt_redirect_dump(0xffffffff, is_ipv6=1) + self.assertEqual(len(punts), 3) + for p in punts: + self.assertEqual(p.punt.tx_sw_if_index, self.pg3.sw_if_index) + self.assertNotEqual(punts[1].punt.nh, self.pg3.remote_ip6) + self.assertEqual(str(punts[2].punt.nh), '::') + + +class TestIPDeag(VppTestCase): + """ IPv6 Deaggregate Routes """ + + @classmethod + def setUpClass(cls): + super(TestIPDeag, cls).setUpClass() + + @classmethod + def tearDownClass(cls): + super(TestIPDeag, cls).tearDownClass() def setUp(self): - super(TestIP6Input, self).setUp() + super(TestIPDeag, self).setUp() - self.create_pg_interfaces(range(2)) + self.create_pg_interfaces(range(3)) for i in self.pg_interfaces: i.admin_up() @@ -1893,46 +2100,199 @@ class TestIP6Input(VppTestCase): i.resolve_ndp() def tearDown(self): - super(TestIP6Input, self).tearDown() + super(TestIPDeag, self).tearDown() for i in self.pg_interfaces: i.unconfig_ip6() i.admin_down() - def test_ip_input(self): - """ IP6 Input Exceptions """ + def test_ip_deag(self): + """ IP Deag Routes """ # - # bad version - this is dropped + # Create a table to be used for: + # 1 - another destination address lookup + # 2 - a source address lookup # - p_version = (Ether(src=self.pg0.remote_mac, - dst=self.pg0.local_mac) / - IPv6(src=self.pg0.remote_ip6, - dst=self.pg1.remote_ip6, - version=3) / - UDP(sport=1234, dport=1234) / - Raw('\xa5' * 100)) + table_dst = VppIpTable(self, 1, is_ip6=1) + table_src = VppIpTable(self, 2, is_ip6=1) + table_dst.add_vpp_config() + table_src.add_vpp_config() + + # + # Add a route in the default table to point to a deag/ + # second lookup in each of these tables + # + route_to_dst = VppIpRoute(self, "1::1", 128, + [VppRoutePath("::", + 0xffffffff, + nh_table_id=1)]) + route_to_src = VppIpRoute( + self, "1::2", 128, + [VppRoutePath("::", + 0xffffffff, + nh_table_id=2, + type=FibPathType.FIB_PATH_TYPE_SOURCE_LOOKUP)]) + + route_to_dst.add_vpp_config() + route_to_src.add_vpp_config() + + # + # packets to these destination are dropped, since they'll + # hit the respective default routes in the second table + # + p_dst = (Ether(src=self.pg0.remote_mac, + dst=self.pg0.local_mac) / + IPv6(src="5::5", dst="1::1") / + inet6.TCP(sport=1234, dport=1234) / + Raw('\xa5' * 100)) + p_src = (Ether(src=self.pg0.remote_mac, + dst=self.pg0.local_mac) / + IPv6(src="2::2", dst="1::2") / + inet6.TCP(sport=1234, dport=1234) / + Raw('\xa5' * 100)) + pkts_dst = p_dst * 257 + pkts_src = p_src * 257 + + self.send_and_assert_no_replies(self.pg0, pkts_dst, + "IP in dst table") + self.send_and_assert_no_replies(self.pg0, pkts_src, + "IP in src table") + + # + # add a route in the dst table to forward via pg1 + # + route_in_dst = VppIpRoute(self, "1::1", 128, + [VppRoutePath(self.pg1.remote_ip6, + self.pg1.sw_if_index)], + table_id=1) + route_in_dst.add_vpp_config() - self.send_and_assert_no_replies(self.pg0, p_version * 65, - "funky version") + self.send_and_expect(self.pg0, pkts_dst, self.pg1) # - # hop limit - IMCP replies + # add a route in the src table to forward via pg2 + # + route_in_src = VppIpRoute(self, "2::2", 128, + [VppRoutePath(self.pg2.remote_ip6, + self.pg2.sw_if_index)], + table_id=2) + route_in_src.add_vpp_config() + self.send_and_expect(self.pg0, pkts_src, self.pg2) + + # + # loop in the lookup DP + # + route_loop = VppIpRoute(self, "3::3", 128, + [VppRoutePath("::", + 0xffffffff)]) + route_loop.add_vpp_config() + + p_l = (Ether(src=self.pg0.remote_mac, + dst=self.pg0.local_mac) / + IPv6(src="3::4", dst="3::3") / + inet6.TCP(sport=1234, dport=1234) / + Raw('\xa5' * 100)) + + self.send_and_assert_no_replies(self.pg0, p_l * 257, + "IP lookup loop") + + +class TestIP6Input(VppTestCase): + """ IPv6 Input Exception Test Cases """ + + @classmethod + def setUpClass(cls): + super(TestIP6Input, cls).setUpClass() + + @classmethod + def tearDownClass(cls): + super(TestIP6Input, cls).tearDownClass() + + def setUp(self): + super(TestIP6Input, self).setUp() + + self.create_pg_interfaces(range(2)) + + for i in self.pg_interfaces: + i.admin_up() + i.config_ip6() + i.resolve_ndp() + + def tearDown(self): + super(TestIP6Input, self).tearDown() + for i in self.pg_interfaces: + i.unconfig_ip6() + i.admin_down() + + def test_ip_input_icmp_reply(self): + """ IP6 Input Exception - Return ICMP (3,0) """ + # + # hop limit - ICMP replies # p_version = (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / IPv6(src=self.pg0.remote_ip6, dst=self.pg1.remote_ip6, hlim=1) / - UDP(sport=1234, dport=1234) / + inet6.UDP(sport=1234, dport=1234) / Raw('\xa5' * 100)) - rx = self.send_and_expect(self.pg0, p_version * 65, self.pg0) + rx = self.send_and_expect(self.pg0, p_version * NUM_PKTS, self.pg0) rx = rx[0] icmp = rx[ICMPv6TimeExceeded] - self.assertEqual(icmp.type, 3) + # 0: "hop limit exceeded in transit", - self.assertEqual(icmp.code, 0) + self.assertEqual((icmp.type, icmp.code), (3, 0)) + + icmpv6_data = '\x0a' * 18 + all_0s = "::" + all_1s = "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF" + + @parameterized.expand([ + # Name, src, dst, l4proto, msg, timeout + ("src='iface', dst='iface'", None, None, + inet6.UDP(sport=1234, dport=1234), "funky version", None), + ("src='All 0's', dst='iface'", all_0s, None, + ICMPv6EchoRequest(id=0xb, seq=5, data=icmpv6_data), None, 0.1), + ("src='iface', dst='All 0's'", None, all_0s, + ICMPv6EchoRequest(id=0xb, seq=5, data=icmpv6_data), None, 0.1), + ("src='All 1's', dst='iface'", all_1s, None, + ICMPv6EchoRequest(id=0xb, seq=5, data=icmpv6_data), None, 0.1), + ("src='iface', dst='All 1's'", None, all_1s, + ICMPv6EchoRequest(id=0xb, seq=5, data=icmpv6_data), None, 0.1), + ("src='All 1's', dst='All 1's'", all_1s, all_1s, + ICMPv6EchoRequest(id=0xb, seq=5, data=icmpv6_data), None, 0.1), + + ]) + def test_ip_input_no_replies(self, name, src, dst, l4, msg, timeout): + + self._testMethodDoc = 'IPv6 Input Exception - %s' % name + p_version = (Ether(src=self.pg0.remote_mac, + dst=self.pg0.local_mac) / + IPv6(src=src or self.pg0.remote_ip6, + dst=dst or self.pg1.remote_ip6, + version=3) / + l4 / + Raw('\xa5' * 100)) + + self.send_and_assert_no_replies(self.pg0, p_version * NUM_PKTS, + remark=msg or "", + timeout=timeout) + + def test_hop_by_hop(self): + """ Hop-by-hop header test """ + + p = (Ether(src=self.pg0.remote_mac, + dst=self.pg0.local_mac) / + IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) / + IPv6ExtHdrHopByHop() / + inet6.UDP(sport=1234, dport=1234) / + Raw('\xa5' * 100)) + + self.pg0.add_stream(p) + self.pg_enable_capture(self.pg_interfaces) + self.pg_start() if __name__ == '__main__': unittest.main(testRunner=VppTestRunner)