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 test_ip_disabled(self):
580 # one accepting interface, pg0, 2 forwarding interfaces
582 route_232_1_1_1 = VppIpMRoute(
586 MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
587 [VppMRoutePath(self.pg1.sw_if_index,
588 MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
589 VppMRoutePath(self.pg0.sw_if_index,
590 MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
591 route_232_1_1_1.add_vpp_config()
593 pu = (Ether(src=self.pg1.remote_mac,
594 dst=self.pg1.local_mac) /
595 IP(src="10.10.10.10", dst=self.pg0.remote_ip4) /
596 UDP(sport=1234, dport=1234) /
598 pm = (Ether(src=self.pg1.remote_mac,
599 dst=self.pg1.local_mac) /
600 IP(src="10.10.10.10", dst="232.1.1.1") /
601 UDP(sport=1234, dport=1234) /
605 # PG1 does not forward IP traffic
607 self.send_and_assert_no_replies(self.pg1, pu, "IP disabled")
608 self.send_and_assert_no_replies(self.pg1, pm, "IP disabled")
613 self.pg1.config_ip4()
616 # Now we get packets through
618 self.pg1.add_stream(pu)
619 self.pg_enable_capture(self.pg_interfaces)
621 rx = self.pg0.get_capture(1)
623 self.pg1.add_stream(pm)
624 self.pg_enable_capture(self.pg_interfaces)
626 rx = self.pg0.get_capture(1)
631 self.pg1.unconfig_ip4()
634 # PG1 does not forward IP traffic
636 self.send_and_assert_no_replies(self.pg1, pu, "IP disabled")
637 self.send_and_assert_no_replies(self.pg1, pm, "IP disabled")
640 class TestIPSubNets(VppTestCase):
644 super(TestIPSubNets, self).setUp()
646 # create a 2 pg interfaces
647 self.create_pg_interfaces(range(2))
649 # pg0 we will use to experiemnt
652 # pg1 is setup normally
654 self.pg1.config_ip4()
655 self.pg1.resolve_arp()
658 super(TestIPSubNets, self).tearDown()
659 for i in self.pg_interfaces:
662 def test_ip_sub_nets(self):
666 # Configure a covering route to forward so we know
667 # when we are dropping
669 cover_route = VppIpRoute(self, "10.0.0.0", 8,
670 [VppRoutePath(self.pg1.remote_ip4,
671 self.pg1.sw_if_index)])
672 cover_route.add_vpp_config()
674 p = (Ether(src=self.pg1.remote_mac,
675 dst=self.pg1.local_mac) /
676 IP(dst="10.10.10.10", src=self.pg0.local_ip4) /
677 UDP(sport=1234, dport=1234) /
680 self.pg1.add_stream(p)
681 self.pg_enable_capture(self.pg_interfaces)
683 rx = self.pg1.get_capture(1)
686 # Configure some non-/24 subnets on an IP interface
688 ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10")
690 self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
694 pn = (Ether(src=self.pg1.remote_mac,
695 dst=self.pg1.local_mac) /
696 IP(dst="10.10.0.0", src=self.pg0.local_ip4) /
697 UDP(sport=1234, dport=1234) /
699 pb = (Ether(src=self.pg1.remote_mac,
700 dst=self.pg1.local_mac) /
701 IP(dst="10.10.255.255", src=self.pg0.local_ip4) /
702 UDP(sport=1234, dport=1234) /
705 self.send_and_assert_no_replies(self.pg1, pn, "IP Network address")
706 self.send_and_assert_no_replies(self.pg1, pb, "IP Broadcast address")
708 # remove the sub-net and we are forwarding via the cover again
709 self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
713 self.pg1.add_stream(pn)
714 self.pg_enable_capture(self.pg_interfaces)
716 rx = self.pg1.get_capture(1)
717 self.pg1.add_stream(pb)
718 self.pg_enable_capture(self.pg_interfaces)
720 rx = self.pg1.get_capture(1)
723 # A /31 is a special case where the 'other-side' is an attached host
724 # packets to that peer generate ARP requests
726 ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10")
728 self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
732 pn = (Ether(src=self.pg1.remote_mac,
733 dst=self.pg1.local_mac) /
734 IP(dst="10.10.10.11", src=self.pg0.local_ip4) /
735 UDP(sport=1234, dport=1234) /
738 self.pg1.add_stream(pn)
739 self.pg_enable_capture(self.pg_interfaces)
741 rx = self.pg0.get_capture(1)
744 # remove the sub-net and we are forwarding via the cover again
745 self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
749 self.pg1.add_stream(pn)
750 self.pg_enable_capture(self.pg_interfaces)
752 rx = self.pg1.get_capture(1)
755 class TestIPLoadBalance(VppTestCase):
756 """ IPv4 Load-Balancing """
759 super(TestIPLoadBalance, self).setUp()
761 self.create_pg_interfaces(range(5))
762 mpls_tbl = VppMplsTable(self, 0)
763 mpls_tbl.add_vpp_config()
765 for i in self.pg_interfaces:
772 for i in self.pg_interfaces:
776 super(TestIPLoadBalance, self).tearDown()
778 def send_and_expect_load_balancing(self, input, pkts, outputs):
779 input.add_stream(pkts)
780 self.pg_enable_capture(self.pg_interfaces)
783 rx = oo._get_capture(1)
784 self.assertNotEqual(0, len(rx))
786 def send_and_expect_one_itf(self, input, pkts, itf):
787 input.add_stream(pkts)
788 self.pg_enable_capture(self.pg_interfaces)
790 rx = itf.get_capture(len(pkts))
792 def test_ip_load_balance(self):
793 """ IP Load-Balancing """
796 # An array of packets that differ only in the destination port
802 # An array of packets that differ only in the source address
808 port_ip_hdr = (IP(dst="10.0.0.1", src="20.0.0.1") /
809 UDP(sport=1234, dport=1234 + ii) /
811 port_ip_pkts.append((Ether(src=self.pg0.remote_mac,
812 dst=self.pg0.local_mac) /
814 port_mpls_pkts.append((Ether(src=self.pg0.remote_mac,
815 dst=self.pg0.local_mac) /
816 MPLS(label=66, ttl=2) /
819 src_ip_hdr = (IP(dst="10.0.0.1", src="20.0.0.%d" % ii) /
820 UDP(sport=1234, dport=1234) /
822 src_ip_pkts.append((Ether(src=self.pg0.remote_mac,
823 dst=self.pg0.local_mac) /
825 src_mpls_pkts.append((Ether(src=self.pg0.remote_mac,
826 dst=self.pg0.local_mac) /
827 MPLS(label=66, ttl=2) /
830 route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
831 [VppRoutePath(self.pg1.remote_ip4,
832 self.pg1.sw_if_index),
833 VppRoutePath(self.pg2.remote_ip4,
834 self.pg2.sw_if_index)])
835 route_10_0_0_1.add_vpp_config()
837 binding = VppMplsIpBind(self, 66, "10.0.0.1", 32)
838 binding.add_vpp_config()
841 # inject the packet on pg0 - expect load-balancing across the 2 paths
842 # - since the default hash config is to use IP src,dst and port
844 # We are not going to ensure equal amounts of packets across each link,
845 # since the hash algorithm is statistical and therefore this can never
846 # be guaranteed. But wuth 64 different packets we do expect some
847 # balancing. So instead just ensure there is traffic on each link.
849 self.send_and_expect_load_balancing(self.pg0, port_ip_pkts,
850 [self.pg1, self.pg2])
851 self.send_and_expect_load_balancing(self.pg0, src_ip_pkts,
852 [self.pg1, self.pg2])
853 self.send_and_expect_load_balancing(self.pg0, port_mpls_pkts,
854 [self.pg1, self.pg2])
855 self.send_and_expect_load_balancing(self.pg0, src_mpls_pkts,
856 [self.pg1, self.pg2])
859 # change the flow hash config so it's only IP src,dst
860 # - now only the stream with differing source address will
863 self.vapi.set_ip_flow_hash(0, src=1, dst=1, sport=0, dport=0)
865 self.send_and_expect_load_balancing(self.pg0, src_ip_pkts,
866 [self.pg1, self.pg2])
867 self.send_and_expect_load_balancing(self.pg0, src_mpls_pkts,
868 [self.pg1, self.pg2])
870 self.send_and_expect_one_itf(self.pg0, port_ip_pkts, self.pg2)
873 # change the flow hash config back to defaults
875 self.vapi.set_ip_flow_hash(0, src=1, dst=1, sport=1, dport=1)
879 # - testing that 2 stages of load-balancing occurs and there is no
880 # polarisation (i.e. only 2 of 4 paths are used)
885 for ii in range(257):
886 port_pkts.append((Ether(src=self.pg0.remote_mac,
887 dst=self.pg0.local_mac) /
888 IP(dst="1.1.1.1", src="20.0.0.1") /
889 UDP(sport=1234, dport=1234 + ii) /
891 src_pkts.append((Ether(src=self.pg0.remote_mac,
892 dst=self.pg0.local_mac) /
893 IP(dst="1.1.1.1", src="20.0.0.%d" % ii) /
894 UDP(sport=1234, dport=1234) /
897 route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
898 [VppRoutePath(self.pg3.remote_ip4,
899 self.pg3.sw_if_index),
900 VppRoutePath(self.pg4.remote_ip4,
901 self.pg4.sw_if_index)])
902 route_10_0_0_2.add_vpp_config()
904 route_1_1_1_1 = VppIpRoute(self, "1.1.1.1", 32,
905 [VppRoutePath("10.0.0.2", 0xffffffff),
906 VppRoutePath("10.0.0.1", 0xffffffff)])
907 route_1_1_1_1.add_vpp_config()
910 # inject the packet on pg0 - expect load-balancing across all 4 paths
912 self.vapi.cli("clear trace")
913 self.send_and_expect_load_balancing(self.pg0, port_pkts,
916 self.send_and_expect_load_balancing(self.pg0, src_pkts,
922 # - testing that 2 stages of load-balancing, no choices
926 for ii in range(257):
927 port_pkts.append((Ether(src=self.pg0.remote_mac,
928 dst=self.pg0.local_mac) /
929 IP(dst="1.1.1.2", src="20.0.0.2") /
930 UDP(sport=1234, dport=1234 + ii) /
933 route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
934 [VppRoutePath(self.pg3.remote_ip4,
935 self.pg3.sw_if_index)])
936 route_10_0_0_3.add_vpp_config()
938 route_1_1_1_2 = VppIpRoute(self, "1.1.1.2", 32,
939 [VppRoutePath("10.0.0.3", 0xffffffff)])
940 route_1_1_1_2.add_vpp_config()
943 # inject the packet on pg0 - expect load-balancing across all 4 paths
945 self.vapi.cli("clear trace")
946 self.send_and_expect_one_itf(self.pg0, port_pkts, self.pg3)
949 class TestIPVlan0(VppTestCase):
953 super(TestIPVlan0, self).setUp()
955 self.create_pg_interfaces(range(2))
956 mpls_tbl = VppMplsTable(self, 0)
957 mpls_tbl.add_vpp_config()
959 for i in self.pg_interfaces:
966 for i in self.pg_interfaces:
970 super(TestIPVlan0, self).tearDown()
972 def test_ip_vlan_0(self):
975 pkts = (Ether(src=self.pg0.remote_mac,
976 dst=self.pg0.local_mac) /
978 IP(dst=self.pg1.remote_ip4,
979 src=self.pg0.remote_ip4) /
980 UDP(sport=1234, dport=1234) /
981 Raw('\xa5' * 100)) * 65
984 # Expect that packets sent on VLAN-0 are forwarded on the
987 self.send_and_expect(self.pg0, pkts, self.pg1)
990 class TestIPPunt(VppTestCase):
991 """ IPv4 Punt Police/Redirect """
994 super(TestIPPunt, self).setUp()
996 self.create_pg_interfaces(range(2))
998 for i in self.pg_interfaces:
1004 super(TestIPPunt, self).tearDown()
1005 for i in self.pg_interfaces:
1009 def test_ip_punt(self):
1010 """ IP punt police and redirect """
1012 p = (Ether(src=self.pg0.remote_mac,
1013 dst=self.pg0.local_mac) /
1014 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
1015 TCP(sport=1234, dport=1234) /
1021 # Configure a punt redirect via pg1.
1023 nh_addr = socket.inet_pton(socket.AF_INET,
1024 self.pg1.remote_ip4)
1025 self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
1026 self.pg1.sw_if_index,
1029 self.send_and_expect(self.pg0, pkts, self.pg1)
1034 policer = self.vapi.policer_add_del("ip4-punt", 400, 0, 10, 0,
1036 self.vapi.ip_punt_police(policer.policer_index)
1038 self.vapi.cli("clear trace")
1039 self.pg0.add_stream(pkts)
1040 self.pg_enable_capture(self.pg_interfaces)
1044 # the number of packet recieved should be greater than 0,
1045 # but not equal to the number sent, since some were policed
1047 rx = self.pg1._get_capture(1)
1048 self.assertTrue(len(rx) > 0)
1049 self.assertTrue(len(rx) < len(pkts))
1052 # remove the poilcer. back to full rx
1054 self.vapi.ip_punt_police(policer.policer_index, is_add=0)
1055 self.vapi.policer_add_del("ip4-punt", 400, 0, 10, 0,
1056 rate_type=1, is_add=0)
1057 self.send_and_expect(self.pg0, pkts, self.pg1)
1060 # remove the redirect. expect full drop.
1062 self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
1063 self.pg1.sw_if_index,
1066 self.send_and_assert_no_replies(self.pg0, pkts,
1067 "IP no punt config")
1070 # Add a redirect that is not input port selective
1072 self.vapi.ip_punt_redirect(0xffffffff,
1073 self.pg1.sw_if_index,
1075 self.send_and_expect(self.pg0, pkts, self.pg1)
1077 self.vapi.ip_punt_redirect(0xffffffff,
1078 self.pg1.sw_if_index,
1083 class TestIPDeag(VppTestCase):
1084 """ IPv4 Deaggregate Routes """
1087 super(TestIPDeag, self).setUp()
1089 self.create_pg_interfaces(range(3))
1091 for i in self.pg_interfaces:
1097 super(TestIPDeag, self).tearDown()
1098 for i in self.pg_interfaces:
1102 def test_ip_deag(self):
1103 """ IP Deag Routes """
1106 # Create a table to be used for:
1107 # 1 - another destination address lookup
1108 # 2 - a source address lookup
1110 table_dst = VppIpTable(self, 1)
1111 table_src = VppIpTable(self, 2)
1112 table_dst.add_vpp_config()
1113 table_src.add_vpp_config()
1116 # Add a route in the default table to point to a deag/
1117 # second lookup in each of these tables
1119 route_to_dst = VppIpRoute(self, "1.1.1.1", 32,
1120 [VppRoutePath("0.0.0.0",
1123 route_to_src = VppIpRoute(self, "1.1.1.2", 32,
1124 [VppRoutePath("0.0.0.0",
1127 is_source_lookup=1)])
1128 route_to_dst.add_vpp_config()
1129 route_to_src.add_vpp_config()
1132 # packets to these destination are dropped, since they'll
1133 # hit the respective default routes in the second table
1135 p_dst = (Ether(src=self.pg0.remote_mac,
1136 dst=self.pg0.local_mac) /
1137 IP(src="5.5.5.5", dst="1.1.1.1") /
1138 TCP(sport=1234, dport=1234) /
1140 p_src = (Ether(src=self.pg0.remote_mac,
1141 dst=self.pg0.local_mac) /
1142 IP(src="2.2.2.2", dst="1.1.1.2") /
1143 TCP(sport=1234, dport=1234) /
1145 pkts_dst = p_dst * 257
1146 pkts_src = p_src * 257
1148 self.send_and_assert_no_replies(self.pg0, pkts_dst,
1150 self.send_and_assert_no_replies(self.pg0, pkts_src,
1154 # add a route in the dst table to forward via pg1
1156 route_in_dst = VppIpRoute(self, "1.1.1.1", 32,
1157 [VppRoutePath(self.pg1.remote_ip4,
1158 self.pg1.sw_if_index)],
1160 route_in_dst.add_vpp_config()
1161 self.send_and_expect(self.pg0, pkts_dst, self.pg1)
1164 # add a route in the src table to forward via pg2
1166 route_in_src = VppIpRoute(self, "2.2.2.2", 32,
1167 [VppRoutePath(self.pg2.remote_ip4,
1168 self.pg2.sw_if_index)],
1170 route_in_src.add_vpp_config()
1171 self.send_and_expect(self.pg0, pkts_src, self.pg2)
1174 class TestIPInput(VppTestCase):
1175 """ IPv4 Input Exceptions """
1178 super(TestIPInput, self).setUp()
1180 self.create_pg_interfaces(range(2))
1182 for i in self.pg_interfaces:
1188 super(TestIPInput, self).tearDown()
1189 for i in self.pg_interfaces:
1193 def test_ip_input(self):
1194 """ IP Input Exceptions """
1196 # i can't find a way in scapy to construct an IP packet
1197 # with a length less than the IP header length
1200 # Packet too short - this is forwarded
1202 p_short = (Ether(src=self.pg0.remote_mac,
1203 dst=self.pg0.local_mac) /
1204 IP(src=self.pg0.remote_ip4,
1205 dst=self.pg1.remote_ip4,
1207 UDP(sport=1234, dport=1234) /
1210 rx = self.send_and_expect(self.pg0, p_short * 65, self.pg1)
1213 # Packet too long - this is dropped
1215 p_long = (Ether(src=self.pg0.remote_mac,
1216 dst=self.pg0.local_mac) /
1217 IP(src=self.pg0.remote_ip4,
1218 dst=self.pg1.remote_ip4,
1220 UDP(sport=1234, dport=1234) /
1223 rx = self.send_and_assert_no_replies(self.pg0, p_long * 65,
1227 # bad chksum - this is dropped
1229 p_chksum = (Ether(src=self.pg0.remote_mac,
1230 dst=self.pg0.local_mac) /
1231 IP(src=self.pg0.remote_ip4,
1232 dst=self.pg1.remote_ip4,
1234 UDP(sport=1234, dport=1234) /
1237 rx = self.send_and_assert_no_replies(self.pg0, p_chksum * 65,
1241 # bad version - this is dropped
1243 p_ver = (Ether(src=self.pg0.remote_mac,
1244 dst=self.pg0.local_mac) /
1245 IP(src=self.pg0.remote_ip4,
1246 dst=self.pg1.remote_ip4,
1248 UDP(sport=1234, dport=1234) /
1251 rx = self.send_and_assert_no_replies(self.pg0, p_ver * 65,
1255 # fragment offset 1 - this is dropped
1257 p_frag = (Ether(src=self.pg0.remote_mac,
1258 dst=self.pg0.local_mac) /
1259 IP(src=self.pg0.remote_ip4,
1260 dst=self.pg1.remote_ip4,
1262 UDP(sport=1234, dport=1234) /
1265 rx = self.send_and_assert_no_replies(self.pg0, p_frag * 65,
1269 # TTL expired packet
1271 p_ttl = (Ether(src=self.pg0.remote_mac,
1272 dst=self.pg0.local_mac) /
1273 IP(src=self.pg0.remote_ip4,
1274 dst=self.pg1.remote_ip4,
1276 UDP(sport=1234, dport=1234) /
1279 rx = self.send_and_expect(self.pg0, p_ttl * 65, self.pg0)
1284 self.assertEqual(icmptypes[icmp.type], "time-exceeded")
1285 self.assertEqual(icmpcodes[icmp.type][icmp.code],
1286 "ttl-zero-during-transit")
1287 self.assertEqual(icmp.src, self.pg0.remote_ip4)
1288 self.assertEqual(icmp.dst, self.pg1.remote_ip4)
1293 p_mtu = (Ether(src=self.pg0.remote_mac,
1294 dst=self.pg0.local_mac) /
1295 IP(src=self.pg0.remote_ip4,
1296 dst=self.pg1.remote_ip4,
1297 ttl=10, flags='DF') /
1298 UDP(sport=1234, dport=1234) /
1301 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, 1500)
1303 rx = self.send_and_expect(self.pg0, p_mtu * 65, self.pg0)
1307 self.assertEqual(icmptypes[icmp.type], "dest-unreach")
1308 self.assertEqual(icmpcodes[icmp.type][icmp.code],
1309 "fragmentation-needed")
1310 self.assertEqual(icmp.src, self.pg0.remote_ip4)
1311 self.assertEqual(icmp.dst, self.pg1.remote_ip4)
1313 self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, 2500)
1314 rx = self.send_and_expect(self.pg0, p_mtu * 65, self.pg1)
1317 if __name__ == '__main__':
1318 unittest.main(testRunner=VppTestRunner)