6 from framework import VppTestCase, VppTestRunner
7 from vpp_sub_interface import VppSubInterface, VppDot1QSubint, VppDot1ADSubint
8 from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpMRoute, \
9 VppMRoutePath, MRouteItfFlags, MRouteEntryFlags, VppMplsIpBind, \
10 VppMplsTable, VppIpTable
12 from scapy.packet import Raw
13 from scapy.layers.l2 import Ether, Dot1Q, ARP
14 from scapy.layers.inet import IP, UDP, TCP, ICMP, icmptypes, icmpcodes
16 from scapy.contrib.mpls import MPLS
19 class TestIPv4(VppTestCase):
20 """ IPv4 Test Case """
24 Perform test setup before test case.
27 - create 3 pg interfaces
28 - untagged pg0 interface
29 - Dot1Q subinterface on pg1
30 - Dot1AD subinterface on pg2
32 - put it into UP state
34 - resolve neighbor address using ARP
35 - configure 200 fib entries
37 :ivar list interfaces: pg interfaces and subinterfaces.
38 :ivar dict flows: IPv4 packet flows in test.
40 super(TestIPv4, self).setUp()
42 # create 3 pg interfaces
43 self.create_pg_interfaces(range(3))
45 # create 2 subinterfaces for pg1 and pg2
46 self.sub_interfaces = [
47 VppDot1QSubint(self, self.pg1, 100),
48 VppDot1ADSubint(self, self.pg2, 200, 300, 400)]
50 # packet flows mapping pg0 -> pg1.sub, pg2.sub, etc.
52 self.flows[self.pg0] = [self.pg1.sub_if, self.pg2.sub_if]
53 self.flows[self.pg1.sub_if] = [self.pg0, self.pg2.sub_if]
54 self.flows[self.pg2.sub_if] = [self.pg0, self.pg1.sub_if]
57 self.pg_if_packet_sizes = [64, 1500, 9020]
59 self.interfaces = list(self.pg_interfaces)
60 self.interfaces.extend(self.sub_interfaces)
62 # setup all interfaces
63 for i in self.interfaces:
68 # config 2M FIB entries
69 self.config_fib_entries(200)
72 """Run standard test teardown and log ``show ip arp``."""
73 super(TestIPv4, self).tearDown()
75 self.logger.info(self.vapi.cli("show ip arp"))
76 # info(self.vapi.cli("show ip fib")) # many entries
78 def config_fib_entries(self, count):
79 """For each interface add to the FIB table *count* routes to
80 "10.0.0.1/32" destination with interface's local address as next-hop
83 :param int count: Number of FIB entries.
85 - *TODO:* check if the next-hop address shouldn't be remote address
86 instead of local address.
88 n_int = len(self.interfaces)
91 dest_addr = socket.inet_pton(socket.AF_INET, "10.0.0.1")
93 for i in self.interfaces:
94 next_hop_address = i.local_ip4n
95 for j in range(count / n_int):
96 self.vapi.ip_add_del_route(
97 dest_addr, dest_addr_len, next_hop_address)
99 if counter / count * 100 > percent:
100 self.logger.info("Configure %d FIB entries .. %d%% done" %
104 def modify_packet(self, src_if, packet_size, pkt):
105 """Add load, set destination IP and extend packet to required packet
106 size for defined interface.
108 :param VppInterface src_if: Interface to create packet for.
109 :param int packet_size: Required packet size.
110 :param Scapy pkt: Packet to be modified.
112 dst_if_idx = packet_size / 10 % 2
113 dst_if = self.flows[src_if][dst_if_idx]
114 info = self.create_packet_info(src_if, dst_if)
115 payload = self.info_to_payload(info)
117 p[IP].dst = dst_if.remote_ip4
119 if isinstance(src_if, VppSubInterface):
120 p = src_if.add_dot1_layer(p)
121 self.extend_packet(p, packet_size)
125 def create_stream(self, src_if):
126 """Create input packet stream for defined interface.
128 :param VppInterface src_if: Interface to create packet stream for.
130 hdr_ext = 4 if isinstance(src_if, VppSubInterface) else 0
131 pkt_tmpl = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
132 IP(src=src_if.remote_ip4) /
133 UDP(sport=1234, dport=1234))
135 pkts = [self.modify_packet(src_if, i, pkt_tmpl)
136 for i in xrange(self.pg_if_packet_sizes[0],
137 self.pg_if_packet_sizes[1], 10)]
138 pkts_b = [self.modify_packet(src_if, i, pkt_tmpl)
139 for i in xrange(self.pg_if_packet_sizes[1] + hdr_ext,
140 self.pg_if_packet_sizes[2] + hdr_ext, 50)]
145 def verify_capture(self, dst_if, capture):
146 """Verify captured input packet stream for defined interface.
148 :param VppInterface dst_if: Interface to verify captured packet stream
150 :param list capture: Captured packet stream.
152 self.logger.info("Verifying capture on interface %s" % dst_if.name)
154 for i in self.interfaces:
155 last_info[i.sw_if_index] = None
157 dst_sw_if_index = dst_if.sw_if_index
158 if hasattr(dst_if, 'parent'):
160 for packet in capture:
162 # Check VLAN tags and Ethernet header
163 packet = dst_if.remove_dot1_layer(packet)
164 self.assertTrue(Dot1Q not in packet)
168 payload_info = self.payload_to_info(str(packet[Raw]))
169 packet_index = payload_info.index
170 self.assertEqual(payload_info.dst, dst_sw_if_index)
172 "Got packet on port %s: src=%u (id=%u)" %
173 (dst_if.name, payload_info.src, packet_index))
174 next_info = self.get_next_packet_info_for_interface2(
175 payload_info.src, dst_sw_if_index,
176 last_info[payload_info.src])
177 last_info[payload_info.src] = next_info
178 self.assertTrue(next_info is not None)
179 self.assertEqual(packet_index, next_info.index)
180 saved_packet = next_info.data
181 # Check standard fields
182 self.assertEqual(ip.src, saved_packet[IP].src)
183 self.assertEqual(ip.dst, saved_packet[IP].dst)
184 self.assertEqual(udp.sport, saved_packet[UDP].sport)
185 self.assertEqual(udp.dport, saved_packet[UDP].dport)
187 self.logger.error(ppp("Unexpected or invalid packet:", packet))
189 for i in self.interfaces:
190 remaining_packet = self.get_next_packet_info_for_interface2(
191 i.sw_if_index, dst_sw_if_index, last_info[i.sw_if_index])
192 self.assertTrue(remaining_packet is None,
193 "Interface %s: Packet expected from interface %s "
194 "didn't arrive" % (dst_if.name, i.name))
201 - Create IPv4 stream for pg0 interface
202 - Create IPv4 tagged streams for pg1's and pg2's sub-interface.
203 - Send and verify received packets on each interface.
206 pkts = self.create_stream(self.pg0)
207 self.pg0.add_stream(pkts)
209 for i in self.sub_interfaces:
210 pkts = self.create_stream(i)
211 i.parent.add_stream(pkts)
213 self.pg_enable_capture(self.pg_interfaces)
216 pkts = self.pg0.get_capture()
217 self.verify_capture(self.pg0, pkts)
219 for i in self.sub_interfaces:
220 pkts = i.parent.get_capture()
221 self.verify_capture(i, pkts)
224 class TestICMPEcho(VppTestCase):
225 """ ICMP Echo Test Case """
228 super(TestICMPEcho, self).setUp()
230 # create 1 pg interface
231 self.create_pg_interfaces(range(1))
233 for i in self.pg_interfaces:
239 super(TestICMPEcho, self).tearDown()
240 for i in self.pg_interfaces:
244 def test_icmp_echo(self):
245 """ VPP replies to ICMP Echo Request
249 - Receive ICMP Echo Request message on pg0 interface.
250 - Check outgoing ICMP Echo Reply message on pg0 interface.
255 icmp_load = '\x0a' * 18
256 p_echo_request = (Ether(src=self.pg0.remote_mac,
257 dst=self.pg0.local_mac) /
258 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
259 ICMP(id=icmp_id, seq=icmp_seq) /
262 self.pg0.add_stream(p_echo_request)
263 self.pg_enable_capture(self.pg_interfaces)
266 rx = self.pg0.get_capture(1)
272 self.assertEqual(ether.src, self.pg0.local_mac)
273 self.assertEqual(ether.dst, self.pg0.remote_mac)
275 self.assertEqual(ipv4.src, self.pg0.local_ip4)
276 self.assertEqual(ipv4.dst, self.pg0.remote_ip4)
278 self.assertEqual(icmptypes[icmp.type], "echo-reply")
279 self.assertEqual(icmp.id, icmp_id)
280 self.assertEqual(icmp.seq, icmp_seq)
281 self.assertEqual(icmp[Raw].load, icmp_load)
284 class TestIPv4FibCrud(VppTestCase):
285 """ FIB - add/update/delete - ip4 routes
293 ..note:: Python API is too slow to add many routes, needs replacement.
296 def config_fib_many_to_one(self, start_dest_addr, next_hop_addr, count):
299 :param start_dest_addr:
300 :param next_hop_addr:
302 :return list: added ips with 32 prefix
305 dest_addr = int(socket.inet_pton(socket.AF_INET,
306 start_dest_addr).encode('hex'),
309 n_next_hop_addr = socket.inet_pton(socket.AF_INET, next_hop_addr)
310 for _ in range(count):
311 n_dest_addr = '{:08x}'.format(dest_addr).decode('hex')
312 self.vapi.ip_add_del_route(n_dest_addr, dest_addr_len,
314 added_ips.append(socket.inet_ntoa(n_dest_addr))
318 def unconfig_fib_many_to_one(self, start_dest_addr, next_hop_addr, count):
321 dest_addr = int(socket.inet_pton(socket.AF_INET,
322 start_dest_addr).encode('hex'),
325 n_next_hop_addr = socket.inet_pton(socket.AF_INET, next_hop_addr)
326 for _ in range(count):
327 n_dest_addr = '{:08x}'.format(dest_addr).decode('hex')
328 self.vapi.ip_add_del_route(n_dest_addr, dest_addr_len,
329 n_next_hop_addr, is_add=0)
330 removed_ips.append(socket.inet_ntoa(n_dest_addr))
334 def create_stream(self, src_if, dst_if, dst_ips, count):
337 for _ in range(count):
338 dst_addr = random.choice(dst_ips)
339 info = self.create_packet_info(src_if, dst_if)
340 payload = self.info_to_payload(info)
341 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
342 IP(src=src_if.remote_ip4, dst=dst_addr) /
343 UDP(sport=1234, dport=1234) /
346 self.extend_packet(p, random.choice(self.pg_if_packet_sizes))
351 def _find_ip_match(self, find_in, pkt):
353 if self.payload_to_info(str(p[Raw])) == \
354 self.payload_to_info(str(pkt[Raw])):
355 if p[IP].src != pkt[IP].src:
357 if p[IP].dst != pkt[IP].dst:
359 if p[UDP].sport != pkt[UDP].sport:
361 if p[UDP].dport != pkt[UDP].dport:
367 def _match_route_detail(route_detail, ip, address_length=32, table_id=0):
368 if route_detail.address == socket.inet_pton(socket.AF_INET, ip):
369 if route_detail.table_id != table_id:
371 elif route_detail.address_length != address_length:
378 def verify_capture(self, dst_interface, received_pkts, expected_pkts):
379 self.assertEqual(len(received_pkts), len(expected_pkts))
380 to_verify = list(expected_pkts)
381 for p in received_pkts:
382 self.assertEqual(p.src, dst_interface.local_mac)
383 self.assertEqual(p.dst, dst_interface.remote_mac)
384 x = self._find_ip_match(to_verify, p)
386 self.assertListEqual(to_verify, [])
388 def verify_route_dump(self, fib_dump, ips):
390 def _ip_in_route_dump(ip, fib_dump):
391 return next((route for route in fib_dump
392 if self._match_route_detail(route, ip)),
396 self.assertTrue(_ip_in_route_dump(ip, fib_dump),
397 'IP {} is not in fib dump.'.format(ip))
399 def verify_not_in_route_dump(self, fib_dump, ips):
401 def _ip_in_route_dump(ip, fib_dump):
402 return next((route for route in fib_dump
403 if self._match_route_detail(route, ip)),
407 self.assertFalse(_ip_in_route_dump(ip, fib_dump),
408 'IP {} is in fib dump.'.format(ip))
413 #. Create and initialize 3 pg interfaces.
414 #. initialize class attributes configured_routes and deleted_routes
415 to store information between tests.
417 super(TestIPv4FibCrud, cls).setUpClass()
420 # create 3 pg interfaces
421 cls.create_pg_interfaces(range(3))
423 cls.interfaces = list(cls.pg_interfaces)
425 # setup all interfaces
426 for i in cls.interfaces:
431 cls.configured_routes = []
432 cls.deleted_routes = []
433 cls.pg_if_packet_sizes = [64, 512, 1518, 9018]
436 super(TestIPv4FibCrud, cls).tearDownClass()
440 super(TestIPv4FibCrud, self).setUp()
441 self.reset_packet_infos()
443 def test_1_add_routes(self):
446 - add 100 routes check with traffic script.
448 # config 1M FIB entries
449 self.configured_routes.extend(self.config_fib_many_to_one(
450 "10.0.0.0", self.pg0.remote_ip4, 100))
452 fib_dump = self.vapi.ip_fib_dump()
453 self.verify_route_dump(fib_dump, self.configured_routes)
455 self.stream_1 = self.create_stream(
456 self.pg1, self.pg0, self.configured_routes, 100)
457 self.stream_2 = self.create_stream(
458 self.pg2, self.pg0, self.configured_routes, 100)
459 self.pg1.add_stream(self.stream_1)
460 self.pg2.add_stream(self.stream_2)
462 self.pg_enable_capture(self.pg_interfaces)
465 pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
466 self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
468 def test_2_del_routes(self):
469 """ Delete 100 routes
471 - delete 10 routes check with traffic script.
473 self.deleted_routes.extend(self.unconfig_fib_many_to_one(
474 "10.0.0.10", self.pg0.remote_ip4, 10))
475 for x in self.deleted_routes:
476 self.configured_routes.remove(x)
478 fib_dump = self.vapi.ip_fib_dump()
479 self.verify_route_dump(fib_dump, self.configured_routes)
481 self.stream_1 = self.create_stream(
482 self.pg1, self.pg0, self.configured_routes, 100)
483 self.stream_2 = self.create_stream(
484 self.pg2, self.pg0, self.configured_routes, 100)
485 self.stream_3 = self.create_stream(
486 self.pg1, self.pg0, self.deleted_routes, 100)
487 self.stream_4 = self.create_stream(
488 self.pg2, self.pg0, self.deleted_routes, 100)
489 self.pg1.add_stream(self.stream_1 + self.stream_3)
490 self.pg2.add_stream(self.stream_2 + self.stream_4)
491 self.pg_enable_capture(self.pg_interfaces)
494 pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
495 self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
497 def test_3_add_new_routes(self):
500 - re-add 5 routes check with traffic script.
501 - add 100 routes check with traffic script.
503 tmp = self.config_fib_many_to_one(
504 "10.0.0.10", self.pg0.remote_ip4, 5)
505 self.configured_routes.extend(tmp)
507 self.deleted_routes.remove(x)
509 self.configured_routes.extend(self.config_fib_many_to_one(
510 "10.0.1.0", self.pg0.remote_ip4, 100))
512 fib_dump = self.vapi.ip_fib_dump()
513 self.verify_route_dump(fib_dump, self.configured_routes)
515 self.stream_1 = self.create_stream(
516 self.pg1, self.pg0, self.configured_routes, 300)
517 self.stream_2 = self.create_stream(
518 self.pg2, self.pg0, self.configured_routes, 300)
519 self.stream_3 = self.create_stream(
520 self.pg1, self.pg0, self.deleted_routes, 100)
521 self.stream_4 = self.create_stream(
522 self.pg2, self.pg0, self.deleted_routes, 100)
524 self.pg1.add_stream(self.stream_1 + self.stream_3)
525 self.pg2.add_stream(self.stream_2 + self.stream_4)
526 self.pg_enable_capture(self.pg_interfaces)
529 pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
530 self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
532 def test_4_del_routes(self):
533 """ Delete 1.5k routes
535 - delete 5 routes check with traffic script.
536 - add 100 routes check with traffic script.
538 self.deleted_routes.extend(self.unconfig_fib_many_to_one(
539 "10.0.0.0", self.pg0.remote_ip4, 15))
540 self.deleted_routes.extend(self.unconfig_fib_many_to_one(
541 "10.0.0.20", self.pg0.remote_ip4, 85))
542 self.deleted_routes.extend(self.unconfig_fib_many_to_one(
543 "10.0.1.0", self.pg0.remote_ip4, 100))
544 fib_dump = self.vapi.ip_fib_dump()
545 self.verify_not_in_route_dump(fib_dump, self.deleted_routes)
548 class TestIPNull(VppTestCase):
549 """ IPv4 routes via NULL """
552 super(TestIPNull, self).setUp()
554 # create 2 pg interfaces
555 self.create_pg_interfaces(range(2))
557 for i in self.pg_interfaces:
563 super(TestIPNull, self).tearDown()
564 for i in self.pg_interfaces:
568 def test_ip_null(self):
569 """ IP NULL route """
572 # A route via IP NULL that will reply with ICMP unreachables
574 ip_unreach = VppIpRoute(self, "10.0.0.1", 32, [], is_unreach=1)
575 ip_unreach.add_vpp_config()
577 p_unreach = (Ether(src=self.pg0.remote_mac,
578 dst=self.pg0.local_mac) /
579 IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
580 UDP(sport=1234, dport=1234) /
583 self.pg0.add_stream(p_unreach)
584 self.pg_enable_capture(self.pg_interfaces)
587 rx = self.pg0.get_capture(1)
591 self.assertEqual(icmptypes[icmp.type], "dest-unreach")
592 self.assertEqual(icmpcodes[icmp.type][icmp.code], "host-unreachable")
593 self.assertEqual(icmp.src, self.pg0.remote_ip4)
594 self.assertEqual(icmp.dst, "10.0.0.1")
597 # ICMP replies are rate limited. so sit and spin.
602 # A route via IP NULL that will reply with ICMP prohibited
604 ip_prohibit = VppIpRoute(self, "10.0.0.2", 32, [], is_prohibit=1)
605 ip_prohibit.add_vpp_config()
607 p_prohibit = (Ether(src=self.pg0.remote_mac,
608 dst=self.pg0.local_mac) /
609 IP(src=self.pg0.remote_ip4, dst="10.0.0.2") /
610 UDP(sport=1234, dport=1234) /
613 self.pg0.add_stream(p_prohibit)
614 self.pg_enable_capture(self.pg_interfaces)
617 rx = self.pg0.get_capture(1)
622 self.assertEqual(icmptypes[icmp.type], "dest-unreach")
623 self.assertEqual(icmpcodes[icmp.type][icmp.code], "host-prohibited")
624 self.assertEqual(icmp.src, self.pg0.remote_ip4)
625 self.assertEqual(icmp.dst, "10.0.0.2")
627 def test_ip_drop(self):
628 """ IP Drop Routes """
630 p = (Ether(src=self.pg0.remote_mac,
631 dst=self.pg0.local_mac) /
632 IP(src=self.pg0.remote_ip4, dst="1.1.1.1") /
633 UDP(sport=1234, dport=1234) /
636 r1 = VppIpRoute(self, "1.1.1.0", 24,
637 [VppRoutePath(self.pg1.remote_ip4,
638 self.pg1.sw_if_index)])
641 rx = self.send_and_expect(self.pg0, p * 65, self.pg1)
644 # insert a more specific as a drop
646 r2 = VppIpRoute(self, "1.1.1.1", 32, [], is_drop=1)
649 self.send_and_assert_no_replies(self.pg0, p * 65, "Drop Route")
650 r2.remove_vpp_config()
651 rx = self.send_and_expect(self.pg0, p * 65, self.pg1)
654 class TestIPDisabled(VppTestCase):
655 """ IPv4 disabled """
658 super(TestIPDisabled, self).setUp()
660 # create 2 pg interfaces
661 self.create_pg_interfaces(range(2))
665 self.pg0.config_ip4()
666 self.pg0.resolve_arp()
668 # PG 1 is not IP enabled
672 super(TestIPDisabled, self).tearDown()
673 for i in self.pg_interfaces:
677 def test_ip_disabled(self):
682 # one accepting interface, pg0, 2 forwarding interfaces
684 route_232_1_1_1 = VppIpMRoute(
688 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
689 [VppMRoutePath(self.pg1.sw_if_index,
690 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
691 VppMRoutePath(self.pg0.sw_if_index,
692 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
693 route_232_1_1_1.add_vpp_config()
695 pu = (Ether(src=self.pg1.remote_mac,
696 dst=self.pg1.local_mac) /
697 IP(src="10.10.10.10", dst=self.pg0.remote_ip4) /
698 UDP(sport=1234, dport=1234) /
700 pm = (Ether(src=self.pg1.remote_mac,
701 dst=self.pg1.local_mac) /
702 IP(src="10.10.10.10", dst="232.1.1.1") /
703 UDP(sport=1234, dport=1234) /
707 # PG1 does not forward IP traffic
709 self.send_and_assert_no_replies(self.pg1, pu, "IP disabled")
710 self.send_and_assert_no_replies(self.pg1, pm, "IP disabled")
715 self.pg1.config_ip4()
718 # Now we get packets through
720 self.pg1.add_stream(pu)
721 self.pg_enable_capture(self.pg_interfaces)
723 rx = self.pg0.get_capture(1)
725 self.pg1.add_stream(pm)
726 self.pg_enable_capture(self.pg_interfaces)
728 rx = self.pg0.get_capture(1)
733 self.pg1.unconfig_ip4()
736 # PG1 does not forward IP traffic
738 self.send_and_assert_no_replies(self.pg1, pu, "IP disabled")
739 self.send_and_assert_no_replies(self.pg1, pm, "IP disabled")
742 class TestIPSubNets(VppTestCase):
746 super(TestIPSubNets, self).setUp()
748 # create a 2 pg interfaces
749 self.create_pg_interfaces(range(2))
751 # pg0 we will use to experiemnt
754 # pg1 is setup normally
756 self.pg1.config_ip4()
757 self.pg1.resolve_arp()
760 super(TestIPSubNets, self).tearDown()
761 for i in self.pg_interfaces:
764 def test_ip_sub_nets(self):
768 # Configure a covering route to forward so we know
769 # when we are dropping
771 cover_route = VppIpRoute(self, "10.0.0.0", 8,
772 [VppRoutePath(self.pg1.remote_ip4,
773 self.pg1.sw_if_index)])
774 cover_route.add_vpp_config()
776 p = (Ether(src=self.pg1.remote_mac,
777 dst=self.pg1.local_mac) /
778 IP(dst="10.10.10.10", src=self.pg0.local_ip4) /
779 UDP(sport=1234, dport=1234) /
782 self.pg1.add_stream(p)
783 self.pg_enable_capture(self.pg_interfaces)
785 rx = self.pg1.get_capture(1)
788 # Configure some non-/24 subnets on an IP interface
790 ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10")
792 self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
796 pn = (Ether(src=self.pg1.remote_mac,
797 dst=self.pg1.local_mac) /
798 IP(dst="10.10.0.0", src=self.pg0.local_ip4) /
799 UDP(sport=1234, dport=1234) /
801 pb = (Ether(src=self.pg1.remote_mac,
802 dst=self.pg1.local_mac) /
803 IP(dst="10.10.255.255", src=self.pg0.local_ip4) /
804 UDP(sport=1234, dport=1234) /
807 self.send_and_assert_no_replies(self.pg1, pn, "IP Network address")
808 self.send_and_assert_no_replies(self.pg1, pb, "IP Broadcast address")
810 # remove the sub-net and we are forwarding via the cover again
811 self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
815 self.pg1.add_stream(pn)
816 self.pg_enable_capture(self.pg_interfaces)
818 rx = self.pg1.get_capture(1)
819 self.pg1.add_stream(pb)
820 self.pg_enable_capture(self.pg_interfaces)
822 rx = self.pg1.get_capture(1)
825 # A /31 is a special case where the 'other-side' is an attached host
826 # packets to that peer generate ARP requests
828 ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10")
830 self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
834 pn = (Ether(src=self.pg1.remote_mac,
835 dst=self.pg1.local_mac) /
836 IP(dst="10.10.10.11", src=self.pg0.local_ip4) /
837 UDP(sport=1234, dport=1234) /
840 self.pg1.add_stream(pn)
841 self.pg_enable_capture(self.pg_interfaces)
843 rx = self.pg0.get_capture(1)
846 # remove the sub-net and we are forwarding via the cover again
847 self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
851 self.pg1.add_stream(pn)
852 self.pg_enable_capture(self.pg_interfaces)
854 rx = self.pg1.get_capture(1)
857 class TestIPLoadBalance(VppTestCase):
858 """ IPv4 Load-Balancing """
861 super(TestIPLoadBalance, self).setUp()
863 self.create_pg_interfaces(range(5))
864 mpls_tbl = VppMplsTable(self, 0)
865 mpls_tbl.add_vpp_config()
867 for i in self.pg_interfaces:
874 for i in self.pg_interfaces:
878 super(TestIPLoadBalance, self).tearDown()
880 def send_and_expect_load_balancing(self, input, pkts, outputs):
881 input.add_stream(pkts)
882 self.pg_enable_capture(self.pg_interfaces)
885 rx = oo._get_capture(1)
886 self.assertNotEqual(0, len(rx))
888 def send_and_expect_one_itf(self, input, pkts, itf):
889 input.add_stream(pkts)
890 self.pg_enable_capture(self.pg_interfaces)
892 rx = itf.get_capture(len(pkts))
894 def test_ip_load_balance(self):
895 """ IP Load-Balancing """
898 # An array of packets that differ only in the destination port
904 # An array of packets that differ only in the source address
910 port_ip_hdr = (IP(dst="10.0.0.1", src="20.0.0.1") /
911 UDP(sport=1234, dport=1234 + ii) /
913 port_ip_pkts.append((Ether(src=self.pg0.remote_mac,
914 dst=self.pg0.local_mac) /
916 port_mpls_pkts.append((Ether(src=self.pg0.remote_mac,
917 dst=self.pg0.local_mac) /
918 MPLS(label=66, ttl=2) /
921 src_ip_hdr = (IP(dst="10.0.0.1", src="20.0.0.%d" % ii) /
922 UDP(sport=1234, dport=1234) /
924 src_ip_pkts.append((Ether(src=self.pg0.remote_mac,
925 dst=self.pg0.local_mac) /
927 src_mpls_pkts.append((Ether(src=self.pg0.remote_mac,
928 dst=self.pg0.local_mac) /
929 MPLS(label=66, ttl=2) /
932 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
933 [VppRoutePath(self.pg1.remote_ip4,
934 self.pg1.sw_if_index),
935 VppRoutePath(self.pg2.remote_ip4,
936 self.pg2.sw_if_index)])
937 route_10_0_0_1.add_vpp_config()
939 binding = VppMplsIpBind(self, 66, "10.0.0.1", 32)
940 binding.add_vpp_config()
943 # inject the packet on pg0 - expect load-balancing across the 2 paths
944 # - since the default hash config is to use IP src,dst and port
946 # We are not going to ensure equal amounts of packets across each link,
947 # since the hash algorithm is statistical and therefore this can never
948 # be guaranteed. But wuth 64 different packets we do expect some
949 # balancing. So instead just ensure there is traffic on each link.
951 self.send_and_expect_load_balancing(self.pg0, port_ip_pkts,
952 [self.pg1, self.pg2])
953 self.send_and_expect_load_balancing(self.pg0, src_ip_pkts,
954 [self.pg1, self.pg2])
955 self.send_and_expect_load_balancing(self.pg0, port_mpls_pkts,
956 [self.pg1, self.pg2])
957 self.send_and_expect_load_balancing(self.pg0, src_mpls_pkts,
958 [self.pg1, self.pg2])
961 # change the flow hash config so it's only IP src,dst
962 # - now only the stream with differing source address will
965 self.vapi.set_ip_flow_hash(0, src=1, dst=1, sport=0, dport=0)
967 self.send_and_expect_load_balancing(self.pg0, src_ip_pkts,
968 [self.pg1, self.pg2])
969 self.send_and_expect_load_balancing(self.pg0, src_mpls_pkts,
970 [self.pg1, self.pg2])
972 self.send_and_expect_one_itf(self.pg0, port_ip_pkts, self.pg2)
975 # change the flow hash config back to defaults
977 self.vapi.set_ip_flow_hash(0, src=1, dst=1, sport=1, dport=1)
981 # - testing that 2 stages of load-balancing occurs and there is no
982 # polarisation (i.e. only 2 of 4 paths are used)
987 for ii in range(257):
988 port_pkts.append((Ether(src=self.pg0.remote_mac,
989 dst=self.pg0.local_mac) /
990 IP(dst="1.1.1.1", src="20.0.0.1") /
991 UDP(sport=1234, dport=1234 + ii) /
993 src_pkts.append((Ether(src=self.pg0.remote_mac,
994 dst=self.pg0.local_mac) /
995 IP(dst="1.1.1.1", src="20.0.0.%d" % ii) /
996 UDP(sport=1234, dport=1234) /
999 route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
1000 [VppRoutePath(self.pg3.remote_ip4,
1001 self.pg3.sw_if_index),
1002 VppRoutePath(self.pg4.remote_ip4,
1003 self.pg4.sw_if_index)])
1004 route_10_0_0_2.add_vpp_config()
1006 route_1_1_1_1 = VppIpRoute(self, "1.1.1.1", 32,
1007 [VppRoutePath("10.0.0.2", 0xffffffff),
1008 VppRoutePath("10.0.0.1", 0xffffffff)])
1009 route_1_1_1_1.add_vpp_config()
1012 # inject the packet on pg0 - expect load-balancing across all 4 paths
1014 self.vapi.cli("clear trace")
1015 self.send_and_expect_load_balancing(self.pg0, port_pkts,
1016 [self.pg1, self.pg2,
1017 self.pg3, self.pg4])
1018 self.send_and_expect_load_balancing(self.pg0, src_pkts,
1019 [self.pg1, self.pg2,
1020 self.pg3, self.pg4])
1023 # Recursive prefixes
1024 # - testing that 2 stages of load-balancing, no choices
1028 for ii in range(257):
1029 port_pkts.append((Ether(src=self.pg0.remote_mac,
1030 dst=self.pg0.local_mac) /
1031 IP(dst="1.1.1.2", src="20.0.0.2") /
1032 UDP(sport=1234, dport=1234 + ii) /
1035 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1036 [VppRoutePath(self.pg3.remote_ip4,
1037 self.pg3.sw_if_index)])
1038 route_10_0_0_3.add_vpp_config()
1040 route_1_1_1_2 = VppIpRoute(self, "1.1.1.2", 32,
1041 [VppRoutePath("10.0.0.3", 0xffffffff)])
1042 route_1_1_1_2.add_vpp_config()
1045 # inject the packet on pg0 - expect load-balancing across all 4 paths
1047 self.vapi.cli("clear trace")
1048 self.send_and_expect_one_itf(self.pg0, port_pkts, self.pg3)
1051 class TestIPVlan0(VppTestCase):
1055 super(TestIPVlan0, self).setUp()
1057 self.create_pg_interfaces(range(2))
1058 mpls_tbl = VppMplsTable(self, 0)
1059 mpls_tbl.add_vpp_config()
1061 for i in self.pg_interfaces:
1068 for i in self.pg_interfaces:
1072 super(TestIPVlan0, self).tearDown()
1074 def test_ip_vlan_0(self):
1077 pkts = (Ether(src=self.pg0.remote_mac,
1078 dst=self.pg0.local_mac) /
1080 IP(dst=self.pg1.remote_ip4,
1081 src=self.pg0.remote_ip4) /
1082 UDP(sport=1234, dport=1234) /
1083 Raw('\xa5' * 100)) * 65
1086 # Expect that packets sent on VLAN-0 are forwarded on the
1089 self.send_and_expect(self.pg0, pkts, self.pg1)
1092 class TestIPPunt(VppTestCase):
1093 """ IPv4 Punt Police/Redirect """
1096 super(TestIPPunt, self).setUp()
1098 self.create_pg_interfaces(range(2))
1100 for i in self.pg_interfaces:
1106 super(TestIPPunt, self).tearDown()
1107 for i in self.pg_interfaces:
1111 def test_ip_punt(self):
1112 """ IP punt police and redirect """
1114 p = (Ether(src=self.pg0.remote_mac,
1115 dst=self.pg0.local_mac) /
1116 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
1117 TCP(sport=1234, dport=1234) /
1123 # Configure a punt redirect via pg1.
1125 nh_addr = socket.inet_pton(socket.AF_INET,
1126 self.pg1.remote_ip4)
1127 self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
1128 self.pg1.sw_if_index,
1131 self.send_and_expect(self.pg0, pkts, self.pg1)
1136 policer = self.vapi.policer_add_del("ip4-punt", 400, 0, 10, 0,
1138 self.vapi.ip_punt_police(policer.policer_index)
1140 self.vapi.cli("clear trace")
1141 self.pg0.add_stream(pkts)
1142 self.pg_enable_capture(self.pg_interfaces)
1146 # the number of packet recieved should be greater than 0,
1147 # but not equal to the number sent, since some were policed
1149 rx = self.pg1._get_capture(1)
1150 self.assertTrue(len(rx) > 0)
1151 self.assertTrue(len(rx) < len(pkts))
1154 # remove the poilcer. back to full rx
1156 self.vapi.ip_punt_police(policer.policer_index, is_add=0)
1157 self.vapi.policer_add_del("ip4-punt", 400, 0, 10, 0,
1158 rate_type=1, is_add=0)
1159 self.send_and_expect(self.pg0, pkts, self.pg1)
1162 # remove the redirect. expect full drop.
1164 self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
1165 self.pg1.sw_if_index,
1168 self.send_and_assert_no_replies(self.pg0, pkts,
1169 "IP no punt config")
1172 # Add a redirect that is not input port selective
1174 self.vapi.ip_punt_redirect(0xffffffff,
1175 self.pg1.sw_if_index,
1177 self.send_and_expect(self.pg0, pkts, self.pg1)
1179 self.vapi.ip_punt_redirect(0xffffffff,
1180 self.pg1.sw_if_index,
1185 class TestIPDeag(VppTestCase):
1186 """ IPv4 Deaggregate Routes """
1189 super(TestIPDeag, self).setUp()
1191 self.create_pg_interfaces(range(3))
1193 for i in self.pg_interfaces:
1199 super(TestIPDeag, self).tearDown()
1200 for i in self.pg_interfaces:
1204 def test_ip_deag(self):
1205 """ IP Deag Routes """
1208 # Create a table to be used for:
1209 # 1 - another destination address lookup
1210 # 2 - a source address lookup
1212 table_dst = VppIpTable(self, 1)
1213 table_src = VppIpTable(self, 2)
1214 table_dst.add_vpp_config()
1215 table_src.add_vpp_config()
1218 # Add a route in the default table to point to a deag/
1219 # second lookup in each of these tables
1221 route_to_dst = VppIpRoute(self, "1.1.1.1", 32,
1222 [VppRoutePath("0.0.0.0",
1225 route_to_src = VppIpRoute(self, "1.1.1.2", 32,
1226 [VppRoutePath("0.0.0.0",
1229 is_source_lookup=1)])
1230 route_to_dst.add_vpp_config()
1231 route_to_src.add_vpp_config()
1234 # packets to these destination are dropped, since they'll
1235 # hit the respective default routes in the second table
1237 p_dst = (Ether(src=self.pg0.remote_mac,
1238 dst=self.pg0.local_mac) /
1239 IP(src="5.5.5.5", dst="1.1.1.1") /
1240 TCP(sport=1234, dport=1234) /
1242 p_src = (Ether(src=self.pg0.remote_mac,
1243 dst=self.pg0.local_mac) /
1244 IP(src="2.2.2.2", dst="1.1.1.2") /
1245 TCP(sport=1234, dport=1234) /
1247 pkts_dst = p_dst * 257
1248 pkts_src = p_src * 257
1250 self.send_and_assert_no_replies(self.pg0, pkts_dst,
1252 self.send_and_assert_no_replies(self.pg0, pkts_src,
1256 # add a route in the dst table to forward via pg1
1258 route_in_dst = VppIpRoute(self, "1.1.1.1", 32,
1259 [VppRoutePath(self.pg1.remote_ip4,
1260 self.pg1.sw_if_index)],
1262 route_in_dst.add_vpp_config()
1263 self.send_and_expect(self.pg0, pkts_dst, self.pg1)
1266 # add a route in the src table to forward via pg2
1268 route_in_src = VppIpRoute(self, "2.2.2.2", 32,
1269 [VppRoutePath(self.pg2.remote_ip4,
1270 self.pg2.sw_if_index)],
1272 route_in_src.add_vpp_config()
1273 self.send_and_expect(self.pg0, pkts_src, self.pg2)
1276 # loop in the lookup DP
1278 route_loop = VppIpRoute(self, "2.2.2.3", 32,
1279 [VppRoutePath("0.0.0.0",
1282 route_loop.add_vpp_config()
1284 p_l = (Ether(src=self.pg0.remote_mac,
1285 dst=self.pg0.local_mac) /
1286 IP(src="2.2.2.4", dst="2.2.2.3") /
1287 TCP(sport=1234, dport=1234) /
1290 self.send_and_assert_no_replies(self.pg0, p_l * 257,
1294 class TestIPInput(VppTestCase):
1295 """ IPv4 Input Exceptions """
1298 super(TestIPInput, self).setUp()
1300 self.create_pg_interfaces(range(2))
1302 for i in self.pg_interfaces:
1308 super(TestIPInput, self).tearDown()
1309 for i in self.pg_interfaces:
1313 def test_ip_input(self):
1314 """ IP Input Exceptions """
1316 # i can't find a way in scapy to construct an IP packet
1317 # with a length less than the IP header length
1320 # Packet too short - this is forwarded
1322 p_short = (Ether(src=self.pg0.remote_mac,
1323 dst=self.pg0.local_mac) /
1324 IP(src=self.pg0.remote_ip4,
1325 dst=self.pg1.remote_ip4,
1327 UDP(sport=1234, dport=1234) /
1330 rx = self.send_and_expect(self.pg0, p_short * 65, self.pg1)
1333 # Packet too long - this is dropped
1335 p_long = (Ether(src=self.pg0.remote_mac,
1336 dst=self.pg0.local_mac) /
1337 IP(src=self.pg0.remote_ip4,
1338 dst=self.pg1.remote_ip4,
1340 UDP(sport=1234, dport=1234) /
1343 rx = self.send_and_assert_no_replies(self.pg0, p_long * 65,
1347 # bad chksum - this is dropped
1349 p_chksum = (Ether(src=self.pg0.remote_mac,
1350 dst=self.pg0.local_mac) /
1351 IP(src=self.pg0.remote_ip4,
1352 dst=self.pg1.remote_ip4,
1354 UDP(sport=1234, dport=1234) /
1357 rx = self.send_and_assert_no_replies(self.pg0, p_chksum * 65,
1361 # bad version - this is dropped
1363 p_ver = (Ether(src=self.pg0.remote_mac,
1364 dst=self.pg0.local_mac) /
1365 IP(src=self.pg0.remote_ip4,
1366 dst=self.pg1.remote_ip4,
1368 UDP(sport=1234, dport=1234) /
1371 rx = self.send_and_assert_no_replies(self.pg0, p_ver * 65,
1375 # fragment offset 1 - this is dropped
1377 p_frag = (Ether(src=self.pg0.remote_mac,
1378 dst=self.pg0.local_mac) /
1379 IP(src=self.pg0.remote_ip4,
1380 dst=self.pg1.remote_ip4,
1382 UDP(sport=1234, dport=1234) /
1385 rx = self.send_and_assert_no_replies(self.pg0, p_frag * 65,
1389 # TTL expired packet
1391 p_ttl = (Ether(src=self.pg0.remote_mac,
1392 dst=self.pg0.local_mac) /
1393 IP(src=self.pg0.remote_ip4,
1394 dst=self.pg1.remote_ip4,
1396 UDP(sport=1234, dport=1234) /
1399 rx = self.send_and_expect(self.pg0, p_ttl * 65, self.pg0)
1404 self.assertEqual(icmptypes[icmp.type], "time-exceeded")
1405 self.assertEqual(icmpcodes[icmp.type][icmp.code],
1406 "ttl-zero-during-transit")
1407 self.assertEqual(icmp.src, self.pg0.remote_ip4)
1408 self.assertEqual(icmp.dst, self.pg1.remote_ip4)
1413 p_mtu = (Ether(src=self.pg0.remote_mac,
1414 dst=self.pg0.local_mac) /
1415 IP(src=self.pg0.remote_ip4,
1416 dst=self.pg1.remote_ip4,
1417 ttl=10, flags='DF') /
1418 UDP(sport=1234, dport=1234) /
1421 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1500, 0, 0, 0])
1423 rx = self.send_and_expect(self.pg0, p_mtu * 65, self.pg0)
1427 self.assertEqual(icmptypes[icmp.type], "dest-unreach")
1428 self.assertEqual(icmpcodes[icmp.type][icmp.code],
1429 "fragmentation-needed")
1430 self.assertEqual(icmp.src, self.pg0.remote_ip4)
1431 self.assertEqual(icmp.dst, self.pg1.remote_ip4)
1433 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2500, 0, 0, 0])
1434 rx = self.send_and_expect(self.pg0, p_mtu * 65, self.pg1)
1436 # Reset MTU for subsequent tests
1437 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [9000, 0, 0, 0])
1440 class TestIPDirectedBroadcast(VppTestCase):
1441 """ IPv4 Directed Broadcast """
1444 super(TestIPDirectedBroadcast, self).setUp()
1446 self.create_pg_interfaces(range(2))
1448 for i in self.pg_interfaces:
1452 super(TestIPDirectedBroadcast, self).tearDown()
1453 for i in self.pg_interfaces:
1456 def test_ip_input(self):
1457 """ IP Directed Broadcast """
1460 # set the directed broadcast on pg0 first, then config IP4 addresses
1461 # for pg1 directed broadcast is always disabled
1462 self.vapi.sw_interface_set_ip_directed_broadcast(
1463 self.pg0.sw_if_index, 1)
1465 p0 = (Ether(src=self.pg1.remote_mac,
1466 dst=self.pg1.local_mac) /
1468 dst=self.pg0._local_ip4_bcast) /
1469 UDP(sport=1234, dport=1234) /
1471 p1 = (Ether(src=self.pg0.remote_mac,
1472 dst=self.pg0.local_mac) /
1474 dst=self.pg1._local_ip4_bcast) /
1475 UDP(sport=1234, dport=1234) /
1478 self.pg0.config_ip4()
1479 self.pg0.resolve_arp()
1480 self.pg1.config_ip4()
1481 self.pg1.resolve_arp()
1484 # test packet is L2 broadcast
1486 rx = self.send_and_expect(self.pg1, p0 * 65, self.pg0)
1487 self.assertTrue(rx[0][Ether].dst, "ff:ff:ff:ff:ff:ff")
1489 self.send_and_assert_no_replies(self.pg0, p1 * 65,
1490 "directed broadcast disabled")
1493 # toggle directed broadcast on pg0
1495 self.vapi.sw_interface_set_ip_directed_broadcast(
1496 self.pg0.sw_if_index, 0)
1497 self.send_and_assert_no_replies(self.pg1, p0 * 65,
1498 "directed broadcast disabled")
1500 self.vapi.sw_interface_set_ip_directed_broadcast(
1501 self.pg0.sw_if_index, 1)
1502 rx = self.send_and_expect(self.pg1, p0 * 65, self.pg0)
1504 self.pg0.unconfig_ip4()
1505 self.pg1.unconfig_ip4()
1508 if __name__ == '__main__':
1509 unittest.main(testRunner=VppTestRunner)