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(1))
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")
628 class TestIPDisabled(VppTestCase):
629 """ IPv4 disabled """
632 super(TestIPDisabled, self).setUp()
634 # create 2 pg interfaces
635 self.create_pg_interfaces(range(2))
639 self.pg0.config_ip4()
640 self.pg0.resolve_arp()
642 # PG 1 is not IP enabled
646 super(TestIPDisabled, self).tearDown()
647 for i in self.pg_interfaces:
651 def test_ip_disabled(self):
656 # one accepting interface, pg0, 2 forwarding interfaces
658 route_232_1_1_1 = VppIpMRoute(
662 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
663 [VppMRoutePath(self.pg1.sw_if_index,
664 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
665 VppMRoutePath(self.pg0.sw_if_index,
666 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
667 route_232_1_1_1.add_vpp_config()
669 pu = (Ether(src=self.pg1.remote_mac,
670 dst=self.pg1.local_mac) /
671 IP(src="10.10.10.10", dst=self.pg0.remote_ip4) /
672 UDP(sport=1234, dport=1234) /
674 pm = (Ether(src=self.pg1.remote_mac,
675 dst=self.pg1.local_mac) /
676 IP(src="10.10.10.10", dst="232.1.1.1") /
677 UDP(sport=1234, dport=1234) /
681 # PG1 does not forward IP traffic
683 self.send_and_assert_no_replies(self.pg1, pu, "IP disabled")
684 self.send_and_assert_no_replies(self.pg1, pm, "IP disabled")
689 self.pg1.config_ip4()
692 # Now we get packets through
694 self.pg1.add_stream(pu)
695 self.pg_enable_capture(self.pg_interfaces)
697 rx = self.pg0.get_capture(1)
699 self.pg1.add_stream(pm)
700 self.pg_enable_capture(self.pg_interfaces)
702 rx = self.pg0.get_capture(1)
707 self.pg1.unconfig_ip4()
710 # PG1 does not forward IP traffic
712 self.send_and_assert_no_replies(self.pg1, pu, "IP disabled")
713 self.send_and_assert_no_replies(self.pg1, pm, "IP disabled")
716 class TestIPSubNets(VppTestCase):
720 super(TestIPSubNets, self).setUp()
722 # create a 2 pg interfaces
723 self.create_pg_interfaces(range(2))
725 # pg0 we will use to experiemnt
728 # pg1 is setup normally
730 self.pg1.config_ip4()
731 self.pg1.resolve_arp()
734 super(TestIPSubNets, self).tearDown()
735 for i in self.pg_interfaces:
738 def test_ip_sub_nets(self):
742 # Configure a covering route to forward so we know
743 # when we are dropping
745 cover_route = VppIpRoute(self, "10.0.0.0", 8,
746 [VppRoutePath(self.pg1.remote_ip4,
747 self.pg1.sw_if_index)])
748 cover_route.add_vpp_config()
750 p = (Ether(src=self.pg1.remote_mac,
751 dst=self.pg1.local_mac) /
752 IP(dst="10.10.10.10", src=self.pg0.local_ip4) /
753 UDP(sport=1234, dport=1234) /
756 self.pg1.add_stream(p)
757 self.pg_enable_capture(self.pg_interfaces)
759 rx = self.pg1.get_capture(1)
762 # Configure some non-/24 subnets on an IP interface
764 ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10")
766 self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
770 pn = (Ether(src=self.pg1.remote_mac,
771 dst=self.pg1.local_mac) /
772 IP(dst="10.10.0.0", src=self.pg0.local_ip4) /
773 UDP(sport=1234, dport=1234) /
775 pb = (Ether(src=self.pg1.remote_mac,
776 dst=self.pg1.local_mac) /
777 IP(dst="10.10.255.255", src=self.pg0.local_ip4) /
778 UDP(sport=1234, dport=1234) /
781 self.send_and_assert_no_replies(self.pg1, pn, "IP Network address")
782 self.send_and_assert_no_replies(self.pg1, pb, "IP Broadcast address")
784 # remove the sub-net and we are forwarding via the cover again
785 self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
789 self.pg1.add_stream(pn)
790 self.pg_enable_capture(self.pg_interfaces)
792 rx = self.pg1.get_capture(1)
793 self.pg1.add_stream(pb)
794 self.pg_enable_capture(self.pg_interfaces)
796 rx = self.pg1.get_capture(1)
799 # A /31 is a special case where the 'other-side' is an attached host
800 # packets to that peer generate ARP requests
802 ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10")
804 self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
808 pn = (Ether(src=self.pg1.remote_mac,
809 dst=self.pg1.local_mac) /
810 IP(dst="10.10.10.11", src=self.pg0.local_ip4) /
811 UDP(sport=1234, dport=1234) /
814 self.pg1.add_stream(pn)
815 self.pg_enable_capture(self.pg_interfaces)
817 rx = self.pg0.get_capture(1)
820 # remove the sub-net and we are forwarding via the cover again
821 self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
825 self.pg1.add_stream(pn)
826 self.pg_enable_capture(self.pg_interfaces)
828 rx = self.pg1.get_capture(1)
831 class TestIPLoadBalance(VppTestCase):
832 """ IPv4 Load-Balancing """
835 super(TestIPLoadBalance, self).setUp()
837 self.create_pg_interfaces(range(5))
838 mpls_tbl = VppMplsTable(self, 0)
839 mpls_tbl.add_vpp_config()
841 for i in self.pg_interfaces:
848 for i in self.pg_interfaces:
852 super(TestIPLoadBalance, self).tearDown()
854 def send_and_expect_load_balancing(self, input, pkts, outputs):
855 input.add_stream(pkts)
856 self.pg_enable_capture(self.pg_interfaces)
859 rx = oo._get_capture(1)
860 self.assertNotEqual(0, len(rx))
862 def send_and_expect_one_itf(self, input, pkts, itf):
863 input.add_stream(pkts)
864 self.pg_enable_capture(self.pg_interfaces)
866 rx = itf.get_capture(len(pkts))
868 def test_ip_load_balance(self):
869 """ IP Load-Balancing """
872 # An array of packets that differ only in the destination port
878 # An array of packets that differ only in the source address
884 port_ip_hdr = (IP(dst="10.0.0.1", src="20.0.0.1") /
885 UDP(sport=1234, dport=1234 + ii) /
887 port_ip_pkts.append((Ether(src=self.pg0.remote_mac,
888 dst=self.pg0.local_mac) /
890 port_mpls_pkts.append((Ether(src=self.pg0.remote_mac,
891 dst=self.pg0.local_mac) /
892 MPLS(label=66, ttl=2) /
895 src_ip_hdr = (IP(dst="10.0.0.1", src="20.0.0.%d" % ii) /
896 UDP(sport=1234, dport=1234) /
898 src_ip_pkts.append((Ether(src=self.pg0.remote_mac,
899 dst=self.pg0.local_mac) /
901 src_mpls_pkts.append((Ether(src=self.pg0.remote_mac,
902 dst=self.pg0.local_mac) /
903 MPLS(label=66, ttl=2) /
906 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
907 [VppRoutePath(self.pg1.remote_ip4,
908 self.pg1.sw_if_index),
909 VppRoutePath(self.pg2.remote_ip4,
910 self.pg2.sw_if_index)])
911 route_10_0_0_1.add_vpp_config()
913 binding = VppMplsIpBind(self, 66, "10.0.0.1", 32)
914 binding.add_vpp_config()
917 # inject the packet on pg0 - expect load-balancing across the 2 paths
918 # - since the default hash config is to use IP src,dst and port
920 # We are not going to ensure equal amounts of packets across each link,
921 # since the hash algorithm is statistical and therefore this can never
922 # be guaranteed. But wuth 64 different packets we do expect some
923 # balancing. So instead just ensure there is traffic on each link.
925 self.send_and_expect_load_balancing(self.pg0, port_ip_pkts,
926 [self.pg1, self.pg2])
927 self.send_and_expect_load_balancing(self.pg0, src_ip_pkts,
928 [self.pg1, self.pg2])
929 self.send_and_expect_load_balancing(self.pg0, port_mpls_pkts,
930 [self.pg1, self.pg2])
931 self.send_and_expect_load_balancing(self.pg0, src_mpls_pkts,
932 [self.pg1, self.pg2])
935 # change the flow hash config so it's only IP src,dst
936 # - now only the stream with differing source address will
939 self.vapi.set_ip_flow_hash(0, src=1, dst=1, sport=0, dport=0)
941 self.send_and_expect_load_balancing(self.pg0, src_ip_pkts,
942 [self.pg1, self.pg2])
943 self.send_and_expect_load_balancing(self.pg0, src_mpls_pkts,
944 [self.pg1, self.pg2])
946 self.send_and_expect_one_itf(self.pg0, port_ip_pkts, self.pg2)
949 # change the flow hash config back to defaults
951 self.vapi.set_ip_flow_hash(0, src=1, dst=1, sport=1, dport=1)
955 # - testing that 2 stages of load-balancing occurs and there is no
956 # polarisation (i.e. only 2 of 4 paths are used)
961 for ii in range(257):
962 port_pkts.append((Ether(src=self.pg0.remote_mac,
963 dst=self.pg0.local_mac) /
964 IP(dst="1.1.1.1", src="20.0.0.1") /
965 UDP(sport=1234, dport=1234 + ii) /
967 src_pkts.append((Ether(src=self.pg0.remote_mac,
968 dst=self.pg0.local_mac) /
969 IP(dst="1.1.1.1", src="20.0.0.%d" % ii) /
970 UDP(sport=1234, dport=1234) /
973 route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
974 [VppRoutePath(self.pg3.remote_ip4,
975 self.pg3.sw_if_index),
976 VppRoutePath(self.pg4.remote_ip4,
977 self.pg4.sw_if_index)])
978 route_10_0_0_2.add_vpp_config()
980 route_1_1_1_1 = VppIpRoute(self, "1.1.1.1", 32,
981 [VppRoutePath("10.0.0.2", 0xffffffff),
982 VppRoutePath("10.0.0.1", 0xffffffff)])
983 route_1_1_1_1.add_vpp_config()
986 # inject the packet on pg0 - expect load-balancing across all 4 paths
988 self.vapi.cli("clear trace")
989 self.send_and_expect_load_balancing(self.pg0, port_pkts,
992 self.send_and_expect_load_balancing(self.pg0, src_pkts,
998 # - testing that 2 stages of load-balancing, no choices
1002 for ii in range(257):
1003 port_pkts.append((Ether(src=self.pg0.remote_mac,
1004 dst=self.pg0.local_mac) /
1005 IP(dst="1.1.1.2", src="20.0.0.2") /
1006 UDP(sport=1234, dport=1234 + ii) /
1009 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1010 [VppRoutePath(self.pg3.remote_ip4,
1011 self.pg3.sw_if_index)])
1012 route_10_0_0_3.add_vpp_config()
1014 route_1_1_1_2 = VppIpRoute(self, "1.1.1.2", 32,
1015 [VppRoutePath("10.0.0.3", 0xffffffff)])
1016 route_1_1_1_2.add_vpp_config()
1019 # inject the packet on pg0 - expect load-balancing across all 4 paths
1021 self.vapi.cli("clear trace")
1022 self.send_and_expect_one_itf(self.pg0, port_pkts, self.pg3)
1025 class TestIPVlan0(VppTestCase):
1029 super(TestIPVlan0, self).setUp()
1031 self.create_pg_interfaces(range(2))
1032 mpls_tbl = VppMplsTable(self, 0)
1033 mpls_tbl.add_vpp_config()
1035 for i in self.pg_interfaces:
1042 for i in self.pg_interfaces:
1046 super(TestIPVlan0, self).tearDown()
1048 def test_ip_vlan_0(self):
1051 pkts = (Ether(src=self.pg0.remote_mac,
1052 dst=self.pg0.local_mac) /
1054 IP(dst=self.pg1.remote_ip4,
1055 src=self.pg0.remote_ip4) /
1056 UDP(sport=1234, dport=1234) /
1057 Raw('\xa5' * 100)) * 65
1060 # Expect that packets sent on VLAN-0 are forwarded on the
1063 self.send_and_expect(self.pg0, pkts, self.pg1)
1066 class TestIPPunt(VppTestCase):
1067 """ IPv4 Punt Police/Redirect """
1070 super(TestIPPunt, self).setUp()
1072 self.create_pg_interfaces(range(2))
1074 for i in self.pg_interfaces:
1080 super(TestIPPunt, self).tearDown()
1081 for i in self.pg_interfaces:
1085 def test_ip_punt(self):
1086 """ IP punt police and redirect """
1088 p = (Ether(src=self.pg0.remote_mac,
1089 dst=self.pg0.local_mac) /
1090 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
1091 TCP(sport=1234, dport=1234) /
1097 # Configure a punt redirect via pg1.
1099 nh_addr = socket.inet_pton(socket.AF_INET,
1100 self.pg1.remote_ip4)
1101 self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
1102 self.pg1.sw_if_index,
1105 self.send_and_expect(self.pg0, pkts, self.pg1)
1110 policer = self.vapi.policer_add_del("ip4-punt", 400, 0, 10, 0,
1112 self.vapi.ip_punt_police(policer.policer_index)
1114 self.vapi.cli("clear trace")
1115 self.pg0.add_stream(pkts)
1116 self.pg_enable_capture(self.pg_interfaces)
1120 # the number of packet recieved should be greater than 0,
1121 # but not equal to the number sent, since some were policed
1123 rx = self.pg1._get_capture(1)
1124 self.assertTrue(len(rx) > 0)
1125 self.assertTrue(len(rx) < len(pkts))
1128 # remove the poilcer. back to full rx
1130 self.vapi.ip_punt_police(policer.policer_index, is_add=0)
1131 self.vapi.policer_add_del("ip4-punt", 400, 0, 10, 0,
1132 rate_type=1, is_add=0)
1133 self.send_and_expect(self.pg0, pkts, self.pg1)
1136 # remove the redirect. expect full drop.
1138 self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
1139 self.pg1.sw_if_index,
1142 self.send_and_assert_no_replies(self.pg0, pkts,
1143 "IP no punt config")
1146 # Add a redirect that is not input port selective
1148 self.vapi.ip_punt_redirect(0xffffffff,
1149 self.pg1.sw_if_index,
1151 self.send_and_expect(self.pg0, pkts, self.pg1)
1153 self.vapi.ip_punt_redirect(0xffffffff,
1154 self.pg1.sw_if_index,
1159 class TestIPDeag(VppTestCase):
1160 """ IPv4 Deaggregate Routes """
1163 super(TestIPDeag, self).setUp()
1165 self.create_pg_interfaces(range(3))
1167 for i in self.pg_interfaces:
1173 super(TestIPDeag, self).tearDown()
1174 for i in self.pg_interfaces:
1178 def test_ip_deag(self):
1179 """ IP Deag Routes """
1182 # Create a table to be used for:
1183 # 1 - another destination address lookup
1184 # 2 - a source address lookup
1186 table_dst = VppIpTable(self, 1)
1187 table_src = VppIpTable(self, 2)
1188 table_dst.add_vpp_config()
1189 table_src.add_vpp_config()
1192 # Add a route in the default table to point to a deag/
1193 # second lookup in each of these tables
1195 route_to_dst = VppIpRoute(self, "1.1.1.1", 32,
1196 [VppRoutePath("0.0.0.0",
1199 route_to_src = VppIpRoute(self, "1.1.1.2", 32,
1200 [VppRoutePath("0.0.0.0",
1203 is_source_lookup=1)])
1204 route_to_dst.add_vpp_config()
1205 route_to_src.add_vpp_config()
1208 # packets to these destination are dropped, since they'll
1209 # hit the respective default routes in the second table
1211 p_dst = (Ether(src=self.pg0.remote_mac,
1212 dst=self.pg0.local_mac) /
1213 IP(src="5.5.5.5", dst="1.1.1.1") /
1214 TCP(sport=1234, dport=1234) /
1216 p_src = (Ether(src=self.pg0.remote_mac,
1217 dst=self.pg0.local_mac) /
1218 IP(src="2.2.2.2", dst="1.1.1.2") /
1219 TCP(sport=1234, dport=1234) /
1221 pkts_dst = p_dst * 257
1222 pkts_src = p_src * 257
1224 self.send_and_assert_no_replies(self.pg0, pkts_dst,
1226 self.send_and_assert_no_replies(self.pg0, pkts_src,
1230 # add a route in the dst table to forward via pg1
1232 route_in_dst = VppIpRoute(self, "1.1.1.1", 32,
1233 [VppRoutePath(self.pg1.remote_ip4,
1234 self.pg1.sw_if_index)],
1236 route_in_dst.add_vpp_config()
1237 self.send_and_expect(self.pg0, pkts_dst, self.pg1)
1240 # add a route in the src table to forward via pg2
1242 route_in_src = VppIpRoute(self, "2.2.2.2", 32,
1243 [VppRoutePath(self.pg2.remote_ip4,
1244 self.pg2.sw_if_index)],
1246 route_in_src.add_vpp_config()
1247 self.send_and_expect(self.pg0, pkts_src, self.pg2)
1250 # loop in the lookup DP
1252 route_loop = VppIpRoute(self, "2.2.2.3", 32,
1253 [VppRoutePath("0.0.0.0",
1256 route_loop.add_vpp_config()
1258 p_l = (Ether(src=self.pg0.remote_mac,
1259 dst=self.pg0.local_mac) /
1260 IP(src="2.2.2.4", dst="2.2.2.3") /
1261 TCP(sport=1234, dport=1234) /
1264 self.send_and_assert_no_replies(self.pg0, p_l * 257,
1268 class TestIPInput(VppTestCase):
1269 """ IPv4 Input Exceptions """
1272 super(TestIPInput, self).setUp()
1274 self.create_pg_interfaces(range(2))
1276 for i in self.pg_interfaces:
1282 super(TestIPInput, self).tearDown()
1283 for i in self.pg_interfaces:
1287 def test_ip_input(self):
1288 """ IP Input Exceptions """
1290 # i can't find a way in scapy to construct an IP packet
1291 # with a length less than the IP header length
1294 # Packet too short - this is forwarded
1296 p_short = (Ether(src=self.pg0.remote_mac,
1297 dst=self.pg0.local_mac) /
1298 IP(src=self.pg0.remote_ip4,
1299 dst=self.pg1.remote_ip4,
1301 UDP(sport=1234, dport=1234) /
1304 rx = self.send_and_expect(self.pg0, p_short * 65, self.pg1)
1307 # Packet too long - this is dropped
1309 p_long = (Ether(src=self.pg0.remote_mac,
1310 dst=self.pg0.local_mac) /
1311 IP(src=self.pg0.remote_ip4,
1312 dst=self.pg1.remote_ip4,
1314 UDP(sport=1234, dport=1234) /
1317 rx = self.send_and_assert_no_replies(self.pg0, p_long * 65,
1321 # bad chksum - this is dropped
1323 p_chksum = (Ether(src=self.pg0.remote_mac,
1324 dst=self.pg0.local_mac) /
1325 IP(src=self.pg0.remote_ip4,
1326 dst=self.pg1.remote_ip4,
1328 UDP(sport=1234, dport=1234) /
1331 rx = self.send_and_assert_no_replies(self.pg0, p_chksum * 65,
1335 # bad version - this is dropped
1337 p_ver = (Ether(src=self.pg0.remote_mac,
1338 dst=self.pg0.local_mac) /
1339 IP(src=self.pg0.remote_ip4,
1340 dst=self.pg1.remote_ip4,
1342 UDP(sport=1234, dport=1234) /
1345 rx = self.send_and_assert_no_replies(self.pg0, p_ver * 65,
1349 # fragment offset 1 - this is dropped
1351 p_frag = (Ether(src=self.pg0.remote_mac,
1352 dst=self.pg0.local_mac) /
1353 IP(src=self.pg0.remote_ip4,
1354 dst=self.pg1.remote_ip4,
1356 UDP(sport=1234, dport=1234) /
1359 rx = self.send_and_assert_no_replies(self.pg0, p_frag * 65,
1363 # TTL expired packet
1365 p_ttl = (Ether(src=self.pg0.remote_mac,
1366 dst=self.pg0.local_mac) /
1367 IP(src=self.pg0.remote_ip4,
1368 dst=self.pg1.remote_ip4,
1370 UDP(sport=1234, dport=1234) /
1373 rx = self.send_and_expect(self.pg0, p_ttl * 65, self.pg0)
1378 self.assertEqual(icmptypes[icmp.type], "time-exceeded")
1379 self.assertEqual(icmpcodes[icmp.type][icmp.code],
1380 "ttl-zero-during-transit")
1381 self.assertEqual(icmp.src, self.pg0.remote_ip4)
1382 self.assertEqual(icmp.dst, self.pg1.remote_ip4)
1387 p_mtu = (Ether(src=self.pg0.remote_mac,
1388 dst=self.pg0.local_mac) /
1389 IP(src=self.pg0.remote_ip4,
1390 dst=self.pg1.remote_ip4,
1391 ttl=10, flags='DF') /
1392 UDP(sport=1234, dport=1234) /
1395 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1500, 0, 0, 0])
1397 rx = self.send_and_expect(self.pg0, p_mtu * 65, self.pg0)
1401 self.assertEqual(icmptypes[icmp.type], "dest-unreach")
1402 self.assertEqual(icmpcodes[icmp.type][icmp.code],
1403 "fragmentation-needed")
1404 self.assertEqual(icmp.src, self.pg0.remote_ip4)
1405 self.assertEqual(icmp.dst, self.pg1.remote_ip4)
1407 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2500, 0, 0, 0])
1408 rx = self.send_and_expect(self.pg0, p_mtu * 65, self.pg1)
1410 # Reset MTU for subsequent tests
1411 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [9000, 0, 0, 0])
1414 class TestIPDirectedBroadcast(VppTestCase):
1415 """ IPv4 Directed Broadcast """
1418 super(TestIPDirectedBroadcast, self).setUp()
1420 self.create_pg_interfaces(range(2))
1422 for i in self.pg_interfaces:
1426 super(TestIPDirectedBroadcast, self).tearDown()
1427 for i in self.pg_interfaces:
1430 def test_ip_input(self):
1431 """ IP Directed Broadcast """
1434 # set the directed broadcast on pg0 first, then config IP4 addresses
1435 # for pg1 directed broadcast is always disabled
1436 self.vapi.sw_interface_set_ip_directed_broadcast(
1437 self.pg0.sw_if_index, 1)
1439 p0 = (Ether(src=self.pg1.remote_mac,
1440 dst=self.pg1.local_mac) /
1442 dst=self.pg0._local_ip4_bcast) /
1443 UDP(sport=1234, dport=1234) /
1445 p1 = (Ether(src=self.pg0.remote_mac,
1446 dst=self.pg0.local_mac) /
1448 dst=self.pg1._local_ip4_bcast) /
1449 UDP(sport=1234, dport=1234) /
1452 self.pg0.config_ip4()
1453 self.pg0.resolve_arp()
1454 self.pg1.config_ip4()
1455 self.pg1.resolve_arp()
1458 # test packet is L2 broadcast
1460 rx = self.send_and_expect(self.pg1, p0 * 65, self.pg0)
1461 self.assertTrue(rx[0][Ether].dst, "ff:ff:ff:ff:ff:ff")
1463 self.send_and_assert_no_replies(self.pg0, p1 * 65,
1464 "directed broadcast disabled")
1467 # toggle directed broadcast on pg0
1469 self.vapi.sw_interface_set_ip_directed_broadcast(
1470 self.pg0.sw_if_index, 0)
1471 self.send_and_assert_no_replies(self.pg1, p0 * 65,
1472 "directed broadcast disabled")
1474 self.vapi.sw_interface_set_ip_directed_broadcast(
1475 self.pg0.sw_if_index, 1)
1476 rx = self.send_and_expect(self.pg1, p0 * 65, self.pg0)
1478 self.pg0.unconfig_ip4()
1479 self.pg1.unconfig_ip4()
1482 if __name__ == '__main__':
1483 unittest.main(testRunner=VppTestRunner)