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):
568 for i in range(count):
571 start_dest_addr % (i + start),
573 [VppRoutePath(next_hop_addr, 0xFFFFFFFF)],
575 r.remove_vpp_config()
579 def create_stream(self, src_if, dst_if, routes, count):
582 for _ in range(count):
583 dst_addr = random.choice(routes).prefix.network_address
584 info = self.create_packet_info(src_if, dst_if)
585 payload = self.info_to_payload(info)
587 Ether(dst=src_if.local_mac, src=src_if.remote_mac)
588 / IP(src=src_if.remote_ip4, dst=str(dst_addr))
589 / UDP(sport=1234, dport=1234)
593 self.extend_packet(p, random.choice(self.pg_if_packet_sizes))
598 def _find_ip_match(self, find_in, pkt):
600 if self.payload_to_info(p[Raw]) == self.payload_to_info(pkt[Raw]):
601 if p[IP].src != pkt[IP].src:
603 if p[IP].dst != pkt[IP].dst:
605 if p[UDP].sport != pkt[UDP].sport:
607 if p[UDP].dport != pkt[UDP].dport:
612 def verify_capture(self, dst_interface, received_pkts, expected_pkts):
613 self.assertEqual(len(received_pkts), len(expected_pkts))
614 to_verify = list(expected_pkts)
615 for p in received_pkts:
616 self.assertEqual(p.src, dst_interface.local_mac)
617 self.assertEqual(p.dst, dst_interface.remote_mac)
618 x = self._find_ip_match(to_verify, p)
620 self.assertListEqual(to_verify, [])
622 def verify_route_dump(self, routes):
625 find_route(self, r.prefix.network_address, r.prefix.prefixlen)
628 def verify_not_in_route_dump(self, routes):
631 find_route(self, r.prefix.network_address, r.prefix.prefixlen)
637 #. Create and initialize 3 pg interfaces.
638 #. initialize class attributes configured_routes and deleted_routes
639 to store information between tests.
641 super(TestIPv4FibCrud, cls).setUpClass()
644 # create 3 pg interfaces
645 cls.create_pg_interfaces(range(3))
647 cls.interfaces = list(cls.pg_interfaces)
649 # setup all interfaces
650 for i in cls.interfaces:
655 cls.configured_routes = []
656 cls.deleted_routes = []
657 cls.pg_if_packet_sizes = [64, 512, 1518, 9018]
660 super(TestIPv4FibCrud, cls).tearDownClass()
664 def tearDownClass(cls):
665 super(TestIPv4FibCrud, cls).tearDownClass()
668 super(TestIPv4FibCrud, self).setUp()
669 self.reset_packet_infos()
671 self.configured_routes = []
672 self.deleted_routes = []
674 def test_1_add_routes(self):
677 # add 100 routes check with traffic script.
678 self.configured_routes.extend(
679 self.config_fib_many_to_one("10.0.0.%d", self.pg0.remote_ip4, 100)
682 self.verify_route_dump(self.configured_routes)
684 self.stream_1 = self.create_stream(
685 self.pg1, self.pg0, self.configured_routes, 100
687 self.stream_2 = self.create_stream(
688 self.pg2, self.pg0, self.configured_routes, 100
690 self.pg1.add_stream(self.stream_1)
691 self.pg2.add_stream(self.stream_2)
693 self.pg_enable_capture(self.pg_interfaces)
696 pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
697 self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
699 def test_2_del_routes(self):
702 - delete 10 routes check with traffic script.
704 # config 1M FIB entries
705 self.configured_routes.extend(
706 self.config_fib_many_to_one("10.0.0.%d", self.pg0.remote_ip4, 100)
708 self.deleted_routes.extend(
709 self.unconfig_fib_many_to_one(
710 "10.0.0.%d", self.pg0.remote_ip4, 10, start=10
713 for x in self.deleted_routes:
714 self.configured_routes.remove(x)
716 self.verify_route_dump(self.configured_routes)
718 self.stream_1 = self.create_stream(
719 self.pg1, self.pg0, self.configured_routes, 100
721 self.stream_2 = self.create_stream(
722 self.pg2, self.pg0, self.configured_routes, 100
724 self.stream_3 = self.create_stream(self.pg1, self.pg0, self.deleted_routes, 100)
725 self.stream_4 = self.create_stream(self.pg2, self.pg0, self.deleted_routes, 100)
726 self.pg1.add_stream(self.stream_1 + self.stream_3)
727 self.pg2.add_stream(self.stream_2 + self.stream_4)
728 self.pg_enable_capture(self.pg_interfaces)
731 pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
732 self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
734 def test_3_add_new_routes(self):
737 - re-add 5 routes check with traffic script.
738 - add 100 routes check with traffic script.
740 # config 1M FIB entries
741 self.configured_routes.extend(
742 self.config_fib_many_to_one("10.0.0.%d", self.pg0.remote_ip4, 100)
744 self.deleted_routes.extend(
745 self.unconfig_fib_many_to_one(
746 "10.0.0.%d", self.pg0.remote_ip4, 10, start=10
749 for x in self.deleted_routes:
750 self.configured_routes.remove(x)
752 tmp = self.config_fib_many_to_one("10.0.0.%d", self.pg0.remote_ip4, 5, start=10)
753 self.configured_routes.extend(tmp)
755 self.deleted_routes.remove(x)
757 self.configured_routes.extend(
758 self.config_fib_many_to_one("10.0.1.%d", self.pg0.remote_ip4, 100)
761 self.verify_route_dump(self.configured_routes)
763 self.stream_1 = self.create_stream(
764 self.pg1, self.pg0, self.configured_routes, 300
766 self.stream_2 = self.create_stream(
767 self.pg2, self.pg0, self.configured_routes, 300
769 self.stream_3 = self.create_stream(self.pg1, self.pg0, self.deleted_routes, 100)
770 self.stream_4 = self.create_stream(self.pg2, self.pg0, self.deleted_routes, 100)
772 self.pg1.add_stream(self.stream_1 + self.stream_3)
773 self.pg2.add_stream(self.stream_2 + self.stream_4)
774 self.pg_enable_capture(self.pg_interfaces)
777 pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
778 self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
780 # delete 5 routes check with traffic script.
781 # add 100 routes check with traffic script.
782 self.deleted_routes.extend(
783 self.unconfig_fib_many_to_one("10.0.0.%d", self.pg0.remote_ip4, 15)
785 self.deleted_routes.extend(
786 self.unconfig_fib_many_to_one("10.0.0.%d", self.pg0.remote_ip4, 85)
788 self.deleted_routes.extend(
789 self.unconfig_fib_many_to_one("10.0.1.%d", self.pg0.remote_ip4, 100)
791 self.verify_not_in_route_dump(self.deleted_routes)
794 class TestIPNull(VppTestCase):
795 """IPv4 routes via NULL"""
799 super(TestIPNull, cls).setUpClass()
802 def tearDownClass(cls):
803 super(TestIPNull, cls).tearDownClass()
806 super(TestIPNull, self).setUp()
808 # create 2 pg interfaces
809 self.create_pg_interfaces(range(2))
811 for i in self.pg_interfaces:
817 super(TestIPNull, self).tearDown()
818 for i in self.pg_interfaces:
822 def test_ip_null(self):
826 # A route via IP NULL that will reply with ICMP unreachables
828 ip_unreach = VppIpRoute(
834 "0.0.0.0", 0xFFFFFFFF, type=FibPathType.FIB_PATH_TYPE_ICMP_UNREACH
838 ip_unreach.add_vpp_config()
841 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
842 / IP(src=self.pg0.remote_ip4, dst="10.0.0.1")
843 / UDP(sport=1234, dport=1234)
846 self.pg0.add_stream(p_unreach)
847 self.pg_enable_capture(self.pg_interfaces)
850 rx = self.pg0.get_capture(1)
854 self.assertEqual(icmptypes[icmp.type], "dest-unreach")
855 self.assertEqual(icmpcodes[icmp.type][icmp.code], "host-unreachable")
856 self.assertEqual(icmp.src, self.pg0.remote_ip4)
857 self.assertEqual(icmp.dst, "10.0.0.1")
860 # ICMP replies are rate limited. so sit and spin.
865 # A route via IP NULL that will reply with ICMP prohibited
867 ip_prohibit = VppIpRoute(
873 "0.0.0.0", 0xFFFFFFFF, type=FibPathType.FIB_PATH_TYPE_ICMP_PROHIBIT
877 ip_prohibit.add_vpp_config()
880 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
881 / IP(src=self.pg0.remote_ip4, dst="10.0.0.2")
882 / UDP(sport=1234, dport=1234)
886 self.pg0.add_stream(p_prohibit)
887 self.pg_enable_capture(self.pg_interfaces)
890 rx = self.pg0.get_capture(1)
895 self.assertEqual(icmptypes[icmp.type], "dest-unreach")
896 self.assertEqual(icmpcodes[icmp.type][icmp.code], "host-prohibited")
897 self.assertEqual(icmp.src, self.pg0.remote_ip4)
898 self.assertEqual(icmp.dst, "10.0.0.2")
900 def test_ip_drop(self):
904 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
905 / IP(src=self.pg0.remote_ip4, dst="1.1.1.1")
906 / UDP(sport=1234, dport=1234)
914 [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)],
918 rx = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg1)
921 # insert a more specific as a drop
927 [VppRoutePath("0.0.0.0", 0xFFFFFFFF, type=FibPathType.FIB_PATH_TYPE_DROP)],
931 self.send_and_assert_no_replies(self.pg0, p * NUM_PKTS, "Drop Route")
932 r2.remove_vpp_config()
933 rx = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg1)
936 class TestIPDisabled(VppTestCase):
941 super(TestIPDisabled, cls).setUpClass()
944 def tearDownClass(cls):
945 super(TestIPDisabled, cls).tearDownClass()
948 super(TestIPDisabled, self).setUp()
950 # create 2 pg interfaces
951 self.create_pg_interfaces(range(2))
955 self.pg0.config_ip4()
956 self.pg0.resolve_arp()
958 # PG 1 is not IP enabled
962 super(TestIPDisabled, self).tearDown()
963 for i in self.pg_interfaces:
967 def test_ip_disabled(self):
970 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
971 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
975 # one accepting interface, pg0, 2 forwarding interfaces
977 route_232_1_1_1 = VppIpMRoute(
982 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
985 self.pg1.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT
988 self.pg0.sw_if_index, MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD
992 route_232_1_1_1.add_vpp_config()
995 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
996 / IP(src="10.10.10.10", dst=self.pg0.remote_ip4)
997 / UDP(sport=1234, dport=1234)
1001 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
1002 / IP(src="10.10.10.10", dst="232.1.1.1")
1003 / UDP(sport=1234, dport=1234)
1004 / Raw(b"\xa5" * 100)
1008 # PG1 does not forward IP traffic
1010 self.send_and_assert_no_replies(self.pg1, pu, "IP disabled")
1011 self.send_and_assert_no_replies(self.pg1, pm, "IP disabled")
1016 self.pg1.config_ip4()
1019 # Now we get packets through
1021 self.pg1.add_stream(pu)
1022 self.pg_enable_capture(self.pg_interfaces)
1024 rx = self.pg0.get_capture(1)
1026 self.pg1.add_stream(pm)
1027 self.pg_enable_capture(self.pg_interfaces)
1029 rx = self.pg0.get_capture(1)
1034 self.pg1.unconfig_ip4()
1037 # PG1 does not forward IP traffic
1039 self.send_and_assert_no_replies(self.pg1, pu, "IP disabled")
1040 self.send_and_assert_no_replies(self.pg1, pm, "IP disabled")
1043 class TestIPSubNets(VppTestCase):
1047 def setUpClass(cls):
1048 super(TestIPSubNets, cls).setUpClass()
1051 def tearDownClass(cls):
1052 super(TestIPSubNets, cls).tearDownClass()
1055 super(TestIPSubNets, self).setUp()
1057 # create a 2 pg interfaces
1058 self.create_pg_interfaces(range(2))
1060 # pg0 we will use to experiment
1063 # pg1 is setup normally
1065 self.pg1.config_ip4()
1066 self.pg1.resolve_arp()
1069 super(TestIPSubNets, self).tearDown()
1070 for i in self.pg_interfaces:
1073 def test_ip_sub_nets(self):
1077 # Configure a covering route to forward so we know
1078 # when we are dropping
1080 cover_route = VppIpRoute(
1084 [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)],
1086 cover_route.add_vpp_config()
1089 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
1090 / IP(dst="10.10.10.10", src=self.pg0.local_ip4)
1091 / UDP(sport=1234, dport=1234)
1092 / Raw(b"\xa5" * 100)
1095 self.pg1.add_stream(p)
1096 self.pg_enable_capture(self.pg_interfaces)
1098 rx = self.pg1.get_capture(1)
1101 # Configure some non-/24 subnets on an IP interface
1103 ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10")
1105 self.vapi.sw_interface_add_del_address(
1106 sw_if_index=self.pg0.sw_if_index, prefix="10.10.10.10/16"
1110 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
1111 / IP(dst="10.10.0.0", src=self.pg0.local_ip4)
1112 / UDP(sport=1234, dport=1234)
1113 / Raw(b"\xa5" * 100)
1116 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
1117 / IP(dst="10.10.255.255", src=self.pg0.local_ip4)
1118 / UDP(sport=1234, dport=1234)
1119 / Raw(b"\xa5" * 100)
1122 self.send_and_assert_no_replies(self.pg1, pn, "IP Network address")
1123 self.send_and_assert_no_replies(self.pg1, pb, "IP Broadcast address")
1125 # remove the sub-net and we are forwarding via the cover again
1126 self.vapi.sw_interface_add_del_address(
1127 sw_if_index=self.pg0.sw_if_index, prefix="10.10.10.10/16", is_add=0
1130 self.pg1.add_stream(pn)
1131 self.pg_enable_capture(self.pg_interfaces)
1133 rx = self.pg1.get_capture(1)
1134 self.pg1.add_stream(pb)
1135 self.pg_enable_capture(self.pg_interfaces)
1137 rx = self.pg1.get_capture(1)
1140 # A /31 is a special case where the 'other-side' is an attached host
1141 # packets to that peer generate ARP requests
1143 ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10")
1145 self.vapi.sw_interface_add_del_address(
1146 sw_if_index=self.pg0.sw_if_index, prefix="10.10.10.10/31"
1150 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
1151 / IP(dst="10.10.10.11", src=self.pg0.local_ip4)
1152 / UDP(sport=1234, dport=1234)
1153 / Raw(b"\xa5" * 100)
1156 self.pg1.add_stream(pn)
1157 self.pg_enable_capture(self.pg_interfaces)
1159 rx = self.pg0.get_capture(1)
1162 # remove the sub-net and we are forwarding via the cover again
1163 self.vapi.sw_interface_add_del_address(
1164 sw_if_index=self.pg0.sw_if_index, prefix="10.10.10.10/31", is_add=0
1167 self.pg1.add_stream(pn)
1168 self.pg_enable_capture(self.pg_interfaces)
1170 rx = self.pg1.get_capture(1)
1173 class TestIPLoadBalance(VppTestCase):
1174 """IPv4 Load-Balancing"""
1177 def setUpClass(cls):
1178 super(TestIPLoadBalance, cls).setUpClass()
1181 def tearDownClass(cls):
1182 super(TestIPLoadBalance, cls).tearDownClass()
1185 super(TestIPLoadBalance, self).setUp()
1187 self.create_pg_interfaces(range(5))
1188 mpls_tbl = VppMplsTable(self, 0)
1189 mpls_tbl.add_vpp_config()
1191 for i in self.pg_interfaces:
1198 for i in self.pg_interfaces:
1202 super(TestIPLoadBalance, self).tearDown()
1204 def total_len(self, rxs):
1210 def test_ip_load_balance(self):
1211 """IP Load-Balancing"""
1213 fhc = VppEnum.vl_api_ip_flow_hash_config_t
1214 fhcv2 = VppEnum.vl_api_ip_flow_hash_config_v2_t
1215 af = VppEnum.vl_api_address_family_t
1218 # An array of packets that differ only in the destination port
1225 # An array of packets that differ only in the source address
1231 for ii in range(NUM_PKTS):
1232 internal_src_ip_hdr = IP(dst="10.0.0.1", src="20.0.0.1")
1236 / UDP(sport=1234, dport=1234 + ii)
1237 / Raw(b"\xa5" * 100)
1239 port_ip_pkts.append(
1240 (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / port_ip_hdr)
1242 port_mpls_pkts.append(
1244 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1245 / MPLS(label=66, ttl=2)
1249 port_gtp_pkts.append(
1251 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1252 / internal_src_ip_hdr
1253 / UDP(sport=2152, dport=2152, chksum=0)
1254 / GTP_U_Header(gtp_type="g_pdu", teid=200)
1255 / Raw(b"\xa5" * 100)
1260 IP(dst="10.0.0.1", src="20.0.0.%d" % ii)
1261 / UDP(sport=1234, dport=1234)
1262 / Raw(b"\xa5" * 100)
1265 (Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac) / src_ip_hdr)
1267 src_mpls_pkts.append(
1269 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1270 / MPLS(label=66, ttl=2)
1274 src_gtp_pkts.append(
1276 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1277 / IP(dst="10.0.0.1", src="20.0.0.1")
1278 / UDP(sport=2152, dport=2152, chksum=0)
1279 / GTP_U_Header(gtp_type="g_pdu", teid=ii)
1280 / Raw(b"\xa5" * 100)
1284 route_10_0_0_1 = VppIpRoute(
1289 VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index),
1290 VppRoutePath(self.pg2.remote_ip4, self.pg2.sw_if_index),
1293 route_10_0_0_1.add_vpp_config()
1295 binding = VppMplsIpBind(self, 66, "10.0.0.1", 32)
1296 binding.add_vpp_config()
1299 # inject the packet on pg0 - expect load-balancing across the 2 paths
1300 # - since the default hash config is to use IP src,dst and port
1302 # We are not going to ensure equal amounts of packets across each link,
1303 # since the hash algorithm is statistical and therefore this can never
1304 # be guaranteed. But with 64 different packets we do expect some
1305 # balancing. So instead just ensure there is traffic on each link.
1307 rx = self.send_and_expect_load_balancing(
1308 self.pg0, port_ip_pkts, [self.pg1, self.pg2]
1310 n_ip_pg0 = len(rx[0])
1311 self.send_and_expect_load_balancing(self.pg0, src_ip_pkts, [self.pg1, self.pg2])
1312 self.send_and_expect_load_balancing(
1313 self.pg0, port_mpls_pkts, [self.pg1, self.pg2]
1315 rx = self.send_and_expect_load_balancing(
1316 self.pg0, src_mpls_pkts, [self.pg1, self.pg2]
1318 n_mpls_pg0 = len(rx[0])
1321 # change the router ID and expect the distribution changes
1323 self.vapi.set_ip_flow_hash_router_id(router_id=0x11111111)
1325 rx = self.send_and_expect_load_balancing(
1326 self.pg0, port_ip_pkts, [self.pg1, self.pg2]
1328 self.assertNotEqual(n_ip_pg0, len(rx[0]))
1330 rx = self.send_and_expect_load_balancing(
1331 self.pg0, src_mpls_pkts, [self.pg1, self.pg2]
1333 self.assertNotEqual(n_mpls_pg0, len(rx[0]))
1336 # change the flow hash config so it's only IP src,dst
1337 # - now only the stream with differing source address will
1340 self.vapi.set_ip_flow_hash_v2(
1344 fhc.IP_API_FLOW_HASH_SRC_IP
1345 | fhc.IP_API_FLOW_HASH_DST_IP
1346 | fhc.IP_API_FLOW_HASH_PROTO
1350 self.send_and_expect_load_balancing(self.pg0, src_ip_pkts, [self.pg1, self.pg2])
1351 self.send_and_expect_load_balancing(
1352 self.pg0, src_mpls_pkts, [self.pg1, self.pg2]
1355 self.send_and_expect_only(self.pg0, port_ip_pkts, self.pg2)
1358 # this case gtp v1 teid key LB
1360 self.vapi.set_ip_flow_hash_v3(
1364 fhcv2.IP_API_V2_FLOW_HASH_SRC_IP
1365 | fhcv2.IP_API_V2_FLOW_HASH_PROTO
1366 | fhcv2.IP_API_V2_FLOW_HASH_GTPV1_TEID
1369 self.logger.info(self.vapi.cli("show ip fib"))
1371 self.send_and_expect_load_balancing(
1372 self.pg0, src_gtp_pkts, [self.pg1, self.pg2]
1375 self.send_and_expect_only(self.pg0, port_gtp_pkts, self.pg2)
1378 # change the flow hash config back to defaults
1380 self.vapi.set_ip_flow_hash(vrf_id=0, src=1, dst=1, proto=1, sport=1, dport=1)
1383 # Recursive prefixes
1384 # - testing that 2 stages of load-balancing occurs and there is no
1385 # polarisation (i.e. only 2 of 4 paths are used)
1390 for ii in range(257):
1393 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1394 / IP(dst="1.1.1.1", src="20.0.0.1")
1395 / UDP(sport=1234, dport=1234 + ii)
1396 / Raw(b"\xa5" * 100)
1401 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1402 / IP(dst="1.1.1.1", src="20.0.0.%d" % ii)
1403 / UDP(sport=1234, dport=1234)
1404 / Raw(b"\xa5" * 100)
1408 route_10_0_0_2 = VppIpRoute(
1413 VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index),
1414 VppRoutePath(self.pg4.remote_ip4, self.pg4.sw_if_index),
1417 route_10_0_0_2.add_vpp_config()
1419 route_1_1_1_1 = VppIpRoute(
1424 VppRoutePath("10.0.0.2", 0xFFFFFFFF),
1425 VppRoutePath("10.0.0.1", 0xFFFFFFFF),
1428 route_1_1_1_1.add_vpp_config()
1431 # inject the packet on pg0 - expect load-balancing across all 4 paths
1433 self.vapi.cli("clear trace")
1434 self.send_and_expect_load_balancing(
1435 self.pg0, port_pkts, [self.pg1, self.pg2, self.pg3, self.pg4]
1437 self.send_and_expect_load_balancing(
1438 self.pg0, src_pkts, [self.pg1, self.pg2, self.pg3, self.pg4]
1442 # bring down pg1 expect LB to adjust to use only those that are up
1444 self.pg1.link_down()
1446 rx = self.send_and_expect_load_balancing(
1447 self.pg0, src_pkts, [self.pg2, self.pg3, self.pg4]
1449 self.assertEqual(len(src_pkts), self.total_len(rx))
1452 # bring down pg2 expect LB to adjust to use only those that are up
1454 self.pg2.link_down()
1456 rx = self.send_and_expect_load_balancing(
1457 self.pg0, src_pkts, [self.pg3, self.pg4]
1459 self.assertEqual(len(src_pkts), self.total_len(rx))
1462 # bring the links back up - expect LB over all again
1467 rx = self.send_and_expect_load_balancing(
1468 self.pg0, src_pkts, [self.pg1, self.pg2, self.pg3, self.pg4]
1470 self.assertEqual(len(src_pkts), self.total_len(rx))
1473 # The same link-up/down but this time admin state
1475 self.pg1.admin_down()
1476 self.pg2.admin_down()
1477 rx = self.send_and_expect_load_balancing(
1478 self.pg0, src_pkts, [self.pg3, self.pg4]
1480 self.assertEqual(len(src_pkts), self.total_len(rx))
1483 self.pg1.resolve_arp()
1484 self.pg2.resolve_arp()
1485 rx = self.send_and_expect_load_balancing(
1486 self.pg0, src_pkts, [self.pg1, self.pg2, self.pg3, self.pg4]
1488 self.assertEqual(len(src_pkts), self.total_len(rx))
1491 # Recursive prefixes
1492 # - testing that 2 stages of load-balancing, no choices
1496 for ii in range(257):
1499 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1500 / IP(dst="1.1.1.2", src="20.0.0.2")
1501 / UDP(sport=1234, dport=1234 + ii)
1502 / Raw(b"\xa5" * 100)
1506 route_10_0_0_3 = VppIpRoute(
1510 [VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index)],
1512 route_10_0_0_3.add_vpp_config()
1514 route_1_1_1_2 = VppIpRoute(
1515 self, "1.1.1.2", 32, [VppRoutePath("10.0.0.3", 0xFFFFFFFF)]
1517 route_1_1_1_2.add_vpp_config()
1520 # inject the packet on pg0 - rx only on via routes output interface
1522 self.vapi.cli("clear trace")
1523 self.send_and_expect_only(self.pg0, port_pkts, self.pg3)
1526 # Add a LB route in the presence of a down link - expect no
1527 # packets over the down link
1529 self.pg3.link_down()
1531 route_10_0_0_3 = VppIpRoute(
1536 VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index),
1537 VppRoutePath(self.pg4.remote_ip4, self.pg4.sw_if_index),
1540 route_10_0_0_3.add_vpp_config()
1543 for ii in range(257):
1545 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1546 / IP(dst="10.0.0.3", src="20.0.0.2")
1547 / UDP(sport=1234, dport=1234 + ii)
1548 / Raw(b"\xa5" * 100)
1551 self.send_and_expect_only(self.pg0, port_pkts, self.pg4)
1553 # bring the link back up
1556 rx = self.send_and_expect_load_balancing(
1557 self.pg0, port_pkts, [self.pg3, self.pg4]
1559 self.assertEqual(len(src_pkts), self.total_len(rx))
1562 class TestIPVlan0(VppTestCase):
1566 def setUpClass(cls):
1567 super(TestIPVlan0, cls).setUpClass()
1570 def tearDownClass(cls):
1571 super(TestIPVlan0, cls).tearDownClass()
1574 super(TestIPVlan0, self).setUp()
1576 self.create_pg_interfaces(range(2))
1577 mpls_tbl = VppMplsTable(self, 0)
1578 mpls_tbl.add_vpp_config()
1580 for i in self.pg_interfaces:
1587 for i in self.pg_interfaces:
1591 super(TestIPVlan0, self).tearDown()
1593 def test_ip_vlan_0(self):
1597 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1599 / IP(dst=self.pg1.remote_ip4, src=self.pg0.remote_ip4)
1600 / UDP(sport=1234, dport=1234)
1601 / Raw(b"\xa5" * 100)
1605 # Expect that packets sent on VLAN-0 are forwarded on the
1608 self.send_and_expect(self.pg0, pkts, self.pg1)
1611 class IPPuntSetup(object):
1612 """Setup for IPv4 Punt Police/Redirect"""
1614 def punt_setup(self):
1615 self.create_pg_interfaces(range(4))
1617 for i in self.pg_interfaces:
1622 # use UDP packet that have a port we need to explicitly
1623 # register to get punted.
1624 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
1625 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
1626 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
1632 "protocol": udp_proto,
1638 self.vapi.set_punt(is_add=1, punt=punt_udp)
1640 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
1646 "protocol": udp_proto,
1652 self.vapi.set_punt(is_add=1, punt=punt_udp)
1655 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1656 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
1657 / UDP(sport=1234, dport=1234)
1658 / Raw(b"\xa5" * 100)
1661 def punt_teardown(self):
1662 for i in self.pg_interfaces:
1667 class TestIPPunt(IPPuntSetup, VppTestCase):
1668 """IPv4 Punt Police/Redirect"""
1672 super().punt_setup()
1675 super().punt_teardown()
1678 def test_ip_punt_api_validation(self):
1679 """IP punt API parameter validation"""
1681 nh_addr = self.pg1.remote_ip4
1683 "rx_sw_if_index": self.pg0.sw_if_index,
1684 "af": VppEnum.vl_api_address_family_t.ADDRESS_IP4,
1689 with self.assertRaises(vpp_papi.VPPIOError):
1690 self.vapi.add_del_ip_punt_redirect_v2(punt=punt, is_add=True)
1693 "rx_sw_if_index": self.pg0.sw_if_index,
1694 "af": VppEnum.vl_api_address_family_t.ADDRESS_IP4,
1699 self.vapi.add_del_ip_punt_redirect_v2(punt=punt, is_add=True)
1701 def test_ip_punt(self):
1702 """IP punt police and redirect"""
1704 pkts = self.pkt * 1025
1707 # Configure a punt redirect via pg1.
1709 nh_addr = self.pg1.remote_ip4
1710 ip_punt_redirect = VppIpPuntRedirect(
1711 self, self.pg0.sw_if_index, self.pg1.sw_if_index, nh_addr
1713 ip_punt_redirect.add_vpp_config()
1715 self.send_and_expect(self.pg0, pkts, self.pg1)
1720 policer = VppPolicer(self, "ip4-punt", 400, 0, 10, 0, rate_type=1)
1721 policer.add_vpp_config()
1722 ip_punt_policer = VppIpPuntPolicer(self, policer.policer_index)
1723 ip_punt_policer.add_vpp_config()
1725 self.vapi.cli("clear trace")
1726 self.pg0.add_stream(pkts)
1727 self.pg_enable_capture(self.pg_interfaces)
1731 # the number of packet received should be greater than 0,
1732 # but not equal to the number sent, since some were policed
1734 rx = self.pg1._get_capture(1)
1736 stats = policer.get_stats()
1738 # Single rate policer - expect conform, violate but no exceed
1739 self.assertGreater(stats["conform_packets"], 0)
1740 self.assertEqual(stats["exceed_packets"], 0)
1741 self.assertGreater(stats["violate_packets"], 0)
1743 self.assertGreater(len(rx), 0)
1744 self.assertLess(len(rx), len(pkts))
1747 # remove the policer. back to full rx
1749 ip_punt_policer.remove_vpp_config()
1750 policer.remove_vpp_config()
1751 self.send_and_expect(self.pg0, pkts, self.pg1)
1754 # remove the redirect. expect full drop.
1756 ip_punt_redirect.remove_vpp_config()
1757 self.send_and_assert_no_replies(self.pg0, pkts, "IP no punt config")
1760 # Add a redirect that is not input port selective
1762 ip_punt_redirect = VppIpPuntRedirect(
1763 self, 0xFFFFFFFF, self.pg1.sw_if_index, nh_addr
1765 ip_punt_redirect.add_vpp_config()
1766 self.send_and_expect(self.pg0, pkts, self.pg1)
1767 ip_punt_redirect.remove_vpp_config()
1769 def test_ip_punt_vrf(self):
1770 """IP punt/local with VRFs"""
1772 # use a punt redirect to test if for-us packets are accepted
1773 pkts = self.pkt * 1025
1775 vlans_pg0 = [VppDot1QSubint(self, self.pg0, v) for v in range(100, 104)]
1776 vlans_pg1 = [VppDot1QSubint(self, self.pg1, v) for v in range(100, 104)]
1777 tbl4 = [VppIpTable(self, v).add_vpp_config() for v in range(100, 104)]
1778 tbl6 = [VppIpTable(self, v, True).add_vpp_config() for v in range(100, 104)]
1780 for v in vlans_pg0 + vlans_pg1:
1782 v.set_table_ip4(v.vlan)
1783 v.set_table_ip6(v.vlan)
1792 vlans_pg0[i].sw_if_index,
1793 vlans_pg1[i].sw_if_index,
1794 vlans_pg1[i].remote_ip4,
1801 vlans_pg0[i].sw_if_index,
1802 vlans_pg1[i].sw_if_index,
1803 vlans_pg1[i].remote_ip6,
1810 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1811 / Dot1Q(vlan=i.vlan)
1812 / IP(src=i.remote_ip4, dst=i.local_ip4)
1813 / UDP(sport=1234, dport=1234)
1814 / Raw(b"\xa5" * 100)
1819 self.send_and_expect(self.pg0, pkts, self.pg1)
1825 # we reject packets for source addresses in the wrong vlan/VRF
1828 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1829 / Dot1Q(vlan=i.vlan)
1830 / IP(src="1.1.1.1", dst=i.local_ip4)
1831 / UDP(sport=1234, dport=1234)
1832 / Raw(b"\xa5" * 100)
1836 # single and dual loop
1837 self.send_and_assert_no_replies(self.pg0, [pkts[0]])
1838 self.send_and_assert_no_replies(self.pg0, pkts)
1840 self.assert_error_counter_equal("/err/ip4-local/src_lookup_miss", len(pkts) + 1)
1842 # using the same source in different tables, should reject
1843 # for the table that the source is not present in
1844 # the first packet in the stream is drop
1847 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1848 / Dot1Q(vlan=i.vlan)
1849 / IP(src=vlans_pg0[0].remote_ip4, dst=i.local_ip4)
1850 / UDP(sport=1234, dport=1234)
1851 / Raw(b"\xa5" * 100)
1855 # single loop accept and drop
1856 # followed by both in the same frame/loop
1857 self.send_and_expect(self.pg0, [pkts[0]], self.pg1)
1858 self.send_and_assert_no_replies(self.pg0, [pkts[1]])
1859 self.send_and_expect(self.pg0, pkts * 4, self.pg1, n_rx=4)
1861 # using the same source in different tables, should reject
1862 # for the table that the source is not present in
1863 # the first packet in the stream is accept
1866 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1867 / Dot1Q(vlan=i.vlan)
1868 / IP(src=vlans_pg0[3].remote_ip4, dst=i.local_ip4)
1869 / UDP(sport=1234, dport=1234)
1870 / 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[3]], 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)
1885 # we reject packets for source addresses in the wrong vlan/VRF
1888 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1889 / Dot1Q(vlan=i.vlan)
1890 / IPv6(src="1::1", dst=i.local_ip6)
1891 / UDP(sport=1236, dport=1236)
1892 / Raw(b"\xa5" * 100)
1896 # single and dual loop
1897 self.send_and_assert_no_replies(self.pg0, [pkts[0]])
1898 self.send_and_assert_no_replies(self.pg0, pkts)
1900 self.assert_error_counter_equal("/err/ip6-input/src_lookup_miss", len(pkts) + 1)
1902 # using the same source in different tables, should reject
1903 # for the table that the source is not present in
1904 # the first packet in the stream is drop
1907 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1908 / Dot1Q(vlan=i.vlan)
1909 / IPv6(src=vlans_pg0[0].remote_ip6, dst=i.local_ip6)
1910 / UDP(sport=1236, dport=1236)
1911 / Raw(b"\xa5" * 100)
1915 # single loop accept and drop
1916 # followed by both in the same frame/loop
1917 self.send_and_expect(self.pg0, [pkts[0]], self.pg1)
1918 self.send_and_assert_no_replies(self.pg0, [pkts[1]])
1919 self.send_and_expect(self.pg0, pkts * 4, self.pg1, n_rx=4)
1921 # using the same source in different tables, should reject
1922 # for the table that the source is not present in
1923 # the first packet in the stream is accept
1926 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1927 / Dot1Q(vlan=i.vlan)
1928 / IPv6(src=vlans_pg0[3].remote_ip6, dst=i.local_ip6)
1929 / UDP(sport=1236, dport=1236)
1930 / Raw(b"\xa5" * 100)
1935 # single loop accept and drop
1936 # followed by both in the same frame/loop
1937 self.send_and_expect(self.pg0, [pkts[3]], self.pg1)
1938 self.send_and_assert_no_replies(self.pg0, [pkts[1]])
1939 self.send_and_expect(self.pg0, pkts * 4, self.pg1, n_rx=4)
1941 for v in vlans_pg0 + vlans_pg1:
1947 def test_ip_punt_dump(self):
1948 """IP4 punt redirect dump"""
1951 # Configure a punt redirects
1953 nh_address = self.pg3.remote_ip4
1954 ipr_03 = VppIpPuntRedirect(
1955 self, self.pg0.sw_if_index, self.pg3.sw_if_index, nh_address
1957 ipr_13 = VppIpPuntRedirect(
1958 self, self.pg1.sw_if_index, self.pg3.sw_if_index, nh_address
1960 ipr_23 = VppIpPuntRedirect(
1961 self, self.pg2.sw_if_index, self.pg3.sw_if_index, "0.0.0.0"
1963 ipr_03.add_vpp_config()
1964 ipr_13.add_vpp_config()
1965 ipr_23.add_vpp_config()
1968 # Dump pg0 punt redirects
1970 self.assertTrue(ipr_03.query_vpp_config())
1971 self.assertTrue(ipr_13.query_vpp_config())
1972 self.assertTrue(ipr_23.query_vpp_config())
1975 # Dump punt redirects for all interfaces
1977 punts = self.vapi.ip_punt_redirect_dump(0xFFFFFFFF)
1978 self.assertEqual(len(punts), 3)
1980 self.assertEqual(p.punt.tx_sw_if_index, self.pg3.sw_if_index)
1981 self.assertNotEqual(punts[1].punt.nh, self.pg3.remote_ip4)
1982 self.assertEqual(str(punts[2].punt.nh), "0.0.0.0")
1985 class TestIPPuntHandoff(IPPuntSetup, VppTestCase):
1986 """IPv4 Punt Policer thread handoff"""
1988 vpp_worker_count = 2
1991 super(TestIPPuntHandoff, self).setUp()
1992 super(TestIPPuntHandoff, self).punt_setup()
1995 super(TestIPPuntHandoff, self).punt_teardown()
1996 super(TestIPPuntHandoff, self).tearDown()
1998 def test_ip_punt_policer_handoff(self):
1999 """IP4 punt policer thread handoff"""
2000 pkts = self.pkt * NUM_PKTS
2003 # Configure a punt redirect via pg1.
2005 nh_addr = self.pg1.remote_ip4
2006 ip_punt_redirect = VppIpPuntRedirect(
2007 self, self.pg0.sw_if_index, self.pg1.sw_if_index, nh_addr
2009 ip_punt_redirect.add_vpp_config()
2011 action_tx = PolicerAction(
2012 VppEnum.vl_api_sse2_qos_action_type_t.SSE2_QOS_ACTION_API_TRANSMIT, 0
2015 # This policer drops no packets, we are just
2016 # testing that they get to the right thread.
2018 policer = VppPolicer(
2033 policer.add_vpp_config()
2034 ip_punt_policer = VppIpPuntPolicer(self, policer.policer_index)
2035 ip_punt_policer.add_vpp_config()
2037 for worker in [0, 1]:
2038 self.send_and_expect(self.pg0, pkts, self.pg1, worker=worker)
2039 self.logger.debug(self.vapi.cli("show trace max 100"))
2041 # Combined stats, all threads
2042 stats = policer.get_stats()
2044 # Single rate policer - expect conform, violate but no exceed
2045 self.assertGreater(stats["conform_packets"], 0)
2046 self.assertEqual(stats["exceed_packets"], 0)
2047 self.assertGreater(stats["violate_packets"], 0)
2049 # Worker 0, should have done all the policing
2050 stats0 = policer.get_stats(worker=0)
2051 self.assertEqual(stats, stats0)
2053 # Worker 1, should have handed everything off
2054 stats1 = policer.get_stats(worker=1)
2055 self.assertEqual(stats1["conform_packets"], 0)
2056 self.assertEqual(stats1["exceed_packets"], 0)
2057 self.assertEqual(stats1["violate_packets"], 0)
2059 # Bind the policer to worker 1 and repeat
2060 policer.bind_vpp_config(1, True)
2061 for worker in [0, 1]:
2062 self.send_and_expect(self.pg0, pkts, self.pg1, worker=worker)
2063 self.logger.debug(self.vapi.cli("show trace max 100"))
2065 # The 2 workers should now have policed the same amount
2066 stats = policer.get_stats()
2067 stats0 = policer.get_stats(worker=0)
2068 stats1 = policer.get_stats(worker=1)
2070 self.assertGreater(stats0["conform_packets"], 0)
2071 self.assertEqual(stats0["exceed_packets"], 0)
2072 self.assertGreater(stats0["violate_packets"], 0)
2074 self.assertGreater(stats1["conform_packets"], 0)
2075 self.assertEqual(stats1["exceed_packets"], 0)
2076 self.assertGreater(stats1["violate_packets"], 0)
2079 stats0["conform_packets"] + stats1["conform_packets"],
2080 stats["conform_packets"],
2084 stats0["violate_packets"] + stats1["violate_packets"],
2085 stats["violate_packets"],
2088 # Unbind the policer and repeat
2089 policer.bind_vpp_config(1, False)
2090 for worker in [0, 1]:
2091 self.send_and_expect(self.pg0, pkts, self.pg1, worker=worker)
2092 self.logger.debug(self.vapi.cli("show trace max 100"))
2094 # The policer should auto-bind to worker 0 when packets arrive
2095 stats = policer.get_stats()
2096 stats0new = policer.get_stats(worker=0)
2097 stats1new = policer.get_stats(worker=1)
2099 self.assertGreater(stats0new["conform_packets"], stats0["conform_packets"])
2100 self.assertEqual(stats0new["exceed_packets"], 0)
2101 self.assertGreater(stats0new["violate_packets"], stats0["violate_packets"])
2103 self.assertEqual(stats1, stats1new)
2108 ip_punt_policer.remove_vpp_config()
2109 policer.remove_vpp_config()
2110 ip_punt_redirect.remove_vpp_config()
2113 class TestIPDeag(VppTestCase):
2114 """IPv4 Deaggregate Routes"""
2117 def setUpClass(cls):
2118 super(TestIPDeag, cls).setUpClass()
2121 def tearDownClass(cls):
2122 super(TestIPDeag, cls).tearDownClass()
2125 super(TestIPDeag, self).setUp()
2127 self.create_pg_interfaces(range(3))
2129 for i in self.pg_interfaces:
2135 super(TestIPDeag, self).tearDown()
2136 for i in self.pg_interfaces:
2140 def test_ip_deag(self):
2141 """IP Deag Routes"""
2144 # Create a table to be used for:
2145 # 1 - another destination address lookup
2146 # 2 - a source address lookup
2148 table_dst = VppIpTable(self, 1)
2149 table_src = VppIpTable(self, 2)
2150 table_dst.add_vpp_config()
2151 table_src.add_vpp_config()
2154 # Add a route in the default table to point to a deag/
2155 # second lookup in each of these tables
2157 route_to_dst = VppIpRoute(
2158 self, "1.1.1.1", 32, [VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=1)]
2160 route_to_src = VppIpRoute(
2169 type=FibPathType.FIB_PATH_TYPE_SOURCE_LOOKUP,
2173 route_to_dst.add_vpp_config()
2174 route_to_src.add_vpp_config()
2177 # packets to these destination are dropped, since they'll
2178 # hit the respective default routes in the second table
2181 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2182 / IP(src="5.5.5.5", dst="1.1.1.1")
2183 / TCP(sport=1234, dport=1234)
2184 / Raw(b"\xa5" * 100)
2187 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2188 / IP(src="2.2.2.2", dst="1.1.1.2")
2189 / TCP(sport=1234, dport=1234)
2190 / Raw(b"\xa5" * 100)
2192 pkts_dst = p_dst * 257
2193 pkts_src = p_src * 257
2195 self.send_and_assert_no_replies(self.pg0, pkts_dst, "IP in dst table")
2196 self.send_and_assert_no_replies(self.pg0, pkts_src, "IP in src table")
2199 # add a route in the dst table to forward via pg1
2201 route_in_dst = VppIpRoute(
2205 [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)],
2208 route_in_dst.add_vpp_config()
2210 self.send_and_expect(self.pg0, pkts_dst, self.pg1)
2213 # add a route in the src table to forward via pg2
2215 route_in_src = VppIpRoute(
2219 [VppRoutePath(self.pg2.remote_ip4, self.pg2.sw_if_index)],
2222 route_in_src.add_vpp_config()
2223 self.send_and_expect(self.pg0, pkts_src, self.pg2)
2226 # loop in the lookup DP
2228 route_loop = VppIpRoute(
2229 self, "2.2.2.3", 32, [VppRoutePath("0.0.0.0", 0xFFFFFFFF, nh_table_id=0)]
2231 route_loop.add_vpp_config()
2234 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2235 / IP(src="2.2.2.4", dst="2.2.2.3")
2236 / TCP(sport=1234, dport=1234)
2237 / Raw(b"\xa5" * 100)
2240 self.send_and_assert_no_replies(self.pg0, p_l * 257, "IP lookup loop")
2243 class TestIPInput(VppTestCase):
2244 """IPv4 Input Exceptions"""
2247 def setUpClass(cls):
2248 super(TestIPInput, cls).setUpClass()
2251 def tearDownClass(cls):
2252 super(TestIPInput, cls).tearDownClass()
2255 super(TestIPInput, self).setUp()
2257 self.create_pg_interfaces(range(2))
2259 for i in self.pg_interfaces:
2265 super(TestIPInput, self).tearDown()
2266 for i in self.pg_interfaces:
2270 def test_ip_input(self):
2271 """IP Input Exceptions"""
2273 # i can't find a way in scapy to construct an IP packet
2274 # with a length less than the IP header length
2277 # Packet too short - this is forwarded
2280 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2281 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, len=40)
2282 / UDP(sport=1234, dport=1234)
2283 / Raw(b"\xa5" * 100)
2286 rx = self.send_and_expect(self.pg0, p_short * NUM_PKTS, self.pg1)
2289 # Packet too long - 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, len=400)
2294 / UDP(sport=1234, dport=1234)
2295 / Raw(b"\xa5" * 100)
2298 rx = self.send_and_assert_no_replies(self.pg0, p_long * NUM_PKTS, "too long")
2301 # bad chksum - this is dropped
2304 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2305 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, chksum=400)
2306 / UDP(sport=1234, dport=1234)
2307 / Raw(b"\xa5" * 100)
2310 rx = self.send_and_assert_no_replies(
2311 self.pg0, p_chksum * NUM_PKTS, "bad checksum"
2315 # bad version - this is dropped
2318 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2319 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, version=3)
2320 / UDP(sport=1234, dport=1234)
2321 / Raw(b"\xa5" * 100)
2324 rx = self.send_and_assert_no_replies(
2325 self.pg0, p_ver * NUM_PKTS, "funky version"
2329 # fragment offset 1 - this is dropped
2332 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2333 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, frag=1)
2334 / UDP(sport=1234, dport=1234)
2335 / Raw(b"\xa5" * 100)
2338 rx = self.send_and_assert_no_replies(self.pg0, p_frag * NUM_PKTS, "frag offset")
2341 # TTL expired packet
2344 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2345 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=1)
2346 / UDP(sport=1234, dport=1234)
2347 / Raw(b"\xa5" * 100)
2350 rxs = self.send_and_expect_some(self.pg0, p_ttl * NUM_PKTS, self.pg0)
2354 self.assertEqual(icmptypes[icmp.type], "time-exceeded")
2355 self.assertEqual(icmpcodes[icmp.type][icmp.code], "ttl-zero-during-transit")
2356 self.assertEqual(icmp.src, self.pg0.remote_ip4)
2357 self.assertEqual(icmp.dst, self.pg1.remote_ip4)
2363 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2364 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4, ttl=10, flags="DF")
2365 / UDP(sport=1234, dport=1234)
2366 / Raw(b"\xa5" * 2000)
2369 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1500, 0, 0, 0])
2371 rxs = self.send_and_expect_some(self.pg0, p_mtu * NUM_PKTS, self.pg0)
2375 self.assertEqual(icmptypes[icmp.type], "dest-unreach")
2376 self.assertEqual(icmpcodes[icmp.type][icmp.code], "fragmentation-needed")
2377 self.assertEqual(icmp.nexthopmtu, 1500)
2378 self.assertEqual(icmp.src, self.pg0.remote_ip4)
2379 self.assertEqual(icmp.dst, self.pg1.remote_ip4)
2381 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2500, 0, 0, 0])
2382 rx = self.send_and_expect(self.pg0, p_mtu * NUM_PKTS, self.pg1)
2384 # Reset MTU for subsequent tests
2385 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [9000, 0, 0, 0])
2388 # source address 0.0.0.0 and 25.255.255.255 and for-us
2391 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2392 / IP(src="0.0.0.0", dst=self.pg0.local_ip4)
2394 / Raw(load=b"\x0a" * 18)
2396 rx = self.send_and_assert_no_replies(self.pg0, p_s0 * 17)
2399 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2400 / IP(src="255.255.255.255", dst=self.pg0.local_ip4)
2402 / Raw(load=b"\x0a" * 18)
2404 rx = self.send_and_assert_no_replies(self.pg0, p_s0 * 17)
2407 class TestIPDirectedBroadcast(VppTestCase):
2408 """IPv4 Directed Broadcast"""
2411 def setUpClass(cls):
2412 super(TestIPDirectedBroadcast, cls).setUpClass()
2415 def tearDownClass(cls):
2416 super(TestIPDirectedBroadcast, cls).tearDownClass()
2419 super(TestIPDirectedBroadcast, self).setUp()
2421 self.create_pg_interfaces(range(2))
2423 for i in self.pg_interfaces:
2427 super(TestIPDirectedBroadcast, self).tearDown()
2428 for i in self.pg_interfaces:
2431 def test_ip_input(self):
2432 """IP Directed Broadcast"""
2435 # set the directed broadcast on pg0 first, then config IP4 addresses
2436 # for pg1 directed broadcast is always disabled
2437 self.vapi.sw_interface_set_ip_directed_broadcast(self.pg0.sw_if_index, 1)
2440 Ether(src=self.pg1.remote_mac, dst=self.pg1.local_mac)
2441 / IP(src="1.1.1.1", dst=self.pg0._local_ip4_bcast)
2442 / UDP(sport=1234, dport=1234)
2443 / Raw(b"\xa5" * 2000)
2446 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2447 / IP(src="1.1.1.1", dst=self.pg1._local_ip4_bcast)
2448 / UDP(sport=1234, dport=1234)
2449 / Raw(b"\xa5" * 2000)
2452 self.pg0.config_ip4()
2453 self.pg0.resolve_arp()
2454 self.pg1.config_ip4()
2455 self.pg1.resolve_arp()
2458 # test packet is L2 broadcast
2460 rx = self.send_and_expect(self.pg1, p0 * NUM_PKTS, self.pg0)
2461 self.assertTrue(rx[0][Ether].dst, "ff:ff:ff:ff:ff:ff")
2463 self.send_and_assert_no_replies(
2464 self.pg0, p1 * NUM_PKTS, "directed broadcast disabled"
2468 # toggle directed broadcast on pg0
2470 self.vapi.sw_interface_set_ip_directed_broadcast(self.pg0.sw_if_index, 0)
2471 self.send_and_assert_no_replies(
2472 self.pg1, p0 * NUM_PKTS, "directed broadcast disabled"
2475 self.vapi.sw_interface_set_ip_directed_broadcast(self.pg0.sw_if_index, 1)
2476 rx = self.send_and_expect(self.pg1, p0 * NUM_PKTS, self.pg0)
2478 self.pg0.unconfig_ip4()
2479 self.pg1.unconfig_ip4()
2482 class TestIPLPM(VppTestCase):
2483 """IPv4 longest Prefix Match"""
2486 def setUpClass(cls):
2487 super(TestIPLPM, cls).setUpClass()
2490 def tearDownClass(cls):
2491 super(TestIPLPM, cls).tearDownClass()
2494 super(TestIPLPM, self).setUp()
2496 self.create_pg_interfaces(range(4))
2498 for i in self.pg_interfaces:
2504 super(TestIPLPM, self).tearDown()
2505 for i in self.pg_interfaces:
2509 def test_ip_lpm(self):
2510 """IP longest Prefix Match"""
2516 [VppRoutePath(self.pg1.remote_ip4, self.pg1.sw_if_index)],
2518 s_24.add_vpp_config()
2523 [VppRoutePath(self.pg2.remote_ip4, self.pg2.sw_if_index)],
2525 s_8.add_vpp_config()
2528 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2529 / IP(src="1.1.1.1", dst="10.1.1.1")
2530 / UDP(sport=1234, dport=1234)
2531 / Raw(b"\xa5" * 2000)
2534 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
2535 / IP(src="1.1.1.1", dst="10.1.2.1")
2536 / UDP(sport=1234, dport=1234)
2537 / Raw(b"\xa5" * 2000)
2540 self.logger.info(self.vapi.cli("sh ip fib mtrie"))
2541 rx = self.send_and_expect(self.pg0, p_8 * NUM_PKTS, self.pg2)
2542 rx = self.send_and_expect(self.pg0, p_24 * NUM_PKTS, self.pg1)
2545 @tag_fixme_vpp_workers
2546 class TestIPv4Frag(VppTestCase):
2547 """IPv4 fragmentation"""
2550 def setUpClass(cls):
2551 super(TestIPv4Frag, cls).setUpClass()
2553 cls.create_pg_interfaces([0, 1])
2554 cls.src_if = cls.pg0
2555 cls.dst_if = cls.pg1
2557 # setup all interfaces
2558 for i in cls.pg_interfaces:
2564 def tearDownClass(cls):
2565 super(TestIPv4Frag, cls).tearDownClass()
2567 def test_frag_large_packets(self):
2568 """Fragmentation of large packets"""
2570 self.vapi.cli("adjacency counters enable")
2573 Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac)
2574 / IP(src=self.src_if.remote_ip4, dst=self.dst_if.remote_ip4)
2575 / UDP(sport=1234, dport=5678)
2578 self.extend_packet(p, 6000, "abcde")
2579 saved_payload = p[Raw].load
2583 self.dst_if.sw_if_index,
2584 self.dst_if.remote_mac,
2585 self.dst_if.remote_ip4,
2588 # Force fragmentation by setting MTU of output interface
2589 # lower than packet size
2590 self.vapi.sw_interface_set_mtu(self.dst_if.sw_if_index, [5000, 0, 0, 0])
2592 self.pg_enable_capture()
2593 self.src_if.add_stream(p)
2596 # Expecting 3 fragments because size of created fragments currently
2597 # cannot be larger then VPP buffer size (which is 2048)
2598 packets = self.dst_if.get_capture(3)
2600 # we should show 3 packets thru the neighbor
2601 self.assertEqual(3, nbr.get_stats()["packets"])
2603 # Assume VPP sends the fragments in order
2606 payload_offset = p.frag * 8
2607 if payload_offset > 0:
2608 payload_offset -= 8 # UDP header is not in payload
2609 self.assert_equal(payload_offset, len(payload))
2610 payload += p[Raw].load
2611 self.assert_equal(payload, saved_payload, "payload")
2614 class TestIPReplace(VppTestCase):
2615 """IPv4 Table Replace"""
2618 def setUpClass(cls):
2619 super(TestIPReplace, cls).setUpClass()
2622 def tearDownClass(cls):
2623 super(TestIPReplace, cls).tearDownClass()
2626 super(TestIPReplace, self).setUp()
2628 self.create_pg_interfaces(range(4))
2633 for i in self.pg_interfaces:
2637 i.generate_remote_hosts(2)
2638 self.tables.append(VppIpTable(self, table_id).add_vpp_config())
2642 super(TestIPReplace, self).tearDown()
2643 for i in self.pg_interfaces:
2647 def test_replace(self):
2648 """IP Table Replace"""
2650 MRouteItfFlags = VppEnum.vl_api_mfib_itf_flags_t
2651 MRouteEntryFlags = VppEnum.vl_api_mfib_entry_flags_t
2653 links = [self.pg0, self.pg1, self.pg2, self.pg3]
2654 routes = [[], [], [], []]
2656 # load up the tables with some routes
2657 for ii, t in enumerate(self.tables):
2658 for jj in range(N_ROUTES):
2665 links[ii].remote_hosts[0].ip4, links[ii].sw_if_index
2668 links[ii].remote_hosts[1].ip4, links[ii].sw_if_index
2671 table_id=t.table_id,
2673 multi = VppIpMRoute(
2678 MRouteEntryFlags.MFIB_API_ENTRY_FLAG_NONE,
2681 self.pg0.sw_if_index,
2682 MRouteItfFlags.MFIB_API_ITF_FLAG_ACCEPT,
2685 self.pg1.sw_if_index,
2686 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
2689 self.pg2.sw_if_index,
2690 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
2693 self.pg3.sw_if_index,
2694 MRouteItfFlags.MFIB_API_ITF_FLAG_FORWARD,
2697 table_id=t.table_id,
2699 routes[ii].append({"uni": uni, "multi": multi})
2702 # replace the tables a few times
2705 # replace_begin each table
2706 for t in self.tables:
2709 # all the routes are still there
2710 for ii, t in enumerate(self.tables):
2713 for r in routes[ii]:
2714 self.assertTrue(find_route_in_dump(dump, r["uni"], t))
2715 self.assertTrue(find_mroute_in_dump(mdump, r["multi"], t))
2717 # redownload the even numbered routes
2718 for ii, t in enumerate(self.tables):
2719 for jj in range(0, N_ROUTES, 2):
2720 routes[ii][jj]["uni"].add_vpp_config()
2721 routes[ii][jj]["multi"].add_vpp_config()
2723 # signal each table replace_end
2724 for t in self.tables:
2727 # we should find the even routes, but not the odd
2728 for ii, t in enumerate(self.tables):
2731 for jj in range(0, N_ROUTES, 2):
2732 self.assertTrue(find_route_in_dump(dump, routes[ii][jj]["uni"], t))
2734 find_mroute_in_dump(mdump, routes[ii][jj]["multi"], t)
2736 for jj in range(1, N_ROUTES - 1, 2):
2737 self.assertFalse(find_route_in_dump(dump, routes[ii][jj]["uni"], t))
2739 find_mroute_in_dump(mdump, routes[ii][jj]["multi"], t)
2742 # reload all the routes
2743 for ii, t in enumerate(self.tables):
2744 for r in routes[ii]:
2745 r["uni"].add_vpp_config()
2746 r["multi"].add_vpp_config()
2748 # all the routes are still there
2749 for ii, t in enumerate(self.tables):
2752 for r in routes[ii]:
2753 self.assertTrue(find_route_in_dump(dump, r["uni"], t))
2754 self.assertTrue(find_mroute_in_dump(mdump, r["multi"], t))
2757 # finally flush the tables for good measure
2759 for t in self.tables:
2761 self.assertEqual(len(t.dump()), 5)
2762 self.assertEqual(len(t.mdump()), 3)
2765 class TestIPCover(VppTestCase):
2766 """IPv4 Table Cover"""
2769 def setUpClass(cls):
2770 super(TestIPCover, cls).setUpClass()
2773 def tearDownClass(cls):
2774 super(TestIPCover, cls).tearDownClass()
2777 super(TestIPCover, self).setUp()
2779 self.create_pg_interfaces(range(4))
2784 for i in self.pg_interfaces:
2788 i.generate_remote_hosts(2)
2789 self.tables.append(VppIpTable(self, table_id).add_vpp_config())
2793 super(TestIPCover, self).tearDown()
2794 for i in self.pg_interfaces:
2798 def test_cover(self):
2799 """IP Table Cover"""
2801 # add a loop back with a /32 prefix
2802 lo = VppLoInterface(self)
2804 a = VppIpInterfaceAddress(self, lo, "127.0.0.1", 32).add_vpp_config()
2806 # add a neighbour that matches the loopback's /32
2808 self, lo.sw_if_index, lo.remote_mac, "127.0.0.1"
2811 # add the default route which will be the cover for /32
2816 [VppRoutePath("127.0.0.1", lo.sw_if_index)],
2820 # add/remove/add a longer mask cover
2822 self, "127.0.0.0", 8, [VppRoutePath("127.0.0.1", lo.sw_if_index)]
2824 r8.remove_vpp_config()
2826 r8.remove_vpp_config()
2828 # remove the default route
2829 r.remove_vpp_config()
2831 # remove the interface prefix
2832 a.remove_vpp_config()
2835 class TestIP4Replace(VppTestCase):
2836 """IPv4 Interface Address Replace"""
2839 def setUpClass(cls):
2840 super(TestIP4Replace, cls).setUpClass()
2843 def tearDownClass(cls):
2844 super(TestIP4Replace, cls).tearDownClass()
2847 super(TestIP4Replace, self).setUp()
2849 self.create_pg_interfaces(range(4))
2851 for i in self.pg_interfaces:
2855 super(TestIP4Replace, self).tearDown()
2856 for i in self.pg_interfaces:
2859 def get_n_pfxs(self, intf):
2860 return len(self.vapi.ip_address_dump(intf.sw_if_index))
2862 def test_replace(self):
2863 """IP interface address replace"""
2865 intf_pfxs = [[], [], [], []]
2867 # add prefixes to each of the interfaces
2868 for i in range(len(self.pg_interfaces)):
2869 intf = self.pg_interfaces[i]
2872 addr = "172.16.%d.1" % intf.sw_if_index
2873 a = VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config()
2874 intf_pfxs[i].append(a)
2876 # 172.16.x.2/24 - a different address in the same subnet as above
2877 addr = "172.16.%d.2" % intf.sw_if_index
2878 a = VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config()
2879 intf_pfxs[i].append(a)
2881 # 172.15.x.2/24 - a different address and subnet
2882 addr = "172.15.%d.2" % intf.sw_if_index
2883 a = VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config()
2884 intf_pfxs[i].append(a)
2886 # a dump should n_address in it
2887 for intf in self.pg_interfaces:
2888 self.assertEqual(self.get_n_pfxs(intf), 3)
2891 # remove all the address thru a replace
2893 self.vapi.sw_interface_address_replace_begin()
2894 self.vapi.sw_interface_address_replace_end()
2895 for intf in self.pg_interfaces:
2896 self.assertEqual(self.get_n_pfxs(intf), 0)
2899 # add all the interface addresses back
2904 for intf in self.pg_interfaces:
2905 self.assertEqual(self.get_n_pfxs(intf), 3)
2908 # replace again, but this time update/re-add the address on the first
2911 self.vapi.sw_interface_address_replace_begin()
2913 for p in intf_pfxs[:2]:
2917 self.vapi.sw_interface_address_replace_end()
2919 # on the first two the address still exist,
2920 # on the other two they do not
2921 for intf in self.pg_interfaces[:2]:
2922 self.assertEqual(self.get_n_pfxs(intf), 3)
2923 for p in intf_pfxs[:2]:
2925 self.assertTrue(v.query_vpp_config())
2926 for intf in self.pg_interfaces[2:]:
2927 self.assertEqual(self.get_n_pfxs(intf), 0)
2930 # add all the interface addresses back on the last two
2932 for p in intf_pfxs[2:]:
2935 for intf in self.pg_interfaces:
2936 self.assertEqual(self.get_n_pfxs(intf), 3)
2939 # replace again, this time add different prefixes on all the interfaces
2941 self.vapi.sw_interface_address_replace_begin()
2944 for intf in self.pg_interfaces:
2946 addr = "172.18.%d.1" % intf.sw_if_index
2947 pfxs.append(VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config())
2949 self.vapi.sw_interface_address_replace_end()
2951 # only .18 should exist on each interface
2952 for intf in self.pg_interfaces:
2953 self.assertEqual(self.get_n_pfxs(intf), 1)
2955 self.assertTrue(pfx.query_vpp_config())
2960 self.vapi.sw_interface_address_replace_begin()
2961 self.vapi.sw_interface_address_replace_end()
2962 for intf in self.pg_interfaces:
2963 self.assertEqual(self.get_n_pfxs(intf), 0)
2966 # add prefixes to each interface. post-begin add the prefix from
2967 # interface X onto interface Y. this would normally be an error
2968 # since it would generate a 'duplicate address' warning. but in
2969 # this case, since what is newly downloaded is sane, it's ok
2971 for intf in self.pg_interfaces:
2973 addr = "172.18.%d.1" % intf.sw_if_index
2974 VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config()
2976 self.vapi.sw_interface_address_replace_begin()
2979 for intf in self.pg_interfaces:
2981 addr = "172.18.%d.1" % (intf.sw_if_index + 1)
2982 pfxs.append(VppIpInterfaceAddress(self, intf, addr, 24).add_vpp_config())
2984 self.vapi.sw_interface_address_replace_end()
2986 self.logger.info(self.vapi.cli("sh int addr"))
2988 for intf in self.pg_interfaces:
2989 self.assertEqual(self.get_n_pfxs(intf), 1)
2991 self.assertTrue(pfx.query_vpp_config())
2994 class TestIPv4PathMTU(VppTestCase):
2998 def setUpClass(cls):
2999 super(TestIPv4PathMTU, cls).setUpClass()
3001 cls.create_pg_interfaces(range(2))
3003 # setup all interfaces
3004 for i in cls.pg_interfaces:
3010 def tearDownClass(cls):
3011 super(TestIPv4PathMTU, cls).tearDownClass()
3013 def test_path_mtu(self):
3017 # The goal here is not to test that fragmentation works correctly,
3018 # that's done elsewhere, the intent is to ensure that the Path MTU
3019 # settings are honoured.
3021 self.vapi.cli("adjacency counters enable")
3023 # set the interface MTU to a reasonable value
3024 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1800, 0, 0, 0])
3026 self.pg1.generate_remote_hosts(4)
3029 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
3030 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4)
3031 / UDP(sport=1234, dport=5678)
3035 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
3036 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_ip4)
3037 / UDP(sport=1234, dport=5678)
3042 self, self.pg1.sw_if_index, self.pg1.remote_mac, self.pg1.remote_ip4
3045 # this is now the interface MTU frags
3046 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
3047 self.send_and_expect(self.pg0, [p_1k], self.pg1)
3049 # drop the path MTU for this neighbour to below the interface MTU
3051 pmtu = VppIpPathMtu(self, self.pg1.remote_ip4, 900).add_vpp_config()
3053 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3054 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3056 # print/format the adj delegate
3057 self.logger.info(self.vapi.cli("sh adj 5"))
3059 # increase the path MTU to more than the interface
3060 # expect to use the interface MTU
3063 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
3064 self.send_and_expect(self.pg0, [p_1k], self.pg1)
3066 # go back to an MTU from the path
3067 # wrap the call around mark-n-sweep to enusre updates clear stale
3068 self.vapi.ip_path_mtu_replace_begin()
3070 self.vapi.ip_path_mtu_replace_end()
3072 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3073 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3075 # raise the interface's MTU
3076 # should still use that of the path
3077 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2000, 0, 0, 0])
3078 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3079 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3081 # set path high and interface low
3083 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [900, 0, 0, 0])
3084 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3085 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3087 # remove the path MTU using the mark-n-sweep semantics
3088 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1800, 0, 0, 0])
3089 self.vapi.ip_path_mtu_replace_begin()
3090 self.vapi.ip_path_mtu_replace_end()
3092 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=2)
3093 self.send_and_expect(self.pg0, [p_1k], self.pg1)
3096 # set path MTU for a neighbour that doesn't exist, yet
3098 pmtu2 = VppIpPathMtu(self, self.pg1.remote_hosts[2].ip4, 900).add_vpp_config()
3101 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
3102 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[2].ip4)
3103 / UDP(sport=1234, dport=5678)
3107 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
3108 / IP(src=self.pg0.remote_ip4, dst=self.pg1.remote_hosts[2].ip4)
3109 / UDP(sport=1234, dport=5678)
3115 self.pg1.sw_if_index,
3116 self.pg1.remote_hosts[2].mac,
3117 self.pg1.remote_hosts[2].ip4,
3120 # should frag to the path MTU
3121 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3122 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3124 # remove and re-add the neighbour
3125 nbr2.remove_vpp_config()
3126 nbr2.add_vpp_config()
3128 # should frag to the path MTU
3129 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3130 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3133 # set PMTUs for many peers
3136 self.pg1.generate_remote_hosts(16)
3137 self.pg1.configure_ipv4_neighbors()
3139 for h in range(N_HOSTS):
3140 pmtu = VppIpPathMtu(self, self.pg1.remote_hosts[h].ip4, 900)
3141 pmtu.add_vpp_config()
3142 self.assertTrue(pmtu.query_vpp_config())
3144 self.logger.info(self.vapi.cli("sh ip pmtu"))
3145 dump = list(self.vapi.vpp.details_iter(self.vapi.ip_path_mtu_get))
3146 self.assertEqual(N_HOSTS, len(dump))
3148 for h in range(N_HOSTS):
3149 p_2k[IP].dst = self.pg1.remote_hosts[h].ip4
3150 p_1k[IP].dst = self.pg1.remote_hosts[h].ip4
3152 # should frag to the path MTU
3153 self.send_and_expect(self.pg0, [p_2k], self.pg1, n_rx=3)
3154 self.send_and_expect(self.pg0, [p_1k], self.pg1, n_rx=2)
3157 class TestIPv4ItfRebind(VppTestCase):
3158 """IPv4 Interface Bind w/ attached routes"""
3161 super(TestIPv4ItfRebind, self).setUp()
3163 self.create_pg_interfaces(range(3))
3166 super(TestIPv4ItfRebind, self).tearDown()
3168 def test_rebind(self):
3169 """Import to no import"""
3172 tbl = VppIpTable(self, TABLE_ID).add_vpp_config()
3173 self.pg1.set_table_ip4(TABLE_ID)
3175 for i in self.pg_interfaces:
3180 # add an attached route via an pg0
3181 # in a different table. this prefix should import
3186 [VppRoutePath("0.0.0.0", self.pg0.sw_if_index)],
3191 Ether(dst=self.pg1.local_mac, src=self.pg1.remote_mac)
3192 / IP(src=self.pg1.remote_ip4, dst=self.pg0.remote_ip4)
3193 / UDP(sport=1234, dport=5678)
3197 rx = self.send_and_expect(self.pg1, [p], self.pg0)
3198 self.assertFalse(rx[0].haslayer(ARP))
3200 # then bind pg0 to a new table
3201 # so the prefix no longer imports
3202 self.pg0.unconfig_ip4()
3203 self.pg0.set_table_ip4(TABLE_ID)
3204 self.pg0.config_ip4()
3205 self.pg0.resolve_arp()
3207 rx = self.send_and_expect(self.pg1, [p], self.pg0)
3208 self.assertFalse(rx[0].haslayer(ARP))
3210 # revert back to imported
3211 self.pg0.unconfig_ip4()
3212 self.pg0.set_table_ip4(0)
3213 self.pg0.config_ip4()
3214 self.pg0.resolve_arp()
3216 rx = self.send_and_expect(self.pg1, [p], self.pg0)
3217 self.assertFalse(rx[0].haslayer(ARP))
3220 for i in self.pg_interfaces:
3225 rt.remove_vpp_config()
3226 tbl.remove_vpp_config()
3228 def test_delete(self):
3229 """Swap import tables"""
3232 tbl1_4 = VppIpTable(self, TABLE_ID1).add_vpp_config()
3233 tbl1_6 = VppIpTable(self, TABLE_ID1, True).add_vpp_config()
3235 tbl2_4 = VppIpTable(self, TABLE_ID2).add_vpp_config()
3236 tbl2_6 = VppIpTable(self, TABLE_ID2, True).add_vpp_config()
3239 self.pg1.set_table_ip4(TABLE_ID1)
3240 self.pg1.set_table_ip6(TABLE_ID1)
3241 self.pg2.set_table_ip4(TABLE_ID2)
3242 self.pg2.set_table_ip6(TABLE_ID2)
3244 for i in self.pg_interfaces:
3249 # add an attached route in the default table via pg0
3250 # this should import to table 1
3255 [VppRoutePath("0.0.0.0", self.pg1.sw_if_index)],
3261 [VppRoutePath("0.0.0.0", self.pg1.sw_if_index)],
3265 Ether(dst=self.pg0.local_mac, src=self.pg0.remote_mac)
3266 / IP(src=self.pg1.remote_ip4, dst=self.pg1.remote_ip4)
3267 / UDP(sport=1234, dport=5678)
3271 # inject into table 0
3272 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
3273 self.assertFalse(rx[0].haslayer(ARP))
3275 # swap the attached interface to table 2
3276 self.pg1.unconfig_ip4()
3277 self.pg1.unconfig_ip6()
3278 self.pg1.set_table_ip4(TABLE_ID2)
3279 self.pg1.set_table_ip6(TABLE_ID2)
3280 self.pg1.config_ip4()
3281 self.pg1.config_ip6()
3282 self.pg1.resolve_arp()
3287 tbl1_4.remove_vpp_config()
3288 tbl1_6.remove_vpp_config()
3290 rx = self.send_and_expect(self.pg0, [p1], self.pg1)
3291 self.assertFalse(rx[0].haslayer(ARP))
3293 for i in self.pg_interfaces:
3301 if __name__ == "__main__":
3302 unittest.main(testRunner=VppTestRunner)