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(
1797 "/err/ip4-local/ip4 source lookup miss", len(pkts) + 1
1800 # using the same source in different tables, should reject
1801 # for the table that the source is not present in
1802 # the first packet in the stream is drop
1805 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1806 / Dot1Q(vlan=i.vlan)
1807 / IP(src=vlans_pg0[0].remote_ip4, dst=i.local_ip4)
1808 / UDP(sport=1234, dport=1234)
1809 / Raw(b"\xa5" * 100)
1813 # single loop accept and drop
1814 # followed by both in the same frame/loop
1815 self.send_and_expect(self.pg0, [pkts[0]], self.pg1)
1816 self.send_and_assert_no_replies(self.pg0, [pkts[1]])
1817 self.send_and_expect(self.pg0, pkts * 4, self.pg1, n_rx=4)
1819 # using the same source in different tables, should reject
1820 # for the table that the source is not present in
1821 # the first packet in the stream is accept
1824 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1825 / Dot1Q(vlan=i.vlan)
1826 / IP(src=vlans_pg0[3].remote_ip4, dst=i.local_ip4)
1827 / UDP(sport=1234, dport=1234)
1828 / Raw(b"\xa5" * 100)
1833 # single loop accept and drop
1834 # followed by both in the same frame/loop
1835 self.send_and_expect(self.pg0, [pkts[3]], self.pg1)
1836 self.send_and_assert_no_replies(self.pg0, [pkts[1]])
1837 self.send_and_expect(self.pg0, pkts * 4, self.pg1, n_rx=4)
1843 # we reject packets for source addresses in the wrong vlan/VRF
1846 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1847 / Dot1Q(vlan=i.vlan)
1848 / IPv6(src="1::1", dst=i.local_ip6)
1849 / UDP(sport=1236, dport=1236)
1850 / Raw(b"\xa5" * 100)
1854 # single and dual loop
1855 self.send_and_assert_no_replies(self.pg0, [pkts[0]])
1856 self.send_and_assert_no_replies(self.pg0, pkts)
1858 self.assert_error_counter_equal(
1859 "/err/ip6-input/ip6 source lookup miss", len(pkts) + 1
1862 # using the same source in different tables, should reject
1863 # for the table that the source is not present in
1864 # the first packet in the stream is drop
1867 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1868 / Dot1Q(vlan=i.vlan)
1869 / IPv6(src=vlans_pg0[0].remote_ip6, dst=i.local_ip6)
1870 / UDP(sport=1236, dport=1236)
1871 / Raw(b"\xa5" * 100)
1875 # single loop accept and drop
1876 # followed by both in the same frame/loop
1877 self.send_and_expect(self.pg0, [pkts[0]], self.pg1)
1878 self.send_and_assert_no_replies(self.pg0, [pkts[1]])
1879 self.send_and_expect(self.pg0, pkts * 4, self.pg1, n_rx=4)
1881 # using the same source in different tables, should reject
1882 # for the table that the source is not present in
1883 # the first packet in the stream is accept
1886 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1887 / Dot1Q(vlan=i.vlan)
1888 / IPv6(src=vlans_pg0[3].remote_ip6, dst=i.local_ip6)
1889 / UDP(sport=1236, dport=1236)
1890 / Raw(b"\xa5" * 100)
1895 # single loop accept and drop
1896 # followed by both in the same frame/loop
1897 self.send_and_expect(self.pg0, [pkts[3]], self.pg1)
1898 self.send_and_assert_no_replies(self.pg0, [pkts[1]])
1899 self.send_and_expect(self.pg0, pkts * 4, self.pg1, n_rx=4)
1901 for v in vlans_pg0 + vlans_pg1:
1907 def test_ip_punt_dump(self):
1908 """IP4 punt redirect dump"""
1911 # Configure a punt redirects
1913 nh_address = self.pg3.remote_ip4
1914 ipr_03 = VppIpPuntRedirect(
1915 self, self.pg0.sw_if_index, self.pg3.sw_if_index, nh_address
1917 ipr_13 = VppIpPuntRedirect(
1918 self, self.pg1.sw_if_index, self.pg3.sw_if_index, nh_address
1920 ipr_23 = VppIpPuntRedirect(
1921 self, self.pg2.sw_if_index, self.pg3.sw_if_index, "0.0.0.0"
1923 ipr_03.add_vpp_config()
1924 ipr_13.add_vpp_config()
1925 ipr_23.add_vpp_config()
1928 # Dump pg0 punt redirects
1930 self.assertTrue(ipr_03.query_vpp_config())
1931 self.assertTrue(ipr_13.query_vpp_config())
1932 self.assertTrue(ipr_23.query_vpp_config())
1935 # Dump punt redirects for all interfaces
1937 punts = self.vapi.ip_punt_redirect_dump(0xFFFFFFFF)
1938 self.assertEqual(len(punts), 3)
1940 self.assertEqual(p.punt.tx_sw_if_index, self.pg3.sw_if_index)
1941 self.assertNotEqual(punts[1].punt.nh, self.pg3.remote_ip4)
1942 self.assertEqual(str(punts[2].punt.nh), "0.0.0.0")
1945 class TestIPPuntHandoff(IPPuntSetup, VppTestCase):
1946 """IPv4 Punt Policer thread handoff"""
1948 vpp_worker_count = 2
1951 super(TestIPPuntHandoff, self).setUp()
1952 super(TestIPPuntHandoff, self).punt_setup()
1955 super(TestIPPuntHandoff, self).punt_teardown()
1956 super(TestIPPuntHandoff, self).tearDown()
1958 def test_ip_punt_policer_handoff(self):
1959 """IP4 punt policer thread handoff"""
1960 pkts = self.pkt * NUM_PKTS
1963 # Configure a punt redirect via pg1.
1965 nh_addr = self.pg1.remote_ip4
1966 ip_punt_redirect = VppIpPuntRedirect(
1967 self, self.pg0.sw_if_index, self.pg1.sw_if_index, nh_addr
1969 ip_punt_redirect.add_vpp_config()
1971 action_tx = PolicerAction(
1972 VppEnum.vl_api_sse2_qos_action_type_t.SSE2_QOS_ACTION_API_TRANSMIT, 0
1975 # This policer drops no packets, we are just
1976 # testing that they get to the right thread.
1978 policer = VppPolicer(
1993 policer.add_vpp_config()
1994 ip_punt_policer = VppIpPuntPolicer(self, policer.policer_index)
1995 ip_punt_policer.add_vpp_config()
1997 for worker in [0, 1]:
1998 self.send_and_expect(self.pg0, pkts, self.pg1, worker=worker)
1999 self.logger.debug(self.vapi.cli("show trace max 100"))
2001 # Combined stats, all threads
2002 stats = policer.get_stats()
2004 # Single rate policer - expect conform, violate but no exceed
2005 self.assertGreater(stats["conform_packets"], 0)
2006 self.assertEqual(stats["exceed_packets"], 0)
2007 self.assertGreater(stats["violate_packets"], 0)
2009 # Worker 0, should have done all the policing
2010 stats0 = policer.get_stats(worker=0)
2011 self.assertEqual(stats, stats0)
2013 # Worker 1, should have handed everything off
2014 stats1 = policer.get_stats(worker=1)
2015 self.assertEqual(stats1["conform_packets"], 0)
2016 self.assertEqual(stats1["exceed_packets"], 0)
2017 self.assertEqual(stats1["violate_packets"], 0)
2019 # Bind the policer to worker 1 and repeat
2020 policer.bind_vpp_config(1, True)
2021 for worker in [0, 1]:
2022 self.send_and_expect(self.pg0, pkts, self.pg1, worker=worker)
2023 self.logger.debug(self.vapi.cli("show trace max 100"))
2025 # The 2 workers should now have policed the same amount
2026 stats = policer.get_stats()
2027 stats0 = policer.get_stats(worker=0)
2028 stats1 = policer.get_stats(worker=1)
2030 self.assertGreater(stats0["conform_packets"], 0)
2031 self.assertEqual(stats0["exceed_packets"], 0)
2032 self.assertGreater(stats0["violate_packets"], 0)
2034 self.assertGreater(stats1["conform_packets"], 0)
2035 self.assertEqual(stats1["exceed_packets"], 0)
2036 self.assertGreater(stats1["violate_packets"], 0)
2039 stats0["conform_packets"] + stats1["conform_packets"],
2040 stats["conform_packets"],
2044 stats0["violate_packets"] + stats1["violate_packets"],
2045 stats["violate_packets"],
2048 # Unbind the policer and repeat
2049 policer.bind_vpp_config(1, False)
2050 for worker in [0, 1]:
2051 self.send_and_expect(self.pg0, pkts, self.pg1, worker=worker)
2052 self.logger.debug(self.vapi.cli("show trace max 100"))
2054 # The policer should auto-bind to worker 0 when packets arrive
2055 stats = policer.get_stats()
2056 stats0new = policer.get_stats(worker=0)
2057 stats1new = policer.get_stats(worker=1)
2059 self.assertGreater(stats0new["conform_packets"], stats0["conform_packets"])
2060 self.assertEqual(stats0new["exceed_packets"], 0)
2061 self.assertGreater(stats0new["violate_packets"], stats0["violate_packets"])
2063 self.assertEqual(stats1, stats1new)
2068 ip_punt_policer.remove_vpp_config()
2069 policer.remove_vpp_config()
2070 ip_punt_redirect.remove_vpp_config()
2073 class TestIPDeag(VppTestCase):
2074 """IPv4 Deaggregate Routes"""
2077 def setUpClass(cls):
2078 super(TestIPDeag, cls).setUpClass()
2081 def tearDownClass(cls):
2082 super(TestIPDeag, cls).tearDownClass()
2085 super(TestIPDeag, self).setUp()
2087 self.create_pg_interfaces(range(3))
2089 for i in self.pg_interfaces:
2095 super(TestIPDeag, self).tearDown()
2096 for i in self.pg_interfaces:
2100 def test_ip_deag(self):
2101 """IP Deag Routes"""
2104 # Create a table to be used for:
2105 # 1 - another destination address lookup
2106 # 2 - a source address lookup
2108 table_dst = VppIpTable(self, 1)
2109 table_src = VppIpTable(self, 2)
2110 table_dst.add_vpp_config()
2111 table_src.add_vpp_config()
2114 # Add a route in the default table to point to a deag/
2115 # second lookup in each of these tables
2117 route_to_dst = VppIpRoute(
2118 self, "1.1.1.1", 32, [VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=1)]
2120 route_to_src = VppIpRoute(
2129 type=FibPathType.FIB_PATH_TYPE_SOURCE_LOOKUP,
2133 route_to_dst.add_vpp_config()
2134 route_to_src.add_vpp_config()
2137 # packets to these destination are dropped, since they'll
2138 # hit the respective default routes in the second table
2141 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2142 / IP(src="5.5.5.5", dst="1.1.1.1")
2143 / TCP(sport=1234, dport=1234)
2144 / Raw(b"\xa5" * 100)
2147 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2148 / IP(src="2.2.2.2", dst="1.1.1.2")
2149 / TCP(sport=1234, dport=1234)
2150 / Raw(b"\xa5" * 100)
2152 pkts_dst = p_dst * 257
2153 pkts_src = p_src * 257
2155 self.send_and_assert_no_replies(self.pg0, pkts_dst, "IP in dst table")
2156 self.send_and_assert_no_replies(self.pg0, pkts_src, "IP in src table")
2159 # add a route in the dst table to forward via pg1
2161 route_in_dst = VppIpRoute(
2165 [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)],
2168 route_in_dst.add_vpp_config()
2170 self.send_and_expect(self.pg0, pkts_dst, self.pg1)
2173 # add a route in the src table to forward via pg2
2175 route_in_src = VppIpRoute(
2179 [VppRoutePath(self.pg2.remote_ip4, self.pg2.sw_if_index)],
2182 route_in_src.add_vpp_config()
2183 self.send_and_expect(self.pg0, pkts_src, self.pg2)
2186 # loop in the lookup DP
2188 route_loop = VppIpRoute(
2189 self, "2.2.2.3", 32, [VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=0)]
2191 route_loop.add_vpp_config()
2194 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2195 / IP(src="2.2.2.4", dst="2.2.2.3")
2196 / TCP(sport=1234, dport=1234)
2197 / Raw(b"\xa5" * 100)
2200 self.send_and_assert_no_replies(self.pg0, p_l * 257, "IP lookup loop")
2203 class TestIPInput(VppTestCase):
2204 """IPv4 Input Exceptions"""
2207 def setUpClass(cls):
2208 super(TestIPInput, cls).setUpClass()
2211 def tearDownClass(cls):
2212 super(TestIPInput, cls).tearDownClass()
2215 super(TestIPInput, self).setUp()
2217 self.create_pg_interfaces(range(2))
2219 for i in self.pg_interfaces:
2225 super(TestIPInput, self).tearDown()
2226 for i in self.pg_interfaces:
2230 def test_ip_input(self):
2231 """IP Input Exceptions"""
2233 # i can't find a way in scapy to construct an IP packet
2234 # with a length less than the IP header length
2237 # Packet too short - this is forwarded
2240 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2241 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, len=40)
2242 / UDP(sport=1234, dport=1234)
2243 / Raw(b"\xa5" * 100)
2246 rx = self.send_and_expect(self.pg0, p_short * NUM_PKTS, self.pg1)
2249 # Packet too long - this is dropped
2252 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2253 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, len=400)
2254 / UDP(sport=1234, dport=1234)
2255 / Raw(b"\xa5" * 100)
2258 rx = self.send_and_assert_no_replies(self.pg0, p_long * NUM_PKTS, "too long")
2261 # bad chksum - this is dropped
2264 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2265 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, chksum=400)
2266 / UDP(sport=1234, dport=1234)
2267 / Raw(b"\xa5" * 100)
2270 rx = self.send_and_assert_no_replies(
2271 self.pg0, p_chksum * NUM_PKTS, "bad checksum"
2275 # bad version - this is dropped
2278 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2279 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, version=3)
2280 / UDP(sport=1234, dport=1234)
2281 / Raw(b"\xa5" * 100)
2284 rx = self.send_and_assert_no_replies(
2285 self.pg0, p_ver * NUM_PKTS, "funky version"
2289 # fragment offset 1 - this is dropped
2292 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2293 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, frag=1)
2294 / UDP(sport=1234, dport=1234)
2295 / Raw(b"\xa5" * 100)
2298 rx = self.send_and_assert_no_replies(self.pg0, p_frag * NUM_PKTS, "frag offset")
2301 # TTL expired packet
2304 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2305 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=1)
2306 / UDP(sport=1234, dport=1234)
2307 / Raw(b"\xa5" * 100)
2310 rxs = self.send_and_expect_some(self.pg0, p_ttl * NUM_PKTS, self.pg0)
2314 self.assertEqual(icmptypes[icmp.type], "time-exceeded")
2315 self.assertEqual(icmpcodes[icmp.type][icmp.code], "ttl-zero-during-transit")
2316 self.assertEqual(icmp.src, self.pg0.remote_ip4)
2317 self.assertEqual(icmp.dst, self.pg1.remote_ip4)
2323 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2324 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=10, flags="DF")
2325 / UDP(sport=1234, dport=1234)
2326 / Raw(b"\xa5" * 2000)
2329 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1500, 0, 0, 0])
2331 rxs = self.send_and_expect_some(self.pg0, p_mtu * NUM_PKTS, self.pg0)
2335 self.assertEqual(icmptypes[icmp.type], "dest-unreach")
2336 self.assertEqual(icmpcodes[icmp.type][icmp.code], "fragmentation-needed")
2337 self.assertEqual(icmp.nexthopmtu, 1500)
2338 self.assertEqual(icmp.src, self.pg0.remote_ip4)
2339 self.assertEqual(icmp.dst, self.pg1.remote_ip4)
2341 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2500, 0, 0, 0])
2342 rx = self.send_and_expect(self.pg0, p_mtu * NUM_PKTS, self.pg1)
2344 # Reset MTU for subsequent tests
2345 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [9000, 0, 0, 0])
2348 # source address 0.0.0.0 and 25.255.255.255 and for-us
2351 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2352 / IP(src="0.0.0.0", dst=self.pg0.local_ip4)
2354 / Raw(load=b"\x0a" * 18)
2356 rx = self.send_and_assert_no_replies(self.pg0, p_s0 * 17)
2359 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2360 / IP(src="255.255.255.255", dst=self.pg0.local_ip4)
2362 / Raw(load=b"\x0a" * 18)
2364 rx = self.send_and_assert_no_replies(self.pg0, p_s0 * 17)
2367 class TestIPDirectedBroadcast(VppTestCase):
2368 """IPv4 Directed Broadcast"""
2371 def setUpClass(cls):
2372 super(TestIPDirectedBroadcast, cls).setUpClass()
2375 def tearDownClass(cls):
2376 super(TestIPDirectedBroadcast, cls).tearDownClass()
2379 super(TestIPDirectedBroadcast, self).setUp()
2381 self.create_pg_interfaces(range(2))
2383 for i in self.pg_interfaces:
2387 super(TestIPDirectedBroadcast, self).tearDown()
2388 for i in self.pg_interfaces:
2391 def test_ip_input(self):
2392 """IP Directed Broadcast"""
2395 # set the directed broadcast on pg0 first, then config IP4 addresses
2396 # for pg1 directed broadcast is always disabled
2397 self.vapi.sw_interface_set_ip_directed_broadcast(self.pg0.sw_if_index, 1)
2400 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
2401 / IP(src="1.1.1.1", dst=self.pg0._local_ip4_bcast)
2402 / UDP(sport=1234, dport=1234)
2403 / Raw(b"\xa5" * 2000)
2406 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2407 / IP(src="1.1.1.1", dst=self.pg1._local_ip4_bcast)
2408 / UDP(sport=1234, dport=1234)
2409 / Raw(b"\xa5" * 2000)
2412 self.pg0.config_ip4()
2413 self.pg0.resolve_arp()
2414 self.pg1.config_ip4()
2415 self.pg1.resolve_arp()
2418 # test packet is L2 broadcast
2420 rx = self.send_and_expect(self.pg1, p0 * NUM_PKTS, self.pg0)
2421 self.assertTrue(rx[0][Ether].dst, "ff:ff:ff:ff:ff:ff")
2423 self.send_and_assert_no_replies(
2424 self.pg0, p1 * NUM_PKTS, "directed broadcast disabled"
2428 # toggle directed broadcast on pg0
2430 self.vapi.sw_interface_set_ip_directed_broadcast(self.pg0.sw_if_index, 0)
2431 self.send_and_assert_no_replies(
2432 self.pg1, p0 * NUM_PKTS, "directed broadcast disabled"
2435 self.vapi.sw_interface_set_ip_directed_broadcast(self.pg0.sw_if_index, 1)
2436 rx = self.send_and_expect(self.pg1, p0 * NUM_PKTS, self.pg0)
2438 self.pg0.unconfig_ip4()
2439 self.pg1.unconfig_ip4()
2442 class TestIPLPM(VppTestCase):
2443 """IPv4 longest Prefix Match"""
2446 def setUpClass(cls):
2447 super(TestIPLPM, cls).setUpClass()
2450 def tearDownClass(cls):
2451 super(TestIPLPM, cls).tearDownClass()
2454 super(TestIPLPM, self).setUp()
2456 self.create_pg_interfaces(range(4))
2458 for i in self.pg_interfaces:
2464 super(TestIPLPM, self).tearDown()
2465 for i in self.pg_interfaces:
2469 def test_ip_lpm(self):
2470 """IP longest Prefix Match"""
2476 [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)],
2478 s_24.add_vpp_config()
2483 [VppRoutePath(self.pg2.remote_ip4, self.pg2.sw_if_index)],
2485 s_8.add_vpp_config()
2488 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2489 / IP(src="1.1.1.1", dst="10.1.1.1")
2490 / UDP(sport=1234, dport=1234)
2491 / Raw(b"\xa5" * 2000)
2494 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2495 / IP(src="1.1.1.1", dst="10.1.2.1")
2496 / UDP(sport=1234, dport=1234)
2497 / Raw(b"\xa5" * 2000)
2500 self.logger.info(self.vapi.cli("sh ip fib mtrie"))
2501 rx = self.send_and_expect(self.pg0, p_8 * NUM_PKTS, self.pg2)
2502 rx = self.send_and_expect(self.pg0, p_24 * NUM_PKTS, self.pg1)
2505 @tag_fixme_vpp_workers
2506 class TestIPv4Frag(VppTestCase):
2507 """IPv4 fragmentation"""
2510 def setUpClass(cls):
2511 super(TestIPv4Frag, cls).setUpClass()
2513 cls.create_pg_interfaces([0, 1])
2514 cls.src_if = cls.pg0
2515 cls.dst_if = cls.pg1
2517 # setup all interfaces
2518 for i in cls.pg_interfaces:
2524 def tearDownClass(cls):
2525 super(TestIPv4Frag, cls).tearDownClass()
2527 def test_frag_large_packets(self):
2528 """Fragmentation of large packets"""
2530 self.vapi.cli("adjacency counters enable")
2533 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
2534 / IP(src=self.src_if.remote_ip4, dst=self.dst_if.remote_ip4)
2535 / UDP(sport=1234, dport=5678)
2538 self.extend_packet(p, 6000, "abcde")
2539 saved_payload = p[Raw].load
2543 self.dst_if.sw_if_index,
2544 self.dst_if.remote_mac,
2545 self.dst_if.remote_ip4,
2548 # Force fragmentation by setting MTU of output interface
2549 # lower than packet size
2550 self.vapi.sw_interface_set_mtu(self.dst_if.sw_if_index, [5000, 0, 0, 0])
2552 self.pg_enable_capture()
2553 self.src_if.add_stream(p)
2556 # Expecting 3 fragments because size of created fragments currently
2557 # cannot be larger then VPP buffer size (which is 2048)
2558 packets = self.dst_if.get_capture(3)
2560 # we should show 3 packets thru the neighbor
2561 self.assertEqual(3, nbr.get_stats()["packets"])
2563 # Assume VPP sends the fragments in order
2566 payload_offset = p.frag * 8
2567 if payload_offset > 0:
2568 payload_offset -= 8 # UDP header is not in payload
2569 self.assert_equal(payload_offset, len(payload))
2570 payload += p[Raw].load
2571 self.assert_equal(payload, saved_payload, "payload")
2574 class TestIPReplace(VppTestCase):
2575 """IPv4 Table Replace"""
2578 def setUpClass(cls):
2579 super(TestIPReplace, cls).setUpClass()
2582 def tearDownClass(cls):
2583 super(TestIPReplace, cls).tearDownClass()
2586 super(TestIPReplace, self).setUp()
2588 self.create_pg_interfaces(range(4))
2593 for i in self.pg_interfaces:
2597 i.generate_remote_hosts(2)
2598 self.tables.append(VppIpTable(self, table_id).add_vpp_config())
2602 super(TestIPReplace, self).tearDown()
2603 for i in self.pg_interfaces:
2607 def test_replace(self):
2608 """IP Table Replace"""
2610 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
2611 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
2613 links = [self.pg0, self.pg1, self.pg2, self.pg3]
2614 routes = [[], [], [], []]
2616 # load up the tables with some routes
2617 for ii, t in enumerate(self.tables):
2618 for jj in range(N_ROUTES):
2625 links[ii].remote_hosts[0].ip4, links[ii].sw_if_index
2628 links[ii].remote_hosts[1].ip4, links[ii].sw_if_index
2631 table_id=t.table_id,
2633 multi = VppIpMRoute(
2638 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
2641 self.pg0.sw_if_index,
2642 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT,
2645 self.pg1.sw_if_index,
2646 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
2649 self.pg2.sw_if_index,
2650 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
2653 self.pg3.sw_if_index,
2654 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
2657 table_id=t.table_id,
2659 routes[ii].append({"uni": uni, "multi": multi})
2662 # replace the tables a few times
2665 # replace_begin each table
2666 for t in self.tables:
2669 # all the routes are still there
2670 for ii, t in enumerate(self.tables):
2673 for r in routes[ii]:
2674 self.assertTrue(find_route_in_dump(dump, r["uni"], t))
2675 self.assertTrue(find_mroute_in_dump(mdump, r["multi"], t))
2677 # redownload the even numbered routes
2678 for ii, t in enumerate(self.tables):
2679 for jj in range(0, N_ROUTES, 2):
2680 routes[ii][jj]["uni"].add_vpp_config()
2681 routes[ii][jj]["multi"].add_vpp_config()
2683 # signal each table replace_end
2684 for t in self.tables:
2687 # we should find the even routes, but not the odd
2688 for ii, t in enumerate(self.tables):
2691 for jj in range(0, N_ROUTES, 2):
2692 self.assertTrue(find_route_in_dump(dump, routes[ii][jj]["uni"], t))
2694 find_mroute_in_dump(mdump, routes[ii][jj]["multi"], t)
2696 for jj in range(1, N_ROUTES - 1, 2):
2697 self.assertFalse(find_route_in_dump(dump, routes[ii][jj]["uni"], t))
2699 find_mroute_in_dump(mdump, routes[ii][jj]["multi"], t)
2702 # reload all the routes
2703 for ii, t in enumerate(self.tables):
2704 for r in routes[ii]:
2705 r["uni"].add_vpp_config()
2706 r["multi"].add_vpp_config()
2708 # all the routes are still there
2709 for ii, t in enumerate(self.tables):
2712 for r in routes[ii]:
2713 self.assertTrue(find_route_in_dump(dump, r["uni"], t))
2714 self.assertTrue(find_mroute_in_dump(mdump, r["multi"], t))
2717 # finally flush the tables for good measure
2719 for t in self.tables:
2721 self.assertEqual(len(t.dump()), 5)
2722 self.assertEqual(len(t.mdump()), 3)
2725 class TestIPCover(VppTestCase):
2726 """IPv4 Table Cover"""
2729 def setUpClass(cls):
2730 super(TestIPCover, cls).setUpClass()
2733 def tearDownClass(cls):
2734 super(TestIPCover, cls).tearDownClass()
2737 super(TestIPCover, self).setUp()
2739 self.create_pg_interfaces(range(4))
2744 for i in self.pg_interfaces:
2748 i.generate_remote_hosts(2)
2749 self.tables.append(VppIpTable(self, table_id).add_vpp_config())
2753 super(TestIPCover, self).tearDown()
2754 for i in self.pg_interfaces:
2758 def test_cover(self):
2759 """IP Table Cover"""
2761 # add a loop back with a /32 prefix
2762 lo = VppLoInterface(self)
2764 a = VppIpInterfaceAddress(self, lo, "127.0.0.1", 32).add_vpp_config()
2766 # add a neighbour that matches the loopback's /32
2768 self, lo.sw_if_index, lo.remote_mac, "127.0.0.1"
2771 # add the default route which will be the cover for /32
2776 [VppRoutePath("127.0.0.1", lo.sw_if_index)],
2780 # add/remove/add a longer mask cover
2782 self, "127.0.0.0", 8, [VppRoutePath("127.0.0.1", lo.sw_if_index)]
2784 r8.remove_vpp_config()
2786 r8.remove_vpp_config()
2788 # remove the default route
2789 r.remove_vpp_config()
2791 # remove the interface prefix
2792 a.remove_vpp_config()
2795 class TestIP4Replace(VppTestCase):
2796 """IPv4 Interface Address Replace"""
2799 def setUpClass(cls):
2800 super(TestIP4Replace, cls).setUpClass()
2803 def tearDownClass(cls):
2804 super(TestIP4Replace, cls).tearDownClass()
2807 super(TestIP4Replace, self).setUp()
2809 self.create_pg_interfaces(range(4))
2811 for i in self.pg_interfaces:
2815 super(TestIP4Replace, self).tearDown()
2816 for i in self.pg_interfaces:
2819 def get_n_pfxs(self, intf):
2820 return len(self.vapi.ip_address_dump(intf.sw_if_index))
2822 def test_replace(self):
2823 """IP interface address replace"""
2825 intf_pfxs = [[], [], [], []]
2827 # add prefixes to each of the interfaces
2828 for i in range(len(self.pg_interfaces)):
2829 intf = self.pg_interfaces[i]
2832 addr = "172.16.%d.1" % intf.sw_if_index
2833 a = VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config()
2834 intf_pfxs[i].append(a)
2836 # 172.16.x.2/24 - a different address in the same subnet as above
2837 addr = "172.16.%d.2" % intf.sw_if_index
2838 a = VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config()
2839 intf_pfxs[i].append(a)
2841 # 172.15.x.2/24 - a different address and subnet
2842 addr = "172.15.%d.2" % intf.sw_if_index
2843 a = VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config()
2844 intf_pfxs[i].append(a)
2846 # a dump should n_address in it
2847 for intf in self.pg_interfaces:
2848 self.assertEqual(self.get_n_pfxs(intf), 3)
2851 # remove all the address thru a replace
2853 self.vapi.sw_interface_address_replace_begin()
2854 self.vapi.sw_interface_address_replace_end()
2855 for intf in self.pg_interfaces:
2856 self.assertEqual(self.get_n_pfxs(intf), 0)
2859 # add all the interface addresses back
2864 for intf in self.pg_interfaces:
2865 self.assertEqual(self.get_n_pfxs(intf), 3)
2868 # replace again, but this time update/re-add the address on the first
2871 self.vapi.sw_interface_address_replace_begin()
2873 for p in intf_pfxs[:2]:
2877 self.vapi.sw_interface_address_replace_end()
2879 # on the first two the address still exist,
2880 # on the other two they do not
2881 for intf in self.pg_interfaces[:2]:
2882 self.assertEqual(self.get_n_pfxs(intf), 3)
2883 for p in intf_pfxs[:2]:
2885 self.assertTrue(v.query_vpp_config())
2886 for intf in self.pg_interfaces[2:]:
2887 self.assertEqual(self.get_n_pfxs(intf), 0)
2890 # add all the interface addresses back on the last two
2892 for p in intf_pfxs[2:]:
2895 for intf in self.pg_interfaces:
2896 self.assertEqual(self.get_n_pfxs(intf), 3)
2899 # replace again, this time add different prefixes on all the interfaces
2901 self.vapi.sw_interface_address_replace_begin()
2904 for intf in self.pg_interfaces:
2906 addr = "172.18.%d.1" % intf.sw_if_index
2907 pfxs.append(VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config())
2909 self.vapi.sw_interface_address_replace_end()
2911 # only .18 should exist on each interface
2912 for intf in self.pg_interfaces:
2913 self.assertEqual(self.get_n_pfxs(intf), 1)
2915 self.assertTrue(pfx.query_vpp_config())
2920 self.vapi.sw_interface_address_replace_begin()
2921 self.vapi.sw_interface_address_replace_end()
2922 for intf in self.pg_interfaces:
2923 self.assertEqual(self.get_n_pfxs(intf), 0)
2926 # add prefixes to each interface. post-begin add the prefix from
2927 # interface X onto interface Y. this would normally be an error
2928 # since it would generate a 'duplicate address' warning. but in
2929 # this case, since what is newly downloaded is sane, it's ok
2931 for intf in self.pg_interfaces:
2933 addr = "172.18.%d.1" % intf.sw_if_index
2934 VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config()
2936 self.vapi.sw_interface_address_replace_begin()
2939 for intf in self.pg_interfaces:
2941 addr = "172.18.%d.1" % (intf.sw_if_index + 1)
2942 pfxs.append(VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config())
2944 self.vapi.sw_interface_address_replace_end()
2946 self.logger.info(self.vapi.cli("sh int addr"))
2948 for intf in self.pg_interfaces:
2949 self.assertEqual(self.get_n_pfxs(intf), 1)
2951 self.assertTrue(pfx.query_vpp_config())
2954 class TestIPv4PathMTU(VppTestCase):
2958 def setUpClass(cls):
2959 super(TestIPv4PathMTU, cls).setUpClass()
2961 cls.create_pg_interfaces(range(2))
2963 # setup all interfaces
2964 for i in cls.pg_interfaces:
2970 def tearDownClass(cls):
2971 super(TestIPv4PathMTU, cls).tearDownClass()
2973 def test_path_mtu(self):
2977 # The goal here is not to test that fragmentation works correctly,
2978 # that's done elsewhere, the intent is to ensure that the Path MTU
2979 # settings are honoured.
2981 self.vapi.cli("adjacency counters enable")
2983 # set the interface MTU to a reasonable value
2984 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1800, 0, 0, 0])
2986 self.pg1.generate_remote_hosts(4)
2989 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2990 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4)
2991 / UDP(sport=1234, dport=5678)
2995 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
2996 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4)
2997 / UDP(sport=1234, dport=5678)
3002 self, self.pg1.sw_if_index, self.pg1.remote_mac, self.pg1.remote_ip4
3005 # this is now the interface MTU frags
3006 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
3007 self.send_and_expect(self.pg0, [p_1k], self.pg1)
3009 # drop the path MTU for this neighbour to below the interface MTU
3011 pmtu = VppIpPathMtu(self, self.pg1.remote_ip4, 900).add_vpp_config()
3013 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3014 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3016 # print/format the adj delegate
3017 self.logger.info(self.vapi.cli("sh adj 5"))
3019 # increase the path MTU to more than the interface
3020 # expect to use the interface MTU
3023 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
3024 self.send_and_expect(self.pg0, [p_1k], self.pg1)
3026 # go back to an MTU from the path
3027 # wrap the call around mark-n-sweep to enusre updates clear stale
3028 self.vapi.ip_path_mtu_replace_begin()
3030 self.vapi.ip_path_mtu_replace_end()
3032 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3033 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3035 # raise the interface's MTU
3036 # should still use that of the path
3037 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2000, 0, 0, 0])
3038 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3039 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3041 # set path high and interface low
3043 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [900, 0, 0, 0])
3044 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3045 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3047 # remove the path MTU using the mark-n-sweep semantics
3048 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1800, 0, 0, 0])
3049 self.vapi.ip_path_mtu_replace_begin()
3050 self.vapi.ip_path_mtu_replace_end()
3052 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
3053 self.send_and_expect(self.pg0, [p_1k], self.pg1)
3056 # set path MTU for a neighbour that doesn't exist, yet
3058 pmtu2 = VppIpPathMtu(self, self.pg1.remote_hosts[2].ip4, 900).add_vpp_config()
3061 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
3062 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[2].ip4)
3063 / UDP(sport=1234, dport=5678)
3067 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
3068 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[2].ip4)
3069 / UDP(sport=1234, dport=5678)
3075 self.pg1.sw_if_index,
3076 self.pg1.remote_hosts[2].mac,
3077 self.pg1.remote_hosts[2].ip4,
3080 # should frag to the path MTU
3081 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3082 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3084 # remove and re-add the neighbour
3085 nbr2.remove_vpp_config()
3086 nbr2.add_vpp_config()
3088 # should frag to the path MTU
3089 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3090 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3093 # set PMTUs for many peers
3096 self.pg1.generate_remote_hosts(16)
3097 self.pg1.configure_ipv4_neighbors()
3099 for h in range(N_HOSTS):
3100 pmtu = VppIpPathMtu(self, self.pg1.remote_hosts[h].ip4, 900)
3101 pmtu.add_vpp_config()
3102 self.assertTrue(pmtu.query_vpp_config())
3104 self.logger.info(self.vapi.cli("sh ip pmtu"))
3105 dump = list(self.vapi.vpp.details_iter(self.vapi.ip_path_mtu_get))
3106 self.assertEqual(N_HOSTS, len(dump))
3108 for h in range(N_HOSTS):
3109 p_2k[IP].dst = self.pg1.remote_hosts[h].ip4
3110 p_1k[IP].dst = self.pg1.remote_hosts[h].ip4
3112 # should frag to the path MTU
3113 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3114 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3117 class TestIPv4ItfRebind(VppTestCase):
3118 """IPv4 Interface Bind w/ attached routes"""
3121 super(TestIPv4ItfRebind, self).setUp()
3123 self.create_pg_interfaces(range(3))
3126 super(TestIPv4ItfRebind, self).tearDown()
3128 def test_rebind(self):
3129 """Import to no import"""
3132 tbl = VppIpTable(self, TABLE_ID).add_vpp_config()
3133 self.pg1.set_table_ip4(TABLE_ID)
3135 for i in self.pg_interfaces:
3140 # add an attached route via an pg0
3141 # in a different table. this prefix should import
3146 [VppRoutePath("0.0.0.0", self.pg0.sw_if_index)],
3151 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
3152 / IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4)
3153 / UDP(sport=1234, dport=5678)
3157 rx = self.send_and_expect(self.pg1, [p], self.pg0)
3158 self.assertFalse(rx[0].haslayer(ARP))
3160 # then bind pg0 to a new table
3161 # so the prefix no longer imports
3162 self.pg0.unconfig_ip4()
3163 self.pg0.set_table_ip4(TABLE_ID)
3164 self.pg0.config_ip4()
3165 self.pg0.resolve_arp()
3167 rx = self.send_and_expect(self.pg1, [p], self.pg0)
3168 self.assertFalse(rx[0].haslayer(ARP))
3170 # revert back to imported
3171 self.pg0.unconfig_ip4()
3172 self.pg0.set_table_ip4(0)
3173 self.pg0.config_ip4()
3174 self.pg0.resolve_arp()
3176 rx = self.send_and_expect(self.pg1, [p], self.pg0)
3177 self.assertFalse(rx[0].haslayer(ARP))
3180 for i in self.pg_interfaces:
3185 rt.remove_vpp_config()
3186 tbl.remove_vpp_config()
3188 def test_delete(self):
3189 """Swap import tables"""
3192 tbl1_4 = VppIpTable(self, TABLE_ID1).add_vpp_config()
3193 tbl1_6 = VppIpTable(self, TABLE_ID1, True).add_vpp_config()
3195 tbl2_4 = VppIpTable(self, TABLE_ID2).add_vpp_config()
3196 tbl2_6 = VppIpTable(self, TABLE_ID2, True).add_vpp_config()
3199 self.pg1.set_table_ip4(TABLE_ID1)
3200 self.pg1.set_table_ip6(TABLE_ID1)
3201 self.pg2.set_table_ip4(TABLE_ID2)
3202 self.pg2.set_table_ip6(TABLE_ID2)
3204 for i in self.pg_interfaces:
3209 # add an attached route in the default table via pg0
3210 # this should import to table 1
3215 [VppRoutePath("0.0.0.0", self.pg1.sw_if_index)],
3221 [VppRoutePath("0.0.0.0", self.pg1.sw_if_index)],
3225 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
3226 / IP(src=self.pg1.remote_ip4, dst=self.pg1.remote_ip4)
3227 / UDP(sport=1234, dport=5678)
3231 # inject into table 0
3232 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
3233 self.assertFalse(rx[0].haslayer(ARP))
3235 # swap the attached interface to table 2
3236 self.pg1.unconfig_ip4()
3237 self.pg1.unconfig_ip6()
3238 self.pg1.set_table_ip4(TABLE_ID2)
3239 self.pg1.set_table_ip6(TABLE_ID2)
3240 self.pg1.config_ip4()
3241 self.pg1.config_ip6()
3242 self.pg1.resolve_arp()
3247 tbl1_4.remove_vpp_config()
3248 tbl1_6.remove_vpp_config()
3250 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
3251 self.assertFalse(rx[0].haslayer(ARP))
3253 for i in self.pg_interfaces:
3261 if __name__ == "__main__":
3262 unittest.main(testRunner=VppTestRunner)