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.
39 :ivar list pg_if_packet_sizes: packet sizes 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, 512, 1518, 9018]
59 self.sub_if_packet_sizes = [64, 512, 1518 + 4, 9018 + 4]
61 self.interfaces = list(self.pg_interfaces)
62 self.interfaces.extend(self.sub_interfaces)
64 # setup all interfaces
65 for i in self.interfaces:
70 # config 2M FIB entries
71 self.config_fib_entries(200)
74 """Run standard test teardown and log ``show ip arp``."""
75 super(TestIPv4, self).tearDown()
77 self.logger.info(self.vapi.cli("show ip arp"))
78 # info(self.vapi.cli("show ip fib")) # many entries
80 def config_fib_entries(self, count):
81 """For each interface add to the FIB table *count* routes to
82 "10.0.0.1/32" destination with interface's local address as next-hop
85 :param int count: Number of FIB entries.
87 - *TODO:* check if the next-hop address shouldn't be remote address
88 instead of local address.
90 n_int = len(self.interfaces)
93 dest_addr = socket.inet_pton(socket.AF_INET, "10.0.0.1")
95 for i in self.interfaces:
96 next_hop_address = i.local_ip4n
97 for j in range(count / n_int):
98 self.vapi.ip_add_del_route(
99 dest_addr, dest_addr_len, next_hop_address)
101 if counter / count * 100 > percent:
102 self.logger.info("Configure %d FIB entries .. %d%% done" %
106 def create_stream(self, src_if, packet_sizes):
107 """Create input packet stream for defined interface.
109 :param VppInterface src_if: Interface to create packet stream for.
110 :param list packet_sizes: Required packet sizes.
113 for i in range(0, 257):
114 dst_if = self.flows[src_if][i % 2]
115 info = self.create_packet_info(src_if, dst_if)
116 payload = self.info_to_payload(info)
117 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
118 IP(src=src_if.remote_ip4, dst=dst_if.remote_ip4) /
119 UDP(sport=1234, dport=1234) /
122 if isinstance(src_if, VppSubInterface):
123 p = src_if.add_dot1_layer(p)
124 size = packet_sizes[(i // 2) % len(packet_sizes)]
125 self.extend_packet(p, size)
129 def verify_capture(self, dst_if, capture):
130 """Verify captured input packet stream for defined interface.
132 :param VppInterface dst_if: Interface to verify captured packet stream
134 :param list capture: Captured packet stream.
136 self.logger.info("Verifying capture on interface %s" % dst_if.name)
138 for i in self.interfaces:
139 last_info[i.sw_if_index] = None
141 dst_sw_if_index = dst_if.sw_if_index
142 if hasattr(dst_if, 'parent'):
144 for packet in capture:
146 # Check VLAN tags and Ethernet header
147 packet = dst_if.remove_dot1_layer(packet)
148 self.assertTrue(Dot1Q not in packet)
152 payload_info = self.payload_to_info(str(packet[Raw]))
153 packet_index = payload_info.index
154 self.assertEqual(payload_info.dst, dst_sw_if_index)
156 "Got packet on port %s: src=%u (id=%u)" %
157 (dst_if.name, payload_info.src, packet_index))
158 next_info = self.get_next_packet_info_for_interface2(
159 payload_info.src, dst_sw_if_index,
160 last_info[payload_info.src])
161 last_info[payload_info.src] = next_info
162 self.assertTrue(next_info is not None)
163 self.assertEqual(packet_index, next_info.index)
164 saved_packet = next_info.data
165 # Check standard fields
166 self.assertEqual(ip.src, saved_packet[IP].src)
167 self.assertEqual(ip.dst, saved_packet[IP].dst)
168 self.assertEqual(udp.sport, saved_packet[UDP].sport)
169 self.assertEqual(udp.dport, saved_packet[UDP].dport)
171 self.logger.error(ppp("Unexpected or invalid packet:", packet))
173 for i in self.interfaces:
174 remaining_packet = self.get_next_packet_info_for_interface2(
175 i.sw_if_index, dst_sw_if_index, last_info[i.sw_if_index])
176 self.assertTrue(remaining_packet is None,
177 "Interface %s: Packet expected from interface %s "
178 "didn't arrive" % (dst_if.name, i.name))
185 - Create IPv4 stream for pg0 interface
186 - Create IPv4 tagged streams for pg1's and pg2's subinterface.
187 - Send and verify received packets on each interface.
190 pkts = self.create_stream(self.pg0, self.pg_if_packet_sizes)
191 self.pg0.add_stream(pkts)
193 for i in self.sub_interfaces:
194 pkts = self.create_stream(i, self.sub_if_packet_sizes)
195 i.parent.add_stream(pkts)
197 self.pg_enable_capture(self.pg_interfaces)
200 pkts = self.pg0.get_capture()
201 self.verify_capture(self.pg0, pkts)
203 for i in self.sub_interfaces:
204 pkts = i.parent.get_capture()
205 self.verify_capture(i, pkts)
208 class TestIPv4FibCrud(VppTestCase):
209 """ FIB - add/update/delete - ip4 routes
217 ..note:: Python API is too slow to add many routes, needs replacement.
220 def config_fib_many_to_one(self, start_dest_addr, next_hop_addr, count):
223 :param start_dest_addr:
224 :param next_hop_addr:
226 :return list: added ips with 32 prefix
229 dest_addr = int(socket.inet_pton(socket.AF_INET,
230 start_dest_addr).encode('hex'),
233 n_next_hop_addr = socket.inet_pton(socket.AF_INET, next_hop_addr)
234 for _ in range(count):
235 n_dest_addr = '{:08x}'.format(dest_addr).decode('hex')
236 self.vapi.ip_add_del_route(n_dest_addr, dest_addr_len,
238 added_ips.append(socket.inet_ntoa(n_dest_addr))
242 def unconfig_fib_many_to_one(self, start_dest_addr, next_hop_addr, count):
245 dest_addr = int(socket.inet_pton(socket.AF_INET,
246 start_dest_addr).encode('hex'),
249 n_next_hop_addr = socket.inet_pton(socket.AF_INET, next_hop_addr)
250 for _ in range(count):
251 n_dest_addr = '{:08x}'.format(dest_addr).decode('hex')
252 self.vapi.ip_add_del_route(n_dest_addr, dest_addr_len,
253 n_next_hop_addr, is_add=0)
254 removed_ips.append(socket.inet_ntoa(n_dest_addr))
258 def create_stream(self, src_if, dst_if, dst_ips, count):
261 for _ in range(count):
262 dst_addr = random.choice(dst_ips)
263 info = self.create_packet_info(src_if, dst_if)
264 payload = self.info_to_payload(info)
265 p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
266 IP(src=src_if.remote_ip4, dst=dst_addr) /
267 UDP(sport=1234, dport=1234) /
270 self.extend_packet(p, random.choice(self.pg_if_packet_sizes))
275 def _find_ip_match(self, find_in, pkt):
277 if self.payload_to_info(str(p[Raw])) == \
278 self.payload_to_info(str(pkt[Raw])):
279 if p[IP].src != pkt[IP].src:
281 if p[IP].dst != pkt[IP].dst:
283 if p[UDP].sport != pkt[UDP].sport:
285 if p[UDP].dport != pkt[UDP].dport:
291 def _match_route_detail(route_detail, ip, address_length=32, table_id=0):
292 if route_detail.address == socket.inet_pton(socket.AF_INET, ip):
293 if route_detail.table_id != table_id:
295 elif route_detail.address_length != address_length:
302 def verify_capture(self, dst_interface, received_pkts, expected_pkts):
303 self.assertEqual(len(received_pkts), len(expected_pkts))
304 to_verify = list(expected_pkts)
305 for p in received_pkts:
306 self.assertEqual(p.src, dst_interface.local_mac)
307 self.assertEqual(p.dst, dst_interface.remote_mac)
308 x = self._find_ip_match(to_verify, p)
310 self.assertListEqual(to_verify, [])
312 def verify_route_dump(self, fib_dump, ips):
314 def _ip_in_route_dump(ip, fib_dump):
315 return next((route for route in fib_dump
316 if self._match_route_detail(route, ip)),
320 self.assertTrue(_ip_in_route_dump(ip, fib_dump),
321 'IP {} is not in fib dump.'.format(ip))
323 def verify_not_in_route_dump(self, fib_dump, ips):
325 def _ip_in_route_dump(ip, fib_dump):
326 return next((route for route in fib_dump
327 if self._match_route_detail(route, ip)),
331 self.assertFalse(_ip_in_route_dump(ip, fib_dump),
332 'IP {} is in fib dump.'.format(ip))
337 #. Create and initialize 3 pg interfaces.
338 #. initialize class attributes configured_routes and deleted_routes
339 to store information between tests.
341 super(TestIPv4FibCrud, cls).setUpClass()
344 # create 3 pg interfaces
345 cls.create_pg_interfaces(range(3))
347 cls.interfaces = list(cls.pg_interfaces)
349 # setup all interfaces
350 for i in cls.interfaces:
355 cls.configured_routes = []
356 cls.deleted_routes = []
357 cls.pg_if_packet_sizes = [64, 512, 1518, 9018]
360 super(TestIPv4FibCrud, cls).tearDownClass()
364 super(TestIPv4FibCrud, self).setUp()
365 self.reset_packet_infos()
367 def test_1_add_routes(self):
370 - add 100 routes check with traffic script.
372 # config 1M FIB entries
373 self.configured_routes.extend(self.config_fib_many_to_one(
374 "10.0.0.0", self.pg0.remote_ip4, 100))
376 fib_dump = self.vapi.ip_fib_dump()
377 self.verify_route_dump(fib_dump, self.configured_routes)
379 self.stream_1 = self.create_stream(
380 self.pg1, self.pg0, self.configured_routes, 100)
381 self.stream_2 = self.create_stream(
382 self.pg2, self.pg0, self.configured_routes, 100)
383 self.pg1.add_stream(self.stream_1)
384 self.pg2.add_stream(self.stream_2)
386 self.pg_enable_capture(self.pg_interfaces)
389 pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
390 self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
392 def test_2_del_routes(self):
393 """ Delete 100 routes
395 - delete 10 routes check with traffic script.
397 self.deleted_routes.extend(self.unconfig_fib_many_to_one(
398 "10.0.0.10", self.pg0.remote_ip4, 10))
399 for x in self.deleted_routes:
400 self.configured_routes.remove(x)
402 fib_dump = self.vapi.ip_fib_dump()
403 self.verify_route_dump(fib_dump, self.configured_routes)
405 self.stream_1 = self.create_stream(
406 self.pg1, self.pg0, self.configured_routes, 100)
407 self.stream_2 = self.create_stream(
408 self.pg2, self.pg0, self.configured_routes, 100)
409 self.stream_3 = self.create_stream(
410 self.pg1, self.pg0, self.deleted_routes, 100)
411 self.stream_4 = self.create_stream(
412 self.pg2, self.pg0, self.deleted_routes, 100)
413 self.pg1.add_stream(self.stream_1 + self.stream_3)
414 self.pg2.add_stream(self.stream_2 + self.stream_4)
415 self.pg_enable_capture(self.pg_interfaces)
418 pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
419 self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
421 def test_3_add_new_routes(self):
424 - re-add 5 routes check with traffic script.
425 - add 100 routes check with traffic script.
427 tmp = self.config_fib_many_to_one(
428 "10.0.0.10", self.pg0.remote_ip4, 5)
429 self.configured_routes.extend(tmp)
431 self.deleted_routes.remove(x)
433 self.configured_routes.extend(self.config_fib_many_to_one(
434 "10.0.1.0", self.pg0.remote_ip4, 100))
436 fib_dump = self.vapi.ip_fib_dump()
437 self.verify_route_dump(fib_dump, self.configured_routes)
439 self.stream_1 = self.create_stream(
440 self.pg1, self.pg0, self.configured_routes, 300)
441 self.stream_2 = self.create_stream(
442 self.pg2, self.pg0, self.configured_routes, 300)
443 self.stream_3 = self.create_stream(
444 self.pg1, self.pg0, self.deleted_routes, 100)
445 self.stream_4 = self.create_stream(
446 self.pg2, self.pg0, self.deleted_routes, 100)
448 self.pg1.add_stream(self.stream_1 + self.stream_3)
449 self.pg2.add_stream(self.stream_2 + self.stream_4)
450 self.pg_enable_capture(self.pg_interfaces)
453 pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
454 self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
456 def test_4_del_routes(self):
457 """ Delete 1.5k routes
459 - delete 5 routes check with traffic script.
460 - add 100 routes check with traffic script.
462 self.deleted_routes.extend(self.unconfig_fib_many_to_one(
463 "10.0.0.0", self.pg0.remote_ip4, 15))
464 self.deleted_routes.extend(self.unconfig_fib_many_to_one(
465 "10.0.0.20", self.pg0.remote_ip4, 85))
466 self.deleted_routes.extend(self.unconfig_fib_many_to_one(
467 "10.0.1.0", self.pg0.remote_ip4, 100))
468 fib_dump = self.vapi.ip_fib_dump()
469 self.verify_not_in_route_dump(fib_dump, self.deleted_routes)
472 class TestIPNull(VppTestCase):
473 """ IPv4 routes via NULL """
476 super(TestIPNull, self).setUp()
478 # create 2 pg interfaces
479 self.create_pg_interfaces(range(1))
481 for i in self.pg_interfaces:
487 super(TestIPNull, self).tearDown()
488 for i in self.pg_interfaces:
492 def test_ip_null(self):
493 """ IP NULL route """
496 # A route via IP NULL that will reply with ICMP unreachables
498 ip_unreach = VppIpRoute(self, "10.0.0.1", 32, [], is_unreach=1)
499 ip_unreach.add_vpp_config()
501 p_unreach = (Ether(src=self.pg0.remote_mac,
502 dst=self.pg0.local_mac) /
503 IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
504 UDP(sport=1234, dport=1234) /
507 self.pg0.add_stream(p_unreach)
508 self.pg_enable_capture(self.pg_interfaces)
511 rx = self.pg0.get_capture(1)
515 self.assertEqual(icmptypes[icmp.type], "dest-unreach")
516 self.assertEqual(icmpcodes[icmp.type][icmp.code], "host-unreachable")
517 self.assertEqual(icmp.src, self.pg0.remote_ip4)
518 self.assertEqual(icmp.dst, "10.0.0.1")
521 # ICMP replies are rate limited. so sit and spin.
526 # A route via IP NULL that will reply with ICMP prohibited
528 ip_prohibit = VppIpRoute(self, "10.0.0.2", 32, [], is_prohibit=1)
529 ip_prohibit.add_vpp_config()
531 p_prohibit = (Ether(src=self.pg0.remote_mac,
532 dst=self.pg0.local_mac) /
533 IP(src=self.pg0.remote_ip4, dst="10.0.0.2") /
534 UDP(sport=1234, dport=1234) /
537 self.pg0.add_stream(p_prohibit)
538 self.pg_enable_capture(self.pg_interfaces)
541 rx = self.pg0.get_capture(1)
546 self.assertEqual(icmptypes[icmp.type], "dest-unreach")
547 self.assertEqual(icmpcodes[icmp.type][icmp.code], "host-prohibited")
548 self.assertEqual(icmp.src, self.pg0.remote_ip4)
549 self.assertEqual(icmp.dst, "10.0.0.2")
552 class TestIPDisabled(VppTestCase):
553 """ IPv4 disabled """
556 super(TestIPDisabled, self).setUp()
558 # create 2 pg interfaces
559 self.create_pg_interfaces(range(2))
563 self.pg0.config_ip4()
564 self.pg0.resolve_arp()
566 # PG 1 is not IP enabled
570 super(TestIPDisabled, self).tearDown()
571 for i in self.pg_interfaces:
575 def send_and_assert_no_replies(self, intf, pkts, remark):
576 intf.add_stream(pkts)
577 self.pg_enable_capture(self.pg_interfaces)
579 for i in self.pg_interfaces:
581 i.assert_nothing_captured(remark=remark)
583 def test_ip_disabled(self):
588 # one accepting interface, pg0, 2 forwarding interfaces
590 route_232_1_1_1 = VppIpMRoute(
594 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
595 [VppMRoutePath(self.pg1.sw_if_index,
596 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
597 VppMRoutePath(self.pg0.sw_if_index,
598 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
599 route_232_1_1_1.add_vpp_config()
601 pu = (Ether(src=self.pg1.remote_mac,
602 dst=self.pg1.local_mac) /
603 IP(src="10.10.10.10", dst=self.pg0.remote_ip4) /
604 UDP(sport=1234, dport=1234) /
606 pm = (Ether(src=self.pg1.remote_mac,
607 dst=self.pg1.local_mac) /
608 IP(src="10.10.10.10", dst="232.1.1.1") /
609 UDP(sport=1234, dport=1234) /
613 # PG1 does not forward IP traffic
615 self.send_and_assert_no_replies(self.pg1, pu, "IP disabled")
616 self.send_and_assert_no_replies(self.pg1, pm, "IP disabled")
621 self.pg1.config_ip4()
624 # Now we get packets through
626 self.pg1.add_stream(pu)
627 self.pg_enable_capture(self.pg_interfaces)
629 rx = self.pg0.get_capture(1)
631 self.pg1.add_stream(pm)
632 self.pg_enable_capture(self.pg_interfaces)
634 rx = self.pg0.get_capture(1)
639 self.pg1.unconfig_ip4()
642 # PG1 does not forward IP traffic
644 self.send_and_assert_no_replies(self.pg1, pu, "IP disabled")
645 self.send_and_assert_no_replies(self.pg1, pm, "IP disabled")
648 class TestIPSubNets(VppTestCase):
652 super(TestIPSubNets, self).setUp()
654 # create a 2 pg interfaces
655 self.create_pg_interfaces(range(2))
657 # pg0 we will use to experiemnt
660 # pg1 is setup normally
662 self.pg1.config_ip4()
663 self.pg1.resolve_arp()
666 super(TestIPSubNets, self).tearDown()
667 for i in self.pg_interfaces:
670 def send_and_assert_no_replies(self, intf, pkts, remark):
671 intf.add_stream(pkts)
672 self.pg_enable_capture(self.pg_interfaces)
674 for i in self.pg_interfaces:
676 i.assert_nothing_captured(remark=remark)
678 def test_ip_sub_nets(self):
682 # Configure a covering route to forward so we know
683 # when we are dropping
685 cover_route = VppIpRoute(self, "10.0.0.0", 8,
686 [VppRoutePath(self.pg1.remote_ip4,
687 self.pg1.sw_if_index)])
688 cover_route.add_vpp_config()
690 p = (Ether(src=self.pg1.remote_mac,
691 dst=self.pg1.local_mac) /
692 IP(dst="10.10.10.10", src=self.pg0.local_ip4) /
693 UDP(sport=1234, dport=1234) /
696 self.pg1.add_stream(p)
697 self.pg_enable_capture(self.pg_interfaces)
699 rx = self.pg1.get_capture(1)
702 # Configure some non-/24 subnets on an IP interface
704 ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10")
706 self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
710 pn = (Ether(src=self.pg1.remote_mac,
711 dst=self.pg1.local_mac) /
712 IP(dst="10.10.0.0", src=self.pg0.local_ip4) /
713 UDP(sport=1234, dport=1234) /
715 pb = (Ether(src=self.pg1.remote_mac,
716 dst=self.pg1.local_mac) /
717 IP(dst="10.10.255.255", src=self.pg0.local_ip4) /
718 UDP(sport=1234, dport=1234) /
721 self.send_and_assert_no_replies(self.pg1, pn, "IP Network address")
722 self.send_and_assert_no_replies(self.pg1, pb, "IP Broadcast address")
724 # remove the sub-net and we are forwarding via the cover again
725 self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
729 self.pg1.add_stream(pn)
730 self.pg_enable_capture(self.pg_interfaces)
732 rx = self.pg1.get_capture(1)
733 self.pg1.add_stream(pb)
734 self.pg_enable_capture(self.pg_interfaces)
736 rx = self.pg1.get_capture(1)
739 # A /31 is a special case where the 'other-side' is an attached host
740 # packets to that peer generate ARP requests
742 ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10")
744 self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
748 pn = (Ether(src=self.pg1.remote_mac,
749 dst=self.pg1.local_mac) /
750 IP(dst="10.10.10.11", src=self.pg0.local_ip4) /
751 UDP(sport=1234, dport=1234) /
754 self.pg1.add_stream(pn)
755 self.pg_enable_capture(self.pg_interfaces)
757 rx = self.pg0.get_capture(1)
760 # remove the sub-net and we are forwarding via the cover again
761 self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
765 self.pg1.add_stream(pn)
766 self.pg_enable_capture(self.pg_interfaces)
768 rx = self.pg1.get_capture(1)
771 class TestIPLoadBalance(VppTestCase):
772 """ IPv4 Load-Balancing """
775 super(TestIPLoadBalance, self).setUp()
777 self.create_pg_interfaces(range(5))
778 mpls_tbl = VppMplsTable(self, 0)
779 mpls_tbl.add_vpp_config()
781 for i in self.pg_interfaces:
788 for i in self.pg_interfaces:
792 super(TestIPLoadBalance, self).tearDown()
794 def send_and_expect_load_balancing(self, input, pkts, outputs):
795 input.add_stream(pkts)
796 self.pg_enable_capture(self.pg_interfaces)
799 rx = oo._get_capture(1)
800 self.assertNotEqual(0, len(rx))
802 def send_and_expect_one_itf(self, input, pkts, itf):
803 input.add_stream(pkts)
804 self.pg_enable_capture(self.pg_interfaces)
806 rx = itf.get_capture(len(pkts))
808 def test_ip_load_balance(self):
809 """ IP Load-Balancing """
812 # An array of packets that differ only in the destination port
818 # An array of packets that differ only in the source address
824 port_ip_hdr = (IP(dst="10.0.0.1", src="20.0.0.1") /
825 UDP(sport=1234, dport=1234 + ii) /
827 port_ip_pkts.append((Ether(src=self.pg0.remote_mac,
828 dst=self.pg0.local_mac) /
830 port_mpls_pkts.append((Ether(src=self.pg0.remote_mac,
831 dst=self.pg0.local_mac) /
832 MPLS(label=66, ttl=2) /
835 src_ip_hdr = (IP(dst="10.0.0.1", src="20.0.0.%d" % ii) /
836 UDP(sport=1234, dport=1234) /
838 src_ip_pkts.append((Ether(src=self.pg0.remote_mac,
839 dst=self.pg0.local_mac) /
841 src_mpls_pkts.append((Ether(src=self.pg0.remote_mac,
842 dst=self.pg0.local_mac) /
843 MPLS(label=66, ttl=2) /
846 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
847 [VppRoutePath(self.pg1.remote_ip4,
848 self.pg1.sw_if_index),
849 VppRoutePath(self.pg2.remote_ip4,
850 self.pg2.sw_if_index)])
851 route_10_0_0_1.add_vpp_config()
853 binding = VppMplsIpBind(self, 66, "10.0.0.1", 32)
854 binding.add_vpp_config()
857 # inject the packet on pg0 - expect load-balancing across the 2 paths
858 # - since the default hash config is to use IP src,dst and port
860 # We are not going to ensure equal amounts of packets across each link,
861 # since the hash algorithm is statistical and therefore this can never
862 # be guaranteed. But wuth 64 different packets we do expect some
863 # balancing. So instead just ensure there is traffic on each link.
865 self.send_and_expect_load_balancing(self.pg0, port_ip_pkts,
866 [self.pg1, self.pg2])
867 self.send_and_expect_load_balancing(self.pg0, src_ip_pkts,
868 [self.pg1, self.pg2])
869 self.send_and_expect_load_balancing(self.pg0, port_mpls_pkts,
870 [self.pg1, self.pg2])
871 self.send_and_expect_load_balancing(self.pg0, src_mpls_pkts,
872 [self.pg1, self.pg2])
875 # change the flow hash config so it's only IP src,dst
876 # - now only the stream with differing source address will
879 self.vapi.set_ip_flow_hash(0, src=1, dst=1, sport=0, dport=0)
881 self.send_and_expect_load_balancing(self.pg0, src_ip_pkts,
882 [self.pg1, self.pg2])
883 self.send_and_expect_load_balancing(self.pg0, src_mpls_pkts,
884 [self.pg1, self.pg2])
886 self.send_and_expect_one_itf(self.pg0, port_ip_pkts, self.pg2)
889 # change the flow hash config back to defaults
891 self.vapi.set_ip_flow_hash(0, src=1, dst=1, sport=1, dport=1)
895 # - testing that 2 stages of load-balancing occurs and there is no
896 # polarisation (i.e. only 2 of 4 paths are used)
901 for ii in range(257):
902 port_pkts.append((Ether(src=self.pg0.remote_mac,
903 dst=self.pg0.local_mac) /
904 IP(dst="1.1.1.1", src="20.0.0.1") /
905 UDP(sport=1234, dport=1234 + ii) /
907 src_pkts.append((Ether(src=self.pg0.remote_mac,
908 dst=self.pg0.local_mac) /
909 IP(dst="1.1.1.1", src="20.0.0.%d" % ii) /
910 UDP(sport=1234, dport=1234) /
913 route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
914 [VppRoutePath(self.pg3.remote_ip4,
915 self.pg3.sw_if_index),
916 VppRoutePath(self.pg4.remote_ip4,
917 self.pg4.sw_if_index)])
918 route_10_0_0_2.add_vpp_config()
920 route_1_1_1_1 = VppIpRoute(self, "1.1.1.1", 32,
921 [VppRoutePath("10.0.0.2", 0xffffffff),
922 VppRoutePath("10.0.0.1", 0xffffffff)])
923 route_1_1_1_1.add_vpp_config()
926 # inject the packet on pg0 - expect load-balancing across all 4 paths
928 self.vapi.cli("clear trace")
929 self.send_and_expect_load_balancing(self.pg0, port_pkts,
932 self.send_and_expect_load_balancing(self.pg0, src_pkts,
938 # - testing that 2 stages of load-balancing, no choices
942 for ii in range(257):
943 port_pkts.append((Ether(src=self.pg0.remote_mac,
944 dst=self.pg0.local_mac) /
945 IP(dst="1.1.1.2", src="20.0.0.2") /
946 UDP(sport=1234, dport=1234 + ii) /
949 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
950 [VppRoutePath(self.pg3.remote_ip4,
951 self.pg3.sw_if_index)])
952 route_10_0_0_3.add_vpp_config()
954 route_1_1_1_2 = VppIpRoute(self, "1.1.1.2", 32,
955 [VppRoutePath("10.0.0.3", 0xffffffff)])
956 route_1_1_1_2.add_vpp_config()
959 # inject the packet on pg0 - expect load-balancing across all 4 paths
961 self.vapi.cli("clear trace")
962 self.send_and_expect_one_itf(self.pg0, port_pkts, self.pg3)
965 class TestIPVlan0(VppTestCase):
969 super(TestIPVlan0, self).setUp()
971 self.create_pg_interfaces(range(2))
972 mpls_tbl = VppMplsTable(self, 0)
973 mpls_tbl.add_vpp_config()
975 for i in self.pg_interfaces:
982 for i in self.pg_interfaces:
986 super(TestIPVlan0, self).tearDown()
988 def send_and_expect(self, input, pkts, output):
989 input.add_stream(pkts)
990 self.pg_enable_capture(self.pg_interfaces)
992 rx = output.get_capture(len(pkts))
994 def test_ip_vlan_0(self):
997 pkts = (Ether(src=self.pg0.remote_mac,
998 dst=self.pg0.local_mac) /
1000 IP(dst=self.pg1.remote_ip4,
1001 src=self.pg0.remote_ip4) /
1002 UDP(sport=1234, dport=1234) /
1003 Raw('\xa5' * 100)) * 65
1006 # Expect that packets sent on VLAN-0 are forwarded on the
1009 self.send_and_expect(self.pg0, pkts, self.pg1)
1012 class TestIPPunt(VppTestCase):
1013 """ IPv4 Punt Police/Redirect """
1016 super(TestIPPunt, self).setUp()
1018 self.create_pg_interfaces(range(2))
1020 for i in self.pg_interfaces:
1026 super(TestIPPunt, self).tearDown()
1027 for i in self.pg_interfaces:
1031 def send_and_expect(self, input, pkts, output):
1032 self.vapi.cli("clear trace")
1033 input.add_stream(pkts)
1034 self.pg_enable_capture(self.pg_interfaces)
1036 rx = output.get_capture(len(pkts))
1039 def send_and_assert_no_replies(self, intf, pkts, remark):
1040 self.vapi.cli("clear trace")
1041 intf.add_stream(pkts)
1042 self.pg_enable_capture(self.pg_interfaces)
1044 for i in self.pg_interfaces:
1046 i.assert_nothing_captured(remark=remark)
1048 def test_ip_punt(self):
1049 """ IP punt police and redirect """
1051 p = (Ether(src=self.pg0.remote_mac,
1052 dst=self.pg0.local_mac) /
1053 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
1054 TCP(sport=1234, dport=1234) /
1060 # Configure a punt redirect via pg1.
1062 nh_addr = socket.inet_pton(socket.AF_INET,
1063 self.pg1.remote_ip4)
1064 self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
1065 self.pg1.sw_if_index,
1068 self.send_and_expect(self.pg0, pkts, self.pg1)
1073 policer = self.vapi.policer_add_del("ip4-punt", 400, 0, 10, 0,
1075 self.vapi.ip_punt_police(policer.policer_index)
1077 self.vapi.cli("clear trace")
1078 self.pg0.add_stream(pkts)
1079 self.pg_enable_capture(self.pg_interfaces)
1083 # the number of packet recieved should be greater than 0,
1084 # but not equal to the number sent, since some were policed
1086 rx = self.pg1._get_capture(1)
1087 self.assertTrue(len(rx) > 0)
1088 self.assertTrue(len(rx) < len(pkts))
1091 # remove the poilcer. back to full rx
1093 self.vapi.ip_punt_police(policer.policer_index, is_add=0)
1094 self.vapi.policer_add_del("ip4-punt", 400, 0, 10, 0,
1095 rate_type=1, is_add=0)
1096 self.send_and_expect(self.pg0, pkts, self.pg1)
1099 # remove the redirect. expect full drop.
1101 self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
1102 self.pg1.sw_if_index,
1105 self.send_and_assert_no_replies(self.pg0, pkts,
1106 "IP no punt config")
1109 # Add a redirect that is not input port selective
1111 self.vapi.ip_punt_redirect(0xffffffff,
1112 self.pg1.sw_if_index,
1114 self.send_and_expect(self.pg0, pkts, self.pg1)
1116 self.vapi.ip_punt_redirect(0xffffffff,
1117 self.pg1.sw_if_index,
1122 class TestIPDeag(VppTestCase):
1123 """ IPv4 Deaggregate Routes """
1126 super(TestIPDeag, self).setUp()
1128 self.create_pg_interfaces(range(3))
1130 for i in self.pg_interfaces:
1136 super(TestIPDeag, self).tearDown()
1137 for i in self.pg_interfaces:
1141 def send_and_expect(self, input, pkts, output):
1142 self.vapi.cli("clear trace")
1143 input.add_stream(pkts)
1144 self.pg_enable_capture(self.pg_interfaces)
1146 rx = output.get_capture(len(pkts))
1149 def send_and_assert_no_replies(self, intf, pkts, remark):
1150 self.vapi.cli("clear trace")
1151 intf.add_stream(pkts)
1152 self.pg_enable_capture(self.pg_interfaces)
1154 for i in self.pg_interfaces:
1156 i.assert_nothing_captured(remark=remark)
1158 def test_ip_deag(self):
1159 """ IP Deag Routes """
1162 # Create a table to be used for:
1163 # 1 - another destination address lookup
1164 # 2 - a source address lookup
1166 table_dst = VppIpTable(self, 1)
1167 table_src = VppIpTable(self, 2)
1168 table_dst.add_vpp_config()
1169 table_src.add_vpp_config()
1172 # Add a route in the default table to point to a deag/
1173 # second lookup in each of these tables
1175 route_to_dst = VppIpRoute(self, "1.1.1.1", 32,
1176 [VppRoutePath("0.0.0.0",
1179 route_to_src = VppIpRoute(self, "1.1.1.2", 32,
1180 [VppRoutePath("0.0.0.0",
1183 is_source_lookup=1)])
1184 route_to_dst.add_vpp_config()
1185 route_to_src.add_vpp_config()
1188 # packets to these destination are dropped, since they'll
1189 # hit the respective default routes in the second table
1191 p_dst = (Ether(src=self.pg0.remote_mac,
1192 dst=self.pg0.local_mac) /
1193 IP(src="5.5.5.5", dst="1.1.1.1") /
1194 TCP(sport=1234, dport=1234) /
1196 p_src = (Ether(src=self.pg0.remote_mac,
1197 dst=self.pg0.local_mac) /
1198 IP(src="2.2.2.2", dst="1.1.1.2") /
1199 TCP(sport=1234, dport=1234) /
1201 pkts_dst = p_dst * 257
1202 pkts_src = p_src * 257
1204 self.send_and_assert_no_replies(self.pg0, pkts_dst,
1206 self.send_and_assert_no_replies(self.pg0, pkts_src,
1210 # add a route in the dst table to forward via pg1
1212 route_in_dst = VppIpRoute(self, "1.1.1.1", 32,
1213 [VppRoutePath(self.pg1.remote_ip4,
1214 self.pg1.sw_if_index)],
1216 route_in_dst.add_vpp_config()
1217 self.send_and_expect(self.pg0, pkts_dst, self.pg1)
1220 # add a route in the src table to forward via pg2
1222 route_in_src = VppIpRoute(self, "2.2.2.2", 32,
1223 [VppRoutePath(self.pg2.remote_ip4,
1224 self.pg2.sw_if_index)],
1226 route_in_src.add_vpp_config()
1227 self.send_and_expect(self.pg0, pkts_src, self.pg2)
1230 if __name__ == '__main__':
1231 unittest.main(testRunner=VppTestRunner)