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 (
28 VppIpInterfaceAddress,
32 from vpp_ip import VppIpPuntPolicer, VppIpPuntRedirect, VppIpPathMtu
33 from vpp_sub_interface import VppSubInterface, VppDot1QSubint, VppDot1ADSubint
34 from vpp_papi import vpp_papi, VppEnum
35 from vpp_neighbor import VppNeighbor
36 from vpp_lo_interface import VppLoInterface
37 from vpp_policer import VppPolicer, PolicerAction
42 class TestIPv4(VppTestCase):
47 super(TestIPv4, cls).setUpClass()
50 def tearDownClass(cls):
51 super(TestIPv4, cls).tearDownClass()
55 Perform test setup before test case.
58 - create 3 pg interfaces
59 - untagged pg0 interface
60 - Dot1Q subinterface on pg1
61 - Dot1AD subinterface on pg2
63 - put it into UP state
65 - resolve neighbor address using ARP
66 - configure 200 fib entries
68 :ivar list interfaces: pg interfaces and subinterfaces.
69 :ivar dict flows: IPv4 packet flows in test.
71 super(TestIPv4, self).setUp()
73 # create 3 pg interfaces
74 self.create_pg_interfaces(range(3))
76 # create 2 subinterfaces for pg1 and pg2
77 self.sub_interfaces = [
78 VppDot1QSubint(self, self.pg1, 100),
79 VppDot1ADSubint(self, self.pg2, 200, 300, 400),
82 # packet flows mapping pg0 -> pg1.sub, pg2.sub, etc.
84 self.flows[self.pg0] = [self.pg1.sub_if, self.pg2.sub_if]
85 self.flows[self.pg1.sub_if] = [self.pg0, self.pg2.sub_if]
86 self.flows[self.pg2.sub_if] = [self.pg0, self.pg1.sub_if]
89 self.pg_if_packet_sizes = [64, 1500, 9020]
91 self.interfaces = list(self.pg_interfaces)
92 self.interfaces.extend(self.sub_interfaces)
94 # setup all interfaces
95 for i in self.interfaces:
100 # config 2M FIB entries
103 """Run standard test teardown and log ``show ip arp``."""
104 super(TestIPv4, self).tearDown()
106 def show_commands_at_teardown(self):
107 self.logger.info(self.vapi.cli("show ip4 neighbors"))
108 # info(self.vapi.cli("show ip fib")) # many entries
110 def modify_packet(self, src_if, packet_size, pkt):
111 """Add load, set destination IP and extend packet to required packet
112 size for defined interface.
114 :param VppInterface src_if: Interface to create packet for.
115 :param int packet_size: Required packet size.
116 :param Scapy pkt: Packet to be modified.
118 dst_if_idx = int(packet_size / 10 % 2)
119 dst_if = self.flows[src_if][dst_if_idx]
120 info = self.create_packet_info(src_if, dst_if)
121 payload = self.info_to_payload(info)
122 p = pkt / Raw(payload)
123 p[IP].dst = dst_if.remote_ip4
125 if isinstance(src_if, VppSubInterface):
126 p = src_if.add_dot1_layer(p)
127 self.extend_packet(p, packet_size)
131 def create_stream(self, src_if):
132 """Create input packet stream for defined interface.
134 :param VppInterface src_if: Interface to create packet stream for.
136 hdr_ext = 4 if isinstance(src_if, VppSubInterface) else 0
138 Ether(dst=src_if.local_mac, src=src_if.remote_mac)
139 / IP(src=src_if.remote_ip4)
140 / UDP(sport=1234, dport=1234)
144 self.modify_packet(src_if, i, pkt_tmpl)
145 for i in moves.range(
146 self.pg_if_packet_sizes[0], self.pg_if_packet_sizes[1], 10
150 self.modify_packet(src_if, i, pkt_tmpl)
151 for i in moves.range(
152 self.pg_if_packet_sizes[1] + hdr_ext,
153 self.pg_if_packet_sizes[2] + hdr_ext,
161 def verify_capture(self, dst_if, capture):
162 """Verify captured input packet stream for defined interface.
164 :param VppInterface dst_if: Interface to verify captured packet stream
166 :param list capture: Captured packet stream.
168 self.logger.info("Verifying capture on interface %s" % dst_if.name)
170 for i in self.interfaces:
171 last_info[i.sw_if_index] = None
173 dst_sw_if_index = dst_if.sw_if_index
174 if hasattr(dst_if, "parent"):
176 for packet in capture:
178 # Check VLAN tags and Ethernet header
179 packet = dst_if.remove_dot1_layer(packet)
180 self.assertTrue(Dot1Q not in packet)
184 payload_info = self.payload_to_info(packet[Raw])
185 packet_index = payload_info.index
186 self.assertEqual(payload_info.dst, dst_sw_if_index)
188 "Got packet on port %s: src=%u (id=%u)"
189 % (dst_if.name, payload_info.src, packet_index)
191 next_info = self.get_next_packet_info_for_interface2(
192 payload_info.src, dst_sw_if_index, last_info[payload_info.src]
194 last_info[payload_info.src] = next_info
195 self.assertTrue(next_info is not None)
196 self.assertEqual(packet_index, next_info.index)
197 saved_packet = next_info.data
198 # Check standard fields
199 self.assertEqual(ip.src, saved_packet[IP].src)
200 self.assertEqual(ip.dst, saved_packet[IP].dst)
201 self.assertEqual(udp.sport, saved_packet[UDP].sport)
202 self.assertEqual(udp.dport, saved_packet[UDP].dport)
204 self.logger.error(ppp("Unexpected or invalid packet:", packet))
206 for i in self.interfaces:
207 remaining_packet = self.get_next_packet_info_for_interface2(
208 i.sw_if_index, dst_sw_if_index, last_info[i.sw_if_index]
211 remaining_packet is None,
212 "Interface %s: Packet expected from interface %s "
213 "didn't arrive" % (dst_if.name, i.name),
221 - Create IPv4 stream for pg0 interface
222 - Create IPv4 tagged streams for pg1's and pg2's sub-interface.
223 - Send and verify received packets on each interface.
226 pkts = self.create_stream(self.pg0)
227 self.pg0.add_stream(pkts)
229 for i in self.sub_interfaces:
230 pkts = self.create_stream(i)
231 i.parent.add_stream(pkts)
233 self.pg_enable_capture(self.pg_interfaces)
236 pkts = self.pg0.get_capture()
237 self.verify_capture(self.pg0, pkts)
239 for i in self.sub_interfaces:
240 pkts = i.parent.get_capture()
241 self.verify_capture(i, pkts)
244 class TestIPv4RouteLookup(VppTestCase):
245 """IPv4 Route Lookup Test Case"""
249 def route_lookup(self, prefix, exact):
250 return self.vapi.api(
251 self.vapi.papi.ip_route_lookup,
261 super(TestIPv4RouteLookup, cls).setUpClass()
264 def tearDownClass(cls):
265 super(TestIPv4RouteLookup, cls).tearDownClass()
268 super(TestIPv4RouteLookup, self).setUp()
270 drop_nh = VppRoutePath(
271 "127.0.0.1", 0xFFFFFFFF, type=FibPathType.FIB_PATH_TYPE_DROP
275 r = VppIpRoute(self, "1.1.0.0", 16, [drop_nh])
277 self.routes.append(r)
279 r = VppIpRoute(self, "1.1.1.0", 24, [drop_nh])
281 self.routes.append(r)
283 r = VppIpRoute(self, "1.1.1.1", 32, [drop_nh])
285 self.routes.append(r)
288 # Remove the routes we added
289 for r in self.routes:
290 r.remove_vpp_config()
292 super(TestIPv4RouteLookup, self).tearDown()
294 def test_exact_match(self):
295 # Verify we find the host route
296 prefix = "1.1.1.1/32"
297 result = self.route_lookup(prefix, True)
298 assert prefix == str(result.route.prefix)
300 # Verify we find a middle prefix route
301 prefix = "1.1.1.0/24"
302 result = self.route_lookup(prefix, True)
303 assert prefix == str(result.route.prefix)
305 # Verify we do not find an available LPM.
306 with self.vapi.assert_negative_api_retval():
307 self.route_lookup("1.1.1.2/32", True)
309 def test_longest_prefix_match(self):
311 lpm_prefix = "1.1.1.0/24"
312 result = self.route_lookup("1.1.1.2/32", False)
313 assert lpm_prefix == str(result.route.prefix)
315 # Verify we find the exact when not requested
316 result = self.route_lookup(lpm_prefix, False)
317 assert lpm_prefix == str(result.route.prefix)
319 # Can't seem to delete the default route so no negative LPM test.
322 class TestIPv4IfAddrRoute(VppTestCase):
323 """IPv4 Interface Addr Route Test Case"""
327 super(TestIPv4IfAddrRoute, cls).setUpClass()
330 def tearDownClass(cls):
331 super(TestIPv4IfAddrRoute, cls).tearDownClass()
334 super(TestIPv4IfAddrRoute, self).setUp()
336 # create 1 pg interface
337 self.create_pg_interfaces(range(1))
339 for i in self.pg_interfaces:
345 super(TestIPv4IfAddrRoute, self).tearDown()
346 for i in self.pg_interfaces:
350 def test_ipv4_ifaddrs_same_prefix(self):
351 """IPv4 Interface Addresses Same Prefix test
355 - Verify no route in FIB for prefix 10.10.10.0/24
356 - Configure IPv4 address 10.10.10.10/24 on an interface
357 - Verify route in FIB for prefix 10.10.10.0/24
358 - Configure IPv4 address 10.10.10.20/24 on an interface
359 - Delete 10.10.10.10/24 from interface
360 - Verify route in FIB for prefix 10.10.10.0/24
361 - Delete 10.10.10.20/24 from interface
362 - Verify no route in FIB for prefix 10.10.10.0/24
365 # create two addresses, verify route not present
366 if_addr1 = VppIpInterfaceAddress(self, self.pg0, "10.10.10.10", 24)
367 if_addr2 = VppIpInterfaceAddress(self, self.pg0, "10.10.10.20", 24)
368 self.assertFalse(if_addr1.query_vpp_config()) # 10.10.10.10/24
369 self.assertFalse(find_route(self, "10.10.10.10", 32))
370 self.assertFalse(find_route(self, "10.10.10.20", 32))
371 self.assertFalse(find_route(self, "10.10.10.255", 32))
372 self.assertFalse(find_route(self, "10.10.10.0", 32))
374 # configure first address, verify route present
375 if_addr1.add_vpp_config()
376 self.assertTrue(if_addr1.query_vpp_config()) # 10.10.10.10/24
377 self.assertTrue(find_route(self, "10.10.10.10", 32))
378 self.assertFalse(find_route(self, "10.10.10.20", 32))
379 self.assertTrue(find_route(self, "10.10.10.255", 32))
380 self.assertTrue(find_route(self, "10.10.10.0", 32))
382 # configure second address, delete first, verify route not removed
383 if_addr2.add_vpp_config()
384 if_addr1.remove_vpp_config()
385 self.assertFalse(if_addr1.query_vpp_config()) # 10.10.10.10/24
386 self.assertTrue(if_addr2.query_vpp_config()) # 10.10.10.20/24
387 self.assertFalse(find_route(self, "10.10.10.10", 32))
388 self.assertTrue(find_route(self, "10.10.10.20", 32))
389 self.assertTrue(find_route(self, "10.10.10.255", 32))
390 self.assertTrue(find_route(self, "10.10.10.0", 32))
392 # delete second address, verify route removed
393 if_addr2.remove_vpp_config()
394 self.assertFalse(if_addr2.query_vpp_config()) # 10.10.10.20/24
395 self.assertFalse(find_route(self, "10.10.10.10", 32))
396 self.assertFalse(find_route(self, "10.10.10.20", 32))
397 self.assertFalse(find_route(self, "10.10.10.255", 32))
398 self.assertFalse(find_route(self, "10.10.10.0", 32))
400 def test_ipv4_ifaddr_route(self):
401 """IPv4 Interface Address Route test
406 - Configure IPv4 address on loopback
407 - Verify that address is not in the FIB
409 - Verify that address is in the FIB now
410 - Bring loopback down
411 - Verify that address is not in the FIB anymore
413 - Configure IPv4 address on loopback
414 - Verify that address is in the FIB now
417 # create a loopback and configure IPv4
418 loopbacks = self.create_loopback_interfaces(1)
419 lo_if = self.lo_interfaces[0]
421 lo_if.local_ip4_prefix_len = 32
424 # The intf was down when addr was added -> entry not in FIB
425 fib4_dump = self.vapi.ip_route_dump(0)
426 self.assertFalse(lo_if.is_ip4_entry_in_fib_dump(fib4_dump))
428 # When intf is brought up, entry is added
430 fib4_dump = self.vapi.ip_route_dump(0)
431 self.assertTrue(lo_if.is_ip4_entry_in_fib_dump(fib4_dump))
433 # When intf is brought down, entry is removed
435 fib4_dump = self.vapi.ip_route_dump(0)
436 self.assertFalse(lo_if.is_ip4_entry_in_fib_dump(fib4_dump))
438 # Remove addr, bring up interface, re-add -> entry in FIB
442 fib4_dump = self.vapi.ip_route_dump(0)
443 self.assertTrue(lo_if.is_ip4_entry_in_fib_dump(fib4_dump))
445 def test_ipv4_ifaddr_del(self):
446 """Delete an interface address that does not exist"""
448 loopbacks = self.create_loopback_interfaces(1)
449 lo = self.lo_interfaces[0]
455 # try and remove pg0's subnet from lo
457 with self.vapi.assert_negative_api_retval():
458 self.vapi.sw_interface_add_del_address(
459 sw_if_index=lo.sw_if_index, prefix=self.pg0.local_ip4_prefix, is_add=0
463 class TestICMPEcho(VppTestCase):
464 """ICMP Echo Test Case"""
468 super(TestICMPEcho, cls).setUpClass()
471 def tearDownClass(cls):
472 super(TestICMPEcho, cls).tearDownClass()
475 super(TestICMPEcho, self).setUp()
477 # create 1 pg interface
478 self.create_pg_interfaces(range(1))
480 for i in self.pg_interfaces:
486 super(TestICMPEcho, self).tearDown()
487 for i in self.pg_interfaces:
491 def test_icmp_echo(self):
492 """VPP replies to ICMP Echo Request
496 - Receive ICMP Echo Request message on pg0 interface.
497 - Check outgoing ICMP Echo Reply message on pg0 interface.
502 icmp_load = b"\x0a" * 18
504 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
505 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
506 / ICMP(id=icmp_id, seq=icmp_seq)
507 / Raw(load=icmp_load)
510 self.pg0.add_stream(p_echo_request)
511 self.pg_enable_capture(self.pg_interfaces)
514 rx = self.pg0.get_capture(1)
520 self.assertEqual(ether.src, self.pg0.local_mac)
521 self.assertEqual(ether.dst, self.pg0.remote_mac)
523 self.assertEqual(ipv4.src, self.pg0.local_ip4)
524 self.assertEqual(ipv4.dst, self.pg0.remote_ip4)
526 self.assertEqual(icmptypes[icmp.type], "echo-reply")
527 self.assertEqual(icmp.id, icmp_id)
528 self.assertEqual(icmp.seq, icmp_seq)
529 self.assertEqual(icmp[Raw].load, icmp_load)
532 class TestIPv4FibCrud(VppTestCase):
533 """FIB - add/update/delete - ip4 routes
541 ..note:: Python API is too slow to add many routes, needs replacement.
544 def config_fib_many_to_one(self, start_dest_addr, next_hop_addr, count, start=0):
547 :param start_dest_addr:
548 :param next_hop_addr:
550 :return list: added ips with 32 prefix
553 for i in range(count):
556 start_dest_addr % (i + start),
558 [VppRoutePath(next_hop_addr, 0xFFFFFFFF)],
564 def unconfig_fib_many_to_one(self, start_dest_addr, next_hop_addr, count, start=0):
567 for i in range(count):
570 start_dest_addr % (i + start),
572 [VppRoutePath(next_hop_addr, 0xFFFFFFFF)],
574 r.remove_vpp_config()
578 def create_stream(self, src_if, dst_if, routes, count):
581 for _ in range(count):
582 dst_addr = random.choice(routes).prefix.network_address
583 info = self.create_packet_info(src_if, dst_if)
584 payload = self.info_to_payload(info)
586 Ether(dst=src_if.local_mac, src=src_if.remote_mac)
587 / IP(src=src_if.remote_ip4, dst=str(dst_addr))
588 / UDP(sport=1234, dport=1234)
592 self.extend_packet(p, random.choice(self.pg_if_packet_sizes))
597 def _find_ip_match(self, find_in, pkt):
599 if self.payload_to_info(p[Raw]) == self.payload_to_info(pkt[Raw]):
600 if p[IP].src != pkt[IP].src:
602 if p[IP].dst != pkt[IP].dst:
604 if p[UDP].sport != pkt[UDP].sport:
606 if p[UDP].dport != pkt[UDP].dport:
611 def verify_capture(self, dst_interface, received_pkts, expected_pkts):
612 self.assertEqual(len(received_pkts), len(expected_pkts))
613 to_verify = list(expected_pkts)
614 for p in received_pkts:
615 self.assertEqual(p.src, dst_interface.local_mac)
616 self.assertEqual(p.dst, dst_interface.remote_mac)
617 x = self._find_ip_match(to_verify, p)
619 self.assertListEqual(to_verify, [])
621 def verify_route_dump(self, routes):
624 find_route(self, r.prefix.network_address, r.prefix.prefixlen)
627 def verify_not_in_route_dump(self, routes):
630 find_route(self, r.prefix.network_address, r.prefix.prefixlen)
636 #. Create and initialize 3 pg interfaces.
637 #. initialize class attributes configured_routes and deleted_routes
638 to store information between tests.
640 super(TestIPv4FibCrud, cls).setUpClass()
643 # create 3 pg interfaces
644 cls.create_pg_interfaces(range(3))
646 cls.interfaces = list(cls.pg_interfaces)
648 # setup all interfaces
649 for i in cls.interfaces:
654 cls.configured_routes = []
655 cls.deleted_routes = []
656 cls.pg_if_packet_sizes = [64, 512, 1518, 9018]
659 super(TestIPv4FibCrud, cls).tearDownClass()
663 def tearDownClass(cls):
664 super(TestIPv4FibCrud, cls).tearDownClass()
667 super(TestIPv4FibCrud, self).setUp()
668 self.reset_packet_infos()
670 self.configured_routes = []
671 self.deleted_routes = []
673 def test_1_add_routes(self):
676 # add 100 routes check with traffic script.
677 self.configured_routes.extend(
678 self.config_fib_many_to_one("10.0.0.%d", self.pg0.remote_ip4, 100)
681 self.verify_route_dump(self.configured_routes)
683 self.stream_1 = self.create_stream(
684 self.pg1, self.pg0, self.configured_routes, 100
686 self.stream_2 = self.create_stream(
687 self.pg2, self.pg0, self.configured_routes, 100
689 self.pg1.add_stream(self.stream_1)
690 self.pg2.add_stream(self.stream_2)
692 self.pg_enable_capture(self.pg_interfaces)
695 pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
696 self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
698 def test_2_del_routes(self):
701 - delete 10 routes check with traffic script.
703 # config 1M FIB entries
704 self.configured_routes.extend(
705 self.config_fib_many_to_one("10.0.0.%d", self.pg0.remote_ip4, 100)
707 self.deleted_routes.extend(
708 self.unconfig_fib_many_to_one(
709 "10.0.0.%d", self.pg0.remote_ip4, 10, start=10
712 for x in self.deleted_routes:
713 self.configured_routes.remove(x)
715 self.verify_route_dump(self.configured_routes)
717 self.stream_1 = self.create_stream(
718 self.pg1, self.pg0, self.configured_routes, 100
720 self.stream_2 = self.create_stream(
721 self.pg2, self.pg0, self.configured_routes, 100
723 self.stream_3 = self.create_stream(self.pg1, self.pg0, self.deleted_routes, 100)
724 self.stream_4 = self.create_stream(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 def test_3_add_new_routes(self):
736 - re-add 5 routes check with traffic script.
737 - add 100 routes check with traffic script.
739 # config 1M FIB entries
740 self.configured_routes.extend(
741 self.config_fib_many_to_one("10.0.0.%d", self.pg0.remote_ip4, 100)
743 self.deleted_routes.extend(
744 self.unconfig_fib_many_to_one(
745 "10.0.0.%d", self.pg0.remote_ip4, 10, start=10
748 for x in self.deleted_routes:
749 self.configured_routes.remove(x)
751 tmp = self.config_fib_many_to_one("10.0.0.%d", self.pg0.remote_ip4, 5, start=10)
752 self.configured_routes.extend(tmp)
754 self.deleted_routes.remove(x)
756 self.configured_routes.extend(
757 self.config_fib_many_to_one("10.0.1.%d", self.pg0.remote_ip4, 100)
760 self.verify_route_dump(self.configured_routes)
762 self.stream_1 = self.create_stream(
763 self.pg1, self.pg0, self.configured_routes, 300
765 self.stream_2 = self.create_stream(
766 self.pg2, self.pg0, self.configured_routes, 300
768 self.stream_3 = self.create_stream(self.pg1, self.pg0, self.deleted_routes, 100)
769 self.stream_4 = self.create_stream(self.pg2, self.pg0, self.deleted_routes, 100)
771 self.pg1.add_stream(self.stream_1 + self.stream_3)
772 self.pg2.add_stream(self.stream_2 + self.stream_4)
773 self.pg_enable_capture(self.pg_interfaces)
776 pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
777 self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
779 # delete 5 routes check with traffic script.
780 # add 100 routes check with traffic script.
781 self.deleted_routes.extend(
782 self.unconfig_fib_many_to_one("10.0.0.%d", self.pg0.remote_ip4, 15)
784 self.deleted_routes.extend(
785 self.unconfig_fib_many_to_one("10.0.0.%d", self.pg0.remote_ip4, 85)
787 self.deleted_routes.extend(
788 self.unconfig_fib_many_to_one("10.0.1.%d", self.pg0.remote_ip4, 100)
790 self.verify_not_in_route_dump(self.deleted_routes)
793 class TestIPNull(VppTestCase):
794 """IPv4 routes via NULL"""
798 super(TestIPNull, cls).setUpClass()
801 def tearDownClass(cls):
802 super(TestIPNull, cls).tearDownClass()
805 super(TestIPNull, self).setUp()
807 # create 2 pg interfaces
808 self.create_pg_interfaces(range(2))
810 for i in self.pg_interfaces:
816 super(TestIPNull, self).tearDown()
817 for i in self.pg_interfaces:
821 def test_ip_null(self):
825 # A route via IP NULL that will reply with ICMP unreachables
827 ip_unreach = VppIpRoute(
833 "0.0.0.0", 0xFFFFFFFF, type=FibPathType.FIB_PATH_TYPE_ICMP_UNREACH
837 ip_unreach.add_vpp_config()
840 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
841 / IP(src=self.pg0.remote_ip4, dst="10.0.0.1")
842 / UDP(sport=1234, dport=1234)
845 self.pg0.add_stream(p_unreach)
846 self.pg_enable_capture(self.pg_interfaces)
849 rx = self.pg0.get_capture(1)
853 self.assertEqual(icmptypes[icmp.type], "dest-unreach")
854 self.assertEqual(icmpcodes[icmp.type][icmp.code], "host-unreachable")
855 self.assertEqual(icmp.src, self.pg0.remote_ip4)
856 self.assertEqual(icmp.dst, "10.0.0.1")
859 # ICMP replies are rate limited. so sit and spin.
864 # A route via IP NULL that will reply with ICMP prohibited
866 ip_prohibit = VppIpRoute(
872 "0.0.0.0", 0xFFFFFFFF, type=FibPathType.FIB_PATH_TYPE_ICMP_PROHIBIT
876 ip_prohibit.add_vpp_config()
879 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
880 / IP(src=self.pg0.remote_ip4, dst="10.0.0.2")
881 / UDP(sport=1234, dport=1234)
885 self.pg0.add_stream(p_prohibit)
886 self.pg_enable_capture(self.pg_interfaces)
889 rx = self.pg0.get_capture(1)
894 self.assertEqual(icmptypes[icmp.type], "dest-unreach")
895 self.assertEqual(icmpcodes[icmp.type][icmp.code], "host-prohibited")
896 self.assertEqual(icmp.src, self.pg0.remote_ip4)
897 self.assertEqual(icmp.dst, "10.0.0.2")
899 def test_ip_drop(self):
903 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
904 / IP(src=self.pg0.remote_ip4, dst="1.1.1.1")
905 / UDP(sport=1234, dport=1234)
913 [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)],
917 rx = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg1)
920 # insert a more specific as a drop
926 [VppRoutePath("0.0.0.0", 0xFFFFFFFF, type=FibPathType.FIB_PATH_TYPE_DROP)],
930 self.send_and_assert_no_replies(self.pg0, p * NUM_PKTS, "Drop Route")
931 r2.remove_vpp_config()
932 rx = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg1)
935 class TestIPDisabled(VppTestCase):
940 super(TestIPDisabled, cls).setUpClass()
943 def tearDownClass(cls):
944 super(TestIPDisabled, cls).tearDownClass()
947 super(TestIPDisabled, self).setUp()
949 # create 2 pg interfaces
950 self.create_pg_interfaces(range(2))
954 self.pg0.config_ip4()
955 self.pg0.resolve_arp()
957 # PG 1 is not IP enabled
961 super(TestIPDisabled, self).tearDown()
962 for i in self.pg_interfaces:
966 def test_ip_disabled(self):
969 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
970 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
974 # one accepting interface, pg0, 2 forwarding interfaces
976 route_232_1_1_1 = VppIpMRoute(
981 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
984 self.pg1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
987 self.pg0.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
991 route_232_1_1_1.add_vpp_config()
994 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
995 / IP(src="10.10.10.10", dst=self.pg0.remote_ip4)
996 / UDP(sport=1234, dport=1234)
1000 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
1001 / IP(src="10.10.10.10", dst="232.1.1.1")
1002 / UDP(sport=1234, dport=1234)
1003 / Raw(b"\xa5" * 100)
1007 # PG1 does not forward IP traffic
1009 self.send_and_assert_no_replies(self.pg1, pu, "IP disabled")
1010 self.send_and_assert_no_replies(self.pg1, pm, "IP disabled")
1015 self.pg1.config_ip4()
1018 # Now we get packets through
1020 self.pg1.add_stream(pu)
1021 self.pg_enable_capture(self.pg_interfaces)
1023 rx = self.pg0.get_capture(1)
1025 self.pg1.add_stream(pm)
1026 self.pg_enable_capture(self.pg_interfaces)
1028 rx = self.pg0.get_capture(1)
1033 self.pg1.unconfig_ip4()
1036 # PG1 does not forward IP traffic
1038 self.send_and_assert_no_replies(self.pg1, pu, "IP disabled")
1039 self.send_and_assert_no_replies(self.pg1, pm, "IP disabled")
1042 class TestIPSubNets(VppTestCase):
1046 def setUpClass(cls):
1047 super(TestIPSubNets, cls).setUpClass()
1050 def tearDownClass(cls):
1051 super(TestIPSubNets, cls).tearDownClass()
1054 super(TestIPSubNets, self).setUp()
1056 # create a 2 pg interfaces
1057 self.create_pg_interfaces(range(2))
1059 # pg0 we will use to experiment
1062 # pg1 is setup normally
1064 self.pg1.config_ip4()
1065 self.pg1.resolve_arp()
1068 super(TestIPSubNets, self).tearDown()
1069 for i in self.pg_interfaces:
1072 def test_ip_sub_nets(self):
1076 # Configure a covering route to forward so we know
1077 # when we are dropping
1079 cover_route = VppIpRoute(
1083 [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)],
1085 cover_route.add_vpp_config()
1088 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
1089 / IP(dst="10.10.10.10", src=self.pg0.local_ip4)
1090 / UDP(sport=1234, dport=1234)
1091 / Raw(b"\xa5" * 100)
1094 self.pg1.add_stream(p)
1095 self.pg_enable_capture(self.pg_interfaces)
1097 rx = self.pg1.get_capture(1)
1100 # Configure some non-/24 subnets on an IP interface
1102 ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10")
1104 self.vapi.sw_interface_add_del_address(
1105 sw_if_index=self.pg0.sw_if_index, prefix="10.10.10.10/16"
1109 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
1110 / IP(dst="10.10.0.0", src=self.pg0.local_ip4)
1111 / UDP(sport=1234, dport=1234)
1112 / Raw(b"\xa5" * 100)
1115 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
1116 / IP(dst="10.10.255.255", src=self.pg0.local_ip4)
1117 / UDP(sport=1234, dport=1234)
1118 / Raw(b"\xa5" * 100)
1121 self.send_and_assert_no_replies(self.pg1, pn, "IP Network address")
1122 self.send_and_assert_no_replies(self.pg1, pb, "IP Broadcast address")
1124 # remove the sub-net and we are forwarding via the cover again
1125 self.vapi.sw_interface_add_del_address(
1126 sw_if_index=self.pg0.sw_if_index, prefix="10.10.10.10/16", is_add=0
1129 self.pg1.add_stream(pn)
1130 self.pg_enable_capture(self.pg_interfaces)
1132 rx = self.pg1.get_capture(1)
1133 self.pg1.add_stream(pb)
1134 self.pg_enable_capture(self.pg_interfaces)
1136 rx = self.pg1.get_capture(1)
1139 # A /31 is a special case where the 'other-side' is an attached host
1140 # packets to that peer generate ARP requests
1142 ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10")
1144 self.vapi.sw_interface_add_del_address(
1145 sw_if_index=self.pg0.sw_if_index, prefix="10.10.10.10/31"
1149 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
1150 / IP(dst="10.10.10.11", src=self.pg0.local_ip4)
1151 / UDP(sport=1234, dport=1234)
1152 / Raw(b"\xa5" * 100)
1155 self.pg1.add_stream(pn)
1156 self.pg_enable_capture(self.pg_interfaces)
1158 rx = self.pg0.get_capture(1)
1161 # remove the sub-net and we are forwarding via the cover again
1162 self.vapi.sw_interface_add_del_address(
1163 sw_if_index=self.pg0.sw_if_index, prefix="10.10.10.10/31", is_add=0
1166 self.pg1.add_stream(pn)
1167 self.pg_enable_capture(self.pg_interfaces)
1169 rx = self.pg1.get_capture(1)
1172 class TestIPLoadBalance(VppTestCase):
1173 """IPv4 Load-Balancing"""
1176 def setUpClass(cls):
1177 super(TestIPLoadBalance, cls).setUpClass()
1180 def tearDownClass(cls):
1181 super(TestIPLoadBalance, cls).tearDownClass()
1184 super(TestIPLoadBalance, self).setUp()
1186 self.create_pg_interfaces(range(5))
1187 mpls_tbl = VppMplsTable(self, 0)
1188 mpls_tbl.add_vpp_config()
1190 for i in self.pg_interfaces:
1197 for i in self.pg_interfaces:
1201 super(TestIPLoadBalance, self).tearDown()
1203 def total_len(self, rxs):
1209 def test_ip_load_balance(self):
1210 """IP Load-Balancing"""
1212 fhc = VppEnum.vl_api_ip_flow_hash_config_t
1213 af = VppEnum.vl_api_address_family_t
1216 # An array of packets that differ only in the destination port
1222 # An array of packets that differ only in the source address
1227 for ii in range(NUM_PKTS):
1229 IP(dst="10.0.0.1", src="20.0.0.1")
1230 / UDP(sport=1234, dport=1234 + ii)
1231 / Raw(b"\xa5" * 100)
1233 port_ip_pkts.append(
1234 (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / port_ip_hdr)
1236 port_mpls_pkts.append(
1238 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1239 / MPLS(label=66, ttl=2)
1245 IP(dst="10.0.0.1", src="20.0.0.%d" % ii)
1246 / UDP(sport=1234, dport=1234)
1247 / Raw(b"\xa5" * 100)
1250 (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / src_ip_hdr)
1252 src_mpls_pkts.append(
1254 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1255 / MPLS(label=66, ttl=2)
1260 route_10_0_0_1 = VppIpRoute(
1265 VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index),
1266 VppRoutePath(self.pg2.remote_ip4, self.pg2.sw_if_index),
1269 route_10_0_0_1.add_vpp_config()
1271 binding = VppMplsIpBind(self, 66, "10.0.0.1", 32)
1272 binding.add_vpp_config()
1275 # inject the packet on pg0 - expect load-balancing across the 2 paths
1276 # - since the default hash config is to use IP src,dst and port
1278 # We are not going to ensure equal amounts of packets across each link,
1279 # since the hash algorithm is statistical and therefore this can never
1280 # be guaranteed. But with 64 different packets we do expect some
1281 # balancing. So instead just ensure there is traffic on each link.
1283 rx = self.send_and_expect_load_balancing(
1284 self.pg0, port_ip_pkts, [self.pg1, self.pg2]
1286 n_ip_pg0 = len(rx[0])
1287 self.send_and_expect_load_balancing(self.pg0, src_ip_pkts, [self.pg1, self.pg2])
1288 self.send_and_expect_load_balancing(
1289 self.pg0, port_mpls_pkts, [self.pg1, self.pg2]
1291 rx = self.send_and_expect_load_balancing(
1292 self.pg0, src_mpls_pkts, [self.pg1, self.pg2]
1294 n_mpls_pg0 = len(rx[0])
1297 # change the router ID and expect the distribution changes
1299 self.vapi.set_ip_flow_hash_router_id(router_id=0x11111111)
1301 rx = self.send_and_expect_load_balancing(
1302 self.pg0, port_ip_pkts, [self.pg1, self.pg2]
1304 self.assertNotEqual(n_ip_pg0, len(rx[0]))
1306 rx = self.send_and_expect_load_balancing(
1307 self.pg0, src_mpls_pkts, [self.pg1, self.pg2]
1309 self.assertNotEqual(n_mpls_pg0, len(rx[0]))
1312 # change the flow hash config so it's only IP src,dst
1313 # - now only the stream with differing source address will
1316 self.vapi.set_ip_flow_hash_v2(
1320 fhc.IP_API_FLOW_HASH_SRC_IP
1321 | fhc.IP_API_FLOW_HASH_DST_IP
1322 | fhc.IP_API_FLOW_HASH_PROTO
1326 self.send_and_expect_load_balancing(self.pg0, src_ip_pkts, [self.pg1, self.pg2])
1327 self.send_and_expect_load_balancing(
1328 self.pg0, src_mpls_pkts, [self.pg1, self.pg2]
1331 self.send_and_expect_only(self.pg0, port_ip_pkts, self.pg2)
1334 # change the flow hash config back to defaults
1336 self.vapi.set_ip_flow_hash(vrf_id=0, src=1, dst=1, proto=1, sport=1, dport=1)
1339 # Recursive prefixes
1340 # - testing that 2 stages of load-balancing occurs and there is no
1341 # polarisation (i.e. only 2 of 4 paths are used)
1346 for ii in range(257):
1349 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1350 / IP(dst="1.1.1.1", src="20.0.0.1")
1351 / UDP(sport=1234, dport=1234 + ii)
1352 / Raw(b"\xa5" * 100)
1357 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1358 / IP(dst="1.1.1.1", src="20.0.0.%d" % ii)
1359 / UDP(sport=1234, dport=1234)
1360 / Raw(b"\xa5" * 100)
1364 route_10_0_0_2 = VppIpRoute(
1369 VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index),
1370 VppRoutePath(self.pg4.remote_ip4, self.pg4.sw_if_index),
1373 route_10_0_0_2.add_vpp_config()
1375 route_1_1_1_1 = VppIpRoute(
1380 VppRoutePath("10.0.0.2", 0xFFFFFFFF),
1381 VppRoutePath("10.0.0.1", 0xFFFFFFFF),
1384 route_1_1_1_1.add_vpp_config()
1387 # inject the packet on pg0 - expect load-balancing across all 4 paths
1389 self.vapi.cli("clear trace")
1390 self.send_and_expect_load_balancing(
1391 self.pg0, port_pkts, [self.pg1, self.pg2, self.pg3, self.pg4]
1393 self.send_and_expect_load_balancing(
1394 self.pg0, src_pkts, [self.pg1, self.pg2, self.pg3, self.pg4]
1398 # bring down pg1 expect LB to adjust to use only those that are up
1400 self.pg1.link_down()
1402 rx = self.send_and_expect_load_balancing(
1403 self.pg0, src_pkts, [self.pg2, self.pg3, self.pg4]
1405 self.assertEqual(len(src_pkts), self.total_len(rx))
1408 # bring down pg2 expect LB to adjust to use only those that are up
1410 self.pg2.link_down()
1412 rx = self.send_and_expect_load_balancing(
1413 self.pg0, src_pkts, [self.pg3, self.pg4]
1415 self.assertEqual(len(src_pkts), self.total_len(rx))
1418 # bring the links back up - expect LB over all again
1423 rx = self.send_and_expect_load_balancing(
1424 self.pg0, src_pkts, [self.pg1, self.pg2, self.pg3, self.pg4]
1426 self.assertEqual(len(src_pkts), self.total_len(rx))
1429 # The same link-up/down but this time admin state
1431 self.pg1.admin_down()
1432 self.pg2.admin_down()
1433 rx = self.send_and_expect_load_balancing(
1434 self.pg0, src_pkts, [self.pg3, self.pg4]
1436 self.assertEqual(len(src_pkts), self.total_len(rx))
1439 self.pg1.resolve_arp()
1440 self.pg2.resolve_arp()
1441 rx = self.send_and_expect_load_balancing(
1442 self.pg0, src_pkts, [self.pg1, self.pg2, self.pg3, self.pg4]
1444 self.assertEqual(len(src_pkts), self.total_len(rx))
1447 # Recursive prefixes
1448 # - testing that 2 stages of load-balancing, no choices
1452 for ii in range(257):
1455 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1456 / IP(dst="1.1.1.2", src="20.0.0.2")
1457 / UDP(sport=1234, dport=1234 + ii)
1458 / Raw(b"\xa5" * 100)
1462 route_10_0_0_3 = VppIpRoute(
1466 [VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index)],
1468 route_10_0_0_3.add_vpp_config()
1470 route_1_1_1_2 = VppIpRoute(
1471 self, "1.1.1.2", 32, [VppRoutePath("10.0.0.3", 0xFFFFFFFF)]
1473 route_1_1_1_2.add_vpp_config()
1476 # inject the packet on pg0 - rx only on via routes output interface
1478 self.vapi.cli("clear trace")
1479 self.send_and_expect_only(self.pg0, port_pkts, self.pg3)
1482 # Add a LB route in the presence of a down link - expect no
1483 # packets over the down link
1485 self.pg3.link_down()
1487 route_10_0_0_3 = VppIpRoute(
1492 VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index),
1493 VppRoutePath(self.pg4.remote_ip4, self.pg4.sw_if_index),
1496 route_10_0_0_3.add_vpp_config()
1499 for ii in range(257):
1501 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1502 / IP(dst="10.0.0.3", src="20.0.0.2")
1503 / UDP(sport=1234, dport=1234 + ii)
1504 / Raw(b"\xa5" * 100)
1507 self.send_and_expect_only(self.pg0, port_pkts, self.pg4)
1509 # bring the link back up
1512 rx = self.send_and_expect_load_balancing(
1513 self.pg0, port_pkts, [self.pg3, self.pg4]
1515 self.assertEqual(len(src_pkts), self.total_len(rx))
1518 class TestIPVlan0(VppTestCase):
1522 def setUpClass(cls):
1523 super(TestIPVlan0, cls).setUpClass()
1526 def tearDownClass(cls):
1527 super(TestIPVlan0, cls).tearDownClass()
1530 super(TestIPVlan0, self).setUp()
1532 self.create_pg_interfaces(range(2))
1533 mpls_tbl = VppMplsTable(self, 0)
1534 mpls_tbl.add_vpp_config()
1536 for i in self.pg_interfaces:
1543 for i in self.pg_interfaces:
1547 super(TestIPVlan0, self).tearDown()
1549 def test_ip_vlan_0(self):
1553 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1555 / IP(dst=self.pg1.remote_ip4, src=self.pg0.remote_ip4)
1556 / UDP(sport=1234, dport=1234)
1557 / Raw(b"\xa5" * 100)
1561 # Expect that packets sent on VLAN-0 are forwarded on the
1564 self.send_and_expect(self.pg0, pkts, self.pg1)
1567 class IPPuntSetup(object):
1568 """Setup for IPv4 Punt Police/Redirect"""
1570 def punt_setup(self):
1571 self.create_pg_interfaces(range(4))
1573 for i in self.pg_interfaces:
1578 # use UDP packet that have a port we need to explicitly
1579 # register to get punted.
1580 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
1581 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
1582 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
1588 "protocol": udp_proto,
1594 self.vapi.set_punt(is_add=1, punt=punt_udp)
1596 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
1602 "protocol": udp_proto,
1608 self.vapi.set_punt(is_add=1, punt=punt_udp)
1611 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1612 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
1613 / UDP(sport=1234, dport=1234)
1614 / Raw(b"\xa5" * 100)
1617 def punt_teardown(self):
1618 for i in self.pg_interfaces:
1623 class TestIPPunt(IPPuntSetup, VppTestCase):
1624 """IPv4 Punt Police/Redirect"""
1628 super().punt_setup()
1631 super().punt_teardown()
1634 def test_ip_punt_api_validation(self):
1635 """IP punt API parameter validation"""
1637 nh_addr = self.pg1.remote_ip4
1639 "rx_sw_if_index": self.pg0.sw_if_index,
1640 "af": VppEnum.vl_api_address_family_t.ADDRESS_IP4,
1645 with self.assertRaises(vpp_papi.VPPIOError):
1646 self.vapi.add_del_ip_punt_redirect_v2(punt=punt, is_add=True)
1649 "rx_sw_if_index": self.pg0.sw_if_index,
1650 "af": VppEnum.vl_api_address_family_t.ADDRESS_IP4,
1655 self.vapi.add_del_ip_punt_redirect_v2(punt=punt, is_add=True)
1657 def test_ip_punt(self):
1658 """IP punt police and redirect"""
1660 pkts = self.pkt * 1025
1663 # Configure a punt redirect via pg1.
1665 nh_addr = self.pg1.remote_ip4
1666 ip_punt_redirect = VppIpPuntRedirect(
1667 self, self.pg0.sw_if_index, self.pg1.sw_if_index, nh_addr
1669 ip_punt_redirect.add_vpp_config()
1671 self.send_and_expect(self.pg0, pkts, self.pg1)
1676 policer = VppPolicer(self, "ip4-punt", 400, 0, 10, 0, rate_type=1)
1677 policer.add_vpp_config()
1678 ip_punt_policer = VppIpPuntPolicer(self, policer.policer_index)
1679 ip_punt_policer.add_vpp_config()
1681 self.vapi.cli("clear trace")
1682 self.pg0.add_stream(pkts)
1683 self.pg_enable_capture(self.pg_interfaces)
1687 # the number of packet received should be greater than 0,
1688 # but not equal to the number sent, since some were policed
1690 rx = self.pg1._get_capture(1)
1692 stats = policer.get_stats()
1694 # Single rate policer - expect conform, violate but no exceed
1695 self.assertGreater(stats["conform_packets"], 0)
1696 self.assertEqual(stats["exceed_packets"], 0)
1697 self.assertGreater(stats["violate_packets"], 0)
1699 self.assertGreater(len(rx), 0)
1700 self.assertLess(len(rx), len(pkts))
1703 # remove the policer. back to full rx
1705 ip_punt_policer.remove_vpp_config()
1706 policer.remove_vpp_config()
1707 self.send_and_expect(self.pg0, pkts, self.pg1)
1710 # remove the redirect. expect full drop.
1712 ip_punt_redirect.remove_vpp_config()
1713 self.send_and_assert_no_replies(self.pg0, pkts, "IP no punt config")
1716 # Add a redirect that is not input port selective
1718 ip_punt_redirect = VppIpPuntRedirect(
1719 self, 0xFFFFFFFF, self.pg1.sw_if_index, nh_addr
1721 ip_punt_redirect.add_vpp_config()
1722 self.send_and_expect(self.pg0, pkts, self.pg1)
1723 ip_punt_redirect.remove_vpp_config()
1725 def test_ip_punt_vrf(self):
1726 """IP punt/local with VRFs"""
1728 # use a punt redirect to test if for-us packets are accepted
1729 pkts = self.pkt * 1025
1731 vlans_pg0 = [VppDot1QSubint(self, self.pg0, v) for v in range(100, 104)]
1732 vlans_pg1 = [VppDot1QSubint(self, self.pg1, v) for v in range(100, 104)]
1733 tbl4 = [VppIpTable(self, v).add_vpp_config() for v in range(100, 104)]
1734 tbl6 = [VppIpTable(self, v, True).add_vpp_config() for v in range(100, 104)]
1736 for v in vlans_pg0 + vlans_pg1:
1738 v.set_table_ip4(v.vlan)
1739 v.set_table_ip6(v.vlan)
1748 vlans_pg0[i].sw_if_index,
1749 vlans_pg1[i].sw_if_index,
1750 vlans_pg1[i].remote_ip4,
1757 vlans_pg0[i].sw_if_index,
1758 vlans_pg1[i].sw_if_index,
1759 vlans_pg1[i].remote_ip6,
1766 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1767 / Dot1Q(vlan=i.vlan)
1768 / IP(src=i.remote_ip4, dst=i.local_ip4)
1769 / UDP(sport=1234, dport=1234)
1770 / Raw(b"\xa5" * 100)
1775 self.send_and_expect(self.pg0, pkts, self.pg1)
1781 # we reject packets for source addresses in the wrong vlan/VRF
1784 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1785 / Dot1Q(vlan=i.vlan)
1786 / IP(src="1.1.1.1", dst=i.local_ip4)
1787 / UDP(sport=1234, dport=1234)
1788 / Raw(b"\xa5" * 100)
1792 # single and dual loop
1793 self.send_and_assert_no_replies(self.pg0, [pkts[0]])
1794 self.send_and_assert_no_replies(self.pg0, pkts)
1796 self.assert_error_counter_equal("/err/ip4-local/src_lookup_miss", len(pkts) + 1)
1798 # using the same source in different tables, should reject
1799 # for the table that the source is not present in
1800 # the first packet in the stream is drop
1803 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1804 / Dot1Q(vlan=i.vlan)
1805 / IP(src=vlans_pg0[0].remote_ip4, dst=i.local_ip4)
1806 / UDP(sport=1234, dport=1234)
1807 / Raw(b"\xa5" * 100)
1811 # single loop accept and drop
1812 # followed by both in the same frame/loop
1813 self.send_and_expect(self.pg0, [pkts[0]], self.pg1)
1814 self.send_and_assert_no_replies(self.pg0, [pkts[1]])
1815 self.send_and_expect(self.pg0, pkts * 4, self.pg1, n_rx=4)
1817 # using the same source in different tables, should reject
1818 # for the table that the source is not present in
1819 # the first packet in the stream is accept
1822 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1823 / Dot1Q(vlan=i.vlan)
1824 / IP(src=vlans_pg0[3].remote_ip4, dst=i.local_ip4)
1825 / UDP(sport=1234, dport=1234)
1826 / Raw(b"\xa5" * 100)
1831 # single loop accept and drop
1832 # followed by both in the same frame/loop
1833 self.send_and_expect(self.pg0, [pkts[3]], self.pg1)
1834 self.send_and_assert_no_replies(self.pg0, [pkts[1]])
1835 self.send_and_expect(self.pg0, pkts * 4, self.pg1, n_rx=4)
1841 # we reject packets for source addresses in the wrong vlan/VRF
1844 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1845 / Dot1Q(vlan=i.vlan)
1846 / IPv6(src="1::1", dst=i.local_ip6)
1847 / UDP(sport=1236, dport=1236)
1848 / Raw(b"\xa5" * 100)
1852 # single and dual loop
1853 self.send_and_assert_no_replies(self.pg0, [pkts[0]])
1854 self.send_and_assert_no_replies(self.pg0, pkts)
1856 self.assert_error_counter_equal("/err/ip6-input/src_lookup_miss", len(pkts) + 1)
1858 # using the same source in different tables, should reject
1859 # for the table that the source is not present in
1860 # the first packet in the stream is drop
1863 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1864 / Dot1Q(vlan=i.vlan)
1865 / IPv6(src=vlans_pg0[0].remote_ip6, dst=i.local_ip6)
1866 / UDP(sport=1236, dport=1236)
1867 / Raw(b"\xa5" * 100)
1871 # single loop accept and drop
1872 # followed by both in the same frame/loop
1873 self.send_and_expect(self.pg0, [pkts[0]], self.pg1)
1874 self.send_and_assert_no_replies(self.pg0, [pkts[1]])
1875 self.send_and_expect(self.pg0, pkts * 4, self.pg1, n_rx=4)
1877 # using the same source in different tables, should reject
1878 # for the table that the source is not present in
1879 # the first packet in the stream is accept
1882 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1883 / Dot1Q(vlan=i.vlan)
1884 / IPv6(src=vlans_pg0[3].remote_ip6, dst=i.local_ip6)
1885 / UDP(sport=1236, dport=1236)
1886 / Raw(b"\xa5" * 100)
1891 # single loop accept and drop
1892 # followed by both in the same frame/loop
1893 self.send_and_expect(self.pg0, [pkts[3]], self.pg1)
1894 self.send_and_assert_no_replies(self.pg0, [pkts[1]])
1895 self.send_and_expect(self.pg0, pkts * 4, self.pg1, n_rx=4)
1897 for v in vlans_pg0 + vlans_pg1:
1903 def test_ip_punt_dump(self):
1904 """IP4 punt redirect dump"""
1907 # Configure a punt redirects
1909 nh_address = self.pg3.remote_ip4
1910 ipr_03 = VppIpPuntRedirect(
1911 self, self.pg0.sw_if_index, self.pg3.sw_if_index, nh_address
1913 ipr_13 = VppIpPuntRedirect(
1914 self, self.pg1.sw_if_index, self.pg3.sw_if_index, nh_address
1916 ipr_23 = VppIpPuntRedirect(
1917 self, self.pg2.sw_if_index, self.pg3.sw_if_index, "0.0.0.0"
1919 ipr_03.add_vpp_config()
1920 ipr_13.add_vpp_config()
1921 ipr_23.add_vpp_config()
1924 # Dump pg0 punt redirects
1926 self.assertTrue(ipr_03.query_vpp_config())
1927 self.assertTrue(ipr_13.query_vpp_config())
1928 self.assertTrue(ipr_23.query_vpp_config())
1931 # Dump punt redirects for all interfaces
1933 punts = self.vapi.ip_punt_redirect_dump(0xFFFFFFFF)
1934 self.assertEqual(len(punts), 3)
1936 self.assertEqual(p.punt.tx_sw_if_index, self.pg3.sw_if_index)
1937 self.assertNotEqual(punts[1].punt.nh, self.pg3.remote_ip4)
1938 self.assertEqual(str(punts[2].punt.nh), "0.0.0.0")
1941 class TestIPPuntHandoff(IPPuntSetup, VppTestCase):
1942 """IPv4 Punt Policer thread handoff"""
1944 vpp_worker_count = 2
1947 super(TestIPPuntHandoff, self).setUp()
1948 super(TestIPPuntHandoff, self).punt_setup()
1951 super(TestIPPuntHandoff, self).punt_teardown()
1952 super(TestIPPuntHandoff, self).tearDown()
1954 def test_ip_punt_policer_handoff(self):
1955 """IP4 punt policer thread handoff"""
1956 pkts = self.pkt * NUM_PKTS
1959 # Configure a punt redirect via pg1.
1961 nh_addr = self.pg1.remote_ip4
1962 ip_punt_redirect = VppIpPuntRedirect(
1963 self, self.pg0.sw_if_index, self.pg1.sw_if_index, nh_addr
1965 ip_punt_redirect.add_vpp_config()
1967 action_tx = PolicerAction(
1968 VppEnum.vl_api_sse2_qos_action_type_t.SSE2_QOS_ACTION_API_TRANSMIT, 0
1971 # This policer drops no packets, we are just
1972 # testing that they get to the right thread.
1974 policer = VppPolicer(
1989 policer.add_vpp_config()
1990 ip_punt_policer = VppIpPuntPolicer(self, policer.policer_index)
1991 ip_punt_policer.add_vpp_config()
1993 for worker in [0, 1]:
1994 self.send_and_expect(self.pg0, pkts, self.pg1, worker=worker)
1995 self.logger.debug(self.vapi.cli("show trace max 100"))
1997 # Combined stats, all threads
1998 stats = policer.get_stats()
2000 # Single rate policer - expect conform, violate but no exceed
2001 self.assertGreater(stats["conform_packets"], 0)
2002 self.assertEqual(stats["exceed_packets"], 0)
2003 self.assertGreater(stats["violate_packets"], 0)
2005 # Worker 0, should have done all the policing
2006 stats0 = policer.get_stats(worker=0)
2007 self.assertEqual(stats, stats0)
2009 # Worker 1, should have handed everything off
2010 stats1 = policer.get_stats(worker=1)
2011 self.assertEqual(stats1["conform_packets"], 0)
2012 self.assertEqual(stats1["exceed_packets"], 0)
2013 self.assertEqual(stats1["violate_packets"], 0)
2015 # Bind the policer to worker 1 and repeat
2016 policer.bind_vpp_config(1, True)
2017 for worker in [0, 1]:
2018 self.send_and_expect(self.pg0, pkts, self.pg1, worker=worker)
2019 self.logger.debug(self.vapi.cli("show trace max 100"))
2021 # The 2 workers should now have policed the same amount
2022 stats = policer.get_stats()
2023 stats0 = policer.get_stats(worker=0)
2024 stats1 = policer.get_stats(worker=1)
2026 self.assertGreater(stats0["conform_packets"], 0)
2027 self.assertEqual(stats0["exceed_packets"], 0)
2028 self.assertGreater(stats0["violate_packets"], 0)
2030 self.assertGreater(stats1["conform_packets"], 0)
2031 self.assertEqual(stats1["exceed_packets"], 0)
2032 self.assertGreater(stats1["violate_packets"], 0)
2035 stats0["conform_packets"] + stats1["conform_packets"],
2036 stats["conform_packets"],
2040 stats0["violate_packets"] + stats1["violate_packets"],
2041 stats["violate_packets"],
2044 # Unbind the policer and repeat
2045 policer.bind_vpp_config(1, False)
2046 for worker in [0, 1]:
2047 self.send_and_expect(self.pg0, pkts, self.pg1, worker=worker)
2048 self.logger.debug(self.vapi.cli("show trace max 100"))
2050 # The policer should auto-bind to worker 0 when packets arrive
2051 stats = policer.get_stats()
2052 stats0new = policer.get_stats(worker=0)
2053 stats1new = policer.get_stats(worker=1)
2055 self.assertGreater(stats0new["conform_packets"], stats0["conform_packets"])
2056 self.assertEqual(stats0new["exceed_packets"], 0)
2057 self.assertGreater(stats0new["violate_packets"], stats0["violate_packets"])
2059 self.assertEqual(stats1, stats1new)
2064 ip_punt_policer.remove_vpp_config()
2065 policer.remove_vpp_config()
2066 ip_punt_redirect.remove_vpp_config()
2069 class TestIPDeag(VppTestCase):
2070 """IPv4 Deaggregate Routes"""
2073 def setUpClass(cls):
2074 super(TestIPDeag, cls).setUpClass()
2077 def tearDownClass(cls):
2078 super(TestIPDeag, cls).tearDownClass()
2081 super(TestIPDeag, self).setUp()
2083 self.create_pg_interfaces(range(3))
2085 for i in self.pg_interfaces:
2091 super(TestIPDeag, self).tearDown()
2092 for i in self.pg_interfaces:
2096 def test_ip_deag(self):
2097 """IP Deag Routes"""
2100 # Create a table to be used for:
2101 # 1 - another destination address lookup
2102 # 2 - a source address lookup
2104 table_dst = VppIpTable(self, 1)
2105 table_src = VppIpTable(self, 2)
2106 table_dst.add_vpp_config()
2107 table_src.add_vpp_config()
2110 # Add a route in the default table to point to a deag/
2111 # second lookup in each of these tables
2113 route_to_dst = VppIpRoute(
2114 self, "1.1.1.1", 32, [VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=1)]
2116 route_to_src = VppIpRoute(
2125 type=FibPathType.FIB_PATH_TYPE_SOURCE_LOOKUP,
2129 route_to_dst.add_vpp_config()
2130 route_to_src.add_vpp_config()
2133 # packets to these destination are dropped, since they'll
2134 # hit the respective default routes in the second table
2137 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2138 / IP(src="5.5.5.5", dst="1.1.1.1")
2139 / TCP(sport=1234, dport=1234)
2140 / Raw(b"\xa5" * 100)
2143 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2144 / IP(src="2.2.2.2", dst="1.1.1.2")
2145 / TCP(sport=1234, dport=1234)
2146 / Raw(b"\xa5" * 100)
2148 pkts_dst = p_dst * 257
2149 pkts_src = p_src * 257
2151 self.send_and_assert_no_replies(self.pg0, pkts_dst, "IP in dst table")
2152 self.send_and_assert_no_replies(self.pg0, pkts_src, "IP in src table")
2155 # add a route in the dst table to forward via pg1
2157 route_in_dst = VppIpRoute(
2161 [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)],
2164 route_in_dst.add_vpp_config()
2166 self.send_and_expect(self.pg0, pkts_dst, self.pg1)
2169 # add a route in the src table to forward via pg2
2171 route_in_src = VppIpRoute(
2175 [VppRoutePath(self.pg2.remote_ip4, self.pg2.sw_if_index)],
2178 route_in_src.add_vpp_config()
2179 self.send_and_expect(self.pg0, pkts_src, self.pg2)
2182 # loop in the lookup DP
2184 route_loop = VppIpRoute(
2185 self, "2.2.2.3", 32, [VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=0)]
2187 route_loop.add_vpp_config()
2190 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2191 / IP(src="2.2.2.4", dst="2.2.2.3")
2192 / TCP(sport=1234, dport=1234)
2193 / Raw(b"\xa5" * 100)
2196 self.send_and_assert_no_replies(self.pg0, p_l * 257, "IP lookup loop")
2199 class TestIPInput(VppTestCase):
2200 """IPv4 Input Exceptions"""
2203 def setUpClass(cls):
2204 super(TestIPInput, cls).setUpClass()
2207 def tearDownClass(cls):
2208 super(TestIPInput, cls).tearDownClass()
2211 super(TestIPInput, self).setUp()
2213 self.create_pg_interfaces(range(2))
2215 for i in self.pg_interfaces:
2221 super(TestIPInput, self).tearDown()
2222 for i in self.pg_interfaces:
2226 def test_ip_input(self):
2227 """IP Input Exceptions"""
2229 # i can't find a way in scapy to construct an IP packet
2230 # with a length less than the IP header length
2233 # Packet too short - this is forwarded
2236 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2237 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, len=40)
2238 / UDP(sport=1234, dport=1234)
2239 / Raw(b"\xa5" * 100)
2242 rx = self.send_and_expect(self.pg0, p_short * NUM_PKTS, self.pg1)
2245 # Packet too long - this is dropped
2248 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2249 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, len=400)
2250 / UDP(sport=1234, dport=1234)
2251 / Raw(b"\xa5" * 100)
2254 rx = self.send_and_assert_no_replies(self.pg0, p_long * NUM_PKTS, "too long")
2257 # bad chksum - this is dropped
2260 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2261 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, chksum=400)
2262 / UDP(sport=1234, dport=1234)
2263 / Raw(b"\xa5" * 100)
2266 rx = self.send_and_assert_no_replies(
2267 self.pg0, p_chksum * NUM_PKTS, "bad checksum"
2271 # bad version - this is dropped
2274 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2275 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, version=3)
2276 / UDP(sport=1234, dport=1234)
2277 / Raw(b"\xa5" * 100)
2280 rx = self.send_and_assert_no_replies(
2281 self.pg0, p_ver * NUM_PKTS, "funky version"
2285 # fragment offset 1 - this is dropped
2288 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2289 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, frag=1)
2290 / UDP(sport=1234, dport=1234)
2291 / Raw(b"\xa5" * 100)
2294 rx = self.send_and_assert_no_replies(self.pg0, p_frag * NUM_PKTS, "frag offset")
2297 # TTL expired packet
2300 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2301 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=1)
2302 / UDP(sport=1234, dport=1234)
2303 / Raw(b"\xa5" * 100)
2306 rxs = self.send_and_expect_some(self.pg0, p_ttl * NUM_PKTS, self.pg0)
2310 self.assertEqual(icmptypes[icmp.type], "time-exceeded")
2311 self.assertEqual(icmpcodes[icmp.type][icmp.code], "ttl-zero-during-transit")
2312 self.assertEqual(icmp.src, self.pg0.remote_ip4)
2313 self.assertEqual(icmp.dst, self.pg1.remote_ip4)
2319 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2320 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=10, flags="DF")
2321 / UDP(sport=1234, dport=1234)
2322 / Raw(b"\xa5" * 2000)
2325 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1500, 0, 0, 0])
2327 rxs = self.send_and_expect_some(self.pg0, p_mtu * NUM_PKTS, self.pg0)
2331 self.assertEqual(icmptypes[icmp.type], "dest-unreach")
2332 self.assertEqual(icmpcodes[icmp.type][icmp.code], "fragmentation-needed")
2333 self.assertEqual(icmp.nexthopmtu, 1500)
2334 self.assertEqual(icmp.src, self.pg0.remote_ip4)
2335 self.assertEqual(icmp.dst, self.pg1.remote_ip4)
2337 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2500, 0, 0, 0])
2338 rx = self.send_and_expect(self.pg0, p_mtu * NUM_PKTS, self.pg1)
2340 # Reset MTU for subsequent tests
2341 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [9000, 0, 0, 0])
2344 # source address 0.0.0.0 and 25.255.255.255 and for-us
2347 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2348 / IP(src="0.0.0.0", dst=self.pg0.local_ip4)
2350 / Raw(load=b"\x0a" * 18)
2352 rx = self.send_and_assert_no_replies(self.pg0, p_s0 * 17)
2355 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2356 / IP(src="255.255.255.255", dst=self.pg0.local_ip4)
2358 / Raw(load=b"\x0a" * 18)
2360 rx = self.send_and_assert_no_replies(self.pg0, p_s0 * 17)
2363 class TestIPDirectedBroadcast(VppTestCase):
2364 """IPv4 Directed Broadcast"""
2367 def setUpClass(cls):
2368 super(TestIPDirectedBroadcast, cls).setUpClass()
2371 def tearDownClass(cls):
2372 super(TestIPDirectedBroadcast, cls).tearDownClass()
2375 super(TestIPDirectedBroadcast, self).setUp()
2377 self.create_pg_interfaces(range(2))
2379 for i in self.pg_interfaces:
2383 super(TestIPDirectedBroadcast, self).tearDown()
2384 for i in self.pg_interfaces:
2387 def test_ip_input(self):
2388 """IP Directed Broadcast"""
2391 # set the directed broadcast on pg0 first, then config IP4 addresses
2392 # for pg1 directed broadcast is always disabled
2393 self.vapi.sw_interface_set_ip_directed_broadcast(self.pg0.sw_if_index, 1)
2396 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
2397 / IP(src="1.1.1.1", dst=self.pg0._local_ip4_bcast)
2398 / UDP(sport=1234, dport=1234)
2399 / Raw(b"\xa5" * 2000)
2402 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2403 / IP(src="1.1.1.1", dst=self.pg1._local_ip4_bcast)
2404 / UDP(sport=1234, dport=1234)
2405 / Raw(b"\xa5" * 2000)
2408 self.pg0.config_ip4()
2409 self.pg0.resolve_arp()
2410 self.pg1.config_ip4()
2411 self.pg1.resolve_arp()
2414 # test packet is L2 broadcast
2416 rx = self.send_and_expect(self.pg1, p0 * NUM_PKTS, self.pg0)
2417 self.assertTrue(rx[0][Ether].dst, "ff:ff:ff:ff:ff:ff")
2419 self.send_and_assert_no_replies(
2420 self.pg0, p1 * NUM_PKTS, "directed broadcast disabled"
2424 # toggle directed broadcast on pg0
2426 self.vapi.sw_interface_set_ip_directed_broadcast(self.pg0.sw_if_index, 0)
2427 self.send_and_assert_no_replies(
2428 self.pg1, p0 * NUM_PKTS, "directed broadcast disabled"
2431 self.vapi.sw_interface_set_ip_directed_broadcast(self.pg0.sw_if_index, 1)
2432 rx = self.send_and_expect(self.pg1, p0 * NUM_PKTS, self.pg0)
2434 self.pg0.unconfig_ip4()
2435 self.pg1.unconfig_ip4()
2438 class TestIPLPM(VppTestCase):
2439 """IPv4 longest Prefix Match"""
2442 def setUpClass(cls):
2443 super(TestIPLPM, cls).setUpClass()
2446 def tearDownClass(cls):
2447 super(TestIPLPM, cls).tearDownClass()
2450 super(TestIPLPM, self).setUp()
2452 self.create_pg_interfaces(range(4))
2454 for i in self.pg_interfaces:
2460 super(TestIPLPM, self).tearDown()
2461 for i in self.pg_interfaces:
2465 def test_ip_lpm(self):
2466 """IP longest Prefix Match"""
2472 [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)],
2474 s_24.add_vpp_config()
2479 [VppRoutePath(self.pg2.remote_ip4, self.pg2.sw_if_index)],
2481 s_8.add_vpp_config()
2484 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2485 / IP(src="1.1.1.1", dst="10.1.1.1")
2486 / UDP(sport=1234, dport=1234)
2487 / Raw(b"\xa5" * 2000)
2490 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2491 / IP(src="1.1.1.1", dst="10.1.2.1")
2492 / UDP(sport=1234, dport=1234)
2493 / Raw(b"\xa5" * 2000)
2496 self.logger.info(self.vapi.cli("sh ip fib mtrie"))
2497 rx = self.send_and_expect(self.pg0, p_8 * NUM_PKTS, self.pg2)
2498 rx = self.send_and_expect(self.pg0, p_24 * NUM_PKTS, self.pg1)
2501 @tag_fixme_vpp_workers
2502 class TestIPv4Frag(VppTestCase):
2503 """IPv4 fragmentation"""
2506 def setUpClass(cls):
2507 super(TestIPv4Frag, cls).setUpClass()
2509 cls.create_pg_interfaces([0, 1])
2510 cls.src_if = cls.pg0
2511 cls.dst_if = cls.pg1
2513 # setup all interfaces
2514 for i in cls.pg_interfaces:
2520 def tearDownClass(cls):
2521 super(TestIPv4Frag, cls).tearDownClass()
2523 def test_frag_large_packets(self):
2524 """Fragmentation of large packets"""
2526 self.vapi.cli("adjacency counters enable")
2529 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
2530 / IP(src=self.src_if.remote_ip4, dst=self.dst_if.remote_ip4)
2531 / UDP(sport=1234, dport=5678)
2534 self.extend_packet(p, 6000, "abcde")
2535 saved_payload = p[Raw].load
2539 self.dst_if.sw_if_index,
2540 self.dst_if.remote_mac,
2541 self.dst_if.remote_ip4,
2544 # Force fragmentation by setting MTU of output interface
2545 # lower than packet size
2546 self.vapi.sw_interface_set_mtu(self.dst_if.sw_if_index, [5000, 0, 0, 0])
2548 self.pg_enable_capture()
2549 self.src_if.add_stream(p)
2552 # Expecting 3 fragments because size of created fragments currently
2553 # cannot be larger then VPP buffer size (which is 2048)
2554 packets = self.dst_if.get_capture(3)
2556 # we should show 3 packets thru the neighbor
2557 self.assertEqual(3, nbr.get_stats()["packets"])
2559 # Assume VPP sends the fragments in order
2562 payload_offset = p.frag * 8
2563 if payload_offset > 0:
2564 payload_offset -= 8 # UDP header is not in payload
2565 self.assert_equal(payload_offset, len(payload))
2566 payload += p[Raw].load
2567 self.assert_equal(payload, saved_payload, "payload")
2570 class TestIPReplace(VppTestCase):
2571 """IPv4 Table Replace"""
2574 def setUpClass(cls):
2575 super(TestIPReplace, cls).setUpClass()
2578 def tearDownClass(cls):
2579 super(TestIPReplace, cls).tearDownClass()
2582 super(TestIPReplace, self).setUp()
2584 self.create_pg_interfaces(range(4))
2589 for i in self.pg_interfaces:
2593 i.generate_remote_hosts(2)
2594 self.tables.append(VppIpTable(self, table_id).add_vpp_config())
2598 super(TestIPReplace, self).tearDown()
2599 for i in self.pg_interfaces:
2603 def test_replace(self):
2604 """IP Table Replace"""
2606 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
2607 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
2609 links = [self.pg0, self.pg1, self.pg2, self.pg3]
2610 routes = [[], [], [], []]
2612 # load up the tables with some routes
2613 for ii, t in enumerate(self.tables):
2614 for jj in range(N_ROUTES):
2621 links[ii].remote_hosts[0].ip4, links[ii].sw_if_index
2624 links[ii].remote_hosts[1].ip4, links[ii].sw_if_index
2627 table_id=t.table_id,
2629 multi = VppIpMRoute(
2634 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
2637 self.pg0.sw_if_index,
2638 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT,
2641 self.pg1.sw_if_index,
2642 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
2645 self.pg2.sw_if_index,
2646 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
2649 self.pg3.sw_if_index,
2650 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
2653 table_id=t.table_id,
2655 routes[ii].append({"uni": uni, "multi": multi})
2658 # replace the tables a few times
2661 # replace_begin each table
2662 for t in self.tables:
2665 # all the routes are still there
2666 for ii, t in enumerate(self.tables):
2669 for r in routes[ii]:
2670 self.assertTrue(find_route_in_dump(dump, r["uni"], t))
2671 self.assertTrue(find_mroute_in_dump(mdump, r["multi"], t))
2673 # redownload the even numbered routes
2674 for ii, t in enumerate(self.tables):
2675 for jj in range(0, N_ROUTES, 2):
2676 routes[ii][jj]["uni"].add_vpp_config()
2677 routes[ii][jj]["multi"].add_vpp_config()
2679 # signal each table replace_end
2680 for t in self.tables:
2683 # we should find the even routes, but not the odd
2684 for ii, t in enumerate(self.tables):
2687 for jj in range(0, N_ROUTES, 2):
2688 self.assertTrue(find_route_in_dump(dump, routes[ii][jj]["uni"], t))
2690 find_mroute_in_dump(mdump, routes[ii][jj]["multi"], t)
2692 for jj in range(1, N_ROUTES - 1, 2):
2693 self.assertFalse(find_route_in_dump(dump, routes[ii][jj]["uni"], t))
2695 find_mroute_in_dump(mdump, routes[ii][jj]["multi"], t)
2698 # reload all the routes
2699 for ii, t in enumerate(self.tables):
2700 for r in routes[ii]:
2701 r["uni"].add_vpp_config()
2702 r["multi"].add_vpp_config()
2704 # all the routes are still there
2705 for ii, t in enumerate(self.tables):
2708 for r in routes[ii]:
2709 self.assertTrue(find_route_in_dump(dump, r["uni"], t))
2710 self.assertTrue(find_mroute_in_dump(mdump, r["multi"], t))
2713 # finally flush the tables for good measure
2715 for t in self.tables:
2717 self.assertEqual(len(t.dump()), 5)
2718 self.assertEqual(len(t.mdump()), 3)
2721 class TestIPCover(VppTestCase):
2722 """IPv4 Table Cover"""
2725 def setUpClass(cls):
2726 super(TestIPCover, cls).setUpClass()
2729 def tearDownClass(cls):
2730 super(TestIPCover, cls).tearDownClass()
2733 super(TestIPCover, self).setUp()
2735 self.create_pg_interfaces(range(4))
2740 for i in self.pg_interfaces:
2744 i.generate_remote_hosts(2)
2745 self.tables.append(VppIpTable(self, table_id).add_vpp_config())
2749 super(TestIPCover, self).tearDown()
2750 for i in self.pg_interfaces:
2754 def test_cover(self):
2755 """IP Table Cover"""
2757 # add a loop back with a /32 prefix
2758 lo = VppLoInterface(self)
2760 a = VppIpInterfaceAddress(self, lo, "127.0.0.1", 32).add_vpp_config()
2762 # add a neighbour that matches the loopback's /32
2764 self, lo.sw_if_index, lo.remote_mac, "127.0.0.1"
2767 # add the default route which will be the cover for /32
2772 [VppRoutePath("127.0.0.1", lo.sw_if_index)],
2776 # add/remove/add a longer mask cover
2778 self, "127.0.0.0", 8, [VppRoutePath("127.0.0.1", lo.sw_if_index)]
2780 r8.remove_vpp_config()
2782 r8.remove_vpp_config()
2784 # remove the default route
2785 r.remove_vpp_config()
2787 # remove the interface prefix
2788 a.remove_vpp_config()
2791 class TestIP4Replace(VppTestCase):
2792 """IPv4 Interface Address Replace"""
2795 def setUpClass(cls):
2796 super(TestIP4Replace, cls).setUpClass()
2799 def tearDownClass(cls):
2800 super(TestIP4Replace, cls).tearDownClass()
2803 super(TestIP4Replace, self).setUp()
2805 self.create_pg_interfaces(range(4))
2807 for i in self.pg_interfaces:
2811 super(TestIP4Replace, self).tearDown()
2812 for i in self.pg_interfaces:
2815 def get_n_pfxs(self, intf):
2816 return len(self.vapi.ip_address_dump(intf.sw_if_index))
2818 def test_replace(self):
2819 """IP interface address replace"""
2821 intf_pfxs = [[], [], [], []]
2823 # add prefixes to each of the interfaces
2824 for i in range(len(self.pg_interfaces)):
2825 intf = self.pg_interfaces[i]
2828 addr = "172.16.%d.1" % intf.sw_if_index
2829 a = VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config()
2830 intf_pfxs[i].append(a)
2832 # 172.16.x.2/24 - a different address in the same subnet as above
2833 addr = "172.16.%d.2" % intf.sw_if_index
2834 a = VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config()
2835 intf_pfxs[i].append(a)
2837 # 172.15.x.2/24 - a different address and subnet
2838 addr = "172.15.%d.2" % intf.sw_if_index
2839 a = VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config()
2840 intf_pfxs[i].append(a)
2842 # a dump should n_address in it
2843 for intf in self.pg_interfaces:
2844 self.assertEqual(self.get_n_pfxs(intf), 3)
2847 # remove all the address thru a replace
2849 self.vapi.sw_interface_address_replace_begin()
2850 self.vapi.sw_interface_address_replace_end()
2851 for intf in self.pg_interfaces:
2852 self.assertEqual(self.get_n_pfxs(intf), 0)
2855 # add all the interface addresses back
2860 for intf in self.pg_interfaces:
2861 self.assertEqual(self.get_n_pfxs(intf), 3)
2864 # replace again, but this time update/re-add the address on the first
2867 self.vapi.sw_interface_address_replace_begin()
2869 for p in intf_pfxs[:2]:
2873 self.vapi.sw_interface_address_replace_end()
2875 # on the first two the address still exist,
2876 # on the other two they do not
2877 for intf in self.pg_interfaces[:2]:
2878 self.assertEqual(self.get_n_pfxs(intf), 3)
2879 for p in intf_pfxs[:2]:
2881 self.assertTrue(v.query_vpp_config())
2882 for intf in self.pg_interfaces[2:]:
2883 self.assertEqual(self.get_n_pfxs(intf), 0)
2886 # add all the interface addresses back on the last two
2888 for p in intf_pfxs[2:]:
2891 for intf in self.pg_interfaces:
2892 self.assertEqual(self.get_n_pfxs(intf), 3)
2895 # replace again, this time add different prefixes on all the interfaces
2897 self.vapi.sw_interface_address_replace_begin()
2900 for intf in self.pg_interfaces:
2902 addr = "172.18.%d.1" % intf.sw_if_index
2903 pfxs.append(VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config())
2905 self.vapi.sw_interface_address_replace_end()
2907 # only .18 should exist on each interface
2908 for intf in self.pg_interfaces:
2909 self.assertEqual(self.get_n_pfxs(intf), 1)
2911 self.assertTrue(pfx.query_vpp_config())
2916 self.vapi.sw_interface_address_replace_begin()
2917 self.vapi.sw_interface_address_replace_end()
2918 for intf in self.pg_interfaces:
2919 self.assertEqual(self.get_n_pfxs(intf), 0)
2922 # add prefixes to each interface. post-begin add the prefix from
2923 # interface X onto interface Y. this would normally be an error
2924 # since it would generate a 'duplicate address' warning. but in
2925 # this case, since what is newly downloaded is sane, it's ok
2927 for intf in self.pg_interfaces:
2929 addr = "172.18.%d.1" % intf.sw_if_index
2930 VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config()
2932 self.vapi.sw_interface_address_replace_begin()
2935 for intf in self.pg_interfaces:
2937 addr = "172.18.%d.1" % (intf.sw_if_index + 1)
2938 pfxs.append(VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config())
2940 self.vapi.sw_interface_address_replace_end()
2942 self.logger.info(self.vapi.cli("sh int addr"))
2944 for intf in self.pg_interfaces:
2945 self.assertEqual(self.get_n_pfxs(intf), 1)
2947 self.assertTrue(pfx.query_vpp_config())
2950 class TestIPv4PathMTU(VppTestCase):
2954 def setUpClass(cls):
2955 super(TestIPv4PathMTU, cls).setUpClass()
2957 cls.create_pg_interfaces(range(2))
2959 # setup all interfaces
2960 for i in cls.pg_interfaces:
2966 def tearDownClass(cls):
2967 super(TestIPv4PathMTU, cls).tearDownClass()
2969 def test_path_mtu(self):
2973 # The goal here is not to test that fragmentation works correctly,
2974 # that's done elsewhere, the intent is to ensure that the Path MTU
2975 # settings are honoured.
2977 self.vapi.cli("adjacency counters enable")
2979 # set the interface MTU to a reasonable value
2980 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1800, 0, 0, 0])
2982 self.pg1.generate_remote_hosts(4)
2985 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2986 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4)
2987 / UDP(sport=1234, dport=5678)
2991 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2992 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4)
2993 / UDP(sport=1234, dport=5678)
2998 self, self.pg1.sw_if_index, self.pg1.remote_mac, self.pg1.remote_ip4
3001 # this is now the interface MTU frags
3002 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
3003 self.send_and_expect(self.pg0, [p_1k], self.pg1)
3005 # drop the path MTU for this neighbour to below the interface MTU
3007 pmtu = VppIpPathMtu(self, self.pg1.remote_ip4, 900).add_vpp_config()
3009 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3010 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3012 # print/format the adj delegate
3013 self.logger.info(self.vapi.cli("sh adj 5"))
3015 # increase the path MTU to more than the interface
3016 # expect to use the interface MTU
3019 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
3020 self.send_and_expect(self.pg0, [p_1k], self.pg1)
3022 # go back to an MTU from the path
3023 # wrap the call around mark-n-sweep to enusre updates clear stale
3024 self.vapi.ip_path_mtu_replace_begin()
3026 self.vapi.ip_path_mtu_replace_end()
3028 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3029 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3031 # raise the interface's MTU
3032 # should still use that of the path
3033 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2000, 0, 0, 0])
3034 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3035 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3037 # set path high and interface low
3039 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [900, 0, 0, 0])
3040 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3041 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3043 # remove the path MTU using the mark-n-sweep semantics
3044 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1800, 0, 0, 0])
3045 self.vapi.ip_path_mtu_replace_begin()
3046 self.vapi.ip_path_mtu_replace_end()
3048 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
3049 self.send_and_expect(self.pg0, [p_1k], self.pg1)
3052 # set path MTU for a neighbour that doesn't exist, yet
3054 pmtu2 = VppIpPathMtu(self, self.pg1.remote_hosts[2].ip4, 900).add_vpp_config()
3057 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
3058 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[2].ip4)
3059 / UDP(sport=1234, dport=5678)
3063 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
3064 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[2].ip4)
3065 / UDP(sport=1234, dport=5678)
3071 self.pg1.sw_if_index,
3072 self.pg1.remote_hosts[2].mac,
3073 self.pg1.remote_hosts[2].ip4,
3076 # should frag to the path MTU
3077 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3078 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3080 # remove and re-add the neighbour
3081 nbr2.remove_vpp_config()
3082 nbr2.add_vpp_config()
3084 # should frag to the path MTU
3085 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3086 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3089 # set PMTUs for many peers
3092 self.pg1.generate_remote_hosts(16)
3093 self.pg1.configure_ipv4_neighbors()
3095 for h in range(N_HOSTS):
3096 pmtu = VppIpPathMtu(self, self.pg1.remote_hosts[h].ip4, 900)
3097 pmtu.add_vpp_config()
3098 self.assertTrue(pmtu.query_vpp_config())
3100 self.logger.info(self.vapi.cli("sh ip pmtu"))
3101 dump = list(self.vapi.vpp.details_iter(self.vapi.ip_path_mtu_get))
3102 self.assertEqual(N_HOSTS, len(dump))
3104 for h in range(N_HOSTS):
3105 p_2k[IP].dst = self.pg1.remote_hosts[h].ip4
3106 p_1k[IP].dst = self.pg1.remote_hosts[h].ip4
3108 # should frag to the path MTU
3109 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3110 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3113 class TestIPv4ItfRebind(VppTestCase):
3114 """IPv4 Interface Bind w/ attached routes"""
3117 super(TestIPv4ItfRebind, self).setUp()
3119 self.create_pg_interfaces(range(3))
3122 super(TestIPv4ItfRebind, self).tearDown()
3124 def test_rebind(self):
3125 """Import to no import"""
3128 tbl = VppIpTable(self, TABLE_ID).add_vpp_config()
3129 self.pg1.set_table_ip4(TABLE_ID)
3131 for i in self.pg_interfaces:
3136 # add an attached route via an pg0
3137 # in a different table. this prefix should import
3142 [VppRoutePath("0.0.0.0", self.pg0.sw_if_index)],
3147 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
3148 / IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4)
3149 / UDP(sport=1234, dport=5678)
3153 rx = self.send_and_expect(self.pg1, [p], self.pg0)
3154 self.assertFalse(rx[0].haslayer(ARP))
3156 # then bind pg0 to a new table
3157 # so the prefix no longer imports
3158 self.pg0.unconfig_ip4()
3159 self.pg0.set_table_ip4(TABLE_ID)
3160 self.pg0.config_ip4()
3161 self.pg0.resolve_arp()
3163 rx = self.send_and_expect(self.pg1, [p], self.pg0)
3164 self.assertFalse(rx[0].haslayer(ARP))
3166 # revert back to imported
3167 self.pg0.unconfig_ip4()
3168 self.pg0.set_table_ip4(0)
3169 self.pg0.config_ip4()
3170 self.pg0.resolve_arp()
3172 rx = self.send_and_expect(self.pg1, [p], self.pg0)
3173 self.assertFalse(rx[0].haslayer(ARP))
3176 for i in self.pg_interfaces:
3181 rt.remove_vpp_config()
3182 tbl.remove_vpp_config()
3184 def test_delete(self):
3185 """Swap import tables"""
3188 tbl1_4 = VppIpTable(self, TABLE_ID1).add_vpp_config()
3189 tbl1_6 = VppIpTable(self, TABLE_ID1, True).add_vpp_config()
3191 tbl2_4 = VppIpTable(self, TABLE_ID2).add_vpp_config()
3192 tbl2_6 = VppIpTable(self, TABLE_ID2, True).add_vpp_config()
3195 self.pg1.set_table_ip4(TABLE_ID1)
3196 self.pg1.set_table_ip6(TABLE_ID1)
3197 self.pg2.set_table_ip4(TABLE_ID2)
3198 self.pg2.set_table_ip6(TABLE_ID2)
3200 for i in self.pg_interfaces:
3205 # add an attached route in the default table via pg0
3206 # this should import to table 1
3211 [VppRoutePath("0.0.0.0", self.pg1.sw_if_index)],
3217 [VppRoutePath("0.0.0.0", self.pg1.sw_if_index)],
3221 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
3222 / IP(src=self.pg1.remote_ip4, dst=self.pg1.remote_ip4)
3223 / UDP(sport=1234, dport=5678)
3227 # inject into table 0
3228 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
3229 self.assertFalse(rx[0].haslayer(ARP))
3231 # swap the attached interface to table 2
3232 self.pg1.unconfig_ip4()
3233 self.pg1.unconfig_ip6()
3234 self.pg1.set_table_ip4(TABLE_ID2)
3235 self.pg1.set_table_ip6(TABLE_ID2)
3236 self.pg1.config_ip4()
3237 self.pg1.config_ip6()
3238 self.pg1.resolve_arp()
3243 tbl1_4.remove_vpp_config()
3244 tbl1_6.remove_vpp_config()
3246 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
3247 self.assertFalse(rx[0].haslayer(ARP))
3249 for i in self.pg_interfaces:
3257 if __name__ == "__main__":
3258 unittest.main(testRunner=VppTestRunner)