7 from framework import VppTestCase, VppTestRunner
8 from vpp_sub_interface import VppSubInterface, VppDot1QSubint, VppDot1ADSubint
9 from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpMRoute, \
10 VppMRoutePath, MRouteItfFlags, MRouteEntryFlags, VppMplsIpBind, \
11 VppMplsTable, VppIpTable
13 from scapy.packet import Raw
14 from scapy.layers.l2 import Ether, Dot1Q, ARP
15 from scapy.layers.inet import IP, UDP, TCP, ICMP, icmptypes, icmpcodes
17 from scapy.contrib.mpls import MPLS
20 class TestIPv4(VppTestCase):
21 """ IPv4 Test Case """
25 Perform test setup before test case.
28 - create 3 pg interfaces
29 - untagged pg0 interface
30 - Dot1Q subinterface on pg1
31 - Dot1AD subinterface on pg2
33 - put it into UP state
35 - resolve neighbor address using ARP
36 - configure 200 fib entries
38 :ivar list interfaces: pg interfaces and subinterfaces.
39 :ivar dict flows: IPv4 packet flows in test.
41 super(TestIPv4, self).setUp()
43 # create 3 pg interfaces
44 self.create_pg_interfaces(range(3))
46 # create 2 subinterfaces for pg1 and pg2
47 self.sub_interfaces = [
48 VppDot1QSubint(self, self.pg1, 100),
49 VppDot1ADSubint(self, self.pg2, 200, 300, 400)]
51 # packet flows mapping pg0 -> pg1.sub, pg2.sub, etc.
53 self.flows[self.pg0] = [self.pg1.sub_if, self.pg2.sub_if]
54 self.flows[self.pg1.sub_if] = [self.pg0, self.pg2.sub_if]
55 self.flows[self.pg2.sub_if] = [self.pg0, self.pg1.sub_if]
58 self.pg_if_packet_sizes = [64, 1500, 9020]
60 self.interfaces = list(self.pg_interfaces)
61 self.interfaces.extend(self.sub_interfaces)
63 # setup all interfaces
64 for i in self.interfaces:
69 # config 2M FIB entries
70 self.config_fib_entries(200)
73 """Run standard test teardown and log ``show ip arp``."""
74 super(TestIPv4, self).tearDown()
76 self.logger.info(self.vapi.cli("show ip arp"))
77 # info(self.vapi.cli("show ip fib")) # many entries
79 def config_fib_entries(self, count):
80 """For each interface add to the FIB table *count* routes to
81 "10.0.0.1/32" destination with interface's local address as next-hop
84 :param int count: Number of FIB entries.
86 - *TODO:* check if the next-hop address shouldn't be remote address
87 instead of local address.
89 n_int = len(self.interfaces)
92 dest_addr = socket.inet_pton(socket.AF_INET, "10.0.0.1")
94 for i in self.interfaces:
95 next_hop_address = i.local_ip4n
96 for j in range(count / n_int):
97 self.vapi.ip_add_del_route(
98 dest_addr, dest_addr_len, next_hop_address)
100 if counter / count * 100 > percent:
101 self.logger.info("Configure %d FIB entries .. %d%% done" %
105 def modify_packet(self, src_if, packet_size, pkt):
106 """Add load, set destination IP and extend packet to required packet
107 size for defined interface.
109 :param VppInterface src_if: Interface to create packet for.
110 :param int packet_size: Required packet size.
111 :param Scapy pkt: Packet to be modified.
113 dst_if_idx = packet_size / 10 % 2
114 dst_if = self.flows[src_if][dst_if_idx]
115 info = self.create_packet_info(src_if, dst_if)
116 payload = self.info_to_payload(info)
118 p[IP].dst = dst_if.remote_ip4
120 if isinstance(src_if, VppSubInterface):
121 p = src_if.add_dot1_layer(p)
122 self.extend_packet(p, packet_size)
126 def create_stream(self, src_if):
127 """Create input packet stream for defined interface.
129 :param VppInterface src_if: Interface to create packet stream for.
131 hdr_ext = 4 if isinstance(src_if, VppSubInterface) else 0
132 pkt_tmpl = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
133 IP(src=src_if.remote_ip4) /
134 UDP(sport=1234, dport=1234))
136 pkts = [self.modify_packet(src_if, i, pkt_tmpl)
137 for i in xrange(self.pg_if_packet_sizes[0],
138 self.pg_if_packet_sizes[1], 10)]
139 pkts_b = [self.modify_packet(src_if, i, pkt_tmpl)
140 for i in xrange(self.pg_if_packet_sizes[1] + hdr_ext,
141 self.pg_if_packet_sizes[2] + hdr_ext, 50)]
146 def verify_capture(self, dst_if, capture):
147 """Verify captured input packet stream for defined interface.
149 :param VppInterface dst_if: Interface to verify captured packet stream
151 :param list capture: Captured packet stream.
153 self.logger.info("Verifying capture on interface %s" % dst_if.name)
155 for i in self.interfaces:
156 last_info[i.sw_if_index] = None
158 dst_sw_if_index = dst_if.sw_if_index
159 if hasattr(dst_if, 'parent'):
161 for packet in capture:
163 # Check VLAN tags and Ethernet header
164 packet = dst_if.remove_dot1_layer(packet)
165 self.assertTrue(Dot1Q not in packet)
169 payload_info = self.payload_to_info(str(packet[Raw]))
170 packet_index = payload_info.index
171 self.assertEqual(payload_info.dst, dst_sw_if_index)
173 "Got packet on port %s: src=%u (id=%u)" %
174 (dst_if.name, payload_info.src, packet_index))
175 next_info = self.get_next_packet_info_for_interface2(
176 payload_info.src, dst_sw_if_index,
177 last_info[payload_info.src])
178 last_info[payload_info.src] = next_info
179 self.assertTrue(next_info is not None)
180 self.assertEqual(packet_index, next_info.index)
181 saved_packet = next_info.data
182 # Check standard fields
183 self.assertEqual(ip.src, saved_packet[IP].src)
184 self.assertEqual(ip.dst, saved_packet[IP].dst)
185 self.assertEqual(udp.sport, saved_packet[UDP].sport)
186 self.assertEqual(udp.dport, saved_packet[UDP].dport)
188 self.logger.error(ppp("Unexpected or invalid packet:", packet))
190 for i in self.interfaces:
191 remaining_packet = self.get_next_packet_info_for_interface2(
192 i.sw_if_index, dst_sw_if_index, last_info[i.sw_if_index])
193 self.assertTrue(remaining_packet is None,
194 "Interface %s: Packet expected from interface %s "
195 "didn't arrive" % (dst_if.name, i.name))
202 - Create IPv4 stream for pg0 interface
203 - Create IPv4 tagged streams for pg1's and pg2's sub-interface.
204 - Send and verify received packets on each interface.
207 pkts = self.create_stream(self.pg0)
208 self.pg0.add_stream(pkts)
210 for i in self.sub_interfaces:
211 pkts = self.create_stream(i)
212 i.parent.add_stream(pkts)
214 self.pg_enable_capture(self.pg_interfaces)
217 pkts = self.pg0.get_capture()
218 self.verify_capture(self.pg0, pkts)
220 for i in self.sub_interfaces:
221 pkts = i.parent.get_capture()
222 self.verify_capture(i, pkts)
225 class TestICMPEcho(VppTestCase):
226 """ ICMP Echo Test Case """
229 super(TestICMPEcho, self).setUp()
231 # create 1 pg interface
232 self.create_pg_interfaces(range(1))
234 for i in self.pg_interfaces:
240 super(TestICMPEcho, self).tearDown()
241 for i in self.pg_interfaces:
245 def test_icmp_echo(self):
246 """ VPP replies to ICMP Echo Request
250 - Receive ICMP Echo Request message on pg0 interface.
251 - Check outgoing ICMP Echo Reply message on pg0 interface.
256 icmp_load = '\x0a' * 18
257 p_echo_request = (Ether(src=self.pg0.remote_mac,
258 dst=self.pg0.local_mac) /
259 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
260 ICMP(id=icmp_id, seq=icmp_seq) /
263 self.pg0.add_stream(p_echo_request)
264 self.pg_enable_capture(self.pg_interfaces)
267 rx = self.pg0.get_capture(1)
273 self.assertEqual(ether.src, self.pg0.local_mac)
274 self.assertEqual(ether.dst, self.pg0.remote_mac)
276 self.assertEqual(ipv4.src, self.pg0.local_ip4)
277 self.assertEqual(ipv4.dst, self.pg0.remote_ip4)
279 self.assertEqual(icmptypes[icmp.type], "echo-reply")
280 self.assertEqual(icmp.id, icmp_id)
281 self.assertEqual(icmp.seq, icmp_seq)
282 self.assertEqual(icmp[Raw].load, icmp_load)
285 class TestIPv4FibCrud(VppTestCase):
286 """ FIB - add/update/delete - ip4 routes
294 ..note:: Python API is too slow to add many routes, needs replacement.
297 def config_fib_many_to_one(self, start_dest_addr, next_hop_addr, count):
300 :param start_dest_addr:
301 :param next_hop_addr:
303 :return list: added ips with 32 prefix
306 dest_addr = int(binascii.hexlify(socket.inet_pton(socket.AF_INET,
307 start_dest_addr)), 16)
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(binascii.hexlify(socket.inet_pton(socket.AF_INET,
322 start_dest_addr)), 16)
324 n_next_hop_addr = socket.inet_pton(socket.AF_INET, next_hop_addr)
325 for _ in range(count):
326 n_dest_addr = '{:08x}'.format(dest_addr).decode('hex')
327 self.vapi.ip_add_del_route(n_dest_addr, dest_addr_len,
328 n_next_hop_addr, is_add=0)
329 removed_ips.append(socket.inet_ntoa(n_dest_addr))
333 def create_stream(self, src_if, dst_if, dst_ips, count):
336 for _ in range(count):
337 dst_addr = random.choice(dst_ips)
338 info = self.create_packet_info(src_if, dst_if)
339 payload = self.info_to_payload(info)
340 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
341 IP(src=src_if.remote_ip4, dst=dst_addr) /
342 UDP(sport=1234, dport=1234) /
345 self.extend_packet(p, random.choice(self.pg_if_packet_sizes))
350 def _find_ip_match(self, find_in, pkt):
352 if self.payload_to_info(str(p[Raw])) == \
353 self.payload_to_info(str(pkt[Raw])):
354 if p[IP].src != pkt[IP].src:
356 if p[IP].dst != pkt[IP].dst:
358 if p[UDP].sport != pkt[UDP].sport:
360 if p[UDP].dport != pkt[UDP].dport:
366 def _match_route_detail(route_detail, ip, address_length=32, table_id=0):
367 if route_detail.address == socket.inet_pton(socket.AF_INET, ip):
368 if route_detail.table_id != table_id:
370 elif route_detail.address_length != address_length:
377 def verify_capture(self, dst_interface, received_pkts, expected_pkts):
378 self.assertEqual(len(received_pkts), len(expected_pkts))
379 to_verify = list(expected_pkts)
380 for p in received_pkts:
381 self.assertEqual(p.src, dst_interface.local_mac)
382 self.assertEqual(p.dst, dst_interface.remote_mac)
383 x = self._find_ip_match(to_verify, p)
385 self.assertListEqual(to_verify, [])
387 def verify_route_dump(self, fib_dump, ips):
389 def _ip_in_route_dump(ip, fib_dump):
390 return next((route for route in fib_dump
391 if self._match_route_detail(route, ip)),
395 self.assertTrue(_ip_in_route_dump(ip, fib_dump),
396 'IP {} is not in fib dump.'.format(ip))
398 def verify_not_in_route_dump(self, fib_dump, ips):
400 def _ip_in_route_dump(ip, fib_dump):
401 return next((route for route in fib_dump
402 if self._match_route_detail(route, ip)),
406 self.assertFalse(_ip_in_route_dump(ip, fib_dump),
407 'IP {} is in fib dump.'.format(ip))
412 #. Create and initialize 3 pg interfaces.
413 #. initialize class attributes configured_routes and deleted_routes
414 to store information between tests.
416 super(TestIPv4FibCrud, cls).setUpClass()
419 # create 3 pg interfaces
420 cls.create_pg_interfaces(range(3))
422 cls.interfaces = list(cls.pg_interfaces)
424 # setup all interfaces
425 for i in cls.interfaces:
430 cls.configured_routes = []
431 cls.deleted_routes = []
432 cls.pg_if_packet_sizes = [64, 512, 1518, 9018]
435 super(TestIPv4FibCrud, cls).tearDownClass()
439 super(TestIPv4FibCrud, self).setUp()
440 self.reset_packet_infos()
442 def test_1_add_routes(self):
445 - add 100 routes check with traffic script.
447 # config 1M FIB entries
448 self.configured_routes.extend(self.config_fib_many_to_one(
449 "10.0.0.0", self.pg0.remote_ip4, 100))
451 fib_dump = self.vapi.ip_fib_dump()
452 self.verify_route_dump(fib_dump, self.configured_routes)
454 self.stream_1 = self.create_stream(
455 self.pg1, self.pg0, self.configured_routes, 100)
456 self.stream_2 = self.create_stream(
457 self.pg2, self.pg0, self.configured_routes, 100)
458 self.pg1.add_stream(self.stream_1)
459 self.pg2.add_stream(self.stream_2)
461 self.pg_enable_capture(self.pg_interfaces)
464 pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
465 self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
467 def test_2_del_routes(self):
468 """ Delete 100 routes
470 - delete 10 routes check with traffic script.
472 self.deleted_routes.extend(self.unconfig_fib_many_to_one(
473 "10.0.0.10", self.pg0.remote_ip4, 10))
474 for x in self.deleted_routes:
475 self.configured_routes.remove(x)
477 fib_dump = self.vapi.ip_fib_dump()
478 self.verify_route_dump(fib_dump, self.configured_routes)
480 self.stream_1 = self.create_stream(
481 self.pg1, self.pg0, self.configured_routes, 100)
482 self.stream_2 = self.create_stream(
483 self.pg2, self.pg0, self.configured_routes, 100)
484 self.stream_3 = self.create_stream(
485 self.pg1, self.pg0, self.deleted_routes, 100)
486 self.stream_4 = self.create_stream(
487 self.pg2, self.pg0, self.deleted_routes, 100)
488 self.pg1.add_stream(self.stream_1 + self.stream_3)
489 self.pg2.add_stream(self.stream_2 + self.stream_4)
490 self.pg_enable_capture(self.pg_interfaces)
493 pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
494 self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
496 def test_3_add_new_routes(self):
499 - re-add 5 routes check with traffic script.
500 - add 100 routes check with traffic script.
502 tmp = self.config_fib_many_to_one(
503 "10.0.0.10", self.pg0.remote_ip4, 5)
504 self.configured_routes.extend(tmp)
506 self.deleted_routes.remove(x)
508 self.configured_routes.extend(self.config_fib_many_to_one(
509 "10.0.1.0", self.pg0.remote_ip4, 100))
511 fib_dump = self.vapi.ip_fib_dump()
512 self.verify_route_dump(fib_dump, self.configured_routes)
514 self.stream_1 = self.create_stream(
515 self.pg1, self.pg0, self.configured_routes, 300)
516 self.stream_2 = self.create_stream(
517 self.pg2, self.pg0, self.configured_routes, 300)
518 self.stream_3 = self.create_stream(
519 self.pg1, self.pg0, self.deleted_routes, 100)
520 self.stream_4 = self.create_stream(
521 self.pg2, self.pg0, self.deleted_routes, 100)
523 self.pg1.add_stream(self.stream_1 + self.stream_3)
524 self.pg2.add_stream(self.stream_2 + self.stream_4)
525 self.pg_enable_capture(self.pg_interfaces)
528 pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
529 self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
531 def test_4_del_routes(self):
532 """ Delete 1.5k routes
534 - delete 5 routes check with traffic script.
535 - add 100 routes check with traffic script.
537 self.deleted_routes.extend(self.unconfig_fib_many_to_one(
538 "10.0.0.0", self.pg0.remote_ip4, 15))
539 self.deleted_routes.extend(self.unconfig_fib_many_to_one(
540 "10.0.0.20", self.pg0.remote_ip4, 85))
541 self.deleted_routes.extend(self.unconfig_fib_many_to_one(
542 "10.0.1.0", self.pg0.remote_ip4, 100))
543 fib_dump = self.vapi.ip_fib_dump()
544 self.verify_not_in_route_dump(fib_dump, self.deleted_routes)
547 class TestIPNull(VppTestCase):
548 """ IPv4 routes via NULL """
551 super(TestIPNull, self).setUp()
553 # create 2 pg interfaces
554 self.create_pg_interfaces(range(2))
556 for i in self.pg_interfaces:
562 super(TestIPNull, self).tearDown()
563 for i in self.pg_interfaces:
567 def test_ip_null(self):
568 """ IP NULL route """
571 # A route via IP NULL that will reply with ICMP unreachables
573 ip_unreach = VppIpRoute(self, "10.0.0.1", 32, [], is_unreach=1)
574 ip_unreach.add_vpp_config()
576 p_unreach = (Ether(src=self.pg0.remote_mac,
577 dst=self.pg0.local_mac) /
578 IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
579 UDP(sport=1234, dport=1234) /
582 self.pg0.add_stream(p_unreach)
583 self.pg_enable_capture(self.pg_interfaces)
586 rx = self.pg0.get_capture(1)
590 self.assertEqual(icmptypes[icmp.type], "dest-unreach")
591 self.assertEqual(icmpcodes[icmp.type][icmp.code], "host-unreachable")
592 self.assertEqual(icmp.src, self.pg0.remote_ip4)
593 self.assertEqual(icmp.dst, "10.0.0.1")
596 # ICMP replies are rate limited. so sit and spin.
601 # A route via IP NULL that will reply with ICMP prohibited
603 ip_prohibit = VppIpRoute(self, "10.0.0.2", 32, [], is_prohibit=1)
604 ip_prohibit.add_vpp_config()
606 p_prohibit = (Ether(src=self.pg0.remote_mac,
607 dst=self.pg0.local_mac) /
608 IP(src=self.pg0.remote_ip4, dst="10.0.0.2") /
609 UDP(sport=1234, dport=1234) /
612 self.pg0.add_stream(p_prohibit)
613 self.pg_enable_capture(self.pg_interfaces)
616 rx = self.pg0.get_capture(1)
621 self.assertEqual(icmptypes[icmp.type], "dest-unreach")
622 self.assertEqual(icmpcodes[icmp.type][icmp.code], "host-prohibited")
623 self.assertEqual(icmp.src, self.pg0.remote_ip4)
624 self.assertEqual(icmp.dst, "10.0.0.2")
626 def test_ip_drop(self):
627 """ IP Drop Routes """
629 p = (Ether(src=self.pg0.remote_mac,
630 dst=self.pg0.local_mac) /
631 IP(src=self.pg0.remote_ip4, dst="1.1.1.1") /
632 UDP(sport=1234, dport=1234) /
635 r1 = VppIpRoute(self, "1.1.1.0", 24,
636 [VppRoutePath(self.pg1.remote_ip4,
637 self.pg1.sw_if_index)])
640 rx = self.send_and_expect(self.pg0, p * 65, self.pg1)
643 # insert a more specific as a drop
645 r2 = VppIpRoute(self, "1.1.1.1", 32, [], is_drop=1)
648 self.send_and_assert_no_replies(self.pg0, p * 65, "Drop Route")
649 r2.remove_vpp_config()
650 rx = self.send_and_expect(self.pg0, p * 65, self.pg1)
653 class TestIPDisabled(VppTestCase):
654 """ IPv4 disabled """
657 super(TestIPDisabled, self).setUp()
659 # create 2 pg interfaces
660 self.create_pg_interfaces(range(2))
664 self.pg0.config_ip4()
665 self.pg0.resolve_arp()
667 # PG 1 is not IP enabled
671 super(TestIPDisabled, self).tearDown()
672 for i in self.pg_interfaces:
676 def test_ip_disabled(self):
681 # one accepting interface, pg0, 2 forwarding interfaces
683 route_232_1_1_1 = VppIpMRoute(
687 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
688 [VppMRoutePath(self.pg1.sw_if_index,
689 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
690 VppMRoutePath(self.pg0.sw_if_index,
691 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
692 route_232_1_1_1.add_vpp_config()
694 pu = (Ether(src=self.pg1.remote_mac,
695 dst=self.pg1.local_mac) /
696 IP(src="10.10.10.10", dst=self.pg0.remote_ip4) /
697 UDP(sport=1234, dport=1234) /
699 pm = (Ether(src=self.pg1.remote_mac,
700 dst=self.pg1.local_mac) /
701 IP(src="10.10.10.10", dst="232.1.1.1") /
702 UDP(sport=1234, dport=1234) /
706 # PG1 does not forward IP traffic
708 self.send_and_assert_no_replies(self.pg1, pu, "IP disabled")
709 self.send_and_assert_no_replies(self.pg1, pm, "IP disabled")
714 self.pg1.config_ip4()
717 # Now we get packets through
719 self.pg1.add_stream(pu)
720 self.pg_enable_capture(self.pg_interfaces)
722 rx = self.pg0.get_capture(1)
724 self.pg1.add_stream(pm)
725 self.pg_enable_capture(self.pg_interfaces)
727 rx = self.pg0.get_capture(1)
732 self.pg1.unconfig_ip4()
735 # PG1 does not forward IP traffic
737 self.send_and_assert_no_replies(self.pg1, pu, "IP disabled")
738 self.send_and_assert_no_replies(self.pg1, pm, "IP disabled")
741 class TestIPSubNets(VppTestCase):
745 super(TestIPSubNets, self).setUp()
747 # create a 2 pg interfaces
748 self.create_pg_interfaces(range(2))
750 # pg0 we will use to experiemnt
753 # pg1 is setup normally
755 self.pg1.config_ip4()
756 self.pg1.resolve_arp()
759 super(TestIPSubNets, self).tearDown()
760 for i in self.pg_interfaces:
763 def test_ip_sub_nets(self):
767 # Configure a covering route to forward so we know
768 # when we are dropping
770 cover_route = VppIpRoute(self, "10.0.0.0", 8,
771 [VppRoutePath(self.pg1.remote_ip4,
772 self.pg1.sw_if_index)])
773 cover_route.add_vpp_config()
775 p = (Ether(src=self.pg1.remote_mac,
776 dst=self.pg1.local_mac) /
777 IP(dst="10.10.10.10", src=self.pg0.local_ip4) /
778 UDP(sport=1234, dport=1234) /
781 self.pg1.add_stream(p)
782 self.pg_enable_capture(self.pg_interfaces)
784 rx = self.pg1.get_capture(1)
787 # Configure some non-/24 subnets on an IP interface
789 ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10")
791 self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
795 pn = (Ether(src=self.pg1.remote_mac,
796 dst=self.pg1.local_mac) /
797 IP(dst="10.10.0.0", src=self.pg0.local_ip4) /
798 UDP(sport=1234, dport=1234) /
800 pb = (Ether(src=self.pg1.remote_mac,
801 dst=self.pg1.local_mac) /
802 IP(dst="10.10.255.255", src=self.pg0.local_ip4) /
803 UDP(sport=1234, dport=1234) /
806 self.send_and_assert_no_replies(self.pg1, pn, "IP Network address")
807 self.send_and_assert_no_replies(self.pg1, pb, "IP Broadcast address")
809 # remove the sub-net and we are forwarding via the cover again
810 self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
814 self.pg1.add_stream(pn)
815 self.pg_enable_capture(self.pg_interfaces)
817 rx = self.pg1.get_capture(1)
818 self.pg1.add_stream(pb)
819 self.pg_enable_capture(self.pg_interfaces)
821 rx = self.pg1.get_capture(1)
824 # A /31 is a special case where the 'other-side' is an attached host
825 # packets to that peer generate ARP requests
827 ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10")
829 self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
833 pn = (Ether(src=self.pg1.remote_mac,
834 dst=self.pg1.local_mac) /
835 IP(dst="10.10.10.11", src=self.pg0.local_ip4) /
836 UDP(sport=1234, dport=1234) /
839 self.pg1.add_stream(pn)
840 self.pg_enable_capture(self.pg_interfaces)
842 rx = self.pg0.get_capture(1)
845 # remove the sub-net and we are forwarding via the cover again
846 self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
850 self.pg1.add_stream(pn)
851 self.pg_enable_capture(self.pg_interfaces)
853 rx = self.pg1.get_capture(1)
856 class TestIPLoadBalance(VppTestCase):
857 """ IPv4 Load-Balancing """
860 super(TestIPLoadBalance, self).setUp()
862 self.create_pg_interfaces(range(5))
863 mpls_tbl = VppMplsTable(self, 0)
864 mpls_tbl.add_vpp_config()
866 for i in self.pg_interfaces:
873 for i in self.pg_interfaces:
877 super(TestIPLoadBalance, self).tearDown()
879 def send_and_expect_load_balancing(self, input, pkts, outputs):
880 input.add_stream(pkts)
881 self.pg_enable_capture(self.pg_interfaces)
884 rx = oo._get_capture(1)
885 self.assertNotEqual(0, len(rx))
887 def send_and_expect_one_itf(self, input, pkts, itf):
888 input.add_stream(pkts)
889 self.pg_enable_capture(self.pg_interfaces)
891 rx = itf.get_capture(len(pkts))
893 def test_ip_load_balance(self):
894 """ IP Load-Balancing """
897 # An array of packets that differ only in the destination port
903 # An array of packets that differ only in the source address
909 port_ip_hdr = (IP(dst="10.0.0.1", src="20.0.0.1") /
910 UDP(sport=1234, dport=1234 + ii) /
912 port_ip_pkts.append((Ether(src=self.pg0.remote_mac,
913 dst=self.pg0.local_mac) /
915 port_mpls_pkts.append((Ether(src=self.pg0.remote_mac,
916 dst=self.pg0.local_mac) /
917 MPLS(label=66, ttl=2) /
920 src_ip_hdr = (IP(dst="10.0.0.1", src="20.0.0.%d" % ii) /
921 UDP(sport=1234, dport=1234) /
923 src_ip_pkts.append((Ether(src=self.pg0.remote_mac,
924 dst=self.pg0.local_mac) /
926 src_mpls_pkts.append((Ether(src=self.pg0.remote_mac,
927 dst=self.pg0.local_mac) /
928 MPLS(label=66, ttl=2) /
931 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
932 [VppRoutePath(self.pg1.remote_ip4,
933 self.pg1.sw_if_index),
934 VppRoutePath(self.pg2.remote_ip4,
935 self.pg2.sw_if_index)])
936 route_10_0_0_1.add_vpp_config()
938 binding = VppMplsIpBind(self, 66, "10.0.0.1", 32)
939 binding.add_vpp_config()
942 # inject the packet on pg0 - expect load-balancing across the 2 paths
943 # - since the default hash config is to use IP src,dst and port
945 # We are not going to ensure equal amounts of packets across each link,
946 # since the hash algorithm is statistical and therefore this can never
947 # be guaranteed. But wuth 64 different packets we do expect some
948 # balancing. So instead just ensure there is traffic on each link.
950 self.send_and_expect_load_balancing(self.pg0, port_ip_pkts,
951 [self.pg1, self.pg2])
952 self.send_and_expect_load_balancing(self.pg0, src_ip_pkts,
953 [self.pg1, self.pg2])
954 self.send_and_expect_load_balancing(self.pg0, port_mpls_pkts,
955 [self.pg1, self.pg2])
956 self.send_and_expect_load_balancing(self.pg0, src_mpls_pkts,
957 [self.pg1, self.pg2])
960 # change the flow hash config so it's only IP src,dst
961 # - now only the stream with differing source address will
964 self.vapi.set_ip_flow_hash(0, src=1, dst=1, sport=0, dport=0)
966 self.send_and_expect_load_balancing(self.pg0, src_ip_pkts,
967 [self.pg1, self.pg2])
968 self.send_and_expect_load_balancing(self.pg0, src_mpls_pkts,
969 [self.pg1, self.pg2])
971 self.send_and_expect_one_itf(self.pg0, port_ip_pkts, self.pg2)
974 # change the flow hash config back to defaults
976 self.vapi.set_ip_flow_hash(0, src=1, dst=1, sport=1, dport=1)
980 # - testing that 2 stages of load-balancing occurs and there is no
981 # polarisation (i.e. only 2 of 4 paths are used)
986 for ii in range(257):
987 port_pkts.append((Ether(src=self.pg0.remote_mac,
988 dst=self.pg0.local_mac) /
989 IP(dst="1.1.1.1", src="20.0.0.1") /
990 UDP(sport=1234, dport=1234 + ii) /
992 src_pkts.append((Ether(src=self.pg0.remote_mac,
993 dst=self.pg0.local_mac) /
994 IP(dst="1.1.1.1", src="20.0.0.%d" % ii) /
995 UDP(sport=1234, dport=1234) /
998 route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
999 [VppRoutePath(self.pg3.remote_ip4,
1000 self.pg3.sw_if_index),
1001 VppRoutePath(self.pg4.remote_ip4,
1002 self.pg4.sw_if_index)])
1003 route_10_0_0_2.add_vpp_config()
1005 route_1_1_1_1 = VppIpRoute(self, "1.1.1.1", 32,
1006 [VppRoutePath("10.0.0.2", 0xffffffff),
1007 VppRoutePath("10.0.0.1", 0xffffffff)])
1008 route_1_1_1_1.add_vpp_config()
1011 # inject the packet on pg0 - expect load-balancing across all 4 paths
1013 self.vapi.cli("clear trace")
1014 self.send_and_expect_load_balancing(self.pg0, port_pkts,
1015 [self.pg1, self.pg2,
1016 self.pg3, self.pg4])
1017 self.send_and_expect_load_balancing(self.pg0, src_pkts,
1018 [self.pg1, self.pg2,
1019 self.pg3, self.pg4])
1022 # Recursive prefixes
1023 # - testing that 2 stages of load-balancing, no choices
1027 for ii in range(257):
1028 port_pkts.append((Ether(src=self.pg0.remote_mac,
1029 dst=self.pg0.local_mac) /
1030 IP(dst="1.1.1.2", src="20.0.0.2") /
1031 UDP(sport=1234, dport=1234 + ii) /
1034 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1035 [VppRoutePath(self.pg3.remote_ip4,
1036 self.pg3.sw_if_index)])
1037 route_10_0_0_3.add_vpp_config()
1039 route_1_1_1_2 = VppIpRoute(self, "1.1.1.2", 32,
1040 [VppRoutePath("10.0.0.3", 0xffffffff)])
1041 route_1_1_1_2.add_vpp_config()
1044 # inject the packet on pg0 - expect load-balancing across all 4 paths
1046 self.vapi.cli("clear trace")
1047 self.send_and_expect_one_itf(self.pg0, port_pkts, self.pg3)
1050 class TestIPVlan0(VppTestCase):
1054 super(TestIPVlan0, self).setUp()
1056 self.create_pg_interfaces(range(2))
1057 mpls_tbl = VppMplsTable(self, 0)
1058 mpls_tbl.add_vpp_config()
1060 for i in self.pg_interfaces:
1067 for i in self.pg_interfaces:
1071 super(TestIPVlan0, self).tearDown()
1073 def test_ip_vlan_0(self):
1076 pkts = (Ether(src=self.pg0.remote_mac,
1077 dst=self.pg0.local_mac) /
1079 IP(dst=self.pg1.remote_ip4,
1080 src=self.pg0.remote_ip4) /
1081 UDP(sport=1234, dport=1234) /
1082 Raw('\xa5' * 100)) * 65
1085 # Expect that packets sent on VLAN-0 are forwarded on the
1088 self.send_and_expect(self.pg0, pkts, self.pg1)
1091 class TestIPPunt(VppTestCase):
1092 """ IPv4 Punt Police/Redirect """
1095 super(TestIPPunt, self).setUp()
1097 self.create_pg_interfaces(range(2))
1099 for i in self.pg_interfaces:
1105 super(TestIPPunt, self).tearDown()
1106 for i in self.pg_interfaces:
1110 def test_ip_punt(self):
1111 """ IP punt police and redirect """
1113 p = (Ether(src=self.pg0.remote_mac,
1114 dst=self.pg0.local_mac) /
1115 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
1116 TCP(sport=1234, dport=1234) /
1122 # Configure a punt redirect via pg1.
1124 nh_addr = socket.inet_pton(socket.AF_INET,
1125 self.pg1.remote_ip4)
1126 self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
1127 self.pg1.sw_if_index,
1130 self.send_and_expect(self.pg0, pkts, self.pg1)
1135 policer = self.vapi.policer_add_del("ip4-punt", 400, 0, 10, 0,
1137 self.vapi.ip_punt_police(policer.policer_index)
1139 self.vapi.cli("clear trace")
1140 self.pg0.add_stream(pkts)
1141 self.pg_enable_capture(self.pg_interfaces)
1145 # the number of packet recieved should be greater than 0,
1146 # but not equal to the number sent, since some were policed
1148 rx = self.pg1._get_capture(1)
1149 self.assertGreater(len(rx), 0)
1150 self.assertLess(len(rx), len(pkts))
1153 # remove the poilcer. back to full rx
1155 self.vapi.ip_punt_police(policer.policer_index, is_add=0)
1156 self.vapi.policer_add_del("ip4-punt", 400, 0, 10, 0,
1157 rate_type=1, is_add=0)
1158 self.send_and_expect(self.pg0, pkts, self.pg1)
1161 # remove the redirect. expect full drop.
1163 self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
1164 self.pg1.sw_if_index,
1167 self.send_and_assert_no_replies(self.pg0, pkts,
1168 "IP no punt config")
1171 # Add a redirect that is not input port selective
1173 self.vapi.ip_punt_redirect(0xffffffff,
1174 self.pg1.sw_if_index,
1176 self.send_and_expect(self.pg0, pkts, self.pg1)
1178 self.vapi.ip_punt_redirect(0xffffffff,
1179 self.pg1.sw_if_index,
1184 class TestIPDeag(VppTestCase):
1185 """ IPv4 Deaggregate Routes """
1188 super(TestIPDeag, self).setUp()
1190 self.create_pg_interfaces(range(3))
1192 for i in self.pg_interfaces:
1198 super(TestIPDeag, self).tearDown()
1199 for i in self.pg_interfaces:
1203 def test_ip_deag(self):
1204 """ IP Deag Routes """
1207 # Create a table to be used for:
1208 # 1 - another destination address lookup
1209 # 2 - a source address lookup
1211 table_dst = VppIpTable(self, 1)
1212 table_src = VppIpTable(self, 2)
1213 table_dst.add_vpp_config()
1214 table_src.add_vpp_config()
1217 # Add a route in the default table to point to a deag/
1218 # second lookup in each of these tables
1220 route_to_dst = VppIpRoute(self, "1.1.1.1", 32,
1221 [VppRoutePath("0.0.0.0",
1224 route_to_src = VppIpRoute(self, "1.1.1.2", 32,
1225 [VppRoutePath("0.0.0.0",
1228 is_source_lookup=1)])
1229 route_to_dst.add_vpp_config()
1230 route_to_src.add_vpp_config()
1233 # packets to these destination are dropped, since they'll
1234 # hit the respective default routes in the second table
1236 p_dst = (Ether(src=self.pg0.remote_mac,
1237 dst=self.pg0.local_mac) /
1238 IP(src="5.5.5.5", dst="1.1.1.1") /
1239 TCP(sport=1234, dport=1234) /
1241 p_src = (Ether(src=self.pg0.remote_mac,
1242 dst=self.pg0.local_mac) /
1243 IP(src="2.2.2.2", dst="1.1.1.2") /
1244 TCP(sport=1234, dport=1234) /
1246 pkts_dst = p_dst * 257
1247 pkts_src = p_src * 257
1249 self.send_and_assert_no_replies(self.pg0, pkts_dst,
1251 self.send_and_assert_no_replies(self.pg0, pkts_src,
1255 # add a route in the dst table to forward via pg1
1257 route_in_dst = VppIpRoute(self, "1.1.1.1", 32,
1258 [VppRoutePath(self.pg1.remote_ip4,
1259 self.pg1.sw_if_index)],
1261 route_in_dst.add_vpp_config()
1262 self.send_and_expect(self.pg0, pkts_dst, self.pg1)
1265 # add a route in the src table to forward via pg2
1267 route_in_src = VppIpRoute(self, "2.2.2.2", 32,
1268 [VppRoutePath(self.pg2.remote_ip4,
1269 self.pg2.sw_if_index)],
1271 route_in_src.add_vpp_config()
1272 self.send_and_expect(self.pg0, pkts_src, self.pg2)
1275 # loop in the lookup DP
1277 route_loop = VppIpRoute(self, "2.2.2.3", 32,
1278 [VppRoutePath("0.0.0.0",
1281 route_loop.add_vpp_config()
1283 p_l = (Ether(src=self.pg0.remote_mac,
1284 dst=self.pg0.local_mac) /
1285 IP(src="2.2.2.4", dst="2.2.2.3") /
1286 TCP(sport=1234, dport=1234) /
1289 self.send_and_assert_no_replies(self.pg0, p_l * 257,
1293 class TestIPInput(VppTestCase):
1294 """ IPv4 Input Exceptions """
1297 super(TestIPInput, self).setUp()
1299 self.create_pg_interfaces(range(2))
1301 for i in self.pg_interfaces:
1307 super(TestIPInput, self).tearDown()
1308 for i in self.pg_interfaces:
1312 def test_ip_input(self):
1313 """ IP Input Exceptions """
1315 # i can't find a way in scapy to construct an IP packet
1316 # with a length less than the IP header length
1319 # Packet too short - this is forwarded
1321 p_short = (Ether(src=self.pg0.remote_mac,
1322 dst=self.pg0.local_mac) /
1323 IP(src=self.pg0.remote_ip4,
1324 dst=self.pg1.remote_ip4,
1326 UDP(sport=1234, dport=1234) /
1329 rx = self.send_and_expect(self.pg0, p_short * 65, self.pg1)
1332 # Packet too long - this is dropped
1334 p_long = (Ether(src=self.pg0.remote_mac,
1335 dst=self.pg0.local_mac) /
1336 IP(src=self.pg0.remote_ip4,
1337 dst=self.pg1.remote_ip4,
1339 UDP(sport=1234, dport=1234) /
1342 rx = self.send_and_assert_no_replies(self.pg0, p_long * 65,
1346 # bad chksum - this is dropped
1348 p_chksum = (Ether(src=self.pg0.remote_mac,
1349 dst=self.pg0.local_mac) /
1350 IP(src=self.pg0.remote_ip4,
1351 dst=self.pg1.remote_ip4,
1353 UDP(sport=1234, dport=1234) /
1356 rx = self.send_and_assert_no_replies(self.pg0, p_chksum * 65,
1360 # bad version - this is dropped
1362 p_ver = (Ether(src=self.pg0.remote_mac,
1363 dst=self.pg0.local_mac) /
1364 IP(src=self.pg0.remote_ip4,
1365 dst=self.pg1.remote_ip4,
1367 UDP(sport=1234, dport=1234) /
1370 rx = self.send_and_assert_no_replies(self.pg0, p_ver * 65,
1374 # fragment offset 1 - this is dropped
1376 p_frag = (Ether(src=self.pg0.remote_mac,
1377 dst=self.pg0.local_mac) /
1378 IP(src=self.pg0.remote_ip4,
1379 dst=self.pg1.remote_ip4,
1381 UDP(sport=1234, dport=1234) /
1384 rx = self.send_and_assert_no_replies(self.pg0, p_frag * 65,
1388 # TTL expired packet
1390 p_ttl = (Ether(src=self.pg0.remote_mac,
1391 dst=self.pg0.local_mac) /
1392 IP(src=self.pg0.remote_ip4,
1393 dst=self.pg1.remote_ip4,
1395 UDP(sport=1234, dport=1234) /
1398 rx = self.send_and_expect(self.pg0, p_ttl * 65, self.pg0)
1403 self.assertEqual(icmptypes[icmp.type], "time-exceeded")
1404 self.assertEqual(icmpcodes[icmp.type][icmp.code],
1405 "ttl-zero-during-transit")
1406 self.assertEqual(icmp.src, self.pg0.remote_ip4)
1407 self.assertEqual(icmp.dst, self.pg1.remote_ip4)
1412 p_mtu = (Ether(src=self.pg0.remote_mac,
1413 dst=self.pg0.local_mac) /
1414 IP(src=self.pg0.remote_ip4,
1415 dst=self.pg1.remote_ip4,
1416 ttl=10, flags='DF') /
1417 UDP(sport=1234, dport=1234) /
1420 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1500, 0, 0, 0])
1422 rx = self.send_and_expect(self.pg0, p_mtu * 65, self.pg0)
1426 self.assertEqual(icmptypes[icmp.type], "dest-unreach")
1427 self.assertEqual(icmpcodes[icmp.type][icmp.code],
1428 "fragmentation-needed")
1429 self.assertEqual(icmp.src, self.pg0.remote_ip4)
1430 self.assertEqual(icmp.dst, self.pg1.remote_ip4)
1432 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2500, 0, 0, 0])
1433 rx = self.send_and_expect(self.pg0, p_mtu * 65, self.pg1)
1435 # Reset MTU for subsequent tests
1436 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [9000, 0, 0, 0])
1439 class TestIPDirectedBroadcast(VppTestCase):
1440 """ IPv4 Directed Broadcast """
1443 super(TestIPDirectedBroadcast, self).setUp()
1445 self.create_pg_interfaces(range(2))
1447 for i in self.pg_interfaces:
1451 super(TestIPDirectedBroadcast, self).tearDown()
1452 for i in self.pg_interfaces:
1455 def test_ip_input(self):
1456 """ IP Directed Broadcast """
1459 # set the directed broadcast on pg0 first, then config IP4 addresses
1460 # for pg1 directed broadcast is always disabled
1461 self.vapi.sw_interface_set_ip_directed_broadcast(
1462 self.pg0.sw_if_index, 1)
1464 p0 = (Ether(src=self.pg1.remote_mac,
1465 dst=self.pg1.local_mac) /
1467 dst=self.pg0._local_ip4_bcast) /
1468 UDP(sport=1234, dport=1234) /
1470 p1 = (Ether(src=self.pg0.remote_mac,
1471 dst=self.pg0.local_mac) /
1473 dst=self.pg1._local_ip4_bcast) /
1474 UDP(sport=1234, dport=1234) /
1477 self.pg0.config_ip4()
1478 self.pg0.resolve_arp()
1479 self.pg1.config_ip4()
1480 self.pg1.resolve_arp()
1483 # test packet is L2 broadcast
1485 rx = self.send_and_expect(self.pg1, p0 * 65, self.pg0)
1486 self.assertTrue(rx[0][Ether].dst, "ff:ff:ff:ff:ff:ff")
1488 self.send_and_assert_no_replies(self.pg0, p1 * 65,
1489 "directed broadcast disabled")
1492 # toggle directed broadcast on pg0
1494 self.vapi.sw_interface_set_ip_directed_broadcast(
1495 self.pg0.sw_if_index, 0)
1496 self.send_and_assert_no_replies(self.pg1, p0 * 65,
1497 "directed broadcast disabled")
1499 self.vapi.sw_interface_set_ip_directed_broadcast(
1500 self.pg0.sw_if_index, 1)
1501 rx = self.send_and_expect(self.pg1, p0 * 65, self.pg0)
1503 self.pg0.unconfig_ip4()
1504 self.pg1.unconfig_ip4()
1507 class TestIPLPM(VppTestCase):
1508 """ IPv4 longest Prefix Match """
1511 super(TestIPLPM, self).setUp()
1513 self.create_pg_interfaces(range(4))
1515 for i in self.pg_interfaces:
1521 super(TestIPLPM, self).tearDown()
1522 for i in self.pg_interfaces:
1526 def test_ip_lpm(self):
1527 """ IP longest Prefix Match """
1529 s_24 = VppIpRoute(self, "10.1.2.0", 24,
1530 [VppRoutePath(self.pg1.remote_ip4,
1531 self.pg1.sw_if_index)])
1532 s_24.add_vpp_config()
1533 s_8 = VppIpRoute(self, "10.0.0.0", 8,
1534 [VppRoutePath(self.pg2.remote_ip4,
1535 self.pg2.sw_if_index)])
1536 s_8.add_vpp_config()
1538 p_8 = (Ether(src=self.pg0.remote_mac,
1539 dst=self.pg0.local_mac) /
1542 UDP(sport=1234, dport=1234) /
1544 p_24 = (Ether(src=self.pg0.remote_mac,
1545 dst=self.pg0.local_mac) /
1548 UDP(sport=1234, dport=1234) /
1551 self.logger.info(self.vapi.cli("sh ip fib mtrie"))
1552 rx = self.send_and_expect(self.pg0, p_8 * 65, self.pg2)
1553 rx = self.send_and_expect(self.pg0, p_24 * 65, self.pg1)
1556 class TestIPv4Frag(VppTestCase):
1557 """ IPv4 fragmentation """
1560 def setUpClass(cls):
1561 super(TestIPv4Frag, cls).setUpClass()
1563 cls.create_pg_interfaces([0, 1])
1564 cls.src_if = cls.pg0
1565 cls.dst_if = cls.pg1
1567 # setup all interfaces
1568 for i in cls.pg_interfaces:
1573 def test_frag_large_packets(self):
1574 """ Fragmentation of large packets """
1576 p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1577 IP(src=self.src_if.remote_ip4, dst=self.dst_if.remote_ip4) /
1578 UDP(sport=1234, dport=5678) / Raw())
1579 self.extend_packet(p, 6000, "abcde")
1580 saved_payload = p[Raw].load
1582 # Force fragmentation by setting MTU of output interface
1583 # lower than packet size
1584 self.vapi.sw_interface_set_mtu(self.dst_if.sw_if_index,
1587 self.pg_enable_capture()
1588 self.src_if.add_stream(p)
1591 # Expecting 3 fragments because size of created fragments currently
1592 # cannot be larger then VPP buffer size (which is 2048)
1593 packets = self.dst_if.get_capture(3)
1595 # Assume VPP sends the fragments in order
1598 payload_offset = p.frag * 8
1599 if payload_offset > 0:
1600 payload_offset -= 8 # UDP header is not in payload
1601 self.assert_equal(payload_offset, len(payload))
1602 payload += p[Raw].load
1603 self.assert_equal(payload, saved_payload, "payload")
1606 if __name__ == '__main__':
1607 unittest.main(testRunner=VppTestRunner)