8 from scapy.contrib.mpls import MPLS
9 from scapy.layers.inet import IP, UDP, TCP, ICMP, icmptypes, icmpcodes
10 from scapy.layers.inet6 import IPv6
11 from scapy.layers.l2 import Ether, Dot1Q, ARP
12 from scapy.packet import Raw
15 from framework import tag_fixme_vpp_workers
16 from framework import VppTestCase, VppTestRunner
18 from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpMRoute, \
19 VppMRoutePath, VppMplsIpBind, \
20 VppMplsTable, VppIpTable, FibPathType, find_route, \
21 VppIpInterfaceAddress, find_route_in_dump, find_mroute_in_dump
22 from vpp_ip import VppIpPuntPolicer, VppIpPuntRedirect, VppIpPathMtu
23 from vpp_sub_interface import VppSubInterface, VppDot1QSubint, VppDot1ADSubint
24 from vpp_papi import vpp_papi, VppEnum
25 from vpp_neighbor import VppNeighbor
26 from vpp_lo_interface import VppLoInterface
27 from vpp_policer import VppPolicer, PolicerAction
32 class TestIPv4(VppTestCase):
33 """ IPv4 Test Case """
37 super(TestIPv4, cls).setUpClass()
40 def tearDownClass(cls):
41 super(TestIPv4, cls).tearDownClass()
45 Perform test setup before test case.
48 - create 3 pg interfaces
49 - untagged pg0 interface
50 - Dot1Q subinterface on pg1
51 - Dot1AD subinterface on pg2
53 - put it into UP state
55 - resolve neighbor address using ARP
56 - configure 200 fib entries
58 :ivar list interfaces: pg interfaces and subinterfaces.
59 :ivar dict flows: IPv4 packet flows in test.
61 super(TestIPv4, self).setUp()
63 # create 3 pg interfaces
64 self.create_pg_interfaces(range(3))
66 # create 2 subinterfaces for pg1 and pg2
67 self.sub_interfaces = [
68 VppDot1QSubint(self, self.pg1, 100),
69 VppDot1ADSubint(self, self.pg2, 200, 300, 400)]
71 # packet flows mapping pg0 -> pg1.sub, pg2.sub, etc.
73 self.flows[self.pg0] = [self.pg1.sub_if, self.pg2.sub_if]
74 self.flows[self.pg1.sub_if] = [self.pg0, self.pg2.sub_if]
75 self.flows[self.pg2.sub_if] = [self.pg0, self.pg1.sub_if]
78 self.pg_if_packet_sizes = [64, 1500, 9020]
80 self.interfaces = list(self.pg_interfaces)
81 self.interfaces.extend(self.sub_interfaces)
83 # setup all interfaces
84 for i in self.interfaces:
89 # config 2M FIB entries
92 """Run standard test teardown and log ``show ip arp``."""
93 super(TestIPv4, self).tearDown()
95 def show_commands_at_teardown(self):
96 self.logger.info(self.vapi.cli("show ip4 neighbors"))
97 # info(self.vapi.cli("show ip fib")) # many entries
99 def modify_packet(self, src_if, packet_size, pkt):
100 """Add load, set destination IP and extend packet to required packet
101 size for defined interface.
103 :param VppInterface src_if: Interface to create packet for.
104 :param int packet_size: Required packet size.
105 :param Scapy pkt: Packet to be modified.
107 dst_if_idx = int(packet_size / 10 % 2)
108 dst_if = self.flows[src_if][dst_if_idx]
109 info = self.create_packet_info(src_if, dst_if)
110 payload = self.info_to_payload(info)
112 p[IP].dst = dst_if.remote_ip4
114 if isinstance(src_if, VppSubInterface):
115 p = src_if.add_dot1_layer(p)
116 self.extend_packet(p, packet_size)
120 def create_stream(self, src_if):
121 """Create input packet stream for defined interface.
123 :param VppInterface src_if: Interface to create packet stream for.
125 hdr_ext = 4 if isinstance(src_if, VppSubInterface) else 0
126 pkt_tmpl = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
127 IP(src=src_if.remote_ip4) /
128 UDP(sport=1234, dport=1234))
130 pkts = [self.modify_packet(src_if, i, pkt_tmpl)
131 for i in moves.range(self.pg_if_packet_sizes[0],
132 self.pg_if_packet_sizes[1], 10)]
133 pkts_b = [self.modify_packet(src_if, i, pkt_tmpl)
134 for i in moves.range(self.pg_if_packet_sizes[1] + hdr_ext,
135 self.pg_if_packet_sizes[2] + hdr_ext,
141 def verify_capture(self, dst_if, capture):
142 """Verify captured input packet stream for defined interface.
144 :param VppInterface dst_if: Interface to verify captured packet stream
146 :param list capture: Captured packet stream.
148 self.logger.info("Verifying capture on interface %s" % dst_if.name)
150 for i in self.interfaces:
151 last_info[i.sw_if_index] = None
153 dst_sw_if_index = dst_if.sw_if_index
154 if hasattr(dst_if, 'parent'):
156 for packet in capture:
158 # Check VLAN tags and Ethernet header
159 packet = dst_if.remove_dot1_layer(packet)
160 self.assertTrue(Dot1Q not in packet)
164 payload_info = self.payload_to_info(packet[Raw])
165 packet_index = payload_info.index
166 self.assertEqual(payload_info.dst, dst_sw_if_index)
168 "Got packet on port %s: src=%u (id=%u)" %
169 (dst_if.name, payload_info.src, packet_index))
170 next_info = self.get_next_packet_info_for_interface2(
171 payload_info.src, dst_sw_if_index,
172 last_info[payload_info.src])
173 last_info[payload_info.src] = next_info
174 self.assertTrue(next_info is not None)
175 self.assertEqual(packet_index, next_info.index)
176 saved_packet = next_info.data
177 # Check standard fields
178 self.assertEqual(ip.src, saved_packet[IP].src)
179 self.assertEqual(ip.dst, saved_packet[IP].dst)
180 self.assertEqual(udp.sport, saved_packet[UDP].sport)
181 self.assertEqual(udp.dport, saved_packet[UDP].dport)
183 self.logger.error(ppp("Unexpected or invalid packet:", packet))
185 for i in self.interfaces:
186 remaining_packet = self.get_next_packet_info_for_interface2(
187 i.sw_if_index, dst_sw_if_index, last_info[i.sw_if_index])
188 self.assertTrue(remaining_packet is None,
189 "Interface %s: Packet expected from interface %s "
190 "didn't arrive" % (dst_if.name, i.name))
197 - Create IPv4 stream for pg0 interface
198 - Create IPv4 tagged streams for pg1's and pg2's sub-interface.
199 - Send and verify received packets on each interface.
202 pkts = self.create_stream(self.pg0)
203 self.pg0.add_stream(pkts)
205 for i in self.sub_interfaces:
206 pkts = self.create_stream(i)
207 i.parent.add_stream(pkts)
209 self.pg_enable_capture(self.pg_interfaces)
212 pkts = self.pg0.get_capture()
213 self.verify_capture(self.pg0, pkts)
215 for i in self.sub_interfaces:
216 pkts = i.parent.get_capture()
217 self.verify_capture(i, pkts)
220 class TestIPv4RouteLookup(VppTestCase):
221 """ IPv4 Route Lookup Test Case """
224 def route_lookup(self, prefix, exact):
225 return self.vapi.api(self.vapi.papi.ip_route_lookup,
234 super(TestIPv4RouteLookup, cls).setUpClass()
237 def tearDownClass(cls):
238 super(TestIPv4RouteLookup, cls).tearDownClass()
241 super(TestIPv4RouteLookup, self).setUp()
243 drop_nh = VppRoutePath("127.0.0.1", 0xffffffff,
244 type=FibPathType.FIB_PATH_TYPE_DROP)
247 r = VppIpRoute(self, "1.1.0.0", 16, [drop_nh])
249 self.routes.append(r)
251 r = VppIpRoute(self, "1.1.1.0", 24, [drop_nh])
253 self.routes.append(r)
255 r = VppIpRoute(self, "1.1.1.1", 32, [drop_nh])
257 self.routes.append(r)
260 # Remove the routes we added
261 for r in self.routes:
262 r.remove_vpp_config()
264 super(TestIPv4RouteLookup, self).tearDown()
266 def test_exact_match(self):
267 # Verify we find the host route
268 prefix = "1.1.1.1/32"
269 result = self.route_lookup(prefix, True)
270 assert (prefix == str(result.route.prefix))
272 # Verify we find a middle prefix route
273 prefix = "1.1.1.0/24"
274 result = self.route_lookup(prefix, True)
275 assert (prefix == str(result.route.prefix))
277 # Verify we do not find an available LPM.
278 with self.vapi.assert_negative_api_retval():
279 self.route_lookup("1.1.1.2/32", True)
281 def test_longest_prefix_match(self):
283 lpm_prefix = "1.1.1.0/24"
284 result = self.route_lookup("1.1.1.2/32", False)
285 assert (lpm_prefix == str(result.route.prefix))
287 # Verify we find the exact when not requested
288 result = self.route_lookup(lpm_prefix, False)
289 assert (lpm_prefix == str(result.route.prefix))
291 # Can't seem to delete the default route so no negative LPM test.
294 class TestIPv4IfAddrRoute(VppTestCase):
295 """ IPv4 Interface Addr Route Test Case """
299 super(TestIPv4IfAddrRoute, cls).setUpClass()
302 def tearDownClass(cls):
303 super(TestIPv4IfAddrRoute, cls).tearDownClass()
306 super(TestIPv4IfAddrRoute, self).setUp()
308 # create 1 pg interface
309 self.create_pg_interfaces(range(1))
311 for i in self.pg_interfaces:
317 super(TestIPv4IfAddrRoute, self).tearDown()
318 for i in self.pg_interfaces:
322 def test_ipv4_ifaddrs_same_prefix(self):
323 """ IPv4 Interface Addresses Same Prefix test
327 - Verify no route in FIB for prefix 10.10.10.0/24
328 - Configure IPv4 address 10.10.10.10/24 on an interface
329 - Verify route in FIB for prefix 10.10.10.0/24
330 - Configure IPv4 address 10.10.10.20/24 on an interface
331 - Delete 10.10.10.10/24 from interface
332 - Verify route in FIB for prefix 10.10.10.0/24
333 - Delete 10.10.10.20/24 from interface
334 - Verify no route in FIB for prefix 10.10.10.0/24
337 # create two addresses, verify route not present
338 if_addr1 = VppIpInterfaceAddress(self, self.pg0, "10.10.10.10", 24)
339 if_addr2 = VppIpInterfaceAddress(self, self.pg0, "10.10.10.20", 24)
340 self.assertFalse(if_addr1.query_vpp_config()) # 10.10.10.10/24
341 self.assertFalse(find_route(self, "10.10.10.10", 32))
342 self.assertFalse(find_route(self, "10.10.10.20", 32))
343 self.assertFalse(find_route(self, "10.10.10.255", 32))
344 self.assertFalse(find_route(self, "10.10.10.0", 32))
346 # configure first address, verify route present
347 if_addr1.add_vpp_config()
348 self.assertTrue(if_addr1.query_vpp_config()) # 10.10.10.10/24
349 self.assertTrue(find_route(self, "10.10.10.10", 32))
350 self.assertFalse(find_route(self, "10.10.10.20", 32))
351 self.assertTrue(find_route(self, "10.10.10.255", 32))
352 self.assertTrue(find_route(self, "10.10.10.0", 32))
354 # configure second address, delete first, verify route not removed
355 if_addr2.add_vpp_config()
356 if_addr1.remove_vpp_config()
357 self.assertFalse(if_addr1.query_vpp_config()) # 10.10.10.10/24
358 self.assertTrue(if_addr2.query_vpp_config()) # 10.10.10.20/24
359 self.assertFalse(find_route(self, "10.10.10.10", 32))
360 self.assertTrue(find_route(self, "10.10.10.20", 32))
361 self.assertTrue(find_route(self, "10.10.10.255", 32))
362 self.assertTrue(find_route(self, "10.10.10.0", 32))
364 # delete second address, verify route removed
365 if_addr2.remove_vpp_config()
366 self.assertFalse(if_addr2.query_vpp_config()) # 10.10.10.20/24
367 self.assertFalse(find_route(self, "10.10.10.10", 32))
368 self.assertFalse(find_route(self, "10.10.10.20", 32))
369 self.assertFalse(find_route(self, "10.10.10.255", 32))
370 self.assertFalse(find_route(self, "10.10.10.0", 32))
372 def test_ipv4_ifaddr_route(self):
373 """ IPv4 Interface Address Route test
378 - Configure IPv4 address on loopback
379 - Verify that address is not in the FIB
381 - Verify that address is in the FIB now
382 - Bring loopback down
383 - Verify that address is not in the FIB anymore
385 - Configure IPv4 address on loopback
386 - Verify that address is in the FIB now
389 # create a loopback and configure IPv4
390 loopbacks = self.create_loopback_interfaces(1)
391 lo_if = self.lo_interfaces[0]
393 lo_if.local_ip4_prefix_len = 32
396 # The intf was down when addr was added -> entry not in FIB
397 fib4_dump = self.vapi.ip_route_dump(0)
398 self.assertFalse(lo_if.is_ip4_entry_in_fib_dump(fib4_dump))
400 # When intf is brought up, entry is added
402 fib4_dump = self.vapi.ip_route_dump(0)
403 self.assertTrue(lo_if.is_ip4_entry_in_fib_dump(fib4_dump))
405 # When intf is brought down, entry is removed
407 fib4_dump = self.vapi.ip_route_dump(0)
408 self.assertFalse(lo_if.is_ip4_entry_in_fib_dump(fib4_dump))
410 # Remove addr, bring up interface, re-add -> entry in FIB
414 fib4_dump = self.vapi.ip_route_dump(0)
415 self.assertTrue(lo_if.is_ip4_entry_in_fib_dump(fib4_dump))
417 def test_ipv4_ifaddr_del(self):
418 """ Delete an interface address that does not exist """
420 loopbacks = self.create_loopback_interfaces(1)
421 lo = self.lo_interfaces[0]
427 # try and remove pg0's subnet from lo
429 with self.vapi.assert_negative_api_retval():
430 self.vapi.sw_interface_add_del_address(
431 sw_if_index=lo.sw_if_index,
432 prefix=self.pg0.local_ip4_prefix,
436 class TestICMPEcho(VppTestCase):
437 """ ICMP Echo Test Case """
441 super(TestICMPEcho, cls).setUpClass()
444 def tearDownClass(cls):
445 super(TestICMPEcho, cls).tearDownClass()
448 super(TestICMPEcho, self).setUp()
450 # create 1 pg interface
451 self.create_pg_interfaces(range(1))
453 for i in self.pg_interfaces:
459 super(TestICMPEcho, self).tearDown()
460 for i in self.pg_interfaces:
464 def test_icmp_echo(self):
465 """ VPP replies to ICMP Echo Request
469 - Receive ICMP Echo Request message on pg0 interface.
470 - Check outgoing ICMP Echo Reply message on pg0 interface.
475 icmp_load = b'\x0a' * 18
476 p_echo_request = (Ether(src=self.pg0.remote_mac,
477 dst=self.pg0.local_mac) /
478 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
479 ICMP(id=icmp_id, seq=icmp_seq) /
482 self.pg0.add_stream(p_echo_request)
483 self.pg_enable_capture(self.pg_interfaces)
486 rx = self.pg0.get_capture(1)
492 self.assertEqual(ether.src, self.pg0.local_mac)
493 self.assertEqual(ether.dst, self.pg0.remote_mac)
495 self.assertEqual(ipv4.src, self.pg0.local_ip4)
496 self.assertEqual(ipv4.dst, self.pg0.remote_ip4)
498 self.assertEqual(icmptypes[icmp.type], "echo-reply")
499 self.assertEqual(icmp.id, icmp_id)
500 self.assertEqual(icmp.seq, icmp_seq)
501 self.assertEqual(icmp[Raw].load, icmp_load)
504 class TestIPv4FibCrud(VppTestCase):
505 """ FIB - add/update/delete - ip4 routes
513 ..note:: Python API is too slow to add many routes, needs replacement.
516 def config_fib_many_to_one(self, start_dest_addr, next_hop_addr,
520 :param start_dest_addr:
521 :param next_hop_addr:
523 :return list: added ips with 32 prefix
526 for i in range(count):
527 r = VppIpRoute(self, start_dest_addr % (i + start), 32,
528 [VppRoutePath(next_hop_addr, 0xffffffff)])
533 def unconfig_fib_many_to_one(self, start_dest_addr, next_hop_addr,
537 for i in range(count):
538 r = VppIpRoute(self, start_dest_addr % (i + start), 32,
539 [VppRoutePath(next_hop_addr, 0xffffffff)])
540 r.remove_vpp_config()
544 def create_stream(self, src_if, dst_if, routes, count):
547 for _ in range(count):
548 dst_addr = random.choice(routes).prefix.network_address
549 info = self.create_packet_info(src_if, dst_if)
550 payload = self.info_to_payload(info)
551 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
552 IP(src=src_if.remote_ip4, dst=str(dst_addr)) /
553 UDP(sport=1234, dport=1234) /
556 self.extend_packet(p, random.choice(self.pg_if_packet_sizes))
561 def _find_ip_match(self, find_in, pkt):
563 if self.payload_to_info(p[Raw]) == \
564 self.payload_to_info(pkt[Raw]):
565 if p[IP].src != pkt[IP].src:
567 if p[IP].dst != pkt[IP].dst:
569 if p[UDP].sport != pkt[UDP].sport:
571 if p[UDP].dport != pkt[UDP].dport:
576 def verify_capture(self, dst_interface, received_pkts, expected_pkts):
577 self.assertEqual(len(received_pkts), len(expected_pkts))
578 to_verify = list(expected_pkts)
579 for p in received_pkts:
580 self.assertEqual(p.src, dst_interface.local_mac)
581 self.assertEqual(p.dst, dst_interface.remote_mac)
582 x = self._find_ip_match(to_verify, p)
584 self.assertListEqual(to_verify, [])
586 def verify_route_dump(self, routes):
588 self.assertTrue(find_route(self,
589 r.prefix.network_address,
592 def verify_not_in_route_dump(self, routes):
594 self.assertFalse(find_route(self,
595 r.prefix.network_address,
601 #. Create and initialize 3 pg interfaces.
602 #. initialize class attributes configured_routes and deleted_routes
603 to store information between tests.
605 super(TestIPv4FibCrud, cls).setUpClass()
608 # create 3 pg interfaces
609 cls.create_pg_interfaces(range(3))
611 cls.interfaces = list(cls.pg_interfaces)
613 # setup all interfaces
614 for i in cls.interfaces:
619 cls.configured_routes = []
620 cls.deleted_routes = []
621 cls.pg_if_packet_sizes = [64, 512, 1518, 9018]
624 super(TestIPv4FibCrud, cls).tearDownClass()
628 def tearDownClass(cls):
629 super(TestIPv4FibCrud, cls).tearDownClass()
632 super(TestIPv4FibCrud, self).setUp()
633 self.reset_packet_infos()
635 self.configured_routes = []
636 self.deleted_routes = []
638 def test_1_add_routes(self):
639 """ Add 1k routes """
641 # add 100 routes check with traffic script.
642 self.configured_routes.extend(self.config_fib_many_to_one(
643 "10.0.0.%d", self.pg0.remote_ip4, 100))
645 self.verify_route_dump(self.configured_routes)
647 self.stream_1 = self.create_stream(
648 self.pg1, self.pg0, self.configured_routes, 100)
649 self.stream_2 = self.create_stream(
650 self.pg2, self.pg0, self.configured_routes, 100)
651 self.pg1.add_stream(self.stream_1)
652 self.pg2.add_stream(self.stream_2)
654 self.pg_enable_capture(self.pg_interfaces)
657 pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
658 self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
660 def test_2_del_routes(self):
661 """ Delete 100 routes
663 - delete 10 routes check with traffic script.
665 # config 1M FIB entries
666 self.configured_routes.extend(self.config_fib_many_to_one(
667 "10.0.0.%d", self.pg0.remote_ip4, 100))
668 self.deleted_routes.extend(self.unconfig_fib_many_to_one(
669 "10.0.0.%d", self.pg0.remote_ip4, 10, start=10))
670 for x in self.deleted_routes:
671 self.configured_routes.remove(x)
673 self.verify_route_dump(self.configured_routes)
675 self.stream_1 = self.create_stream(
676 self.pg1, self.pg0, self.configured_routes, 100)
677 self.stream_2 = self.create_stream(
678 self.pg2, self.pg0, self.configured_routes, 100)
679 self.stream_3 = self.create_stream(
680 self.pg1, self.pg0, self.deleted_routes, 100)
681 self.stream_4 = self.create_stream(
682 self.pg2, self.pg0, self.deleted_routes, 100)
683 self.pg1.add_stream(self.stream_1 + self.stream_3)
684 self.pg2.add_stream(self.stream_2 + self.stream_4)
685 self.pg_enable_capture(self.pg_interfaces)
688 pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
689 self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
691 def test_3_add_new_routes(self):
694 - re-add 5 routes check with traffic script.
695 - add 100 routes check with traffic script.
697 # config 1M FIB entries
698 self.configured_routes.extend(self.config_fib_many_to_one(
699 "10.0.0.%d", self.pg0.remote_ip4, 100))
700 self.deleted_routes.extend(self.unconfig_fib_many_to_one(
701 "10.0.0.%d", self.pg0.remote_ip4, 10, start=10))
702 for x in self.deleted_routes:
703 self.configured_routes.remove(x)
705 tmp = self.config_fib_many_to_one(
706 "10.0.0.%d", self.pg0.remote_ip4, 5, start=10)
707 self.configured_routes.extend(tmp)
709 self.deleted_routes.remove(x)
711 self.configured_routes.extend(self.config_fib_many_to_one(
712 "10.0.1.%d", self.pg0.remote_ip4, 100))
714 self.verify_route_dump(self.configured_routes)
716 self.stream_1 = self.create_stream(
717 self.pg1, self.pg0, self.configured_routes, 300)
718 self.stream_2 = self.create_stream(
719 self.pg2, self.pg0, self.configured_routes, 300)
720 self.stream_3 = self.create_stream(
721 self.pg1, self.pg0, self.deleted_routes, 100)
722 self.stream_4 = self.create_stream(
723 self.pg2, self.pg0, self.deleted_routes, 100)
725 self.pg1.add_stream(self.stream_1 + self.stream_3)
726 self.pg2.add_stream(self.stream_2 + self.stream_4)
727 self.pg_enable_capture(self.pg_interfaces)
730 pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
731 self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
733 # delete 5 routes check with traffic script.
734 # add 100 routes check with traffic script.
735 self.deleted_routes.extend(self.unconfig_fib_many_to_one(
736 "10.0.0.%d", self.pg0.remote_ip4, 15))
737 self.deleted_routes.extend(self.unconfig_fib_many_to_one(
738 "10.0.0.%d", self.pg0.remote_ip4, 85))
739 self.deleted_routes.extend(self.unconfig_fib_many_to_one(
740 "10.0.1.%d", self.pg0.remote_ip4, 100))
741 self.verify_not_in_route_dump(self.deleted_routes)
744 class TestIPNull(VppTestCase):
745 """ IPv4 routes via NULL """
749 super(TestIPNull, cls).setUpClass()
752 def tearDownClass(cls):
753 super(TestIPNull, cls).tearDownClass()
756 super(TestIPNull, self).setUp()
758 # create 2 pg interfaces
759 self.create_pg_interfaces(range(2))
761 for i in self.pg_interfaces:
767 super(TestIPNull, self).tearDown()
768 for i in self.pg_interfaces:
772 def test_ip_null(self):
773 """ IP NULL route """
776 # A route via IP NULL that will reply with ICMP unreachables
778 ip_unreach = VppIpRoute(
779 self, "10.0.0.1", 32,
780 [VppRoutePath("0.0.0.0",
782 type=FibPathType.FIB_PATH_TYPE_ICMP_UNREACH)])
783 ip_unreach.add_vpp_config()
785 p_unreach = (Ether(src=self.pg0.remote_mac,
786 dst=self.pg0.local_mac) /
787 IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
788 UDP(sport=1234, dport=1234) /
790 self.pg0.add_stream(p_unreach)
791 self.pg_enable_capture(self.pg_interfaces)
794 rx = self.pg0.get_capture(1)
798 self.assertEqual(icmptypes[icmp.type], "dest-unreach")
799 self.assertEqual(icmpcodes[icmp.type][icmp.code], "host-unreachable")
800 self.assertEqual(icmp.src, self.pg0.remote_ip4)
801 self.assertEqual(icmp.dst, "10.0.0.1")
804 # ICMP replies are rate limited. so sit and spin.
809 # A route via IP NULL that will reply with ICMP prohibited
811 ip_prohibit = VppIpRoute(
812 self, "10.0.0.2", 32,
813 [VppRoutePath("0.0.0.0",
815 type=FibPathType.FIB_PATH_TYPE_ICMP_PROHIBIT)])
816 ip_prohibit.add_vpp_config()
818 p_prohibit = (Ether(src=self.pg0.remote_mac,
819 dst=self.pg0.local_mac) /
820 IP(src=self.pg0.remote_ip4, dst="10.0.0.2") /
821 UDP(sport=1234, dport=1234) /
824 self.pg0.add_stream(p_prohibit)
825 self.pg_enable_capture(self.pg_interfaces)
828 rx = self.pg0.get_capture(1)
833 self.assertEqual(icmptypes[icmp.type], "dest-unreach")
834 self.assertEqual(icmpcodes[icmp.type][icmp.code], "host-prohibited")
835 self.assertEqual(icmp.src, self.pg0.remote_ip4)
836 self.assertEqual(icmp.dst, "10.0.0.2")
838 def test_ip_drop(self):
839 """ IP Drop Routes """
841 p = (Ether(src=self.pg0.remote_mac,
842 dst=self.pg0.local_mac) /
843 IP(src=self.pg0.remote_ip4, dst="1.1.1.1") /
844 UDP(sport=1234, dport=1234) /
847 r1 = VppIpRoute(self, "1.1.1.0", 24,
848 [VppRoutePath(self.pg1.remote_ip4,
849 self.pg1.sw_if_index)])
852 rx = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg1)
855 # insert a more specific as a drop
857 r2 = VppIpRoute(self, "1.1.1.1", 32,
858 [VppRoutePath("0.0.0.0",
860 type=FibPathType.FIB_PATH_TYPE_DROP)])
863 self.send_and_assert_no_replies(self.pg0, p * NUM_PKTS, "Drop Route")
864 r2.remove_vpp_config()
865 rx = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg1)
868 class TestIPDisabled(VppTestCase):
869 """ IPv4 disabled """
873 super(TestIPDisabled, cls).setUpClass()
876 def tearDownClass(cls):
877 super(TestIPDisabled, cls).tearDownClass()
880 super(TestIPDisabled, self).setUp()
882 # create 2 pg interfaces
883 self.create_pg_interfaces(range(2))
887 self.pg0.config_ip4()
888 self.pg0.resolve_arp()
890 # PG 1 is not IP enabled
894 super(TestIPDisabled, self).tearDown()
895 for i in self.pg_interfaces:
899 def test_ip_disabled(self):
902 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
903 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
907 # one accepting interface, pg0, 2 forwarding interfaces
909 route_232_1_1_1 = VppIpMRoute(
913 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
914 [VppMRoutePath(self.pg1.sw_if_index,
915 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT),
916 VppMRoutePath(self.pg0.sw_if_index,
917 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD)])
918 route_232_1_1_1.add_vpp_config()
920 pu = (Ether(src=self.pg1.remote_mac,
921 dst=self.pg1.local_mac) /
922 IP(src="10.10.10.10", dst=self.pg0.remote_ip4) /
923 UDP(sport=1234, dport=1234) /
925 pm = (Ether(src=self.pg1.remote_mac,
926 dst=self.pg1.local_mac) /
927 IP(src="10.10.10.10", dst="232.1.1.1") /
928 UDP(sport=1234, dport=1234) /
932 # PG1 does not forward IP traffic
934 self.send_and_assert_no_replies(self.pg1, pu, "IP disabled")
935 self.send_and_assert_no_replies(self.pg1, pm, "IP disabled")
940 self.pg1.config_ip4()
943 # Now we get packets through
945 self.pg1.add_stream(pu)
946 self.pg_enable_capture(self.pg_interfaces)
948 rx = self.pg0.get_capture(1)
950 self.pg1.add_stream(pm)
951 self.pg_enable_capture(self.pg_interfaces)
953 rx = self.pg0.get_capture(1)
958 self.pg1.unconfig_ip4()
961 # PG1 does not forward IP traffic
963 self.send_and_assert_no_replies(self.pg1, pu, "IP disabled")
964 self.send_and_assert_no_replies(self.pg1, pm, "IP disabled")
967 class TestIPSubNets(VppTestCase):
972 super(TestIPSubNets, cls).setUpClass()
975 def tearDownClass(cls):
976 super(TestIPSubNets, cls).tearDownClass()
979 super(TestIPSubNets, self).setUp()
981 # create a 2 pg interfaces
982 self.create_pg_interfaces(range(2))
984 # pg0 we will use to experiment
987 # pg1 is setup normally
989 self.pg1.config_ip4()
990 self.pg1.resolve_arp()
993 super(TestIPSubNets, self).tearDown()
994 for i in self.pg_interfaces:
997 def test_ip_sub_nets(self):
1001 # Configure a covering route to forward so we know
1002 # when we are dropping
1004 cover_route = VppIpRoute(self, "10.0.0.0", 8,
1005 [VppRoutePath(self.pg1.remote_ip4,
1006 self.pg1.sw_if_index)])
1007 cover_route.add_vpp_config()
1009 p = (Ether(src=self.pg1.remote_mac,
1010 dst=self.pg1.local_mac) /
1011 IP(dst="10.10.10.10", src=self.pg0.local_ip4) /
1012 UDP(sport=1234, dport=1234) /
1015 self.pg1.add_stream(p)
1016 self.pg_enable_capture(self.pg_interfaces)
1018 rx = self.pg1.get_capture(1)
1021 # Configure some non-/24 subnets on an IP interface
1023 ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10")
1025 self.vapi.sw_interface_add_del_address(
1026 sw_if_index=self.pg0.sw_if_index,
1027 prefix="10.10.10.10/16")
1029 pn = (Ether(src=self.pg1.remote_mac,
1030 dst=self.pg1.local_mac) /
1031 IP(dst="10.10.0.0", src=self.pg0.local_ip4) /
1032 UDP(sport=1234, dport=1234) /
1034 pb = (Ether(src=self.pg1.remote_mac,
1035 dst=self.pg1.local_mac) /
1036 IP(dst="10.10.255.255", src=self.pg0.local_ip4) /
1037 UDP(sport=1234, dport=1234) /
1040 self.send_and_assert_no_replies(self.pg1, pn, "IP Network address")
1041 self.send_and_assert_no_replies(self.pg1, pb, "IP Broadcast address")
1043 # remove the sub-net and we are forwarding via the cover again
1044 self.vapi.sw_interface_add_del_address(
1045 sw_if_index=self.pg0.sw_if_index,
1046 prefix="10.10.10.10/16",
1049 self.pg1.add_stream(pn)
1050 self.pg_enable_capture(self.pg_interfaces)
1052 rx = self.pg1.get_capture(1)
1053 self.pg1.add_stream(pb)
1054 self.pg_enable_capture(self.pg_interfaces)
1056 rx = self.pg1.get_capture(1)
1059 # A /31 is a special case where the 'other-side' is an attached host
1060 # packets to that peer generate ARP requests
1062 ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10")
1064 self.vapi.sw_interface_add_del_address(
1065 sw_if_index=self.pg0.sw_if_index,
1066 prefix="10.10.10.10/31")
1068 pn = (Ether(src=self.pg1.remote_mac,
1069 dst=self.pg1.local_mac) /
1070 IP(dst="10.10.10.11", src=self.pg0.local_ip4) /
1071 UDP(sport=1234, dport=1234) /
1074 self.pg1.add_stream(pn)
1075 self.pg_enable_capture(self.pg_interfaces)
1077 rx = self.pg0.get_capture(1)
1080 # remove the sub-net and we are forwarding via the cover again
1081 self.vapi.sw_interface_add_del_address(
1082 sw_if_index=self.pg0.sw_if_index,
1083 prefix="10.10.10.10/31", is_add=0)
1085 self.pg1.add_stream(pn)
1086 self.pg_enable_capture(self.pg_interfaces)
1088 rx = self.pg1.get_capture(1)
1091 class TestIPLoadBalance(VppTestCase):
1092 """ IPv4 Load-Balancing """
1095 def setUpClass(cls):
1096 super(TestIPLoadBalance, cls).setUpClass()
1099 def tearDownClass(cls):
1100 super(TestIPLoadBalance, cls).tearDownClass()
1103 super(TestIPLoadBalance, self).setUp()
1105 self.create_pg_interfaces(range(5))
1106 mpls_tbl = VppMplsTable(self, 0)
1107 mpls_tbl.add_vpp_config()
1109 for i in self.pg_interfaces:
1116 for i in self.pg_interfaces:
1120 super(TestIPLoadBalance, self).tearDown()
1122 def total_len(self, rxs):
1128 def test_ip_load_balance(self):
1129 """ IP Load-Balancing """
1131 fhc = VppEnum.vl_api_ip_flow_hash_config_t
1132 af = VppEnum.vl_api_address_family_t
1135 # An array of packets that differ only in the destination port
1141 # An array of packets that differ only in the source address
1146 for ii in range(NUM_PKTS):
1147 port_ip_hdr = (IP(dst="10.0.0.1", src="20.0.0.1") /
1148 UDP(sport=1234, dport=1234 + ii) /
1150 port_ip_pkts.append((Ether(src=self.pg0.remote_mac,
1151 dst=self.pg0.local_mac) /
1153 port_mpls_pkts.append((Ether(src=self.pg0.remote_mac,
1154 dst=self.pg0.local_mac) /
1155 MPLS(label=66, ttl=2) /
1158 src_ip_hdr = (IP(dst="10.0.0.1", src="20.0.0.%d" % ii) /
1159 UDP(sport=1234, dport=1234) /
1161 src_ip_pkts.append((Ether(src=self.pg0.remote_mac,
1162 dst=self.pg0.local_mac) /
1164 src_mpls_pkts.append((Ether(src=self.pg0.remote_mac,
1165 dst=self.pg0.local_mac) /
1166 MPLS(label=66, ttl=2) /
1169 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1170 [VppRoutePath(self.pg1.remote_ip4,
1171 self.pg1.sw_if_index),
1172 VppRoutePath(self.pg2.remote_ip4,
1173 self.pg2.sw_if_index)])
1174 route_10_0_0_1.add_vpp_config()
1176 binding = VppMplsIpBind(self, 66, "10.0.0.1", 32)
1177 binding.add_vpp_config()
1180 # inject the packet on pg0 - expect load-balancing across the 2 paths
1181 # - since the default hash config is to use IP src,dst and port
1183 # We are not going to ensure equal amounts of packets across each link,
1184 # since the hash algorithm is statistical and therefore this can never
1185 # be guaranteed. But with 64 different packets we do expect some
1186 # balancing. So instead just ensure there is traffic on each link.
1188 rx = self.send_and_expect_load_balancing(self.pg0, port_ip_pkts,
1189 [self.pg1, self.pg2])
1190 n_ip_pg0 = len(rx[0])
1191 self.send_and_expect_load_balancing(self.pg0, src_ip_pkts,
1192 [self.pg1, self.pg2])
1193 self.send_and_expect_load_balancing(self.pg0, port_mpls_pkts,
1194 [self.pg1, self.pg2])
1195 rx = self.send_and_expect_load_balancing(self.pg0, src_mpls_pkts,
1196 [self.pg1, self.pg2])
1197 n_mpls_pg0 = len(rx[0])
1200 # change the router ID and expect the distribution changes
1202 self.vapi.set_ip_flow_hash_router_id(router_id=0x11111111)
1204 rx = self.send_and_expect_load_balancing(self.pg0, port_ip_pkts,
1205 [self.pg1, self.pg2])
1206 self.assertNotEqual(n_ip_pg0, len(rx[0]))
1208 rx = self.send_and_expect_load_balancing(self.pg0, src_mpls_pkts,
1209 [self.pg1, self.pg2])
1210 self.assertNotEqual(n_mpls_pg0, len(rx[0]))
1213 # change the flow hash config so it's only IP src,dst
1214 # - now only the stream with differing source address will
1217 self.vapi.set_ip_flow_hash_v2(
1220 flow_hash_config=(fhc.IP_API_FLOW_HASH_SRC_IP |
1221 fhc.IP_API_FLOW_HASH_DST_IP |
1222 fhc.IP_API_FLOW_HASH_PROTO))
1224 self.send_and_expect_load_balancing(self.pg0, src_ip_pkts,
1225 [self.pg1, self.pg2])
1226 self.send_and_expect_load_balancing(self.pg0, src_mpls_pkts,
1227 [self.pg1, self.pg2])
1229 self.send_and_expect_only(self.pg0, port_ip_pkts, self.pg2)
1232 # change the flow hash config back to defaults
1234 self.vapi.set_ip_flow_hash(vrf_id=0, src=1, dst=1,
1235 proto=1, sport=1, dport=1)
1238 # Recursive prefixes
1239 # - testing that 2 stages of load-balancing occurs and there is no
1240 # polarisation (i.e. only 2 of 4 paths are used)
1245 for ii in range(257):
1246 port_pkts.append((Ether(src=self.pg0.remote_mac,
1247 dst=self.pg0.local_mac) /
1248 IP(dst="1.1.1.1", src="20.0.0.1") /
1249 UDP(sport=1234, dport=1234 + ii) /
1250 Raw(b'\xa5' * 100)))
1251 src_pkts.append((Ether(src=self.pg0.remote_mac,
1252 dst=self.pg0.local_mac) /
1253 IP(dst="1.1.1.1", src="20.0.0.%d" % ii) /
1254 UDP(sport=1234, dport=1234) /
1255 Raw(b'\xa5' * 100)))
1257 route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
1258 [VppRoutePath(self.pg3.remote_ip4,
1259 self.pg3.sw_if_index),
1260 VppRoutePath(self.pg4.remote_ip4,
1261 self.pg4.sw_if_index)])
1262 route_10_0_0_2.add_vpp_config()
1264 route_1_1_1_1 = VppIpRoute(self, "1.1.1.1", 32,
1265 [VppRoutePath("10.0.0.2", 0xffffffff),
1266 VppRoutePath("10.0.0.1", 0xffffffff)])
1267 route_1_1_1_1.add_vpp_config()
1270 # inject the packet on pg0 - expect load-balancing across all 4 paths
1272 self.vapi.cli("clear trace")
1273 self.send_and_expect_load_balancing(self.pg0, port_pkts,
1274 [self.pg1, self.pg2,
1275 self.pg3, self.pg4])
1276 self.send_and_expect_load_balancing(self.pg0, src_pkts,
1277 [self.pg1, self.pg2,
1278 self.pg3, self.pg4])
1281 # bring down pg1 expect LB to adjust to use only those that are up
1283 self.pg1.link_down()
1285 rx = self.send_and_expect_load_balancing(self.pg0, src_pkts,
1286 [self.pg2, self.pg3,
1288 self.assertEqual(len(src_pkts), self.total_len(rx))
1291 # bring down pg2 expect LB to adjust to use only those that are up
1293 self.pg2.link_down()
1295 rx = self.send_and_expect_load_balancing(self.pg0, src_pkts,
1296 [self.pg3, self.pg4])
1297 self.assertEqual(len(src_pkts), self.total_len(rx))
1300 # bring the links back up - expect LB over all again
1305 rx = self.send_and_expect_load_balancing(self.pg0, src_pkts,
1306 [self.pg1, self.pg2,
1307 self.pg3, self.pg4])
1308 self.assertEqual(len(src_pkts), self.total_len(rx))
1311 # The same link-up/down but this time admin state
1313 self.pg1.admin_down()
1314 self.pg2.admin_down()
1315 rx = self.send_and_expect_load_balancing(self.pg0, src_pkts,
1316 [self.pg3, self.pg4])
1317 self.assertEqual(len(src_pkts), self.total_len(rx))
1320 self.pg1.resolve_arp()
1321 self.pg2.resolve_arp()
1322 rx = self.send_and_expect_load_balancing(self.pg0, src_pkts,
1323 [self.pg1, self.pg2,
1324 self.pg3, self.pg4])
1325 self.assertEqual(len(src_pkts), self.total_len(rx))
1328 # Recursive prefixes
1329 # - testing that 2 stages of load-balancing, no choices
1333 for ii in range(257):
1334 port_pkts.append((Ether(src=self.pg0.remote_mac,
1335 dst=self.pg0.local_mac) /
1336 IP(dst="1.1.1.2", src="20.0.0.2") /
1337 UDP(sport=1234, dport=1234 + ii) /
1338 Raw(b'\xa5' * 100)))
1340 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1341 [VppRoutePath(self.pg3.remote_ip4,
1342 self.pg3.sw_if_index)])
1343 route_10_0_0_3.add_vpp_config()
1345 route_1_1_1_2 = VppIpRoute(self, "1.1.1.2", 32,
1346 [VppRoutePath("10.0.0.3", 0xffffffff)])
1347 route_1_1_1_2.add_vpp_config()
1350 # inject the packet on pg0 - rx only on via routes output interface
1352 self.vapi.cli("clear trace")
1353 self.send_and_expect_only(self.pg0, port_pkts, self.pg3)
1356 # Add a LB route in the presence of a down link - expect no
1357 # packets over the down link
1359 self.pg3.link_down()
1361 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1362 [VppRoutePath(self.pg3.remote_ip4,
1363 self.pg3.sw_if_index),
1364 VppRoutePath(self.pg4.remote_ip4,
1365 self.pg4.sw_if_index)])
1366 route_10_0_0_3.add_vpp_config()
1369 for ii in range(257):
1370 port_pkts.append(Ether(src=self.pg0.remote_mac,
1371 dst=self.pg0.local_mac) /
1372 IP(dst="10.0.0.3", src="20.0.0.2") /
1373 UDP(sport=1234, dport=1234 + ii) /
1376 self.send_and_expect_only(self.pg0, port_pkts, self.pg4)
1378 # bring the link back up
1381 rx = self.send_and_expect_load_balancing(self.pg0, port_pkts,
1382 [self.pg3, self.pg4])
1383 self.assertEqual(len(src_pkts), self.total_len(rx))
1386 class TestIPVlan0(VppTestCase):
1390 def setUpClass(cls):
1391 super(TestIPVlan0, cls).setUpClass()
1394 def tearDownClass(cls):
1395 super(TestIPVlan0, cls).tearDownClass()
1398 super(TestIPVlan0, self).setUp()
1400 self.create_pg_interfaces(range(2))
1401 mpls_tbl = VppMplsTable(self, 0)
1402 mpls_tbl.add_vpp_config()
1404 for i in self.pg_interfaces:
1411 for i in self.pg_interfaces:
1415 super(TestIPVlan0, self).tearDown()
1417 def test_ip_vlan_0(self):
1420 pkts = (Ether(src=self.pg0.remote_mac,
1421 dst=self.pg0.local_mac) /
1423 IP(dst=self.pg1.remote_ip4,
1424 src=self.pg0.remote_ip4) /
1425 UDP(sport=1234, dport=1234) /
1426 Raw(b'\xa5' * 100)) * NUM_PKTS
1429 # Expect that packets sent on VLAN-0 are forwarded on the
1432 self.send_and_expect(self.pg0, pkts, self.pg1)
1435 class IPPuntSetup(object):
1436 """ Setup for IPv4 Punt Police/Redirect """
1438 def punt_setup(self):
1439 self.create_pg_interfaces(range(4))
1441 for i in self.pg_interfaces:
1446 # use UDP packet that have a port we need to explicitly
1447 # register to get punted.
1448 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
1449 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
1450 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
1456 'protocol': udp_proto,
1462 self.vapi.set_punt(is_add=1, punt=punt_udp)
1464 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
1470 'protocol': udp_proto,
1476 self.vapi.set_punt(is_add=1, punt=punt_udp)
1478 self.pkt = (Ether(src=self.pg0.remote_mac,
1479 dst=self.pg0.local_mac) /
1480 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
1481 UDP(sport=1234, dport=1234) /
1484 def punt_teardown(self):
1485 for i in self.pg_interfaces:
1490 class TestIPPunt(IPPuntSetup, VppTestCase):
1491 """ IPv4 Punt Police/Redirect """
1495 super().punt_setup()
1498 super().punt_teardown()
1501 def test_ip_punt_api_validation(self):
1502 """ IP punt API parameter validation """
1504 nh_addr = self.pg1.remote_ip4
1505 punt = {"rx_sw_if_index": self.pg0.sw_if_index,
1506 "af": VppEnum.vl_api_address_family_t.ADDRESS_IP4,
1510 with self.assertRaises(vpp_papi.VPPIOError):
1511 self.vapi.add_del_ip_punt_redirect_v2(punt=punt, is_add=True)
1513 punt = {"rx_sw_if_index": self.pg0.sw_if_index,
1514 "af": VppEnum.vl_api_address_family_t.ADDRESS_IP4,
1518 self.vapi.add_del_ip_punt_redirect_v2(punt=punt, is_add=True)
1520 def test_ip_punt(self):
1521 """ IP punt police and redirect """
1523 pkts = self.pkt * 1025
1526 # Configure a punt redirect via pg1.
1528 nh_addr = self.pg1.remote_ip4
1529 ip_punt_redirect = VppIpPuntRedirect(self, self.pg0.sw_if_index,
1530 self.pg1.sw_if_index, nh_addr)
1531 ip_punt_redirect.add_vpp_config()
1533 self.send_and_expect(self.pg0, pkts, self.pg1)
1538 policer = VppPolicer(self, "ip4-punt", 400, 0, 10, 0, rate_type=1)
1539 policer.add_vpp_config()
1540 ip_punt_policer = VppIpPuntPolicer(self, policer.policer_index)
1541 ip_punt_policer.add_vpp_config()
1543 self.vapi.cli("clear trace")
1544 self.pg0.add_stream(pkts)
1545 self.pg_enable_capture(self.pg_interfaces)
1549 # the number of packet received should be greater than 0,
1550 # but not equal to the number sent, since some were policed
1552 rx = self.pg1._get_capture(1)
1554 stats = policer.get_stats()
1556 # Single rate policer - expect conform, violate but no exceed
1557 self.assertGreater(stats['conform_packets'], 0)
1558 self.assertEqual(stats['exceed_packets'], 0)
1559 self.assertGreater(stats['violate_packets'], 0)
1561 self.assertGreater(len(rx), 0)
1562 self.assertLess(len(rx), len(pkts))
1565 # remove the policer. back to full rx
1567 ip_punt_policer.remove_vpp_config()
1568 policer.remove_vpp_config()
1569 self.send_and_expect(self.pg0, pkts, self.pg1)
1572 # remove the redirect. expect full drop.
1574 ip_punt_redirect.remove_vpp_config()
1575 self.send_and_assert_no_replies(self.pg0, pkts,
1576 "IP no punt config")
1579 # Add a redirect that is not input port selective
1581 ip_punt_redirect = VppIpPuntRedirect(self, 0xffffffff,
1582 self.pg1.sw_if_index, nh_addr)
1583 ip_punt_redirect.add_vpp_config()
1584 self.send_and_expect(self.pg0, pkts, self.pg1)
1585 ip_punt_redirect.remove_vpp_config()
1587 def test_ip_punt_vrf(self):
1588 """ IP punt/local with VRFs """
1590 # use a punt redirect to test if for-us packets are accepted
1591 pkts = self.pkt * 1025
1593 vlans_pg0 = [VppDot1QSubint(self, self.pg0, v)
1594 for v in range(100, 104)]
1595 vlans_pg1 = [VppDot1QSubint(self, self.pg1, v)
1596 for v in range(100, 104)]
1597 tbl4 = [VppIpTable(self, v).add_vpp_config()
1598 for v in range(100, 104)]
1599 tbl6 = [VppIpTable(self, v, True).add_vpp_config()
1600 for v in range(100, 104)]
1602 for v in vlans_pg0 + vlans_pg1:
1604 v.set_table_ip4(v.vlan)
1605 v.set_table_ip6(v.vlan)
1613 vlans_pg0[i].sw_if_index,
1614 vlans_pg1[i].sw_if_index,
1615 vlans_pg1[i].remote_ip4).add_vpp_config()
1619 vlans_pg0[i].sw_if_index,
1620 vlans_pg1[i].sw_if_index,
1621 vlans_pg1[i].remote_ip6).add_vpp_config()
1624 pkts = [(Ether(src=self.pg0.remote_mac,
1625 dst=self.pg0.local_mac) /
1626 Dot1Q(vlan=i.vlan) /
1627 IP(src=i.remote_ip4,
1629 UDP(sport=1234, dport=1234) /
1633 self.send_and_expect(self.pg0, pkts, self.pg1)
1639 # we reject packets for source addresses in the wrong vlan/VRF
1640 pkts = [(Ether(src=self.pg0.remote_mac,
1641 dst=self.pg0.local_mac) /
1642 Dot1Q(vlan=i.vlan) /
1645 UDP(sport=1234, dport=1234) /
1648 # single and dual loop
1649 self.send_and_assert_no_replies(self.pg0, [pkts[0]])
1650 self.send_and_assert_no_replies(self.pg0, pkts)
1652 self.assert_error_counter_equal(
1653 "/err/ip4-local/ip4 source lookup miss",
1656 # using the same source in different tables, should reject
1657 # for the table that the source is not present in
1658 # the first packet in the stream is drop
1659 pkts = [(Ether(src=self.pg0.remote_mac,
1660 dst=self.pg0.local_mac) /
1661 Dot1Q(vlan=i.vlan) /
1662 IP(src=vlans_pg0[0].remote_ip4,
1664 UDP(sport=1234, dport=1234) /
1667 # single loop accept and drop
1668 # followed by both in the same frame/loop
1669 self.send_and_expect(self.pg0, [pkts[0]], self.pg1)
1670 self.send_and_assert_no_replies(self.pg0, [pkts[1]])
1671 self.send_and_expect(self.pg0, pkts * 4, self.pg1, n_rx=4)
1673 # using the same source in different tables, should reject
1674 # for the table that the source is not present in
1675 # the first packet in the stream is accept
1676 pkts = [(Ether(src=self.pg0.remote_mac,
1677 dst=self.pg0.local_mac) /
1678 Dot1Q(vlan=i.vlan) /
1679 IP(src=vlans_pg0[3].remote_ip4,
1681 UDP(sport=1234, dport=1234) /
1685 # single loop accept and drop
1686 # followed by both in the same frame/loop
1687 self.send_and_expect(self.pg0, [pkts[3]], self.pg1)
1688 self.send_and_assert_no_replies(self.pg0, [pkts[1]])
1689 self.send_and_expect(self.pg0, pkts * 4, self.pg1, n_rx=4)
1695 # we reject packets for source addresses in the wrong vlan/VRF
1696 pkts = [(Ether(src=self.pg0.remote_mac,
1697 dst=self.pg0.local_mac) /
1698 Dot1Q(vlan=i.vlan) /
1701 UDP(sport=1236, dport=1236) /
1704 # single and dual loop
1705 self.send_and_assert_no_replies(self.pg0, [pkts[0]])
1706 self.send_and_assert_no_replies(self.pg0, pkts)
1708 self.assert_error_counter_equal(
1709 "/err/ip6-input/ip6 source lookup miss",
1712 # using the same source in different tables, should reject
1713 # for the table that the source is not present in
1714 # the first packet in the stream is drop
1715 pkts = [(Ether(src=self.pg0.remote_mac,
1716 dst=self.pg0.local_mac) /
1717 Dot1Q(vlan=i.vlan) /
1718 IPv6(src=vlans_pg0[0].remote_ip6,
1720 UDP(sport=1236, dport=1236) /
1723 # single loop accept and drop
1724 # followed by both in the same frame/loop
1725 self.send_and_expect(self.pg0, [pkts[0]], self.pg1)
1726 self.send_and_assert_no_replies(self.pg0, [pkts[1]])
1727 self.send_and_expect(self.pg0, pkts * 4, self.pg1, n_rx=4)
1729 # using the same source in different tables, should reject
1730 # for the table that the source is not present in
1731 # the first packet in the stream is accept
1732 pkts = [(Ether(src=self.pg0.remote_mac,
1733 dst=self.pg0.local_mac) /
1734 Dot1Q(vlan=i.vlan) /
1735 IPv6(src=vlans_pg0[3].remote_ip6,
1737 UDP(sport=1236, dport=1236) /
1741 # single loop accept and drop
1742 # followed by both in the same frame/loop
1743 self.send_and_expect(self.pg0, [pkts[3]], self.pg1)
1744 self.send_and_assert_no_replies(self.pg0, [pkts[1]])
1745 self.send_and_expect(self.pg0, pkts * 4, self.pg1, n_rx=4)
1747 for v in vlans_pg0 + vlans_pg1:
1753 def test_ip_punt_dump(self):
1754 """ IP4 punt redirect dump"""
1757 # Configure a punt redirects
1759 nh_address = self.pg3.remote_ip4
1760 ipr_03 = VppIpPuntRedirect(self, self.pg0.sw_if_index,
1761 self.pg3.sw_if_index, nh_address)
1762 ipr_13 = VppIpPuntRedirect(self, self.pg1.sw_if_index,
1763 self.pg3.sw_if_index, nh_address)
1764 ipr_23 = VppIpPuntRedirect(self, self.pg2.sw_if_index,
1765 self.pg3.sw_if_index, "0.0.0.0")
1766 ipr_03.add_vpp_config()
1767 ipr_13.add_vpp_config()
1768 ipr_23.add_vpp_config()
1771 # Dump pg0 punt redirects
1773 self.assertTrue(ipr_03.query_vpp_config())
1774 self.assertTrue(ipr_13.query_vpp_config())
1775 self.assertTrue(ipr_23.query_vpp_config())
1778 # Dump punt redirects for all interfaces
1780 punts = self.vapi.ip_punt_redirect_dump(0xffffffff)
1781 self.assertEqual(len(punts), 3)
1783 self.assertEqual(p.punt.tx_sw_if_index, self.pg3.sw_if_index)
1784 self.assertNotEqual(punts[1].punt.nh, self.pg3.remote_ip4)
1785 self.assertEqual(str(punts[2].punt.nh), '0.0.0.0')
1788 class TestIPPuntHandoff(IPPuntSetup, VppTestCase):
1789 """ IPv4 Punt Policer thread handoff """
1790 vpp_worker_count = 2
1793 super(TestIPPuntHandoff, self).setUp()
1794 super(TestIPPuntHandoff, self).punt_setup()
1797 super(TestIPPuntHandoff, self).punt_teardown()
1798 super(TestIPPuntHandoff, self).tearDown()
1800 def test_ip_punt_policer_handoff(self):
1801 """ IP4 punt policer thread handoff """
1802 pkts = self.pkt * NUM_PKTS
1805 # Configure a punt redirect via pg1.
1807 nh_addr = self.pg1.remote_ip4
1808 ip_punt_redirect = VppIpPuntRedirect(self, self.pg0.sw_if_index,
1809 self.pg1.sw_if_index, nh_addr)
1810 ip_punt_redirect.add_vpp_config()
1812 action_tx = PolicerAction(
1813 VppEnum.vl_api_sse2_qos_action_type_t.SSE2_QOS_ACTION_API_TRANSMIT,
1816 # This policer drops no packets, we are just
1817 # testing that they get to the right thread.
1819 policer = VppPolicer(self, "ip4-punt", 400, 0, 10, 0, 1,
1820 0, 0, False, action_tx, action_tx, action_tx)
1821 policer.add_vpp_config()
1822 ip_punt_policer = VppIpPuntPolicer(self, policer.policer_index)
1823 ip_punt_policer.add_vpp_config()
1825 for worker in [0, 1]:
1826 self.send_and_expect(self.pg0, pkts, self.pg1, worker=worker)
1827 self.logger.debug(self.vapi.cli("show trace max 100"))
1829 # Combined stats, all threads
1830 stats = policer.get_stats()
1832 # Single rate policer - expect conform, violate but no exceed
1833 self.assertGreater(stats['conform_packets'], 0)
1834 self.assertEqual(stats['exceed_packets'], 0)
1835 self.assertGreater(stats['violate_packets'], 0)
1837 # Worker 0, should have done all the policing
1838 stats0 = policer.get_stats(worker=0)
1839 self.assertEqual(stats, stats0)
1841 # Worker 1, should have handed everything off
1842 stats1 = policer.get_stats(worker=1)
1843 self.assertEqual(stats1['conform_packets'], 0)
1844 self.assertEqual(stats1['exceed_packets'], 0)
1845 self.assertEqual(stats1['violate_packets'], 0)
1847 # Bind the policer to worker 1 and repeat
1848 policer.bind_vpp_config(1, True)
1849 for worker in [0, 1]:
1850 self.send_and_expect(self.pg0, pkts, self.pg1, worker=worker)
1851 self.logger.debug(self.vapi.cli("show trace max 100"))
1853 # The 2 workers should now have policed the same amount
1854 stats = policer.get_stats()
1855 stats0 = policer.get_stats(worker=0)
1856 stats1 = policer.get_stats(worker=1)
1858 self.assertGreater(stats0['conform_packets'], 0)
1859 self.assertEqual(stats0['exceed_packets'], 0)
1860 self.assertGreater(stats0['violate_packets'], 0)
1862 self.assertGreater(stats1['conform_packets'], 0)
1863 self.assertEqual(stats1['exceed_packets'], 0)
1864 self.assertGreater(stats1['violate_packets'], 0)
1866 self.assertEqual(stats0['conform_packets'] + stats1['conform_packets'],
1867 stats['conform_packets'])
1869 self.assertEqual(stats0['violate_packets'] + stats1['violate_packets'],
1870 stats['violate_packets'])
1872 # Unbind the policer and repeat
1873 policer.bind_vpp_config(1, False)
1874 for worker in [0, 1]:
1875 self.send_and_expect(self.pg0, pkts, self.pg1, worker=worker)
1876 self.logger.debug(self.vapi.cli("show trace max 100"))
1878 # The policer should auto-bind to worker 0 when packets arrive
1879 stats = policer.get_stats()
1880 stats0new = policer.get_stats(worker=0)
1881 stats1new = policer.get_stats(worker=1)
1883 self.assertGreater(stats0new['conform_packets'],
1884 stats0['conform_packets'])
1885 self.assertEqual(stats0new['exceed_packets'], 0)
1886 self.assertGreater(stats0new['violate_packets'],
1887 stats0['violate_packets'])
1889 self.assertEqual(stats1, stats1new)
1894 ip_punt_policer.remove_vpp_config()
1895 policer.remove_vpp_config()
1896 ip_punt_redirect.remove_vpp_config()
1899 class TestIPDeag(VppTestCase):
1900 """ IPv4 Deaggregate Routes """
1903 def setUpClass(cls):
1904 super(TestIPDeag, cls).setUpClass()
1907 def tearDownClass(cls):
1908 super(TestIPDeag, cls).tearDownClass()
1911 super(TestIPDeag, self).setUp()
1913 self.create_pg_interfaces(range(3))
1915 for i in self.pg_interfaces:
1921 super(TestIPDeag, self).tearDown()
1922 for i in self.pg_interfaces:
1926 def test_ip_deag(self):
1927 """ IP Deag Routes """
1930 # Create a table to be used for:
1931 # 1 - another destination address lookup
1932 # 2 - a source address lookup
1934 table_dst = VppIpTable(self, 1)
1935 table_src = VppIpTable(self, 2)
1936 table_dst.add_vpp_config()
1937 table_src.add_vpp_config()
1940 # Add a route in the default table to point to a deag/
1941 # second lookup in each of these tables
1943 route_to_dst = VppIpRoute(self, "1.1.1.1", 32,
1944 [VppRoutePath("0.0.0.0",
1947 route_to_src = VppIpRoute(
1948 self, "1.1.1.2", 32,
1949 [VppRoutePath("0.0.0.0",
1952 type=FibPathType.FIB_PATH_TYPE_SOURCE_LOOKUP)])
1953 route_to_dst.add_vpp_config()
1954 route_to_src.add_vpp_config()
1957 # packets to these destination are dropped, since they'll
1958 # hit the respective default routes in the second table
1960 p_dst = (Ether(src=self.pg0.remote_mac,
1961 dst=self.pg0.local_mac) /
1962 IP(src="5.5.5.5", dst="1.1.1.1") /
1963 TCP(sport=1234, dport=1234) /
1965 p_src = (Ether(src=self.pg0.remote_mac,
1966 dst=self.pg0.local_mac) /
1967 IP(src="2.2.2.2", dst="1.1.1.2") /
1968 TCP(sport=1234, dport=1234) /
1970 pkts_dst = p_dst * 257
1971 pkts_src = p_src * 257
1973 self.send_and_assert_no_replies(self.pg0, pkts_dst,
1975 self.send_and_assert_no_replies(self.pg0, pkts_src,
1979 # add a route in the dst table to forward via pg1
1981 route_in_dst = VppIpRoute(self, "1.1.1.1", 32,
1982 [VppRoutePath(self.pg1.remote_ip4,
1983 self.pg1.sw_if_index)],
1985 route_in_dst.add_vpp_config()
1987 self.send_and_expect(self.pg0, pkts_dst, self.pg1)
1990 # add a route in the src table to forward via pg2
1992 route_in_src = VppIpRoute(self, "2.2.2.2", 32,
1993 [VppRoutePath(self.pg2.remote_ip4,
1994 self.pg2.sw_if_index)],
1996 route_in_src.add_vpp_config()
1997 self.send_and_expect(self.pg0, pkts_src, self.pg2)
2000 # loop in the lookup DP
2002 route_loop = VppIpRoute(self, "2.2.2.3", 32,
2003 [VppRoutePath("0.0.0.0",
2006 route_loop.add_vpp_config()
2008 p_l = (Ether(src=self.pg0.remote_mac,
2009 dst=self.pg0.local_mac) /
2010 IP(src="2.2.2.4", dst="2.2.2.3") /
2011 TCP(sport=1234, dport=1234) /
2014 self.send_and_assert_no_replies(self.pg0, p_l * 257,
2018 class TestIPInput(VppTestCase):
2019 """ IPv4 Input Exceptions """
2022 def setUpClass(cls):
2023 super(TestIPInput, cls).setUpClass()
2026 def tearDownClass(cls):
2027 super(TestIPInput, cls).tearDownClass()
2030 super(TestIPInput, self).setUp()
2032 self.create_pg_interfaces(range(2))
2034 for i in self.pg_interfaces:
2040 super(TestIPInput, self).tearDown()
2041 for i in self.pg_interfaces:
2045 def test_ip_input(self):
2046 """ IP Input Exceptions """
2048 # i can't find a way in scapy to construct an IP packet
2049 # with a length less than the IP header length
2052 # Packet too short - this is forwarded
2054 p_short = (Ether(src=self.pg0.remote_mac,
2055 dst=self.pg0.local_mac) /
2056 IP(src=self.pg0.remote_ip4,
2057 dst=self.pg1.remote_ip4,
2059 UDP(sport=1234, dport=1234) /
2062 rx = self.send_and_expect(self.pg0, p_short * NUM_PKTS, self.pg1)
2065 # Packet too long - this is dropped
2067 p_long = (Ether(src=self.pg0.remote_mac,
2068 dst=self.pg0.local_mac) /
2069 IP(src=self.pg0.remote_ip4,
2070 dst=self.pg1.remote_ip4,
2072 UDP(sport=1234, dport=1234) /
2075 rx = self.send_and_assert_no_replies(self.pg0, p_long * NUM_PKTS,
2079 # bad chksum - this is dropped
2081 p_chksum = (Ether(src=self.pg0.remote_mac,
2082 dst=self.pg0.local_mac) /
2083 IP(src=self.pg0.remote_ip4,
2084 dst=self.pg1.remote_ip4,
2086 UDP(sport=1234, dport=1234) /
2089 rx = self.send_and_assert_no_replies(self.pg0, p_chksum * NUM_PKTS,
2093 # bad version - this is dropped
2095 p_ver = (Ether(src=self.pg0.remote_mac,
2096 dst=self.pg0.local_mac) /
2097 IP(src=self.pg0.remote_ip4,
2098 dst=self.pg1.remote_ip4,
2100 UDP(sport=1234, dport=1234) /
2103 rx = self.send_and_assert_no_replies(self.pg0, p_ver * NUM_PKTS,
2107 # fragment offset 1 - this is dropped
2109 p_frag = (Ether(src=self.pg0.remote_mac,
2110 dst=self.pg0.local_mac) /
2111 IP(src=self.pg0.remote_ip4,
2112 dst=self.pg1.remote_ip4,
2114 UDP(sport=1234, dport=1234) /
2117 rx = self.send_and_assert_no_replies(self.pg0, p_frag * NUM_PKTS,
2121 # TTL expired packet
2123 p_ttl = (Ether(src=self.pg0.remote_mac,
2124 dst=self.pg0.local_mac) /
2125 IP(src=self.pg0.remote_ip4,
2126 dst=self.pg1.remote_ip4,
2128 UDP(sport=1234, dport=1234) /
2131 rxs = self.send_and_expect_some(self.pg0, p_ttl * NUM_PKTS, self.pg0)
2135 self.assertEqual(icmptypes[icmp.type], "time-exceeded")
2136 self.assertEqual(icmpcodes[icmp.type][icmp.code],
2137 "ttl-zero-during-transit")
2138 self.assertEqual(icmp.src, self.pg0.remote_ip4)
2139 self.assertEqual(icmp.dst, self.pg1.remote_ip4)
2144 p_mtu = (Ether(src=self.pg0.remote_mac,
2145 dst=self.pg0.local_mac) /
2146 IP(src=self.pg0.remote_ip4,
2147 dst=self.pg1.remote_ip4,
2148 ttl=10, flags='DF') /
2149 UDP(sport=1234, dport=1234) /
2150 Raw(b'\xa5' * 2000))
2152 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1500, 0, 0, 0])
2154 rxs = self.send_and_expect_some(self.pg0, p_mtu * NUM_PKTS, self.pg0)
2158 self.assertEqual(icmptypes[icmp.type], "dest-unreach")
2159 self.assertEqual(icmpcodes[icmp.type][icmp.code],
2160 "fragmentation-needed")
2161 self.assertEqual(icmp.nexthopmtu, 1500)
2162 self.assertEqual(icmp.src, self.pg0.remote_ip4)
2163 self.assertEqual(icmp.dst, self.pg1.remote_ip4)
2165 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2500, 0, 0, 0])
2166 rx = self.send_and_expect(self.pg0, p_mtu * NUM_PKTS, self.pg1)
2168 # Reset MTU for subsequent tests
2169 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [9000, 0, 0, 0])
2172 # source address 0.0.0.0 and 25.255.255.255 and for-us
2174 p_s0 = (Ether(src=self.pg0.remote_mac,
2175 dst=self.pg0.local_mac) /
2177 dst=self.pg0.local_ip4) /
2179 Raw(load=b'\x0a' * 18))
2180 rx = self.send_and_assert_no_replies(self.pg0, p_s0 * 17)
2182 p_s0 = (Ether(src=self.pg0.remote_mac,
2183 dst=self.pg0.local_mac) /
2184 IP(src="255.255.255.255",
2185 dst=self.pg0.local_ip4) /
2187 Raw(load=b'\x0a' * 18))
2188 rx = self.send_and_assert_no_replies(self.pg0, p_s0 * 17)
2191 class TestIPDirectedBroadcast(VppTestCase):
2192 """ IPv4 Directed Broadcast """
2195 def setUpClass(cls):
2196 super(TestIPDirectedBroadcast, cls).setUpClass()
2199 def tearDownClass(cls):
2200 super(TestIPDirectedBroadcast, cls).tearDownClass()
2203 super(TestIPDirectedBroadcast, self).setUp()
2205 self.create_pg_interfaces(range(2))
2207 for i in self.pg_interfaces:
2211 super(TestIPDirectedBroadcast, self).tearDown()
2212 for i in self.pg_interfaces:
2215 def test_ip_input(self):
2216 """ IP Directed Broadcast """
2219 # set the directed broadcast on pg0 first, then config IP4 addresses
2220 # for pg1 directed broadcast is always disabled
2221 self.vapi.sw_interface_set_ip_directed_broadcast(
2222 self.pg0.sw_if_index, 1)
2224 p0 = (Ether(src=self.pg1.remote_mac,
2225 dst=self.pg1.local_mac) /
2227 dst=self.pg0._local_ip4_bcast) /
2228 UDP(sport=1234, dport=1234) /
2229 Raw(b'\xa5' * 2000))
2230 p1 = (Ether(src=self.pg0.remote_mac,
2231 dst=self.pg0.local_mac) /
2233 dst=self.pg1._local_ip4_bcast) /
2234 UDP(sport=1234, dport=1234) /
2235 Raw(b'\xa5' * 2000))
2237 self.pg0.config_ip4()
2238 self.pg0.resolve_arp()
2239 self.pg1.config_ip4()
2240 self.pg1.resolve_arp()
2243 # test packet is L2 broadcast
2245 rx = self.send_and_expect(self.pg1, p0 * NUM_PKTS, self.pg0)
2246 self.assertTrue(rx[0][Ether].dst, "ff:ff:ff:ff:ff:ff")
2248 self.send_and_assert_no_replies(self.pg0, p1 * NUM_PKTS,
2249 "directed broadcast disabled")
2252 # toggle directed broadcast on pg0
2254 self.vapi.sw_interface_set_ip_directed_broadcast(
2255 self.pg0.sw_if_index, 0)
2256 self.send_and_assert_no_replies(self.pg1, p0 * NUM_PKTS,
2257 "directed broadcast disabled")
2259 self.vapi.sw_interface_set_ip_directed_broadcast(
2260 self.pg0.sw_if_index, 1)
2261 rx = self.send_and_expect(self.pg1, p0 * NUM_PKTS, self.pg0)
2263 self.pg0.unconfig_ip4()
2264 self.pg1.unconfig_ip4()
2267 class TestIPLPM(VppTestCase):
2268 """ IPv4 longest Prefix Match """
2271 def setUpClass(cls):
2272 super(TestIPLPM, cls).setUpClass()
2275 def tearDownClass(cls):
2276 super(TestIPLPM, cls).tearDownClass()
2279 super(TestIPLPM, self).setUp()
2281 self.create_pg_interfaces(range(4))
2283 for i in self.pg_interfaces:
2289 super(TestIPLPM, self).tearDown()
2290 for i in self.pg_interfaces:
2294 def test_ip_lpm(self):
2295 """ IP longest Prefix Match """
2297 s_24 = VppIpRoute(self, "10.1.2.0", 24,
2298 [VppRoutePath(self.pg1.remote_ip4,
2299 self.pg1.sw_if_index)])
2300 s_24.add_vpp_config()
2301 s_8 = VppIpRoute(self, "10.0.0.0", 8,
2302 [VppRoutePath(self.pg2.remote_ip4,
2303 self.pg2.sw_if_index)])
2304 s_8.add_vpp_config()
2306 p_8 = (Ether(src=self.pg0.remote_mac,
2307 dst=self.pg0.local_mac) /
2310 UDP(sport=1234, dport=1234) /
2311 Raw(b'\xa5' * 2000))
2312 p_24 = (Ether(src=self.pg0.remote_mac,
2313 dst=self.pg0.local_mac) /
2316 UDP(sport=1234, dport=1234) /
2317 Raw(b'\xa5' * 2000))
2319 self.logger.info(self.vapi.cli("sh ip fib mtrie"))
2320 rx = self.send_and_expect(self.pg0, p_8 * NUM_PKTS, self.pg2)
2321 rx = self.send_and_expect(self.pg0, p_24 * NUM_PKTS, self.pg1)
2324 @tag_fixme_vpp_workers
2325 class TestIPv4Frag(VppTestCase):
2326 """ IPv4 fragmentation """
2329 def setUpClass(cls):
2330 super(TestIPv4Frag, cls).setUpClass()
2332 cls.create_pg_interfaces([0, 1])
2333 cls.src_if = cls.pg0
2334 cls.dst_if = cls.pg1
2336 # setup all interfaces
2337 for i in cls.pg_interfaces:
2343 def tearDownClass(cls):
2344 super(TestIPv4Frag, cls).tearDownClass()
2346 def test_frag_large_packets(self):
2347 """ Fragmentation of large packets """
2349 self.vapi.cli("adjacency counters enable")
2351 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
2352 IP(src=self.src_if.remote_ip4, dst=self.dst_if.remote_ip4) /
2353 UDP(sport=1234, dport=5678) / Raw())
2354 self.extend_packet(p, 6000, "abcde")
2355 saved_payload = p[Raw].load
2357 nbr = VppNeighbor(self,
2358 self.dst_if.sw_if_index,
2359 self.dst_if.remote_mac,
2360 self.dst_if.remote_ip4).add_vpp_config()
2362 # Force fragmentation by setting MTU of output interface
2363 # lower than packet size
2364 self.vapi.sw_interface_set_mtu(self.dst_if.sw_if_index,
2367 self.pg_enable_capture()
2368 self.src_if.add_stream(p)
2371 # Expecting 3 fragments because size of created fragments currently
2372 # cannot be larger then VPP buffer size (which is 2048)
2373 packets = self.dst_if.get_capture(3)
2375 # we should show 3 packets thru the neighbor
2376 self.assertEqual(3, nbr.get_stats()['packets'])
2378 # Assume VPP sends the fragments in order
2381 payload_offset = p.frag * 8
2382 if payload_offset > 0:
2383 payload_offset -= 8 # UDP header is not in payload
2384 self.assert_equal(payload_offset, len(payload))
2385 payload += p[Raw].load
2386 self.assert_equal(payload, saved_payload, "payload")
2389 class TestIPReplace(VppTestCase):
2390 """ IPv4 Table Replace """
2393 def setUpClass(cls):
2394 super(TestIPReplace, cls).setUpClass()
2397 def tearDownClass(cls):
2398 super(TestIPReplace, cls).tearDownClass()
2401 super(TestIPReplace, self).setUp()
2403 self.create_pg_interfaces(range(4))
2408 for i in self.pg_interfaces:
2412 i.generate_remote_hosts(2)
2413 self.tables.append(VppIpTable(self, table_id).add_vpp_config())
2417 super(TestIPReplace, self).tearDown()
2418 for i in self.pg_interfaces:
2422 def test_replace(self):
2423 """ IP Table Replace """
2425 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
2426 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
2428 links = [self.pg0, self.pg1, self.pg2, self.pg3]
2429 routes = [[], [], [], []]
2431 # load up the tables with some routes
2432 for ii, t in enumerate(self.tables):
2433 for jj in range(N_ROUTES):
2435 self, "10.0.0.%d" % jj, 32,
2436 [VppRoutePath(links[ii].remote_hosts[0].ip4,
2437 links[ii].sw_if_index),
2438 VppRoutePath(links[ii].remote_hosts[1].ip4,
2439 links[ii].sw_if_index)],
2440 table_id=t.table_id).add_vpp_config()
2441 multi = VppIpMRoute(
2443 "239.0.0.%d" % jj, 32,
2444 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
2445 [VppMRoutePath(self.pg0.sw_if_index,
2446 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT),
2447 VppMRoutePath(self.pg1.sw_if_index,
2448 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD),
2449 VppMRoutePath(self.pg2.sw_if_index,
2450 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD),
2451 VppMRoutePath(self.pg3.sw_if_index,
2452 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD)],
2453 table_id=t.table_id).add_vpp_config()
2454 routes[ii].append({'uni': uni,
2458 # replace the tables a few times
2461 # replace_begin each table
2462 for t in self.tables:
2465 # all the routes are still there
2466 for ii, t in enumerate(self.tables):
2469 for r in routes[ii]:
2470 self.assertTrue(find_route_in_dump(dump, r['uni'], t))
2471 self.assertTrue(find_mroute_in_dump(mdump, r['multi'], t))
2473 # redownload the even numbered routes
2474 for ii, t in enumerate(self.tables):
2475 for jj in range(0, N_ROUTES, 2):
2476 routes[ii][jj]['uni'].add_vpp_config()
2477 routes[ii][jj]['multi'].add_vpp_config()
2479 # signal each table replace_end
2480 for t in self.tables:
2483 # we should find the even routes, but not the odd
2484 for ii, t in enumerate(self.tables):
2487 for jj in range(0, N_ROUTES, 2):
2488 self.assertTrue(find_route_in_dump(
2489 dump, routes[ii][jj]['uni'], t))
2490 self.assertTrue(find_mroute_in_dump(
2491 mdump, routes[ii][jj]['multi'], t))
2492 for jj in range(1, N_ROUTES - 1, 2):
2493 self.assertFalse(find_route_in_dump(
2494 dump, routes[ii][jj]['uni'], t))
2495 self.assertFalse(find_mroute_in_dump(
2496 mdump, routes[ii][jj]['multi'], t))
2498 # reload all the routes
2499 for ii, t in enumerate(self.tables):
2500 for r in routes[ii]:
2501 r['uni'].add_vpp_config()
2502 r['multi'].add_vpp_config()
2504 # all the routes are still there
2505 for ii, t in enumerate(self.tables):
2508 for r in routes[ii]:
2509 self.assertTrue(find_route_in_dump(dump, r['uni'], t))
2510 self.assertTrue(find_mroute_in_dump(mdump, r['multi'], t))
2513 # finally flush the tables for good measure
2515 for t in self.tables:
2517 self.assertEqual(len(t.dump()), 5)
2518 self.assertEqual(len(t.mdump()), 3)
2521 class TestIPCover(VppTestCase):
2522 """ IPv4 Table Cover """
2525 def setUpClass(cls):
2526 super(TestIPCover, cls).setUpClass()
2529 def tearDownClass(cls):
2530 super(TestIPCover, cls).tearDownClass()
2533 super(TestIPCover, self).setUp()
2535 self.create_pg_interfaces(range(4))
2540 for i in self.pg_interfaces:
2544 i.generate_remote_hosts(2)
2545 self.tables.append(VppIpTable(self, table_id).add_vpp_config())
2549 super(TestIPCover, self).tearDown()
2550 for i in self.pg_interfaces:
2554 def test_cover(self):
2555 """ IP Table Cover """
2557 # add a loop back with a /32 prefix
2558 lo = VppLoInterface(self)
2560 a = VppIpInterfaceAddress(self, lo, "127.0.0.1", 32).add_vpp_config()
2562 # add a neighbour that matches the loopback's /32
2563 nbr = VppNeighbor(self,
2566 "127.0.0.1").add_vpp_config()
2568 # add the default route which will be the cover for /32
2569 r = VppIpRoute(self, "0.0.0.0", 0,
2570 [VppRoutePath("127.0.0.1",
2572 register=False).add_vpp_config()
2574 # add/remove/add a longer mask cover
2575 r8 = VppIpRoute(self, "127.0.0.0", 8,
2576 [VppRoutePath("127.0.0.1",
2577 lo.sw_if_index)]).add_vpp_config()
2578 r8.remove_vpp_config()
2580 r8.remove_vpp_config()
2582 # remove the default route
2583 r.remove_vpp_config()
2585 # remove the interface prefix
2586 a.remove_vpp_config()
2589 class TestIP4Replace(VppTestCase):
2590 """ IPv4 Interface Address Replace """
2593 def setUpClass(cls):
2594 super(TestIP4Replace, cls).setUpClass()
2597 def tearDownClass(cls):
2598 super(TestIP4Replace, cls).tearDownClass()
2601 super(TestIP4Replace, self).setUp()
2603 self.create_pg_interfaces(range(4))
2605 for i in self.pg_interfaces:
2609 super(TestIP4Replace, self).tearDown()
2610 for i in self.pg_interfaces:
2613 def get_n_pfxs(self, intf):
2614 return len(self.vapi.ip_address_dump(intf.sw_if_index))
2616 def test_replace(self):
2617 """ IP interface address replace """
2619 intf_pfxs = [[], [], [], []]
2621 # add prefixes to each of the interfaces
2622 for i in range(len(self.pg_interfaces)):
2623 intf = self.pg_interfaces[i]
2626 addr = "172.16.%d.1" % intf.sw_if_index
2627 a = VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config()
2628 intf_pfxs[i].append(a)
2630 # 172.16.x.2/24 - a different address in the same subnet as above
2631 addr = "172.16.%d.2" % intf.sw_if_index
2632 a = VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config()
2633 intf_pfxs[i].append(a)
2635 # 172.15.x.2/24 - a different address and subnet
2636 addr = "172.15.%d.2" % intf.sw_if_index
2637 a = VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config()
2638 intf_pfxs[i].append(a)
2640 # a dump should n_address in it
2641 for intf in self.pg_interfaces:
2642 self.assertEqual(self.get_n_pfxs(intf), 3)
2645 # remove all the address thru a replace
2647 self.vapi.sw_interface_address_replace_begin()
2648 self.vapi.sw_interface_address_replace_end()
2649 for intf in self.pg_interfaces:
2650 self.assertEqual(self.get_n_pfxs(intf), 0)
2653 # add all the interface addresses back
2658 for intf in self.pg_interfaces:
2659 self.assertEqual(self.get_n_pfxs(intf), 3)
2662 # replace again, but this time update/re-add the address on the first
2665 self.vapi.sw_interface_address_replace_begin()
2667 for p in intf_pfxs[:2]:
2671 self.vapi.sw_interface_address_replace_end()
2673 # on the first two the address still exist,
2674 # on the other two they do not
2675 for intf in self.pg_interfaces[:2]:
2676 self.assertEqual(self.get_n_pfxs(intf), 3)
2677 for p in intf_pfxs[:2]:
2679 self.assertTrue(v.query_vpp_config())
2680 for intf in self.pg_interfaces[2:]:
2681 self.assertEqual(self.get_n_pfxs(intf), 0)
2684 # add all the interface addresses back on the last two
2686 for p in intf_pfxs[2:]:
2689 for intf in self.pg_interfaces:
2690 self.assertEqual(self.get_n_pfxs(intf), 3)
2693 # replace again, this time add different prefixes on all the interfaces
2695 self.vapi.sw_interface_address_replace_begin()
2698 for intf in self.pg_interfaces:
2700 addr = "172.18.%d.1" % intf.sw_if_index
2701 pfxs.append(VppIpInterfaceAddress(self, intf, addr,
2702 24).add_vpp_config())
2704 self.vapi.sw_interface_address_replace_end()
2706 # only .18 should exist on each interface
2707 for intf in self.pg_interfaces:
2708 self.assertEqual(self.get_n_pfxs(intf), 1)
2710 self.assertTrue(pfx.query_vpp_config())
2715 self.vapi.sw_interface_address_replace_begin()
2716 self.vapi.sw_interface_address_replace_end()
2717 for intf in self.pg_interfaces:
2718 self.assertEqual(self.get_n_pfxs(intf), 0)
2721 # add prefixes to each interface. post-begin add the prefix from
2722 # interface X onto interface Y. this would normally be an error
2723 # since it would generate a 'duplicate address' warning. but in
2724 # this case, since what is newly downloaded is sane, it's ok
2726 for intf in self.pg_interfaces:
2728 addr = "172.18.%d.1" % intf.sw_if_index
2729 VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config()
2731 self.vapi.sw_interface_address_replace_begin()
2734 for intf in self.pg_interfaces:
2736 addr = "172.18.%d.1" % (intf.sw_if_index + 1)
2737 pfxs.append(VppIpInterfaceAddress(self, intf,
2738 addr, 24).add_vpp_config())
2740 self.vapi.sw_interface_address_replace_end()
2742 self.logger.info(self.vapi.cli("sh int addr"))
2744 for intf in self.pg_interfaces:
2745 self.assertEqual(self.get_n_pfxs(intf), 1)
2747 self.assertTrue(pfx.query_vpp_config())
2750 class TestIPv4PathMTU(VppTestCase):
2751 """ IPv4 Path MTU """
2754 def setUpClass(cls):
2755 super(TestIPv4PathMTU, cls).setUpClass()
2757 cls.create_pg_interfaces(range(2))
2759 # setup all interfaces
2760 for i in cls.pg_interfaces:
2766 def tearDownClass(cls):
2767 super(TestIPv4PathMTU, cls).tearDownClass()
2769 def test_path_mtu(self):
2773 # The goal here is not to test that fragmentation works correctly,
2774 # that's done elsewhere, the intent is to ensure that the Path MTU
2775 # settings are honoured.
2777 self.vapi.cli("adjacency counters enable")
2779 # set the interface MTU to a reasonable value
2780 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index,
2783 self.pg1.generate_remote_hosts(4)
2785 p_2k = (Ether(dst=self.pg0.local_mac,
2786 src=self.pg0.remote_mac) /
2787 IP(src=self.pg0.remote_ip4,
2788 dst=self.pg1.remote_ip4) /
2789 UDP(sport=1234, dport=5678) /
2791 p_1k = (Ether(dst=self.pg0.local_mac,
2792 src=self.pg0.remote_mac) /
2793 IP(src=self.pg0.remote_ip4,
2794 dst=self.pg1.remote_ip4) /
2795 UDP(sport=1234, dport=5678) /
2798 nbr = VppNeighbor(self,
2799 self.pg1.sw_if_index,
2800 self.pg1.remote_mac,
2801 self.pg1.remote_ip4).add_vpp_config()
2803 # this is now the interface MTU frags
2804 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
2805 self.send_and_expect(self.pg0, [p_1k], self.pg1)
2807 # drop the path MTU for this neighbour to below the interface MTU
2809 pmtu = VppIpPathMtu(self, self.pg1.remote_ip4, 900).add_vpp_config()
2811 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
2812 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
2814 # print/format the adj delegate
2815 self.logger.info(self.vapi.cli("sh adj 5"))
2817 # increase the path MTU to more than the interface
2818 # expect to use the interface MTU
2821 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
2822 self.send_and_expect(self.pg0, [p_1k], self.pg1)
2824 # go back to an MTU from the path
2825 # wrap the call around mark-n-sweep to enusre updates clear stale
2826 self.vapi.ip_path_mtu_replace_begin()
2828 self.vapi.ip_path_mtu_replace_end()
2830 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
2831 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
2833 # raise the interface's MTU
2834 # should still use that of the path
2835 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index,
2837 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
2838 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
2840 # set path high and interface low
2842 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index,
2844 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
2845 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
2847 # remove the path MTU using the mark-n-sweep semantics
2848 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index,
2850 self.vapi.ip_path_mtu_replace_begin()
2851 self.vapi.ip_path_mtu_replace_end()
2853 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
2854 self.send_and_expect(self.pg0, [p_1k], self.pg1)
2857 # set path MTU for a neighbour that doesn't exist, yet
2859 pmtu2 = VppIpPathMtu(self,
2860 self.pg1.remote_hosts[2].ip4,
2861 900).add_vpp_config()
2863 p_2k = (Ether(dst=self.pg0.local_mac,
2864 src=self.pg0.remote_mac) /
2865 IP(src=self.pg0.remote_ip4,
2866 dst=self.pg1.remote_hosts[2].ip4) /
2867 UDP(sport=1234, dport=5678) /
2869 p_1k = (Ether(dst=self.pg0.local_mac,
2870 src=self.pg0.remote_mac) /
2871 IP(src=self.pg0.remote_ip4,
2872 dst=self.pg1.remote_hosts[2].ip4) /
2873 UDP(sport=1234, dport=5678) /
2876 nbr2 = VppNeighbor(self,
2877 self.pg1.sw_if_index,
2878 self.pg1.remote_hosts[2].mac,
2879 self.pg1.remote_hosts[2].ip4).add_vpp_config()
2881 # should frag to the path MTU
2882 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
2883 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
2885 # remove and re-add the neighbour
2886 nbr2.remove_vpp_config()
2887 nbr2.add_vpp_config()
2889 # should frag to the path MTU
2890 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
2891 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
2894 # set PMTUs for many peers
2897 self.pg1.generate_remote_hosts(16)
2898 self.pg1.configure_ipv4_neighbors()
2900 for h in range(N_HOSTS):
2901 pmtu = VppIpPathMtu(self, self.pg1.remote_hosts[h].ip4, 900)
2902 pmtu.add_vpp_config()
2903 self.assertTrue(pmtu.query_vpp_config())
2905 self.logger.info(self.vapi.cli("sh ip pmtu"))
2906 dump = list(self.vapi.vpp.details_iter(self.vapi.ip_path_mtu_get))
2907 self.assertEqual(N_HOSTS, len(dump))
2909 for h in range(N_HOSTS):
2910 p_2k[IP].dst = self.pg1.remote_hosts[h].ip4
2911 p_1k[IP].dst = self.pg1.remote_hosts[h].ip4
2913 # should frag to the path MTU
2914 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
2915 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
2918 class TestIPv4ItfRebind(VppTestCase):
2919 """ IPv4 Interface Bind w/ attached routes """
2922 super(TestIPv4ItfRebind, self).setUp()
2924 self.create_pg_interfaces(range(3))
2927 super(TestIPv4ItfRebind, self).tearDown()
2929 def test_rebind(self):
2930 """ Import to no import """
2933 tbl = VppIpTable(self, TABLE_ID).add_vpp_config()
2934 self.pg1.set_table_ip4(TABLE_ID)
2936 for i in self.pg_interfaces:
2941 # add an attached route via an pg0
2942 # in a different table. this prefix should import
2943 rt = VppIpRoute(self, self.pg0.local_ip4, 24,
2944 [VppRoutePath("0.0.0.0",
2945 self.pg0.sw_if_index)],
2946 table_id=TABLE_ID).add_vpp_config()
2948 p = (Ether(dst=self.pg1.local_mac,
2949 src=self.pg1.remote_mac) /
2950 IP(src=self.pg1.remote_ip4,
2951 dst=self.pg0.remote_ip4) /
2952 UDP(sport=1234, dport=5678) /
2955 rx = self.send_and_expect(self.pg1, [p], self.pg0)
2956 self.assertFalse(rx[0].haslayer(ARP))
2958 # then bind pg0 to a new table
2959 # so the prefix no longer imports
2960 self.pg0.unconfig_ip4()
2961 self.pg0.set_table_ip4(TABLE_ID)
2962 self.pg0.config_ip4()
2963 self.pg0.resolve_arp()
2965 rx = self.send_and_expect(self.pg1, [p], self.pg0)
2966 self.assertFalse(rx[0].haslayer(ARP))
2968 # revert back to imported
2969 self.pg0.unconfig_ip4()
2970 self.pg0.set_table_ip4(0)
2971 self.pg0.config_ip4()
2972 self.pg0.resolve_arp()
2974 rx = self.send_and_expect(self.pg1, [p], self.pg0)
2975 self.assertFalse(rx[0].haslayer(ARP))
2978 for i in self.pg_interfaces:
2983 rt.remove_vpp_config()
2984 tbl.remove_vpp_config()
2986 def test_delete(self):
2987 """ Swap import tables """
2990 tbl1_4 = VppIpTable(self, TABLE_ID1).add_vpp_config()
2991 tbl1_6 = VppIpTable(self, TABLE_ID1, True).add_vpp_config()
2993 tbl2_4 = VppIpTable(self, TABLE_ID2).add_vpp_config()
2994 tbl2_6 = VppIpTable(self, TABLE_ID2, True).add_vpp_config()
2997 self.pg1.set_table_ip4(TABLE_ID1)
2998 self.pg1.set_table_ip6(TABLE_ID1)
2999 self.pg2.set_table_ip4(TABLE_ID2)
3000 self.pg2.set_table_ip6(TABLE_ID2)
3002 for i in self.pg_interfaces:
3007 # add an attached route in the default table via pg0
3008 # this should import to table 1
3009 rt4 = VppIpRoute(self, self.pg1.local_ip4, 24,
3010 [VppRoutePath("0.0.0.0",
3011 self.pg1.sw_if_index)]).add_vpp_config()
3012 rt6 = VppIpRoute(self, self.pg1.local_ip6, 64,
3013 [VppRoutePath("0.0.0.0",
3014 self.pg1.sw_if_index)]).add_vpp_config()
3016 p1 = (Ether(dst=self.pg0.local_mac,
3017 src=self.pg0.remote_mac) /
3018 IP(src=self.pg1.remote_ip4,
3019 dst=self.pg1.remote_ip4) /
3020 UDP(sport=1234, dport=5678) /
3023 # inject into table 0
3024 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
3025 self.assertFalse(rx[0].haslayer(ARP))
3027 # swap the attached interface to table 2
3028 self.pg1.unconfig_ip4()
3029 self.pg1.unconfig_ip6()
3030 self.pg1.set_table_ip4(TABLE_ID2)
3031 self.pg1.set_table_ip6(TABLE_ID2)
3032 self.pg1.config_ip4()
3033 self.pg1.config_ip6()
3034 self.pg1.resolve_arp()
3039 tbl1_4.remove_vpp_config()
3040 tbl1_6.remove_vpp_config()
3042 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
3043 self.assertFalse(rx[0].haslayer(ARP))
3045 for i in self.pg_interfaces:
3053 if __name__ == '__main__':
3054 unittest.main(testRunner=VppTestRunner)