+class TestIPv6PathMTU(VppTestCase):
+ """ IPv6 Path MTU """
+
+ def setUp(self):
+ super(TestIPv6PathMTU, self).setUp()
+
+ self.create_pg_interfaces(range(2))
+
+ # setup all interfaces
+ for i in self.pg_interfaces:
+ i.admin_up()
+ i.config_ip6()
+ i.resolve_ndp()
+
+ def tearDown(self):
+ super(TestIPv6PathMTU, self).tearDown()
+ for i in self.pg_interfaces:
+ i.unconfig_ip6()
+ i.admin_down()
+
+ def test_path_mtu_local(self):
+ """ Path MTU for attached neighbour """
+
+ self.vapi.cli("set log class ip level debug")
+ #
+ # The goal here is not test that fragmentation works correctly,
+ # that's done elsewhere, the intent is to ensure that the Path MTU
+ # settings are honoured.
+ #
+
+ #
+ # IPv6 will only frag locally generated packets, so use tunnelled
+ # packets post encap
+ #
+ tun = VppIpIpTunInterface(
+ self,
+ self.pg1,
+ self.pg1.local_ip6,
+ self.pg1.remote_ip6)
+ tun.add_vpp_config()
+ tun.admin_up()
+ tun.config_ip6()
+
+ # set the interface MTU to a reasonable value
+ self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index,
+ [2800, 0, 0, 0])
+
+ p_2k = (Ether(dst=self.pg0.local_mac,
+ src=self.pg0.remote_mac) /
+ IPv6(src=self.pg0.remote_ip6,
+ dst=tun.remote_ip6) /
+ UDP(sport=1234, dport=5678) /
+ Raw(b'0xa' * 1000))
+ p_1k = (Ether(dst=self.pg0.local_mac,
+ src=self.pg0.remote_mac) /
+ IPv6(src=self.pg0.remote_ip6,
+ dst=tun.remote_ip6) /
+ UDP(sport=1234, dport=5678) /
+ Raw(b'0xa' * 600))
+
+ nbr = VppNeighbor(self,
+ self.pg1.sw_if_index,
+ self.pg1.remote_mac,
+ self.pg1.remote_ip6).add_vpp_config()
+
+ # this is now the interface MTU frags
+ self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
+ self.send_and_expect(self.pg0, [p_1k], self.pg1)
+
+ # drop the path MTU for this neighbour to below the interface MTU
+ # expect more frags
+ pmtu = VppIpPathMtu(self, self.pg1.remote_ip6, 1300).add_vpp_config()
+
+ # print/format the adj delegate and trackers
+ self.logger.info(self.vapi.cli("sh ip pmtu"))
+ self.logger.info(self.vapi.cli("sh adj 7"))
+
+ self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
+ self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
+
+ # increase the path MTU to more than the interface
+ # expect to use the interface MTU
+ pmtu.modify(8192)
+
+ self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
+ self.send_and_expect(self.pg0, [p_1k], self.pg1)
+
+ # go back to an MTU from the path
+ pmtu.modify(1300)
+
+ self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
+ self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
+
+ # raise the interface's MTU
+ # should still use that of the path
+ self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index,
+ [2000, 0, 0, 0])
+ self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
+ self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
+
+ # set path high and interface low
+ pmtu.modify(2000)
+ self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index,
+ [1300, 0, 0, 0])
+ self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
+ self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
+
+ # remove the path MTU
+ self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index,
+ [2800, 0, 0, 0])
+ pmtu.modify(0)
+
+ self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
+ self.send_and_expect(self.pg0, [p_1k], self.pg1)
+
+ def test_path_mtu_remote(self):
+ """ Path MTU for remote neighbour """
+
+ self.vapi.cli("set log class ip level debug")
+ #
+ # The goal here is not test that fragmentation works correctly,
+ # that's done elsewhere, the intent is to ensure that the Path MTU
+ # settings are honoured.
+ #
+ tun_dst = "2001::1"
+
+ route = VppIpRoute(
+ self, tun_dst, 64,
+ [VppRoutePath(self.pg1.remote_ip6,
+ self.pg1.sw_if_index)]).add_vpp_config()
+
+ #
+ # IPv6 will only frag locally generated packets, so use tunnelled
+ # packets post encap
+ #
+ tun = VppIpIpTunInterface(
+ self,
+ self.pg1,
+ self.pg1.local_ip6,
+ tun_dst)
+ tun.add_vpp_config()
+ tun.admin_up()
+ tun.config_ip6()
+
+ # set the interface MTU to a reasonable value
+ self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index,
+ [2800, 0, 0, 0])
+
+ p_2k = (Ether(dst=self.pg0.local_mac,
+ src=self.pg0.remote_mac) /
+ IPv6(src=self.pg0.remote_ip6,
+ dst=tun.remote_ip6) /
+ UDP(sport=1234, dport=5678) /
+ Raw(b'0xa' * 1000))
+ p_1k = (Ether(dst=self.pg0.local_mac,
+ src=self.pg0.remote_mac) /
+ IPv6(src=self.pg0.remote_ip6,
+ dst=tun.remote_ip6) /
+ UDP(sport=1234, dport=5678) /
+ Raw(b'0xa' * 600))
+
+ nbr = VppNeighbor(self,
+ self.pg1.sw_if_index,
+ self.pg1.remote_mac,
+ self.pg1.remote_ip6).add_vpp_config()
+
+ # this is now the interface MTU frags
+ self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
+ self.send_and_expect(self.pg0, [p_1k], self.pg1)
+
+ # drop the path MTU for this neighbour to below the interface MTU
+ # expect more frags
+ pmtu = VppIpPathMtu(self, tun_dst, 1300).add_vpp_config()
+
+ # print/format the fib entry/dpo
+ self.logger.info(self.vapi.cli("sh ip6 fib 2001::1"))
+
+ self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
+ self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
+
+ # increase the path MTU to more than the interface
+ # expect to use the interface MTU
+ pmtu.modify(8192)
+
+ self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
+ self.send_and_expect(self.pg0, [p_1k], self.pg1)
+
+ # go back to an MTU from the path
+ pmtu.modify(1300)
+
+ self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
+ self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
+
+ # raise the interface's MTU
+ # should still use that of the path
+ self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index,
+ [2000, 0, 0, 0])
+ self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
+ self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
+
+ # turn the tun_dst into an attached neighbour
+ route.modify([VppRoutePath("::",
+ self.pg1.sw_if_index)])
+ nbr2 = VppNeighbor(self,
+ self.pg1.sw_if_index,
+ self.pg1.remote_mac,
+ tun_dst).add_vpp_config()
+
+ self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
+ self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
+
+ # add back to not attached
+ nbr2.remove_vpp_config()
+ route.modify([VppRoutePath(self.pg1.remote_ip6,
+ self.pg1.sw_if_index)])
+
+ # set path high and interface low
+ pmtu.modify(2000)
+ self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index,
+ [1300, 0, 0, 0])
+ self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
+ self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
+
+ # remove the path MTU
+ self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index,
+ [2800, 0, 0, 0])
+ pmtu.remove_vpp_config()
+ self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
+ self.send_and_expect(self.pg0, [p_1k], self.pg1)
+
+
+class TestIPFibSource(VppTestCase):
+ """ IPv6 Table FibSource """
+
+ @classmethod
+ def setUpClass(cls):
+ super(TestIPFibSource, cls).setUpClass()
+
+ @classmethod
+ def tearDownClass(cls):
+ super(TestIPFibSource, cls).tearDownClass()
+
+ def setUp(self):
+ super(TestIPFibSource, self).setUp()
+
+ self.create_pg_interfaces(range(2))
+
+ for i in self.pg_interfaces:
+ i.admin_up()
+ i.config_ip6()
+ i.resolve_arp()
+ i.generate_remote_hosts(2)
+ i.configure_ipv6_neighbors()
+
+ def tearDown(self):
+ super(TestIPFibSource, self).tearDown()
+ for i in self.pg_interfaces:
+ i.admin_down()
+ i.unconfig_ip4()
+
+ def test_fib_source(self):
+ """ IP Table FibSource """
+
+ routes = self.vapi.ip_route_v2_dump(0, True)
+
+ # 2 interfaces (4 routes) + 2 specials + 4 neighbours = 10 routes
+ self.assertEqual(len(routes), 10)
+
+ # dump all the sources in the FIB
+ sources = self.vapi.fib_source_dump()
+ for source in sources:
+ if (source.src.name == "API"):
+ api_source = source.src
+ if (source.src.name == "interface"):
+ intf_source = source.src
+ if (source.src.name == "adjacency"):
+ adj_source = source.src
+ if (source.src.name == "special"):
+ special_source = source.src
+ if (source.src.name == "default-route"):
+ dr_source = source.src
+
+ # dump the individual route types
+ routes = self.vapi.ip_route_v2_dump(0, True, src=adj_source.id)
+ self.assertEqual(len(routes), 4)
+ routes = self.vapi.ip_route_v2_dump(0, True, src=intf_source.id)
+ self.assertEqual(len(routes), 4)
+ routes = self.vapi.ip_route_v2_dump(0, True, src=special_source.id)
+ self.assertEqual(len(routes), 1)
+ routes = self.vapi.ip_route_v2_dump(0, True, src=dr_source.id)
+ self.assertEqual(len(routes), 1)
+
+ # add a new soure that'a better than the API
+ self.vapi.fib_source_add(src={'name': "bgp",
+ "priority": api_source.priority - 1})
+
+ # dump all the sources to check our new one is there
+ sources = self.vapi.fib_source_dump()
+
+ for source in sources:
+ if (source.src.name == "bgp"):
+ bgp_source = source.src
+
+ self.assertTrue(bgp_source)
+ self.assertEqual(bgp_source.priority,
+ api_source.priority - 1)
+
+ # add a route with the default API source
+ r1 = VppIpRouteV2(
+ self, "2001::1", 128,
+ [VppRoutePath(self.pg0.remote_ip6,
+ self.pg0.sw_if_index)]).add_vpp_config()
+
+ r2 = VppIpRouteV2(self, "2001::1", 128,
+ [VppRoutePath(self.pg1.remote_ip6,
+ self.pg1.sw_if_index)],
+ src=bgp_source.id).add_vpp_config()
+
+ # ensure the BGP source takes priority
+ p = (Ether(src=self.pg0.remote_mac,
+ dst=self.pg0.local_mac) /
+ IPv6(src=self.pg0.remote_ip6, dst="2001::1") /
+ inet6.UDP(sport=1234, dport=1234) /
+ Raw(b'\xa5' * 100))
+
+ self.send_and_expect(self.pg0, [p], self.pg1)
+
+ r2.remove_vpp_config()
+ r1.remove_vpp_config()
+
+ self.assertFalse(find_route(self, "2001::1", 128))
+
+