8 from scapy.contrib.mpls import MPLS
9 from scapy.contrib.gtp import GTP_U_Header
10 from scapy.layers.inet import IP, UDP, TCP, ICMP, icmptypes, icmpcodes
11 from scapy.layers.inet6 import IPv6
12 from scapy.layers.l2 import Ether, Dot1Q, ARP
13 from scapy.packet import Raw
16 from framework import tag_fixme_vpp_workers
17 from framework import VppTestCase, VppTestRunner
19 from vpp_ip_route import (
29 VppIpInterfaceAddress,
33 from vpp_ip import VppIpPuntPolicer, VppIpPuntRedirect, VppIpPathMtu
34 from vpp_sub_interface import VppSubInterface, VppDot1QSubint, VppDot1ADSubint
35 from vpp_papi import vpp_papi, VppEnum
36 from vpp_neighbor import VppNeighbor
37 from vpp_lo_interface import VppLoInterface
38 from vpp_policer import VppPolicer, PolicerAction
43 class TestIPv4(VppTestCase):
48 super(TestIPv4, cls).setUpClass()
51 def tearDownClass(cls):
52 super(TestIPv4, cls).tearDownClass()
56 Perform test setup before test case.
59 - create 3 pg interfaces
60 - untagged pg0 interface
61 - Dot1Q subinterface on pg1
62 - Dot1AD subinterface on pg2
64 - put it into UP state
66 - resolve neighbor address using ARP
67 - configure 200 fib entries
69 :ivar list interfaces: pg interfaces and subinterfaces.
70 :ivar dict flows: IPv4 packet flows in test.
72 super(TestIPv4, self).setUp()
74 # create 3 pg interfaces
75 self.create_pg_interfaces(range(3))
77 # create 2 subinterfaces for pg1 and pg2
78 self.sub_interfaces = [
79 VppDot1QSubint(self, self.pg1, 100),
80 VppDot1ADSubint(self, self.pg2, 200, 300, 400),
83 # packet flows mapping pg0 -> pg1.sub, pg2.sub, etc.
85 self.flows[self.pg0] = [self.pg1.sub_if, self.pg2.sub_if]
86 self.flows[self.pg1.sub_if] = [self.pg0, self.pg2.sub_if]
87 self.flows[self.pg2.sub_if] = [self.pg0, self.pg1.sub_if]
90 self.pg_if_packet_sizes = [64, 1500, 9020]
92 self.interfaces = list(self.pg_interfaces)
93 self.interfaces.extend(self.sub_interfaces)
95 # setup all interfaces
96 for i in self.interfaces:
101 # config 2M FIB entries
104 """Run standard test teardown and log ``show ip arp``."""
105 super(TestIPv4, self).tearDown()
107 def show_commands_at_teardown(self):
108 self.logger.info(self.vapi.cli("show ip4 neighbors"))
109 # info(self.vapi.cli("show ip fib")) # many entries
111 def modify_packet(self, src_if, packet_size, pkt):
112 """Add load, set destination IP and extend packet to required packet
113 size for defined interface.
115 :param VppInterface src_if: Interface to create packet for.
116 :param int packet_size: Required packet size.
117 :param Scapy pkt: Packet to be modified.
119 dst_if_idx = int(packet_size / 10 % 2)
120 dst_if = self.flows[src_if][dst_if_idx]
121 info = self.create_packet_info(src_if, dst_if)
122 payload = self.info_to_payload(info)
123 p = pkt / Raw(payload)
124 p[IP].dst = dst_if.remote_ip4
126 if isinstance(src_if, VppSubInterface):
127 p = src_if.add_dot1_layer(p)
128 self.extend_packet(p, packet_size)
132 def create_stream(self, src_if):
133 """Create input packet stream for defined interface.
135 :param VppInterface src_if: Interface to create packet stream for.
137 hdr_ext = 4 if isinstance(src_if, VppSubInterface) else 0
139 Ether(dst=src_if.local_mac, src=src_if.remote_mac)
140 / IP(src=src_if.remote_ip4)
141 / UDP(sport=1234, dport=1234)
145 self.modify_packet(src_if, i, pkt_tmpl)
146 for i in moves.range(
147 self.pg_if_packet_sizes[0], self.pg_if_packet_sizes[1], 10
151 self.modify_packet(src_if, i, pkt_tmpl)
152 for i in moves.range(
153 self.pg_if_packet_sizes[1] + hdr_ext,
154 self.pg_if_packet_sizes[2] + hdr_ext,
162 def verify_capture(self, dst_if, capture):
163 """Verify captured input packet stream for defined interface.
165 :param VppInterface dst_if: Interface to verify captured packet stream
167 :param list capture: Captured packet stream.
169 self.logger.info("Verifying capture on interface %s" % dst_if.name)
171 for i in self.interfaces:
172 last_info[i.sw_if_index] = None
174 dst_sw_if_index = dst_if.sw_if_index
175 if hasattr(dst_if, "parent"):
177 for packet in capture:
179 # Check VLAN tags and Ethernet header
180 packet = dst_if.remove_dot1_layer(packet)
181 self.assertTrue(Dot1Q not in packet)
185 payload_info = self.payload_to_info(packet[Raw])
186 packet_index = payload_info.index
187 self.assertEqual(payload_info.dst, dst_sw_if_index)
189 "Got packet on port %s: src=%u (id=%u)"
190 % (dst_if.name, payload_info.src, packet_index)
192 next_info = self.get_next_packet_info_for_interface2(
193 payload_info.src, dst_sw_if_index, last_info[payload_info.src]
195 last_info[payload_info.src] = next_info
196 self.assertTrue(next_info is not None)
197 self.assertEqual(packet_index, next_info.index)
198 saved_packet = next_info.data
199 # Check standard fields
200 self.assertEqual(ip.src, saved_packet[IP].src)
201 self.assertEqual(ip.dst, saved_packet[IP].dst)
202 self.assertEqual(udp.sport, saved_packet[UDP].sport)
203 self.assertEqual(udp.dport, saved_packet[UDP].dport)
205 self.logger.error(ppp("Unexpected or invalid packet:", packet))
207 for i in self.interfaces:
208 remaining_packet = self.get_next_packet_info_for_interface2(
209 i.sw_if_index, dst_sw_if_index, last_info[i.sw_if_index]
212 remaining_packet is None,
213 "Interface %s: Packet expected from interface %s "
214 "didn't arrive" % (dst_if.name, i.name),
222 - Create IPv4 stream for pg0 interface
223 - Create IPv4 tagged streams for pg1's and pg2's sub-interface.
224 - Send and verify received packets on each interface.
227 pkts = self.create_stream(self.pg0)
228 self.pg0.add_stream(pkts)
230 for i in self.sub_interfaces:
231 pkts = self.create_stream(i)
232 i.parent.add_stream(pkts)
234 self.pg_enable_capture(self.pg_interfaces)
237 pkts = self.pg0.get_capture()
238 self.verify_capture(self.pg0, pkts)
240 for i in self.sub_interfaces:
241 pkts = i.parent.get_capture()
242 self.verify_capture(i, pkts)
245 class TestIPv4RouteLookup(VppTestCase):
246 """IPv4 Route Lookup Test Case"""
250 def route_lookup(self, prefix, exact):
251 return self.vapi.api(
252 self.vapi.papi.ip_route_lookup,
262 super(TestIPv4RouteLookup, cls).setUpClass()
265 def tearDownClass(cls):
266 super(TestIPv4RouteLookup, cls).tearDownClass()
269 super(TestIPv4RouteLookup, self).setUp()
271 drop_nh = VppRoutePath(
272 "127.0.0.1", 0xFFFFFFFF, type=FibPathType.FIB_PATH_TYPE_DROP
276 r = VppIpRoute(self, "1.1.0.0", 16, [drop_nh])
278 self.routes.append(r)
280 r = VppIpRoute(self, "1.1.1.0", 24, [drop_nh])
282 self.routes.append(r)
284 r = VppIpRoute(self, "1.1.1.1", 32, [drop_nh])
286 self.routes.append(r)
289 # Remove the routes we added
290 for r in self.routes:
291 r.remove_vpp_config()
293 super(TestIPv4RouteLookup, self).tearDown()
295 def test_exact_match(self):
296 # Verify we find the host route
297 prefix = "1.1.1.1/32"
298 result = self.route_lookup(prefix, True)
299 assert prefix == str(result.route.prefix)
301 # Verify we find a middle prefix route
302 prefix = "1.1.1.0/24"
303 result = self.route_lookup(prefix, True)
304 assert prefix == str(result.route.prefix)
306 # Verify we do not find an available LPM.
307 with self.vapi.assert_negative_api_retval():
308 self.route_lookup("1.1.1.2/32", True)
310 def test_longest_prefix_match(self):
312 lpm_prefix = "1.1.1.0/24"
313 result = self.route_lookup("1.1.1.2/32", False)
314 assert lpm_prefix == str(result.route.prefix)
316 # Verify we find the exact when not requested
317 result = self.route_lookup(lpm_prefix, False)
318 assert lpm_prefix == str(result.route.prefix)
320 # Can't seem to delete the default route so no negative LPM test.
323 class TestIPv4IfAddrRoute(VppTestCase):
324 """IPv4 Interface Addr Route Test Case"""
328 super(TestIPv4IfAddrRoute, cls).setUpClass()
331 def tearDownClass(cls):
332 super(TestIPv4IfAddrRoute, cls).tearDownClass()
335 super(TestIPv4IfAddrRoute, self).setUp()
337 # create 1 pg interface
338 self.create_pg_interfaces(range(1))
340 for i in self.pg_interfaces:
346 super(TestIPv4IfAddrRoute, self).tearDown()
347 for i in self.pg_interfaces:
351 def test_ipv4_ifaddrs_same_prefix(self):
352 """IPv4 Interface Addresses Same Prefix test
356 - Verify no route in FIB for prefix 10.10.10.0/24
357 - Configure IPv4 address 10.10.10.10/24 on an interface
358 - Verify route in FIB for prefix 10.10.10.0/24
359 - Configure IPv4 address 10.10.10.20/24 on an interface
360 - Delete 10.10.10.10/24 from interface
361 - Verify route in FIB for prefix 10.10.10.0/24
362 - Delete 10.10.10.20/24 from interface
363 - Verify no route in FIB for prefix 10.10.10.0/24
366 # create two addresses, verify route not present
367 if_addr1 = VppIpInterfaceAddress(self, self.pg0, "10.10.10.10", 24)
368 if_addr2 = VppIpInterfaceAddress(self, self.pg0, "10.10.10.20", 24)
369 self.assertFalse(if_addr1.query_vpp_config()) # 10.10.10.10/24
370 self.assertFalse(find_route(self, "10.10.10.10", 32))
371 self.assertFalse(find_route(self, "10.10.10.20", 32))
372 self.assertFalse(find_route(self, "10.10.10.255", 32))
373 self.assertFalse(find_route(self, "10.10.10.0", 32))
375 # configure first address, verify route present
376 if_addr1.add_vpp_config()
377 self.assertTrue(if_addr1.query_vpp_config()) # 10.10.10.10/24
378 self.assertTrue(find_route(self, "10.10.10.10", 32))
379 self.assertFalse(find_route(self, "10.10.10.20", 32))
380 self.assertTrue(find_route(self, "10.10.10.255", 32))
381 self.assertTrue(find_route(self, "10.10.10.0", 32))
383 # configure second address, delete first, verify route not removed
384 if_addr2.add_vpp_config()
385 if_addr1.remove_vpp_config()
386 self.assertFalse(if_addr1.query_vpp_config()) # 10.10.10.10/24
387 self.assertTrue(if_addr2.query_vpp_config()) # 10.10.10.20/24
388 self.assertFalse(find_route(self, "10.10.10.10", 32))
389 self.assertTrue(find_route(self, "10.10.10.20", 32))
390 self.assertTrue(find_route(self, "10.10.10.255", 32))
391 self.assertTrue(find_route(self, "10.10.10.0", 32))
393 # delete second address, verify route removed
394 if_addr2.remove_vpp_config()
395 self.assertFalse(if_addr2.query_vpp_config()) # 10.10.10.20/24
396 self.assertFalse(find_route(self, "10.10.10.10", 32))
397 self.assertFalse(find_route(self, "10.10.10.20", 32))
398 self.assertFalse(find_route(self, "10.10.10.255", 32))
399 self.assertFalse(find_route(self, "10.10.10.0", 32))
401 def test_ipv4_ifaddr_route(self):
402 """IPv4 Interface Address Route test
407 - Configure IPv4 address on loopback
408 - Verify that address is not in the FIB
410 - Verify that address is in the FIB now
411 - Bring loopback down
412 - Verify that address is not in the FIB anymore
414 - Configure IPv4 address on loopback
415 - Verify that address is in the FIB now
418 # create a loopback and configure IPv4
419 loopbacks = self.create_loopback_interfaces(1)
420 lo_if = self.lo_interfaces[0]
422 lo_if.local_ip4_prefix_len = 32
425 # The intf was down when addr was added -> entry not in FIB
426 fib4_dump = self.vapi.ip_route_dump(0)
427 self.assertFalse(lo_if.is_ip4_entry_in_fib_dump(fib4_dump))
429 # When intf is brought up, entry is added
431 fib4_dump = self.vapi.ip_route_dump(0)
432 self.assertTrue(lo_if.is_ip4_entry_in_fib_dump(fib4_dump))
434 # When intf is brought down, entry is removed
436 fib4_dump = self.vapi.ip_route_dump(0)
437 self.assertFalse(lo_if.is_ip4_entry_in_fib_dump(fib4_dump))
439 # Remove addr, bring up interface, re-add -> entry in FIB
443 fib4_dump = self.vapi.ip_route_dump(0)
444 self.assertTrue(lo_if.is_ip4_entry_in_fib_dump(fib4_dump))
446 def test_ipv4_ifaddr_del(self):
447 """Delete an interface address that does not exist"""
449 loopbacks = self.create_loopback_interfaces(1)
450 lo = self.lo_interfaces[0]
456 # try and remove pg0's subnet from lo
458 with self.vapi.assert_negative_api_retval():
459 self.vapi.sw_interface_add_del_address(
460 sw_if_index=lo.sw_if_index, prefix=self.pg0.local_ip4_prefix, is_add=0
464 class TestICMPEcho(VppTestCase):
465 """ICMP Echo Test Case"""
469 super(TestICMPEcho, cls).setUpClass()
472 def tearDownClass(cls):
473 super(TestICMPEcho, cls).tearDownClass()
476 super(TestICMPEcho, self).setUp()
478 # create 1 pg interface
479 self.create_pg_interfaces(range(1))
481 for i in self.pg_interfaces:
487 super(TestICMPEcho, self).tearDown()
488 for i in self.pg_interfaces:
492 def test_icmp_echo(self):
493 """VPP replies to ICMP Echo Request
497 - Receive ICMP Echo Request message on pg0 interface.
498 - Check outgoing ICMP Echo Reply message on pg0 interface.
503 icmp_load = b"\x0a" * 18
505 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
506 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
507 / ICMP(id=icmp_id, seq=icmp_seq)
508 / Raw(load=icmp_load)
511 self.pg0.add_stream(p_echo_request)
512 self.pg_enable_capture(self.pg_interfaces)
515 rx = self.pg0.get_capture(1)
521 self.assertEqual(ether.src, self.pg0.local_mac)
522 self.assertEqual(ether.dst, self.pg0.remote_mac)
524 self.assertEqual(ipv4.src, self.pg0.local_ip4)
525 self.assertEqual(ipv4.dst, self.pg0.remote_ip4)
527 self.assertEqual(icmptypes[icmp.type], "echo-reply")
528 self.assertEqual(icmp.id, icmp_id)
529 self.assertEqual(icmp.seq, icmp_seq)
530 self.assertEqual(icmp[Raw].load, icmp_load)
533 class TestIPv4FibCrud(VppTestCase):
534 """FIB - add/update/delete - ip4 routes
542 ..note:: Python API is too slow to add many routes, needs replacement.
545 def config_fib_many_to_one(self, start_dest_addr, next_hop_addr, count, start=0):
548 :param start_dest_addr:
549 :param next_hop_addr:
551 :return list: added ips with 32 prefix
554 for i in range(count):
557 start_dest_addr % (i + start),
559 [VppRoutePath(next_hop_addr, 0xFFFFFFFF)],
565 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 fhcv2 = VppEnum.vl_api_ip_flow_hash_config_v2_t
1214 af = VppEnum.vl_api_address_family_t
1217 # An array of packets that differ only in the destination port
1224 # An array of packets that differ only in the source address
1230 for ii in range(NUM_PKTS):
1231 internal_src_ip_hdr = IP(dst="10.0.0.1", src="20.0.0.1")
1235 / UDP(sport=1234, dport=1234 + ii)
1236 / Raw(b"\xa5" * 100)
1238 port_ip_pkts.append(
1239 (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / port_ip_hdr)
1241 port_mpls_pkts.append(
1243 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1244 / MPLS(label=66, ttl=2)
1248 port_gtp_pkts.append(
1250 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1251 / internal_src_ip_hdr
1252 / UDP(sport=2152, dport=2152, chksum=0)
1253 / GTP_U_Header(gtp_type="g_pdu", teid=200)
1254 / Raw(b"\xa5" * 100)
1259 IP(dst="10.0.0.1", src="20.0.0.%d" % ii)
1260 / UDP(sport=1234, dport=1234)
1261 / Raw(b"\xa5" * 100)
1264 (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / src_ip_hdr)
1266 src_mpls_pkts.append(
1268 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1269 / MPLS(label=66, ttl=2)
1273 src_gtp_pkts.append(
1275 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1276 / IP(dst="10.0.0.1", src="20.0.0.1")
1277 / UDP(sport=2152, dport=2152, chksum=0)
1278 / GTP_U_Header(gtp_type="g_pdu", teid=ii)
1279 / Raw(b"\xa5" * 100)
1283 route_10_0_0_1 = VppIpRoute(
1288 VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index),
1289 VppRoutePath(self.pg2.remote_ip4, self.pg2.sw_if_index),
1292 route_10_0_0_1.add_vpp_config()
1294 binding = VppMplsIpBind(self, 66, "10.0.0.1", 32)
1295 binding.add_vpp_config()
1298 # inject the packet on pg0 - expect load-balancing across the 2 paths
1299 # - since the default hash config is to use IP src,dst and port
1301 # We are not going to ensure equal amounts of packets across each link,
1302 # since the hash algorithm is statistical and therefore this can never
1303 # be guaranteed. But with 64 different packets we do expect some
1304 # balancing. So instead just ensure there is traffic on each link.
1306 rx = self.send_and_expect_load_balancing(
1307 self.pg0, port_ip_pkts, [self.pg1, self.pg2]
1309 n_ip_pg0 = len(rx[0])
1310 self.send_and_expect_load_balancing(self.pg0, src_ip_pkts, [self.pg1, self.pg2])
1311 self.send_and_expect_load_balancing(
1312 self.pg0, port_mpls_pkts, [self.pg1, self.pg2]
1314 rx = self.send_and_expect_load_balancing(
1315 self.pg0, src_mpls_pkts, [self.pg1, self.pg2]
1317 n_mpls_pg0 = len(rx[0])
1320 # change the router ID and expect the distribution changes
1322 self.vapi.set_ip_flow_hash_router_id(router_id=0x11111111)
1324 rx = self.send_and_expect_load_balancing(
1325 self.pg0, port_ip_pkts, [self.pg1, self.pg2]
1327 self.assertNotEqual(n_ip_pg0, len(rx[0]))
1329 rx = self.send_and_expect_load_balancing(
1330 self.pg0, src_mpls_pkts, [self.pg1, self.pg2]
1332 self.assertNotEqual(n_mpls_pg0, len(rx[0]))
1335 # change the flow hash config so it's only IP src,dst
1336 # - now only the stream with differing source address will
1339 self.vapi.set_ip_flow_hash_v2(
1343 fhc.IP_API_FLOW_HASH_SRC_IP
1344 | fhc.IP_API_FLOW_HASH_DST_IP
1345 | fhc.IP_API_FLOW_HASH_PROTO
1349 self.send_and_expect_load_balancing(self.pg0, src_ip_pkts, [self.pg1, self.pg2])
1350 self.send_and_expect_load_balancing(
1351 self.pg0, src_mpls_pkts, [self.pg1, self.pg2]
1354 self.send_and_expect_only(self.pg0, port_ip_pkts, self.pg2)
1357 # this case gtp v1 teid key LB
1359 self.vapi.set_ip_flow_hash_v3(
1363 fhcv2.IP_API_V2_FLOW_HASH_SRC_IP
1364 | fhcv2.IP_API_V2_FLOW_HASH_PROTO
1365 | fhcv2.IP_API_V2_FLOW_HASH_GTPV1_TEID
1368 self.logger.info(self.vapi.cli("show ip fib"))
1370 self.send_and_expect_load_balancing(
1371 self.pg0, src_gtp_pkts, [self.pg1, self.pg2]
1374 self.send_and_expect_only(self.pg0, port_gtp_pkts, self.pg2)
1377 # change the flow hash config back to defaults
1379 self.vapi.set_ip_flow_hash(vrf_id=0, src=1, dst=1, proto=1, sport=1, dport=1)
1382 # Recursive prefixes
1383 # - testing that 2 stages of load-balancing occurs and there is no
1384 # polarisation (i.e. only 2 of 4 paths are used)
1389 for ii in range(257):
1392 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1393 / IP(dst="1.1.1.1", src="20.0.0.1")
1394 / UDP(sport=1234, dport=1234 + ii)
1395 / Raw(b"\xa5" * 100)
1400 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1401 / IP(dst="1.1.1.1", src="20.0.0.%d" % ii)
1402 / UDP(sport=1234, dport=1234)
1403 / Raw(b"\xa5" * 100)
1407 route_10_0_0_2 = VppIpRoute(
1412 VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index),
1413 VppRoutePath(self.pg4.remote_ip4, self.pg4.sw_if_index),
1416 route_10_0_0_2.add_vpp_config()
1418 route_1_1_1_1 = VppIpRoute(
1423 VppRoutePath("10.0.0.2", 0xFFFFFFFF),
1424 VppRoutePath("10.0.0.1", 0xFFFFFFFF),
1427 route_1_1_1_1.add_vpp_config()
1430 # inject the packet on pg0 - expect load-balancing across all 4 paths
1432 self.vapi.cli("clear trace")
1433 self.send_and_expect_load_balancing(
1434 self.pg0, port_pkts, [self.pg1, self.pg2, self.pg3, self.pg4]
1436 self.send_and_expect_load_balancing(
1437 self.pg0, src_pkts, [self.pg1, self.pg2, self.pg3, self.pg4]
1441 # bring down pg1 expect LB to adjust to use only those that are up
1443 self.pg1.link_down()
1445 rx = self.send_and_expect_load_balancing(
1446 self.pg0, src_pkts, [self.pg2, self.pg3, self.pg4]
1448 self.assertEqual(len(src_pkts), self.total_len(rx))
1451 # bring down pg2 expect LB to adjust to use only those that are up
1453 self.pg2.link_down()
1455 rx = self.send_and_expect_load_balancing(
1456 self.pg0, src_pkts, [self.pg3, self.pg4]
1458 self.assertEqual(len(src_pkts), self.total_len(rx))
1461 # bring the links back up - expect LB over all again
1466 rx = self.send_and_expect_load_balancing(
1467 self.pg0, src_pkts, [self.pg1, self.pg2, self.pg3, self.pg4]
1469 self.assertEqual(len(src_pkts), self.total_len(rx))
1472 # The same link-up/down but this time admin state
1474 self.pg1.admin_down()
1475 self.pg2.admin_down()
1476 rx = self.send_and_expect_load_balancing(
1477 self.pg0, src_pkts, [self.pg3, self.pg4]
1479 self.assertEqual(len(src_pkts), self.total_len(rx))
1482 self.pg1.resolve_arp()
1483 self.pg2.resolve_arp()
1484 rx = self.send_and_expect_load_balancing(
1485 self.pg0, src_pkts, [self.pg1, self.pg2, self.pg3, self.pg4]
1487 self.assertEqual(len(src_pkts), self.total_len(rx))
1490 # Recursive prefixes
1491 # - testing that 2 stages of load-balancing, no choices
1495 for ii in range(257):
1498 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1499 / IP(dst="1.1.1.2", src="20.0.0.2")
1500 / UDP(sport=1234, dport=1234 + ii)
1501 / Raw(b"\xa5" * 100)
1505 route_10_0_0_3 = VppIpRoute(
1509 [VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index)],
1511 route_10_0_0_3.add_vpp_config()
1513 route_1_1_1_2 = VppIpRoute(
1514 self, "1.1.1.2", 32, [VppRoutePath("10.0.0.3", 0xFFFFFFFF)]
1516 route_1_1_1_2.add_vpp_config()
1519 # inject the packet on pg0 - rx only on via routes output interface
1521 self.vapi.cli("clear trace")
1522 self.send_and_expect_only(self.pg0, port_pkts, self.pg3)
1525 # Add a LB route in the presence of a down link - expect no
1526 # packets over the down link
1528 self.pg3.link_down()
1530 route_10_0_0_3 = VppIpRoute(
1535 VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index),
1536 VppRoutePath(self.pg4.remote_ip4, self.pg4.sw_if_index),
1539 route_10_0_0_3.add_vpp_config()
1542 for ii in range(257):
1544 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1545 / IP(dst="10.0.0.3", src="20.0.0.2")
1546 / UDP(sport=1234, dport=1234 + ii)
1547 / Raw(b"\xa5" * 100)
1550 self.send_and_expect_only(self.pg0, port_pkts, self.pg4)
1552 # bring the link back up
1555 rx = self.send_and_expect_load_balancing(
1556 self.pg0, port_pkts, [self.pg3, self.pg4]
1558 self.assertEqual(len(src_pkts), self.total_len(rx))
1561 class TestIPVlan0(VppTestCase):
1565 def setUpClass(cls):
1566 super(TestIPVlan0, cls).setUpClass()
1569 def tearDownClass(cls):
1570 super(TestIPVlan0, cls).tearDownClass()
1573 super(TestIPVlan0, self).setUp()
1575 self.create_pg_interfaces(range(2))
1576 mpls_tbl = VppMplsTable(self, 0)
1577 mpls_tbl.add_vpp_config()
1579 for i in self.pg_interfaces:
1586 for i in self.pg_interfaces:
1590 super(TestIPVlan0, self).tearDown()
1592 def test_ip_vlan_0(self):
1596 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1598 / IP(dst=self.pg1.remote_ip4, src=self.pg0.remote_ip4)
1599 / UDP(sport=1234, dport=1234)
1600 / Raw(b"\xa5" * 100)
1604 # Expect that packets sent on VLAN-0 are forwarded on the
1607 self.send_and_expect(self.pg0, pkts, self.pg1)
1610 class IPPuntSetup(object):
1611 """Setup for IPv4 Punt Police/Redirect"""
1613 def punt_setup(self):
1614 self.create_pg_interfaces(range(4))
1616 for i in self.pg_interfaces:
1621 # use UDP packet that have a port we need to explicitly
1622 # register to get punted.
1623 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
1624 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
1625 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
1631 "protocol": udp_proto,
1637 self.vapi.set_punt(is_add=1, punt=punt_udp)
1639 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
1645 "protocol": udp_proto,
1651 self.vapi.set_punt(is_add=1, punt=punt_udp)
1654 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1655 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
1656 / UDP(sport=1234, dport=1234)
1657 / Raw(b"\xa5" * 100)
1660 def punt_teardown(self):
1661 for i in self.pg_interfaces:
1666 class TestIPPunt(IPPuntSetup, VppTestCase):
1667 """IPv4 Punt Police/Redirect"""
1671 super().punt_setup()
1674 super().punt_teardown()
1677 def test_ip_punt_api_validation(self):
1678 """IP punt API parameter validation"""
1680 nh_addr = self.pg1.remote_ip4
1682 "rx_sw_if_index": self.pg0.sw_if_index,
1683 "af": VppEnum.vl_api_address_family_t.ADDRESS_IP4,
1688 with self.assertRaises(vpp_papi.VPPIOError):
1689 self.vapi.add_del_ip_punt_redirect_v2(punt=punt, is_add=True)
1692 "rx_sw_if_index": self.pg0.sw_if_index,
1693 "af": VppEnum.vl_api_address_family_t.ADDRESS_IP4,
1698 self.vapi.add_del_ip_punt_redirect_v2(punt=punt, is_add=True)
1700 def test_ip_punt(self):
1701 """IP punt police and redirect"""
1703 pkts = self.pkt * 1025
1706 # Configure a punt redirect via pg1.
1708 nh_addr = self.pg1.remote_ip4
1709 ip_punt_redirect = VppIpPuntRedirect(
1710 self, self.pg0.sw_if_index, self.pg1.sw_if_index, nh_addr
1712 ip_punt_redirect.add_vpp_config()
1714 self.send_and_expect(self.pg0, pkts, self.pg1)
1719 policer = VppPolicer(self, "ip4-punt", 400, 0, 10, 0, rate_type=1)
1720 policer.add_vpp_config()
1721 ip_punt_policer = VppIpPuntPolicer(self, policer.policer_index)
1722 ip_punt_policer.add_vpp_config()
1724 self.vapi.cli("clear trace")
1725 self.pg0.add_stream(pkts)
1726 self.pg_enable_capture(self.pg_interfaces)
1730 # the number of packet received should be greater than 0,
1731 # but not equal to the number sent, since some were policed
1733 rx = self.pg1._get_capture(1)
1735 stats = policer.get_stats()
1737 # Single rate policer - expect conform, violate but no exceed
1738 self.assertGreater(stats["conform_packets"], 0)
1739 self.assertEqual(stats["exceed_packets"], 0)
1740 self.assertGreater(stats["violate_packets"], 0)
1742 self.assertGreater(len(rx), 0)
1743 self.assertLess(len(rx), len(pkts))
1746 # remove the policer. back to full rx
1748 ip_punt_policer.remove_vpp_config()
1749 policer.remove_vpp_config()
1750 self.send_and_expect(self.pg0, pkts, self.pg1)
1753 # remove the redirect. expect full drop.
1755 ip_punt_redirect.remove_vpp_config()
1756 self.send_and_assert_no_replies(self.pg0, pkts, "IP no punt config")
1759 # Add a redirect that is not input port selective
1761 ip_punt_redirect = VppIpPuntRedirect(
1762 self, 0xFFFFFFFF, self.pg1.sw_if_index, nh_addr
1764 ip_punt_redirect.add_vpp_config()
1765 self.send_and_expect(self.pg0, pkts, self.pg1)
1766 ip_punt_redirect.remove_vpp_config()
1768 def test_ip_punt_vrf(self):
1769 """IP punt/local with VRFs"""
1771 # use a punt redirect to test if for-us packets are accepted
1772 pkts = self.pkt * 1025
1774 vlans_pg0 = [VppDot1QSubint(self, self.pg0, v) for v in range(100, 104)]
1775 vlans_pg1 = [VppDot1QSubint(self, self.pg1, v) for v in range(100, 104)]
1776 tbl4 = [VppIpTable(self, v).add_vpp_config() for v in range(100, 104)]
1777 tbl6 = [VppIpTable(self, v, True).add_vpp_config() for v in range(100, 104)]
1779 for v in vlans_pg0 + vlans_pg1:
1781 v.set_table_ip4(v.vlan)
1782 v.set_table_ip6(v.vlan)
1791 vlans_pg0[i].sw_if_index,
1792 vlans_pg1[i].sw_if_index,
1793 vlans_pg1[i].remote_ip4,
1800 vlans_pg0[i].sw_if_index,
1801 vlans_pg1[i].sw_if_index,
1802 vlans_pg1[i].remote_ip6,
1809 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1810 / Dot1Q(vlan=i.vlan)
1811 / IP(src=i.remote_ip4, dst=i.local_ip4)
1812 / UDP(sport=1234, dport=1234)
1813 / Raw(b"\xa5" * 100)
1818 self.send_and_expect(self.pg0, pkts, self.pg1)
1824 # we reject packets for source addresses in the wrong vlan/VRF
1827 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1828 / Dot1Q(vlan=i.vlan)
1829 / IP(src="1.1.1.1", dst=i.local_ip4)
1830 / UDP(sport=1234, dport=1234)
1831 / Raw(b"\xa5" * 100)
1835 # single and dual loop
1836 self.send_and_assert_no_replies(self.pg0, [pkts[0]])
1837 self.send_and_assert_no_replies(self.pg0, pkts)
1839 self.assert_error_counter_equal("/err/ip4-local/src_lookup_miss", len(pkts) + 1)
1841 # using the same source in different tables, should reject
1842 # for the table that the source is not present in
1843 # the first packet in the stream is drop
1846 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1847 / Dot1Q(vlan=i.vlan)
1848 / IP(src=vlans_pg0[0].remote_ip4, dst=i.local_ip4)
1849 / UDP(sport=1234, dport=1234)
1850 / Raw(b"\xa5" * 100)
1854 # single loop accept and drop
1855 # followed by both in the same frame/loop
1856 self.send_and_expect(self.pg0, [pkts[0]], self.pg1)
1857 self.send_and_assert_no_replies(self.pg0, [pkts[1]])
1858 self.send_and_expect(self.pg0, pkts * 4, self.pg1, n_rx=4)
1860 # using the same source in different tables, should reject
1861 # for the table that the source is not present in
1862 # the first packet in the stream is accept
1865 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1866 / Dot1Q(vlan=i.vlan)
1867 / IP(src=vlans_pg0[3].remote_ip4, dst=i.local_ip4)
1868 / UDP(sport=1234, dport=1234)
1869 / Raw(b"\xa5" * 100)
1874 # single loop accept and drop
1875 # followed by both in the same frame/loop
1876 self.send_and_expect(self.pg0, [pkts[3]], self.pg1)
1877 self.send_and_assert_no_replies(self.pg0, [pkts[1]])
1878 self.send_and_expect(self.pg0, pkts * 4, self.pg1, n_rx=4)
1884 # we reject packets for source addresses in the wrong vlan/VRF
1887 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1888 / Dot1Q(vlan=i.vlan)
1889 / IPv6(src="1::1", dst=i.local_ip6)
1890 / UDP(sport=1236, dport=1236)
1891 / Raw(b"\xa5" * 100)
1895 # single and dual loop
1896 self.send_and_assert_no_replies(self.pg0, [pkts[0]])
1897 self.send_and_assert_no_replies(self.pg0, pkts)
1899 self.assert_error_counter_equal("/err/ip6-input/src_lookup_miss", len(pkts) + 1)
1901 # using the same source in different tables, should reject
1902 # for the table that the source is not present in
1903 # the first packet in the stream is drop
1906 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1907 / Dot1Q(vlan=i.vlan)
1908 / IPv6(src=vlans_pg0[0].remote_ip6, dst=i.local_ip6)
1909 / UDP(sport=1236, dport=1236)
1910 / Raw(b"\xa5" * 100)
1914 # single loop accept and drop
1915 # followed by both in the same frame/loop
1916 self.send_and_expect(self.pg0, [pkts[0]], self.pg1)
1917 self.send_and_assert_no_replies(self.pg0, [pkts[1]])
1918 self.send_and_expect(self.pg0, pkts * 4, self.pg1, n_rx=4)
1920 # using the same source in different tables, should reject
1921 # for the table that the source is not present in
1922 # the first packet in the stream is accept
1925 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1926 / Dot1Q(vlan=i.vlan)
1927 / IPv6(src=vlans_pg0[3].remote_ip6, dst=i.local_ip6)
1928 / UDP(sport=1236, dport=1236)
1929 / Raw(b"\xa5" * 100)
1934 # single loop accept and drop
1935 # followed by both in the same frame/loop
1936 self.send_and_expect(self.pg0, [pkts[3]], self.pg1)
1937 self.send_and_assert_no_replies(self.pg0, [pkts[1]])
1938 self.send_and_expect(self.pg0, pkts * 4, self.pg1, n_rx=4)
1940 for v in vlans_pg0 + vlans_pg1:
1946 def test_ip_punt_dump(self):
1947 """IP4 punt redirect dump"""
1950 # Configure a punt redirects
1952 nh_address = self.pg3.remote_ip4
1953 ipr_03 = VppIpPuntRedirect(
1954 self, self.pg0.sw_if_index, self.pg3.sw_if_index, nh_address
1956 ipr_13 = VppIpPuntRedirect(
1957 self, self.pg1.sw_if_index, self.pg3.sw_if_index, nh_address
1959 ipr_23 = VppIpPuntRedirect(
1960 self, self.pg2.sw_if_index, self.pg3.sw_if_index, "0.0.0.0"
1962 ipr_03.add_vpp_config()
1963 ipr_13.add_vpp_config()
1964 ipr_23.add_vpp_config()
1967 # Dump pg0 punt redirects
1969 self.assertTrue(ipr_03.query_vpp_config())
1970 self.assertTrue(ipr_13.query_vpp_config())
1971 self.assertTrue(ipr_23.query_vpp_config())
1974 # Dump punt redirects for all interfaces
1976 punts = self.vapi.ip_punt_redirect_dump(0xFFFFFFFF)
1977 self.assertEqual(len(punts), 3)
1979 self.assertEqual(p.punt.tx_sw_if_index, self.pg3.sw_if_index)
1980 self.assertNotEqual(punts[1].punt.nh, self.pg3.remote_ip4)
1981 self.assertEqual(str(punts[2].punt.nh), "0.0.0.0")
1984 class TestIPPuntHandoff(IPPuntSetup, VppTestCase):
1985 """IPv4 Punt Policer thread handoff"""
1987 vpp_worker_count = 2
1990 super(TestIPPuntHandoff, self).setUp()
1991 super(TestIPPuntHandoff, self).punt_setup()
1994 super(TestIPPuntHandoff, self).punt_teardown()
1995 super(TestIPPuntHandoff, self).tearDown()
1997 def test_ip_punt_policer_handoff(self):
1998 """IP4 punt policer thread handoff"""
1999 pkts = self.pkt * NUM_PKTS
2002 # Configure a punt redirect via pg1.
2004 nh_addr = self.pg1.remote_ip4
2005 ip_punt_redirect = VppIpPuntRedirect(
2006 self, self.pg0.sw_if_index, self.pg1.sw_if_index, nh_addr
2008 ip_punt_redirect.add_vpp_config()
2010 action_tx = PolicerAction(
2011 VppEnum.vl_api_sse2_qos_action_type_t.SSE2_QOS_ACTION_API_TRANSMIT, 0
2014 # This policer drops no packets, we are just
2015 # testing that they get to the right thread.
2017 policer = VppPolicer(
2032 policer.add_vpp_config()
2033 ip_punt_policer = VppIpPuntPolicer(self, policer.policer_index)
2034 ip_punt_policer.add_vpp_config()
2036 for worker in [0, 1]:
2037 self.send_and_expect(self.pg0, pkts, self.pg1, worker=worker)
2038 self.logger.debug(self.vapi.cli("show trace max 100"))
2040 # Combined stats, all threads
2041 stats = policer.get_stats()
2043 # Single rate policer - expect conform, violate but no exceed
2044 self.assertGreater(stats["conform_packets"], 0)
2045 self.assertEqual(stats["exceed_packets"], 0)
2046 self.assertGreater(stats["violate_packets"], 0)
2048 # Worker 0, should have done all the policing
2049 stats0 = policer.get_stats(worker=0)
2050 self.assertEqual(stats, stats0)
2052 # Worker 1, should have handed everything off
2053 stats1 = policer.get_stats(worker=1)
2054 self.assertEqual(stats1["conform_packets"], 0)
2055 self.assertEqual(stats1["exceed_packets"], 0)
2056 self.assertEqual(stats1["violate_packets"], 0)
2058 # Bind the policer to worker 1 and repeat
2059 policer.bind_vpp_config(1, True)
2060 for worker in [0, 1]:
2061 self.send_and_expect(self.pg0, pkts, self.pg1, worker=worker)
2062 self.logger.debug(self.vapi.cli("show trace max 100"))
2064 # The 2 workers should now have policed the same amount
2065 stats = policer.get_stats()
2066 stats0 = policer.get_stats(worker=0)
2067 stats1 = policer.get_stats(worker=1)
2069 self.assertGreater(stats0["conform_packets"], 0)
2070 self.assertEqual(stats0["exceed_packets"], 0)
2071 self.assertGreater(stats0["violate_packets"], 0)
2073 self.assertGreater(stats1["conform_packets"], 0)
2074 self.assertEqual(stats1["exceed_packets"], 0)
2075 self.assertGreater(stats1["violate_packets"], 0)
2078 stats0["conform_packets"] + stats1["conform_packets"],
2079 stats["conform_packets"],
2083 stats0["violate_packets"] + stats1["violate_packets"],
2084 stats["violate_packets"],
2087 # Unbind the policer and repeat
2088 policer.bind_vpp_config(1, False)
2089 for worker in [0, 1]:
2090 self.send_and_expect(self.pg0, pkts, self.pg1, worker=worker)
2091 self.logger.debug(self.vapi.cli("show trace max 100"))
2093 # The policer should auto-bind to worker 0 when packets arrive
2094 stats = policer.get_stats()
2095 stats0new = policer.get_stats(worker=0)
2096 stats1new = policer.get_stats(worker=1)
2098 self.assertGreater(stats0new["conform_packets"], stats0["conform_packets"])
2099 self.assertEqual(stats0new["exceed_packets"], 0)
2100 self.assertGreater(stats0new["violate_packets"], stats0["violate_packets"])
2102 self.assertEqual(stats1, stats1new)
2107 ip_punt_policer.remove_vpp_config()
2108 policer.remove_vpp_config()
2109 ip_punt_redirect.remove_vpp_config()
2112 class TestIPDeag(VppTestCase):
2113 """IPv4 Deaggregate Routes"""
2116 def setUpClass(cls):
2117 super(TestIPDeag, cls).setUpClass()
2120 def tearDownClass(cls):
2121 super(TestIPDeag, cls).tearDownClass()
2124 super(TestIPDeag, self).setUp()
2126 self.create_pg_interfaces(range(3))
2128 for i in self.pg_interfaces:
2134 super(TestIPDeag, self).tearDown()
2135 for i in self.pg_interfaces:
2139 def test_ip_deag(self):
2140 """IP Deag Routes"""
2143 # Create a table to be used for:
2144 # 1 - another destination address lookup
2145 # 2 - a source address lookup
2147 table_dst = VppIpTable(self, 1)
2148 table_src = VppIpTable(self, 2)
2149 table_dst.add_vpp_config()
2150 table_src.add_vpp_config()
2153 # Add a route in the default table to point to a deag/
2154 # second lookup in each of these tables
2156 route_to_dst = VppIpRoute(
2157 self, "1.1.1.1", 32, [VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=1)]
2159 route_to_src = VppIpRoute(
2168 type=FibPathType.FIB_PATH_TYPE_SOURCE_LOOKUP,
2172 route_to_dst.add_vpp_config()
2173 route_to_src.add_vpp_config()
2176 # packets to these destination are dropped, since they'll
2177 # hit the respective default routes in the second table
2180 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2181 / IP(src="5.5.5.5", dst="1.1.1.1")
2182 / TCP(sport=1234, dport=1234)
2183 / Raw(b"\xa5" * 100)
2186 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2187 / IP(src="2.2.2.2", dst="1.1.1.2")
2188 / TCP(sport=1234, dport=1234)
2189 / Raw(b"\xa5" * 100)
2191 pkts_dst = p_dst * 257
2192 pkts_src = p_src * 257
2194 self.send_and_assert_no_replies(self.pg0, pkts_dst, "IP in dst table")
2195 self.send_and_assert_no_replies(self.pg0, pkts_src, "IP in src table")
2198 # add a route in the dst table to forward via pg1
2200 route_in_dst = VppIpRoute(
2204 [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)],
2207 route_in_dst.add_vpp_config()
2209 self.send_and_expect(self.pg0, pkts_dst, self.pg1)
2212 # add a route in the src table to forward via pg2
2214 route_in_src = VppIpRoute(
2218 [VppRoutePath(self.pg2.remote_ip4, self.pg2.sw_if_index)],
2221 route_in_src.add_vpp_config()
2222 self.send_and_expect(self.pg0, pkts_src, self.pg2)
2225 # loop in the lookup DP
2227 route_loop = VppIpRoute(
2228 self, "2.2.2.3", 32, [VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=0)]
2230 route_loop.add_vpp_config()
2233 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2234 / IP(src="2.2.2.4", dst="2.2.2.3")
2235 / TCP(sport=1234, dport=1234)
2236 / Raw(b"\xa5" * 100)
2239 self.send_and_assert_no_replies(self.pg0, p_l * 257, "IP lookup loop")
2242 class TestIPInput(VppTestCase):
2243 """IPv4 Input Exceptions"""
2246 def setUpClass(cls):
2247 super(TestIPInput, cls).setUpClass()
2250 def tearDownClass(cls):
2251 super(TestIPInput, cls).tearDownClass()
2254 super(TestIPInput, self).setUp()
2256 self.create_pg_interfaces(range(2))
2258 for i in self.pg_interfaces:
2264 super(TestIPInput, self).tearDown()
2265 for i in self.pg_interfaces:
2269 def test_ip_input(self):
2270 """IP Input Exceptions"""
2272 # i can't find a way in scapy to construct an IP packet
2273 # with a length less than the IP header length
2276 # Packet too short - this is forwarded
2279 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2280 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, len=40)
2281 / UDP(sport=1234, dport=1234)
2282 / Raw(b"\xa5" * 100)
2285 rx = self.send_and_expect(self.pg0, p_short * NUM_PKTS, self.pg1)
2288 # Packet too long - this is dropped
2291 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2292 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, len=400)
2293 / UDP(sport=1234, dport=1234)
2294 / Raw(b"\xa5" * 100)
2297 rx = self.send_and_assert_no_replies(self.pg0, p_long * NUM_PKTS, "too long")
2300 # bad chksum - this is dropped
2303 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2304 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, chksum=400)
2305 / UDP(sport=1234, dport=1234)
2306 / Raw(b"\xa5" * 100)
2309 rx = self.send_and_assert_no_replies(
2310 self.pg0, p_chksum * NUM_PKTS, "bad checksum"
2314 # bad version - this is dropped
2317 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2318 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, version=3)
2319 / UDP(sport=1234, dport=1234)
2320 / Raw(b"\xa5" * 100)
2323 rx = self.send_and_assert_no_replies(
2324 self.pg0, p_ver * NUM_PKTS, "funky version"
2328 # fragment offset 1 - this is dropped
2331 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2332 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, frag=1)
2333 / UDP(sport=1234, dport=1234)
2334 / Raw(b"\xa5" * 100)
2337 rx = self.send_and_assert_no_replies(self.pg0, p_frag * NUM_PKTS, "frag offset")
2340 # TTL expired packet
2343 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2344 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=1)
2345 / UDP(sport=1234, dport=1234)
2346 / Raw(b"\xa5" * 100)
2349 rxs = self.send_and_expect_some(self.pg0, p_ttl * NUM_PKTS, self.pg0)
2353 self.assertEqual(icmptypes[icmp.type], "time-exceeded")
2354 self.assertEqual(icmpcodes[icmp.type][icmp.code], "ttl-zero-during-transit")
2355 self.assertEqual(icmp.src, self.pg0.remote_ip4)
2356 self.assertEqual(icmp.dst, self.pg1.remote_ip4)
2362 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2363 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=10, flags="DF")
2364 / UDP(sport=1234, dport=1234)
2365 / Raw(b"\xa5" * 2000)
2368 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1500, 0, 0, 0])
2370 rxs = self.send_and_expect_some(self.pg0, p_mtu * NUM_PKTS, self.pg0)
2374 self.assertEqual(icmptypes[icmp.type], "dest-unreach")
2375 self.assertEqual(icmpcodes[icmp.type][icmp.code], "fragmentation-needed")
2376 self.assertEqual(icmp.nexthopmtu, 1500)
2377 self.assertEqual(icmp.src, self.pg0.remote_ip4)
2378 self.assertEqual(icmp.dst, self.pg1.remote_ip4)
2380 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2500, 0, 0, 0])
2381 rx = self.send_and_expect(self.pg0, p_mtu * NUM_PKTS, self.pg1)
2383 # Reset MTU for subsequent tests
2384 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [9000, 0, 0, 0])
2387 # source address 0.0.0.0 and 25.255.255.255 and for-us
2390 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2391 / IP(src="0.0.0.0", dst=self.pg0.local_ip4)
2393 / Raw(load=b"\x0a" * 18)
2395 rx = self.send_and_assert_no_replies(self.pg0, p_s0 * 17)
2398 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2399 / IP(src="255.255.255.255", dst=self.pg0.local_ip4)
2401 / Raw(load=b"\x0a" * 18)
2403 rx = self.send_and_assert_no_replies(self.pg0, p_s0 * 17)
2406 class TestIPDirectedBroadcast(VppTestCase):
2407 """IPv4 Directed Broadcast"""
2410 def setUpClass(cls):
2411 super(TestIPDirectedBroadcast, cls).setUpClass()
2414 def tearDownClass(cls):
2415 super(TestIPDirectedBroadcast, cls).tearDownClass()
2418 super(TestIPDirectedBroadcast, self).setUp()
2420 self.create_pg_interfaces(range(2))
2422 for i in self.pg_interfaces:
2426 super(TestIPDirectedBroadcast, self).tearDown()
2427 for i in self.pg_interfaces:
2430 def test_ip_input(self):
2431 """IP Directed Broadcast"""
2434 # set the directed broadcast on pg0 first, then config IP4 addresses
2435 # for pg1 directed broadcast is always disabled
2436 self.vapi.sw_interface_set_ip_directed_broadcast(self.pg0.sw_if_index, 1)
2439 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
2440 / IP(src="1.1.1.1", dst=self.pg0._local_ip4_bcast)
2441 / UDP(sport=1234, dport=1234)
2442 / Raw(b"\xa5" * 2000)
2445 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2446 / IP(src="1.1.1.1", dst=self.pg1._local_ip4_bcast)
2447 / UDP(sport=1234, dport=1234)
2448 / Raw(b"\xa5" * 2000)
2451 self.pg0.config_ip4()
2452 self.pg0.resolve_arp()
2453 self.pg1.config_ip4()
2454 self.pg1.resolve_arp()
2457 # test packet is L2 broadcast
2459 rx = self.send_and_expect(self.pg1, p0 * NUM_PKTS, self.pg0)
2460 self.assertTrue(rx[0][Ether].dst, "ff:ff:ff:ff:ff:ff")
2462 self.send_and_assert_no_replies(
2463 self.pg0, p1 * NUM_PKTS, "directed broadcast disabled"
2467 # toggle directed broadcast on pg0
2469 self.vapi.sw_interface_set_ip_directed_broadcast(self.pg0.sw_if_index, 0)
2470 self.send_and_assert_no_replies(
2471 self.pg1, p0 * NUM_PKTS, "directed broadcast disabled"
2474 self.vapi.sw_interface_set_ip_directed_broadcast(self.pg0.sw_if_index, 1)
2475 rx = self.send_and_expect(self.pg1, p0 * NUM_PKTS, self.pg0)
2477 self.pg0.unconfig_ip4()
2478 self.pg1.unconfig_ip4()
2481 class TestIPLPM(VppTestCase):
2482 """IPv4 longest Prefix Match"""
2485 def setUpClass(cls):
2486 super(TestIPLPM, cls).setUpClass()
2489 def tearDownClass(cls):
2490 super(TestIPLPM, cls).tearDownClass()
2493 super(TestIPLPM, self).setUp()
2495 self.create_pg_interfaces(range(4))
2497 for i in self.pg_interfaces:
2503 super(TestIPLPM, self).tearDown()
2504 for i in self.pg_interfaces:
2508 def test_ip_lpm(self):
2509 """IP longest Prefix Match"""
2515 [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)],
2517 s_24.add_vpp_config()
2522 [VppRoutePath(self.pg2.remote_ip4, self.pg2.sw_if_index)],
2524 s_8.add_vpp_config()
2527 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2528 / IP(src="1.1.1.1", dst="10.1.1.1")
2529 / UDP(sport=1234, dport=1234)
2530 / Raw(b"\xa5" * 2000)
2533 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2534 / IP(src="1.1.1.1", dst="10.1.2.1")
2535 / UDP(sport=1234, dport=1234)
2536 / Raw(b"\xa5" * 2000)
2539 self.logger.info(self.vapi.cli("sh ip fib mtrie"))
2540 rx = self.send_and_expect(self.pg0, p_8 * NUM_PKTS, self.pg2)
2541 rx = self.send_and_expect(self.pg0, p_24 * NUM_PKTS, self.pg1)
2544 @tag_fixme_vpp_workers
2545 class TestIPv4Frag(VppTestCase):
2546 """IPv4 fragmentation"""
2549 def setUpClass(cls):
2550 super(TestIPv4Frag, cls).setUpClass()
2552 cls.create_pg_interfaces([0, 1])
2553 cls.src_if = cls.pg0
2554 cls.dst_if = cls.pg1
2556 # setup all interfaces
2557 for i in cls.pg_interfaces:
2563 def tearDownClass(cls):
2564 super(TestIPv4Frag, cls).tearDownClass()
2566 def test_frag_large_packets(self):
2567 """Fragmentation of large packets"""
2569 self.vapi.cli("adjacency counters enable")
2572 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
2573 / IP(src=self.src_if.remote_ip4, dst=self.dst_if.remote_ip4)
2574 / UDP(sport=1234, dport=5678)
2577 self.extend_packet(p, 6000, "abcde")
2578 saved_payload = p[Raw].load
2582 self.dst_if.sw_if_index,
2583 self.dst_if.remote_mac,
2584 self.dst_if.remote_ip4,
2587 # Force fragmentation by setting MTU of output interface
2588 # lower than packet size
2589 self.vapi.sw_interface_set_mtu(self.dst_if.sw_if_index, [5000, 0, 0, 0])
2591 self.pg_enable_capture()
2592 self.src_if.add_stream(p)
2595 # Expecting 3 fragments because size of created fragments currently
2596 # cannot be larger then VPP buffer size (which is 2048)
2597 packets = self.dst_if.get_capture(3)
2599 # we should show 3 packets thru the neighbor
2600 self.assertEqual(3, nbr.get_stats()["packets"])
2602 # Assume VPP sends the fragments in order
2605 payload_offset = p.frag * 8
2606 if payload_offset > 0:
2607 payload_offset -= 8 # UDP header is not in payload
2608 self.assert_equal(payload_offset, len(payload))
2609 payload += p[Raw].load
2610 self.assert_equal(payload, saved_payload, "payload")
2613 class TestIPReplace(VppTestCase):
2614 """IPv4 Table Replace"""
2617 def setUpClass(cls):
2618 super(TestIPReplace, cls).setUpClass()
2621 def tearDownClass(cls):
2622 super(TestIPReplace, cls).tearDownClass()
2625 super(TestIPReplace, self).setUp()
2627 self.create_pg_interfaces(range(4))
2632 for i in self.pg_interfaces:
2636 i.generate_remote_hosts(2)
2637 self.tables.append(VppIpTable(self, table_id).add_vpp_config())
2641 super(TestIPReplace, self).tearDown()
2642 for i in self.pg_interfaces:
2646 def test_replace(self):
2647 """IP Table Replace"""
2649 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
2650 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
2652 links = [self.pg0, self.pg1, self.pg2, self.pg3]
2653 routes = [[], [], [], []]
2655 # load up the tables with some routes
2656 for ii, t in enumerate(self.tables):
2657 for jj in range(N_ROUTES):
2664 links[ii].remote_hosts[0].ip4, links[ii].sw_if_index
2667 links[ii].remote_hosts[1].ip4, links[ii].sw_if_index
2670 table_id=t.table_id,
2672 multi = VppIpMRoute(
2677 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
2680 self.pg0.sw_if_index,
2681 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT,
2684 self.pg1.sw_if_index,
2685 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
2688 self.pg2.sw_if_index,
2689 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
2692 self.pg3.sw_if_index,
2693 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
2696 table_id=t.table_id,
2698 routes[ii].append({"uni": uni, "multi": multi})
2701 # replace the tables a few times
2704 # replace_begin each table
2705 for t in self.tables:
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))
2716 # redownload the even numbered routes
2717 for ii, t in enumerate(self.tables):
2718 for jj in range(0, N_ROUTES, 2):
2719 routes[ii][jj]["uni"].add_vpp_config()
2720 routes[ii][jj]["multi"].add_vpp_config()
2722 # signal each table replace_end
2723 for t in self.tables:
2726 # we should find the even routes, but not the odd
2727 for ii, t in enumerate(self.tables):
2730 for jj in range(0, N_ROUTES, 2):
2731 self.assertTrue(find_route_in_dump(dump, routes[ii][jj]["uni"], t))
2733 find_mroute_in_dump(mdump, routes[ii][jj]["multi"], t)
2735 for jj in range(1, N_ROUTES - 1, 2):
2736 self.assertFalse(find_route_in_dump(dump, routes[ii][jj]["uni"], t))
2738 find_mroute_in_dump(mdump, routes[ii][jj]["multi"], t)
2741 # reload all the routes
2742 for ii, t in enumerate(self.tables):
2743 for r in routes[ii]:
2744 r["uni"].add_vpp_config()
2745 r["multi"].add_vpp_config()
2747 # all the routes are still there
2748 for ii, t in enumerate(self.tables):
2751 for r in routes[ii]:
2752 self.assertTrue(find_route_in_dump(dump, r["uni"], t))
2753 self.assertTrue(find_mroute_in_dump(mdump, r["multi"], t))
2756 # finally flush the tables for good measure
2758 for t in self.tables:
2760 self.assertEqual(len(t.dump()), 5)
2761 self.assertEqual(len(t.mdump()), 3)
2764 class TestIPCover(VppTestCase):
2765 """IPv4 Table Cover"""
2768 def setUpClass(cls):
2769 super(TestIPCover, cls).setUpClass()
2772 def tearDownClass(cls):
2773 super(TestIPCover, cls).tearDownClass()
2776 super(TestIPCover, self).setUp()
2778 self.create_pg_interfaces(range(4))
2783 for i in self.pg_interfaces:
2787 i.generate_remote_hosts(2)
2788 self.tables.append(VppIpTable(self, table_id).add_vpp_config())
2792 super(TestIPCover, self).tearDown()
2793 for i in self.pg_interfaces:
2797 def test_cover(self):
2798 """IP Table Cover"""
2800 # add a loop back with a /32 prefix
2801 lo = VppLoInterface(self)
2803 a = VppIpInterfaceAddress(self, lo, "127.0.0.1", 32).add_vpp_config()
2805 # add a neighbour that matches the loopback's /32
2807 self, lo.sw_if_index, lo.remote_mac, "127.0.0.1"
2810 # add the default route which will be the cover for /32
2815 [VppRoutePath("127.0.0.1", lo.sw_if_index)],
2819 # add/remove/add a longer mask cover
2821 self, "127.0.0.0", 8, [VppRoutePath("127.0.0.1", lo.sw_if_index)]
2823 r8.remove_vpp_config()
2825 r8.remove_vpp_config()
2827 # remove the default route
2828 r.remove_vpp_config()
2830 # remove the interface prefix
2831 a.remove_vpp_config()
2834 class TestIP4Replace(VppTestCase):
2835 """IPv4 Interface Address Replace"""
2838 def setUpClass(cls):
2839 super(TestIP4Replace, cls).setUpClass()
2842 def tearDownClass(cls):
2843 super(TestIP4Replace, cls).tearDownClass()
2846 super(TestIP4Replace, self).setUp()
2848 self.create_pg_interfaces(range(4))
2850 for i in self.pg_interfaces:
2854 super(TestIP4Replace, self).tearDown()
2855 for i in self.pg_interfaces:
2858 def get_n_pfxs(self, intf):
2859 return len(self.vapi.ip_address_dump(intf.sw_if_index))
2861 def test_replace(self):
2862 """IP interface address replace"""
2864 intf_pfxs = [[], [], [], []]
2866 # add prefixes to each of the interfaces
2867 for i in range(len(self.pg_interfaces)):
2868 intf = self.pg_interfaces[i]
2871 addr = "172.16.%d.1" % intf.sw_if_index
2872 a = VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config()
2873 intf_pfxs[i].append(a)
2875 # 172.16.x.2/24 - a different address in the same subnet as above
2876 addr = "172.16.%d.2" % intf.sw_if_index
2877 a = VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config()
2878 intf_pfxs[i].append(a)
2880 # 172.15.x.2/24 - a different address and subnet
2881 addr = "172.15.%d.2" % intf.sw_if_index
2882 a = VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config()
2883 intf_pfxs[i].append(a)
2885 # a dump should n_address in it
2886 for intf in self.pg_interfaces:
2887 self.assertEqual(self.get_n_pfxs(intf), 3)
2890 # remove all the address thru a replace
2892 self.vapi.sw_interface_address_replace_begin()
2893 self.vapi.sw_interface_address_replace_end()
2894 for intf in self.pg_interfaces:
2895 self.assertEqual(self.get_n_pfxs(intf), 0)
2898 # add all the interface addresses back
2903 for intf in self.pg_interfaces:
2904 self.assertEqual(self.get_n_pfxs(intf), 3)
2907 # replace again, but this time update/re-add the address on the first
2910 self.vapi.sw_interface_address_replace_begin()
2912 for p in intf_pfxs[:2]:
2916 self.vapi.sw_interface_address_replace_end()
2918 # on the first two the address still exist,
2919 # on the other two they do not
2920 for intf in self.pg_interfaces[:2]:
2921 self.assertEqual(self.get_n_pfxs(intf), 3)
2922 for p in intf_pfxs[:2]:
2924 self.assertTrue(v.query_vpp_config())
2925 for intf in self.pg_interfaces[2:]:
2926 self.assertEqual(self.get_n_pfxs(intf), 0)
2929 # add all the interface addresses back on the last two
2931 for p in intf_pfxs[2:]:
2934 for intf in self.pg_interfaces:
2935 self.assertEqual(self.get_n_pfxs(intf), 3)
2938 # replace again, this time add different prefixes on all the interfaces
2940 self.vapi.sw_interface_address_replace_begin()
2943 for intf in self.pg_interfaces:
2945 addr = "172.18.%d.1" % intf.sw_if_index
2946 pfxs.append(VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config())
2948 self.vapi.sw_interface_address_replace_end()
2950 # only .18 should exist on each interface
2951 for intf in self.pg_interfaces:
2952 self.assertEqual(self.get_n_pfxs(intf), 1)
2954 self.assertTrue(pfx.query_vpp_config())
2959 self.vapi.sw_interface_address_replace_begin()
2960 self.vapi.sw_interface_address_replace_end()
2961 for intf in self.pg_interfaces:
2962 self.assertEqual(self.get_n_pfxs(intf), 0)
2965 # add prefixes to each interface. post-begin add the prefix from
2966 # interface X onto interface Y. this would normally be an error
2967 # since it would generate a 'duplicate address' warning. but in
2968 # this case, since what is newly downloaded is sane, it's ok
2970 for intf in self.pg_interfaces:
2972 addr = "172.18.%d.1" % intf.sw_if_index
2973 VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config()
2975 self.vapi.sw_interface_address_replace_begin()
2978 for intf in self.pg_interfaces:
2980 addr = "172.18.%d.1" % (intf.sw_if_index + 1)
2981 pfxs.append(VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config())
2983 self.vapi.sw_interface_address_replace_end()
2985 self.logger.info(self.vapi.cli("sh int addr"))
2987 for intf in self.pg_interfaces:
2988 self.assertEqual(self.get_n_pfxs(intf), 1)
2990 self.assertTrue(pfx.query_vpp_config())
2993 class TestIPv4PathMTU(VppTestCase):
2997 def setUpClass(cls):
2998 super(TestIPv4PathMTU, cls).setUpClass()
3000 cls.create_pg_interfaces(range(2))
3002 # setup all interfaces
3003 for i in cls.pg_interfaces:
3009 def tearDownClass(cls):
3010 super(TestIPv4PathMTU, cls).tearDownClass()
3012 def test_path_mtu(self):
3016 # The goal here is not to test that fragmentation works correctly,
3017 # that's done elsewhere, the intent is to ensure that the Path MTU
3018 # settings are honoured.
3020 self.vapi.cli("adjacency counters enable")
3022 # set the interface MTU to a reasonable value
3023 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1800, 0, 0, 0])
3025 self.pg1.generate_remote_hosts(4)
3028 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
3029 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4)
3030 / UDP(sport=1234, dport=5678)
3034 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
3035 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4)
3036 / UDP(sport=1234, dport=5678)
3041 self, self.pg1.sw_if_index, self.pg1.remote_mac, self.pg1.remote_ip4
3044 # this is now the interface MTU frags
3045 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
3046 self.send_and_expect(self.pg0, [p_1k], self.pg1)
3048 # drop the path MTU for this neighbour to below the interface MTU
3050 pmtu = VppIpPathMtu(self, self.pg1.remote_ip4, 900).add_vpp_config()
3052 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3053 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3055 # print/format the adj delegate
3056 self.logger.info(self.vapi.cli("sh adj 5"))
3058 # increase the path MTU to more than the interface
3059 # expect to use the interface MTU
3062 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
3063 self.send_and_expect(self.pg0, [p_1k], self.pg1)
3065 # go back to an MTU from the path
3066 # wrap the call around mark-n-sweep to enusre updates clear stale
3067 self.vapi.ip_path_mtu_replace_begin()
3069 self.vapi.ip_path_mtu_replace_end()
3071 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3072 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3074 # raise the interface's MTU
3075 # should still use that of the path
3076 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2000, 0, 0, 0])
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 # set path high and interface low
3082 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [900, 0, 0, 0])
3083 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3084 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3086 # remove the path MTU using the mark-n-sweep semantics
3087 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1800, 0, 0, 0])
3088 self.vapi.ip_path_mtu_replace_begin()
3089 self.vapi.ip_path_mtu_replace_end()
3091 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
3092 self.send_and_expect(self.pg0, [p_1k], self.pg1)
3095 # set path MTU for a neighbour that doesn't exist, yet
3097 pmtu2 = VppIpPathMtu(self, self.pg1.remote_hosts[2].ip4, 900).add_vpp_config()
3100 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
3101 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[2].ip4)
3102 / UDP(sport=1234, dport=5678)
3106 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
3107 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[2].ip4)
3108 / UDP(sport=1234, dport=5678)
3114 self.pg1.sw_if_index,
3115 self.pg1.remote_hosts[2].mac,
3116 self.pg1.remote_hosts[2].ip4,
3119 # should frag to the path MTU
3120 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3121 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3123 # remove and re-add the neighbour
3124 nbr2.remove_vpp_config()
3125 nbr2.add_vpp_config()
3127 # should frag to the path MTU
3128 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3129 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3132 # set PMTUs for many peers
3135 self.pg1.generate_remote_hosts(16)
3136 self.pg1.configure_ipv4_neighbors()
3138 for h in range(N_HOSTS):
3139 pmtu = VppIpPathMtu(self, self.pg1.remote_hosts[h].ip4, 900)
3140 pmtu.add_vpp_config()
3141 self.assertTrue(pmtu.query_vpp_config())
3143 self.logger.info(self.vapi.cli("sh ip pmtu"))
3144 dump = list(self.vapi.vpp.details_iter(self.vapi.ip_path_mtu_get))
3145 self.assertEqual(N_HOSTS, len(dump))
3147 for h in range(N_HOSTS):
3148 p_2k[IP].dst = self.pg1.remote_hosts[h].ip4
3149 p_1k[IP].dst = self.pg1.remote_hosts[h].ip4
3151 # should frag to the path MTU
3152 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3153 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3156 class TestIPv4ItfRebind(VppTestCase):
3157 """IPv4 Interface Bind w/ attached routes"""
3160 super(TestIPv4ItfRebind, self).setUp()
3162 self.create_pg_interfaces(range(3))
3165 super(TestIPv4ItfRebind, self).tearDown()
3167 def test_rebind(self):
3168 """Import to no import"""
3171 tbl = VppIpTable(self, TABLE_ID).add_vpp_config()
3172 self.pg1.set_table_ip4(TABLE_ID)
3174 for i in self.pg_interfaces:
3179 # add an attached route via an pg0
3180 # in a different table. this prefix should import
3185 [VppRoutePath("0.0.0.0", self.pg0.sw_if_index)],
3190 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
3191 / IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4)
3192 / UDP(sport=1234, dport=5678)
3196 rx = self.send_and_expect(self.pg1, [p], self.pg0)
3197 self.assertFalse(rx[0].haslayer(ARP))
3199 # then bind pg0 to a new table
3200 # so the prefix no longer imports
3201 self.pg0.unconfig_ip4()
3202 self.pg0.set_table_ip4(TABLE_ID)
3203 self.pg0.config_ip4()
3204 self.pg0.resolve_arp()
3206 rx = self.send_and_expect(self.pg1, [p], self.pg0)
3207 self.assertFalse(rx[0].haslayer(ARP))
3209 # revert back to imported
3210 self.pg0.unconfig_ip4()
3211 self.pg0.set_table_ip4(0)
3212 self.pg0.config_ip4()
3213 self.pg0.resolve_arp()
3215 rx = self.send_and_expect(self.pg1, [p], self.pg0)
3216 self.assertFalse(rx[0].haslayer(ARP))
3219 for i in self.pg_interfaces:
3224 rt.remove_vpp_config()
3225 tbl.remove_vpp_config()
3227 def test_delete(self):
3228 """Swap import tables"""
3231 tbl1_4 = VppIpTable(self, TABLE_ID1).add_vpp_config()
3232 tbl1_6 = VppIpTable(self, TABLE_ID1, True).add_vpp_config()
3234 tbl2_4 = VppIpTable(self, TABLE_ID2).add_vpp_config()
3235 tbl2_6 = VppIpTable(self, TABLE_ID2, True).add_vpp_config()
3238 self.pg1.set_table_ip4(TABLE_ID1)
3239 self.pg1.set_table_ip6(TABLE_ID1)
3240 self.pg2.set_table_ip4(TABLE_ID2)
3241 self.pg2.set_table_ip6(TABLE_ID2)
3243 for i in self.pg_interfaces:
3248 # add an attached route in the default table via pg0
3249 # this should import to table 1
3254 [VppRoutePath("0.0.0.0", self.pg1.sw_if_index)],
3260 [VppRoutePath("0.0.0.0", self.pg1.sw_if_index)],
3264 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
3265 / IP(src=self.pg1.remote_ip4, dst=self.pg1.remote_ip4)
3266 / UDP(sport=1234, dport=5678)
3270 # inject into table 0
3271 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
3272 self.assertFalse(rx[0].haslayer(ARP))
3274 # swap the attached interface to table 2
3275 self.pg1.unconfig_ip4()
3276 self.pg1.unconfig_ip6()
3277 self.pg1.set_table_ip4(TABLE_ID2)
3278 self.pg1.set_table_ip6(TABLE_ID2)
3279 self.pg1.config_ip4()
3280 self.pg1.config_ip6()
3281 self.pg1.resolve_arp()
3286 tbl1_4.remove_vpp_config()
3287 tbl1_6.remove_vpp_config()
3289 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
3290 self.assertFalse(rx[0].haslayer(ARP))
3292 for i in self.pg_interfaces:
3300 if __name__ == "__main__":
3301 unittest.main(testRunner=VppTestRunner)