misc: Fix python scripts shebang line
[vpp.git] / test / test_ip4.py
1 #!/usr/bin/env python3
2 import binascii
3 import random
4 import socket
5 import unittest
6
7 import scapy.compat
8 from scapy.contrib.mpls import MPLS
9 from scapy.layers.inet import IP, UDP, TCP, ICMP, icmptypes, icmpcodes
10 from scapy.layers.l2 import Ether, Dot1Q, ARP
11 from scapy.packet import Raw
12 from six import moves
13
14 from framework import VppTestCase, VppTestRunner
15 from util import ppp
16 from vpp_ip import VppIpPrefix
17 from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpMRoute, \
18     VppMRoutePath, MRouteItfFlags, MRouteEntryFlags, VppMplsIpBind, \
19     VppMplsTable, VppIpTable, FibPathType, find_route, \
20     VppIpInterfaceAddress
21 from vpp_ip import VppIpAddress
22 from vpp_sub_interface import VppSubInterface, VppDot1QSubint, VppDot1ADSubint
23 from vpp_papi import VppEnum
24 from vpp_neighbor import VppNeighbor
25
26 NUM_PKTS = 67
27
28
29 class TestIPv4(VppTestCase):
30     """ IPv4 Test Case """
31
32     @classmethod
33     def setUpClass(cls):
34         super(TestIPv4, cls).setUpClass()
35
36     @classmethod
37     def tearDownClass(cls):
38         super(TestIPv4, cls).tearDownClass()
39
40     def setUp(self):
41         """
42         Perform test setup before test case.
43
44         **Config:**
45             - create 3 pg interfaces
46                 - untagged pg0 interface
47                 - Dot1Q subinterface on pg1
48                 - Dot1AD subinterface on pg2
49             - setup interfaces:
50                 - put it into UP state
51                 - set IPv4 addresses
52                 - resolve neighbor address using ARP
53             - configure 200 fib entries
54
55         :ivar list interfaces: pg interfaces and subinterfaces.
56         :ivar dict flows: IPv4 packet flows in test.
57         """
58         super(TestIPv4, self).setUp()
59
60         # create 3 pg interfaces
61         self.create_pg_interfaces(range(3))
62
63         # create 2 subinterfaces for pg1 and pg2
64         self.sub_interfaces = [
65             VppDot1QSubint(self, self.pg1, 100),
66             VppDot1ADSubint(self, self.pg2, 200, 300, 400)]
67
68         # packet flows mapping pg0 -> pg1.sub, pg2.sub, etc.
69         self.flows = dict()
70         self.flows[self.pg0] = [self.pg1.sub_if, self.pg2.sub_if]
71         self.flows[self.pg1.sub_if] = [self.pg0, self.pg2.sub_if]
72         self.flows[self.pg2.sub_if] = [self.pg0, self.pg1.sub_if]
73
74         # packet sizes
75         self.pg_if_packet_sizes = [64, 1500, 9020]
76
77         self.interfaces = list(self.pg_interfaces)
78         self.interfaces.extend(self.sub_interfaces)
79
80         # setup all interfaces
81         for i in self.interfaces:
82             i.admin_up()
83             i.config_ip4()
84             i.resolve_arp()
85
86         # config 2M FIB entries
87
88     def tearDown(self):
89         """Run standard test teardown and log ``show ip arp``."""
90         super(TestIPv4, self).tearDown()
91
92     def show_commands_at_teardown(self):
93         self.logger.info(self.vapi.cli("show ip arp"))
94         # info(self.vapi.cli("show ip fib"))  # many entries
95
96     def modify_packet(self, src_if, packet_size, pkt):
97         """Add load, set destination IP and extend packet to required packet
98         size for defined interface.
99
100         :param VppInterface src_if: Interface to create packet for.
101         :param int packet_size: Required packet size.
102         :param Scapy pkt: Packet to be modified.
103         """
104         dst_if_idx = int(packet_size / 10 % 2)
105         dst_if = self.flows[src_if][dst_if_idx]
106         info = self.create_packet_info(src_if, dst_if)
107         payload = self.info_to_payload(info)
108         p = pkt/Raw(payload)
109         p[IP].dst = dst_if.remote_ip4
110         info.data = p.copy()
111         if isinstance(src_if, VppSubInterface):
112             p = src_if.add_dot1_layer(p)
113         self.extend_packet(p, packet_size)
114
115         return p
116
117     def create_stream(self, src_if):
118         """Create input packet stream for defined interface.
119
120         :param VppInterface src_if: Interface to create packet stream for.
121         """
122         hdr_ext = 4 if isinstance(src_if, VppSubInterface) else 0
123         pkt_tmpl = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
124                     IP(src=src_if.remote_ip4) /
125                     UDP(sport=1234, dport=1234))
126
127         pkts = [self.modify_packet(src_if, i, pkt_tmpl)
128                 for i in moves.range(self.pg_if_packet_sizes[0],
129                                      self.pg_if_packet_sizes[1], 10)]
130         pkts_b = [self.modify_packet(src_if, i, pkt_tmpl)
131                   for i in moves.range(self.pg_if_packet_sizes[1] + hdr_ext,
132                                        self.pg_if_packet_sizes[2] + hdr_ext,
133                                        50)]
134         pkts.extend(pkts_b)
135
136         return pkts
137
138     def verify_capture(self, dst_if, capture):
139         """Verify captured input packet stream for defined interface.
140
141         :param VppInterface dst_if: Interface to verify captured packet stream
142             for.
143         :param list capture: Captured packet stream.
144         """
145         self.logger.info("Verifying capture on interface %s" % dst_if.name)
146         last_info = dict()
147         for i in self.interfaces:
148             last_info[i.sw_if_index] = None
149         is_sub_if = False
150         dst_sw_if_index = dst_if.sw_if_index
151         if hasattr(dst_if, 'parent'):
152             is_sub_if = True
153         for packet in capture:
154             if is_sub_if:
155                 # Check VLAN tags and Ethernet header
156                 packet = dst_if.remove_dot1_layer(packet)
157             self.assertTrue(Dot1Q not in packet)
158             try:
159                 ip = packet[IP]
160                 udp = packet[UDP]
161                 payload_info = self.payload_to_info(packet[Raw])
162                 packet_index = payload_info.index
163                 self.assertEqual(payload_info.dst, dst_sw_if_index)
164                 self.logger.debug(
165                     "Got packet on port %s: src=%u (id=%u)" %
166                     (dst_if.name, payload_info.src, packet_index))
167                 next_info = self.get_next_packet_info_for_interface2(
168                     payload_info.src, dst_sw_if_index,
169                     last_info[payload_info.src])
170                 last_info[payload_info.src] = next_info
171                 self.assertTrue(next_info is not None)
172                 self.assertEqual(packet_index, next_info.index)
173                 saved_packet = next_info.data
174                 # Check standard fields
175                 self.assertEqual(ip.src, saved_packet[IP].src)
176                 self.assertEqual(ip.dst, saved_packet[IP].dst)
177                 self.assertEqual(udp.sport, saved_packet[UDP].sport)
178                 self.assertEqual(udp.dport, saved_packet[UDP].dport)
179             except:
180                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
181                 raise
182         for i in self.interfaces:
183             remaining_packet = self.get_next_packet_info_for_interface2(
184                 i.sw_if_index, dst_sw_if_index, last_info[i.sw_if_index])
185             self.assertTrue(remaining_packet is None,
186                             "Interface %s: Packet expected from interface %s "
187                             "didn't arrive" % (dst_if.name, i.name))
188
189     def test_fib(self):
190         """ IPv4 FIB test
191
192         Test scenario:
193
194             - Create IPv4 stream for pg0 interface
195             - Create IPv4 tagged streams for pg1's and pg2's sub-interface.
196             - Send and verify received packets on each interface.
197         """
198
199         pkts = self.create_stream(self.pg0)
200         self.pg0.add_stream(pkts)
201
202         for i in self.sub_interfaces:
203             pkts = self.create_stream(i)
204             i.parent.add_stream(pkts)
205
206         self.pg_enable_capture(self.pg_interfaces)
207         self.pg_start()
208
209         pkts = self.pg0.get_capture()
210         self.verify_capture(self.pg0, pkts)
211
212         for i in self.sub_interfaces:
213             pkts = i.parent.get_capture()
214             self.verify_capture(i, pkts)
215
216
217 class TestIPv4IfAddrRoute(VppTestCase):
218     """ IPv4 Interface Addr Route Test Case """
219
220     @classmethod
221     def setUpClass(cls):
222         super(TestIPv4IfAddrRoute, cls).setUpClass()
223
224     @classmethod
225     def tearDownClass(cls):
226         super(TestIPv4IfAddrRoute, cls).tearDownClass()
227
228     def setUp(self):
229         super(TestIPv4IfAddrRoute, self).setUp()
230
231         # create 1 pg interface
232         self.create_pg_interfaces(range(1))
233
234         for i in self.pg_interfaces:
235             i.admin_up()
236             i.config_ip4()
237             i.resolve_arp()
238
239     def tearDown(self):
240         super(TestIPv4IfAddrRoute, self).tearDown()
241         for i in self.pg_interfaces:
242             i.unconfig_ip4()
243             i.admin_down()
244
245     def test_ipv4_ifaddrs_same_prefix(self):
246         """ IPv4 Interface Addresses Same Prefix test
247
248         Test scenario:
249
250             - Verify no route in FIB for prefix 10.10.10.0/24
251             - Configure IPv4 address 10.10.10.10/24 on an interface
252             - Verify route in FIB for prefix 10.10.10.0/24
253             - Configure IPv4 address 10.10.10.20/24 on an interface
254             - Delete 10.10.10.10/24 from interface
255             - Verify route in FIB for prefix 10.10.10.0/24
256             - Delete 10.10.10.20/24 from interface
257             - Verify no route in FIB for prefix 10.10.10.0/24
258         """
259
260         # create two addresses, verify route not present
261         if_addr1 = VppIpInterfaceAddress(self, self.pg0,
262                                          VppIpAddress("10.10.10.10"), 24)
263         if_addr2 = VppIpInterfaceAddress(self, self.pg0,
264                                          VppIpAddress("10.10.10.20"), 24)
265         self.assertFalse(if_addr1.query_vpp_config())  # 10.10.10.0/24
266         self.assertFalse(find_route(self, "10.10.10.10", 32))
267         self.assertFalse(find_route(self, "10.10.10.20", 32))
268         self.assertFalse(find_route(self, "10.10.10.255", 32))
269         self.assertFalse(find_route(self, "10.10.10.0", 32))
270
271         # configure first address, verify route present
272         if_addr1.add_vpp_config()
273         self.assertTrue(if_addr1.query_vpp_config())  # 10.10.10.0/24
274         self.assertTrue(find_route(self, "10.10.10.10", 32))
275         self.assertFalse(find_route(self, "10.10.10.20", 32))
276         self.assertTrue(find_route(self, "10.10.10.255", 32))
277         self.assertTrue(find_route(self, "10.10.10.0", 32))
278
279         # configure second address, delete first, verify route not removed
280         if_addr2.add_vpp_config()
281         if_addr1.remove_vpp_config()
282         self.assertTrue(if_addr1.query_vpp_config())  # 10.10.10.0/24
283         self.assertFalse(find_route(self, "10.10.10.10", 32))
284         self.assertTrue(find_route(self, "10.10.10.20", 32))
285         self.assertTrue(find_route(self, "10.10.10.255", 32))
286         self.assertTrue(find_route(self, "10.10.10.0", 32))
287
288         # delete second address, verify route removed
289         if_addr2.remove_vpp_config()
290         self.assertFalse(if_addr1.query_vpp_config())  # 10.10.10.0/24
291         self.assertFalse(find_route(self, "10.10.10.10", 32))
292         self.assertFalse(find_route(self, "10.10.10.20", 32))
293         self.assertFalse(find_route(self, "10.10.10.255", 32))
294         self.assertFalse(find_route(self, "10.10.10.0", 32))
295
296     def test_ipv4_ifaddr_route(self):
297         """ IPv4 Interface Address Route test
298
299         Test scenario:
300
301             - Create loopback
302             - Configure IPv4 address on loopback
303             - Verify that address is not in the FIB
304             - Bring loopback up
305             - Verify that address is in the FIB now
306             - Bring loopback down
307             - Verify that address is not in the FIB anymore
308             - Bring loopback up
309             - Configure IPv4 address on loopback
310             - Verify that address is in the FIB now
311         """
312
313         # create a loopback and configure IPv4
314         loopbacks = self.create_loopback_interfaces(1)
315         lo_if = self.lo_interfaces[0]
316
317         lo_if.local_ip4_prefix_len = 32
318         lo_if.config_ip4()
319
320         # The intf was down when addr was added -> entry not in FIB
321         fib4_dump = self.vapi.ip_route_dump(0)
322         self.assertFalse(lo_if.is_ip4_entry_in_fib_dump(fib4_dump))
323
324         # When intf is brought up, entry is added
325         lo_if.admin_up()
326         fib4_dump = self.vapi.ip_route_dump(0)
327         self.assertTrue(lo_if.is_ip4_entry_in_fib_dump(fib4_dump))
328
329         # When intf is brought down, entry is removed
330         lo_if.admin_down()
331         fib4_dump = self.vapi.ip_route_dump(0)
332         self.assertFalse(lo_if.is_ip4_entry_in_fib_dump(fib4_dump))
333
334         # Remove addr, bring up interface, re-add -> entry in FIB
335         lo_if.unconfig_ip4()
336         lo_if.admin_up()
337         lo_if.config_ip4()
338         fib4_dump = self.vapi.ip_route_dump(0)
339         self.assertTrue(lo_if.is_ip4_entry_in_fib_dump(fib4_dump))
340
341
342 class TestICMPEcho(VppTestCase):
343     """ ICMP Echo Test Case """
344
345     @classmethod
346     def setUpClass(cls):
347         super(TestICMPEcho, cls).setUpClass()
348
349     @classmethod
350     def tearDownClass(cls):
351         super(TestICMPEcho, cls).tearDownClass()
352
353     def setUp(self):
354         super(TestICMPEcho, self).setUp()
355
356         # create 1 pg interface
357         self.create_pg_interfaces(range(1))
358
359         for i in self.pg_interfaces:
360             i.admin_up()
361             i.config_ip4()
362             i.resolve_arp()
363
364     def tearDown(self):
365         super(TestICMPEcho, self).tearDown()
366         for i in self.pg_interfaces:
367             i.unconfig_ip4()
368             i.admin_down()
369
370     def test_icmp_echo(self):
371         """ VPP replies to ICMP Echo Request
372
373         Test scenario:
374
375             - Receive ICMP Echo Request message on pg0 interface.
376             - Check outgoing ICMP Echo Reply message on pg0 interface.
377         """
378
379         icmp_id = 0xb
380         icmp_seq = 5
381         icmp_load = b'\x0a' * 18
382         p_echo_request = (Ether(src=self.pg0.remote_mac,
383                                 dst=self.pg0.local_mac) /
384                           IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
385                           ICMP(id=icmp_id, seq=icmp_seq) /
386                           Raw(load=icmp_load))
387
388         self.pg0.add_stream(p_echo_request)
389         self.pg_enable_capture(self.pg_interfaces)
390         self.pg_start()
391
392         rx = self.pg0.get_capture(1)
393         rx = rx[0]
394         ether = rx[Ether]
395         ipv4 = rx[IP]
396         icmp = rx[ICMP]
397
398         self.assertEqual(ether.src, self.pg0.local_mac)
399         self.assertEqual(ether.dst, self.pg0.remote_mac)
400
401         self.assertEqual(ipv4.src, self.pg0.local_ip4)
402         self.assertEqual(ipv4.dst, self.pg0.remote_ip4)
403
404         self.assertEqual(icmptypes[icmp.type], "echo-reply")
405         self.assertEqual(icmp.id, icmp_id)
406         self.assertEqual(icmp.seq, icmp_seq)
407         self.assertEqual(icmp[Raw].load, icmp_load)
408
409
410 class TestIPv4FibCrud(VppTestCase):
411     """ FIB - add/update/delete - ip4 routes
412
413     Test scenario:
414         - add 1k,
415         - del 100,
416         - add new 1k,
417         - del 1.5k
418
419     ..note:: Python API is too slow to add many routes, needs replacement.
420     """
421
422     def config_fib_many_to_one(self, start_dest_addr, next_hop_addr,
423                                count, start=0):
424         """
425
426         :param start_dest_addr:
427         :param next_hop_addr:
428         :param count:
429         :return list: added ips with 32 prefix
430         """
431         routes = []
432         for i in range(count):
433             r = VppIpRoute(self, start_dest_addr % (i + start), 32,
434                            [VppRoutePath(next_hop_addr, 0xffffffff)])
435             r.add_vpp_config()
436             routes.append(r)
437         return routes
438
439     def unconfig_fib_many_to_one(self, start_dest_addr, next_hop_addr,
440                                  count, start=0):
441
442         routes = []
443         for i in range(count):
444             r = VppIpRoute(self, start_dest_addr % (i + start), 32,
445                            [VppRoutePath(next_hop_addr, 0xffffffff)])
446             r.remove_vpp_config()
447             routes.append(r)
448         return routes
449
450     def create_stream(self, src_if, dst_if, routes, count):
451         pkts = []
452
453         for _ in range(count):
454             dst_addr = random.choice(routes).prefix.address
455             info = self.create_packet_info(src_if, dst_if)
456             payload = self.info_to_payload(info)
457             p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
458                  IP(src=src_if.remote_ip4, dst=dst_addr) /
459                  UDP(sport=1234, dport=1234) /
460                  Raw(payload))
461             info.data = p.copy()
462             self.extend_packet(p, random.choice(self.pg_if_packet_sizes))
463             pkts.append(p)
464
465         return pkts
466
467     def _find_ip_match(self, find_in, pkt):
468         for p in find_in:
469             if self.payload_to_info(p[Raw]) == \
470                     self.payload_to_info(pkt[Raw]):
471                 if p[IP].src != pkt[IP].src:
472                     break
473                 if p[IP].dst != pkt[IP].dst:
474                     break
475                 if p[UDP].sport != pkt[UDP].sport:
476                     break
477                 if p[UDP].dport != pkt[UDP].dport:
478                     break
479                 return p
480         return None
481
482     def verify_capture(self, dst_interface, received_pkts, expected_pkts):
483         self.assertEqual(len(received_pkts), len(expected_pkts))
484         to_verify = list(expected_pkts)
485         for p in received_pkts:
486             self.assertEqual(p.src, dst_interface.local_mac)
487             self.assertEqual(p.dst, dst_interface.remote_mac)
488             x = self._find_ip_match(to_verify, p)
489             to_verify.remove(x)
490         self.assertListEqual(to_verify, [])
491
492     def verify_route_dump(self, routes):
493         for r in routes:
494             self.assertTrue(find_route(self, r.prefix.address, r.prefix.len))
495
496     def verify_not_in_route_dump(self, routes):
497         for r in routes:
498             self.assertFalse(find_route(self, r.prefix.address, r.prefix.len))
499
500     @classmethod
501     def setUpClass(cls):
502         """
503         #. Create and initialize 3 pg interfaces.
504         #. initialize class attributes configured_routes and deleted_routes
505            to store information between tests.
506         """
507         super(TestIPv4FibCrud, cls).setUpClass()
508
509         try:
510             # create 3 pg interfaces
511             cls.create_pg_interfaces(range(3))
512
513             cls.interfaces = list(cls.pg_interfaces)
514
515             # setup all interfaces
516             for i in cls.interfaces:
517                 i.admin_up()
518                 i.config_ip4()
519                 i.resolve_arp()
520
521             cls.configured_routes = []
522             cls.deleted_routes = []
523             cls.pg_if_packet_sizes = [64, 512, 1518, 9018]
524
525         except Exception:
526             super(TestIPv4FibCrud, cls).tearDownClass()
527             raise
528
529     @classmethod
530     def tearDownClass(cls):
531         super(TestIPv4FibCrud, cls).tearDownClass()
532
533     def setUp(self):
534         super(TestIPv4FibCrud, self).setUp()
535         self.reset_packet_infos()
536
537         self.configured_routes = []
538         self.deleted_routes = []
539
540     def test_1_add_routes(self):
541         """ Add 1k routes """
542
543         # add 100 routes check with traffic script.
544         self.configured_routes.extend(self.config_fib_many_to_one(
545             "10.0.0.%d", self.pg0.remote_ip4, 100))
546
547         self.verify_route_dump(self.configured_routes)
548
549         self.stream_1 = self.create_stream(
550             self.pg1, self.pg0, self.configured_routes, 100)
551         self.stream_2 = self.create_stream(
552             self.pg2, self.pg0, self.configured_routes, 100)
553         self.pg1.add_stream(self.stream_1)
554         self.pg2.add_stream(self.stream_2)
555
556         self.pg_enable_capture(self.pg_interfaces)
557         self.pg_start()
558
559         pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
560         self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
561
562     def test_2_del_routes(self):
563         """ Delete 100 routes
564
565         - delete 10 routes check with traffic script.
566         """
567         # config 1M FIB entries
568         self.configured_routes.extend(self.config_fib_many_to_one(
569             "10.0.0.%d", self.pg0.remote_ip4, 100))
570         self.deleted_routes.extend(self.unconfig_fib_many_to_one(
571             "10.0.0.%d", self.pg0.remote_ip4, 10, start=10))
572         for x in self.deleted_routes:
573             self.configured_routes.remove(x)
574
575         self.verify_route_dump(self.configured_routes)
576
577         self.stream_1 = self.create_stream(
578             self.pg1, self.pg0, self.configured_routes, 100)
579         self.stream_2 = self.create_stream(
580             self.pg2, self.pg0, self.configured_routes, 100)
581         self.stream_3 = self.create_stream(
582             self.pg1, self.pg0, self.deleted_routes, 100)
583         self.stream_4 = self.create_stream(
584             self.pg2, self.pg0, self.deleted_routes, 100)
585         self.pg1.add_stream(self.stream_1 + self.stream_3)
586         self.pg2.add_stream(self.stream_2 + self.stream_4)
587         self.pg_enable_capture(self.pg_interfaces)
588         self.pg_start()
589
590         pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
591         self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
592
593     def test_3_add_new_routes(self):
594         """ Add 1k routes
595
596         - re-add 5 routes check with traffic script.
597         - add 100 routes check with traffic script.
598         """
599         # config 1M FIB entries
600         self.configured_routes.extend(self.config_fib_many_to_one(
601             "10.0.0.%d", self.pg0.remote_ip4, 100))
602         self.deleted_routes.extend(self.unconfig_fib_many_to_one(
603             "10.0.0.%d", self.pg0.remote_ip4, 10, start=10))
604         for x in self.deleted_routes:
605             self.configured_routes.remove(x)
606
607         tmp = self.config_fib_many_to_one(
608             "10.0.0.%d", self.pg0.remote_ip4, 5, start=10)
609         self.configured_routes.extend(tmp)
610         for x in tmp:
611             self.deleted_routes.remove(x)
612
613         self.configured_routes.extend(self.config_fib_many_to_one(
614             "10.0.1.%d", self.pg0.remote_ip4, 100))
615
616         self.verify_route_dump(self.configured_routes)
617
618         self.stream_1 = self.create_stream(
619             self.pg1, self.pg0, self.configured_routes, 300)
620         self.stream_2 = self.create_stream(
621             self.pg2, self.pg0, self.configured_routes, 300)
622         self.stream_3 = self.create_stream(
623             self.pg1, self.pg0, self.deleted_routes, 100)
624         self.stream_4 = self.create_stream(
625             self.pg2, self.pg0, self.deleted_routes, 100)
626
627         self.pg1.add_stream(self.stream_1 + self.stream_3)
628         self.pg2.add_stream(self.stream_2 + self.stream_4)
629         self.pg_enable_capture(self.pg_interfaces)
630         self.pg_start()
631
632         pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
633         self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
634
635         # delete 5 routes check with traffic script.
636         # add 100 routes check with traffic script.
637         self.deleted_routes.extend(self.unconfig_fib_many_to_one(
638             "10.0.0.%d", self.pg0.remote_ip4, 15))
639         self.deleted_routes.extend(self.unconfig_fib_many_to_one(
640             "10.0.0.%d", self.pg0.remote_ip4, 85))
641         self.deleted_routes.extend(self.unconfig_fib_many_to_one(
642             "10.0.1.%d", self.pg0.remote_ip4, 100))
643         self.verify_not_in_route_dump(self.deleted_routes)
644
645
646 class TestIPNull(VppTestCase):
647     """ IPv4 routes via NULL """
648
649     @classmethod
650     def setUpClass(cls):
651         super(TestIPNull, cls).setUpClass()
652
653     @classmethod
654     def tearDownClass(cls):
655         super(TestIPNull, cls).tearDownClass()
656
657     def setUp(self):
658         super(TestIPNull, self).setUp()
659
660         # create 2 pg interfaces
661         self.create_pg_interfaces(range(2))
662
663         for i in self.pg_interfaces:
664             i.admin_up()
665             i.config_ip4()
666             i.resolve_arp()
667
668     def tearDown(self):
669         super(TestIPNull, self).tearDown()
670         for i in self.pg_interfaces:
671             i.unconfig_ip4()
672             i.admin_down()
673
674     def test_ip_null(self):
675         """ IP NULL route """
676
677         #
678         # A route via IP NULL that will reply with ICMP unreachables
679         #
680         ip_unreach = VppIpRoute(
681             self, "10.0.0.1", 32,
682             [VppRoutePath("0.0.0.0",
683                           0xffffffff,
684                           type=FibPathType.FIB_PATH_TYPE_ICMP_UNREACH)])
685         ip_unreach.add_vpp_config()
686
687         p_unreach = (Ether(src=self.pg0.remote_mac,
688                            dst=self.pg0.local_mac) /
689                      IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
690                      UDP(sport=1234, dport=1234) /
691                      Raw(b'\xa5' * 100))
692         self.pg0.add_stream(p_unreach)
693         self.pg_enable_capture(self.pg_interfaces)
694         self.pg_start()
695
696         rx = self.pg0.get_capture(1)
697         rx = rx[0]
698         icmp = rx[ICMP]
699
700         self.assertEqual(icmptypes[icmp.type], "dest-unreach")
701         self.assertEqual(icmpcodes[icmp.type][icmp.code], "host-unreachable")
702         self.assertEqual(icmp.src, self.pg0.remote_ip4)
703         self.assertEqual(icmp.dst, "10.0.0.1")
704
705         #
706         # ICMP replies are rate limited. so sit and spin.
707         #
708         self.sleep(1)
709
710         #
711         # A route via IP NULL that will reply with ICMP prohibited
712         #
713         ip_prohibit = VppIpRoute(
714             self, "10.0.0.2", 32,
715             [VppRoutePath("0.0.0.0",
716                           0xffffffff,
717                           type=FibPathType.FIB_PATH_TYPE_ICMP_PROHIBIT)])
718         ip_prohibit.add_vpp_config()
719
720         p_prohibit = (Ether(src=self.pg0.remote_mac,
721                             dst=self.pg0.local_mac) /
722                       IP(src=self.pg0.remote_ip4, dst="10.0.0.2") /
723                       UDP(sport=1234, dport=1234) /
724                       Raw(b'\xa5' * 100))
725
726         self.pg0.add_stream(p_prohibit)
727         self.pg_enable_capture(self.pg_interfaces)
728         self.pg_start()
729
730         rx = self.pg0.get_capture(1)
731
732         rx = rx[0]
733         icmp = rx[ICMP]
734
735         self.assertEqual(icmptypes[icmp.type], "dest-unreach")
736         self.assertEqual(icmpcodes[icmp.type][icmp.code], "host-prohibited")
737         self.assertEqual(icmp.src, self.pg0.remote_ip4)
738         self.assertEqual(icmp.dst, "10.0.0.2")
739
740     def test_ip_drop(self):
741         """ IP Drop Routes """
742
743         p = (Ether(src=self.pg0.remote_mac,
744                    dst=self.pg0.local_mac) /
745              IP(src=self.pg0.remote_ip4, dst="1.1.1.1") /
746              UDP(sport=1234, dport=1234) /
747              Raw(b'\xa5' * 100))
748
749         r1 = VppIpRoute(self, "1.1.1.0", 24,
750                         [VppRoutePath(self.pg1.remote_ip4,
751                                       self.pg1.sw_if_index)])
752         r1.add_vpp_config()
753
754         rx = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg1)
755
756         #
757         # insert a more specific as a drop
758         #
759         r2 = VppIpRoute(self, "1.1.1.1", 32,
760                         [VppRoutePath("0.0.0.0",
761                                       0xffffffff,
762                                       type=FibPathType.FIB_PATH_TYPE_DROP)])
763         r2.add_vpp_config()
764
765         self.send_and_assert_no_replies(self.pg0, p * NUM_PKTS, "Drop Route")
766         r2.remove_vpp_config()
767         rx = self.send_and_expect(self.pg0, p * NUM_PKTS, self.pg1)
768
769
770 class TestIPDisabled(VppTestCase):
771     """ IPv4 disabled """
772
773     @classmethod
774     def setUpClass(cls):
775         super(TestIPDisabled, cls).setUpClass()
776
777     @classmethod
778     def tearDownClass(cls):
779         super(TestIPDisabled, cls).tearDownClass()
780
781     def setUp(self):
782         super(TestIPDisabled, self).setUp()
783
784         # create 2 pg interfaces
785         self.create_pg_interfaces(range(2))
786
787         # PG0 is IP enalbed
788         self.pg0.admin_up()
789         self.pg0.config_ip4()
790         self.pg0.resolve_arp()
791
792         # PG 1 is not IP enabled
793         self.pg1.admin_up()
794
795     def tearDown(self):
796         super(TestIPDisabled, self).tearDown()
797         for i in self.pg_interfaces:
798             i.unconfig_ip4()
799             i.admin_down()
800
801     def test_ip_disabled(self):
802         """ IP Disabled """
803
804         #
805         # An (S,G).
806         # one accepting interface, pg0, 2 forwarding interfaces
807         #
808         route_232_1_1_1 = VppIpMRoute(
809             self,
810             "0.0.0.0",
811             "232.1.1.1", 32,
812             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
813             [VppMRoutePath(self.pg1.sw_if_index,
814                            MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
815              VppMRoutePath(self.pg0.sw_if_index,
816                            MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
817         route_232_1_1_1.add_vpp_config()
818
819         pu = (Ether(src=self.pg1.remote_mac,
820                     dst=self.pg1.local_mac) /
821               IP(src="10.10.10.10", dst=self.pg0.remote_ip4) /
822               UDP(sport=1234, dport=1234) /
823               Raw(b'\xa5' * 100))
824         pm = (Ether(src=self.pg1.remote_mac,
825                     dst=self.pg1.local_mac) /
826               IP(src="10.10.10.10", dst="232.1.1.1") /
827               UDP(sport=1234, dport=1234) /
828               Raw(b'\xa5' * 100))
829
830         #
831         # PG1 does not forward IP traffic
832         #
833         self.send_and_assert_no_replies(self.pg1, pu, "IP disabled")
834         self.send_and_assert_no_replies(self.pg1, pm, "IP disabled")
835
836         #
837         # IP enable PG1
838         #
839         self.pg1.config_ip4()
840
841         #
842         # Now we get packets through
843         #
844         self.pg1.add_stream(pu)
845         self.pg_enable_capture(self.pg_interfaces)
846         self.pg_start()
847         rx = self.pg0.get_capture(1)
848
849         self.pg1.add_stream(pm)
850         self.pg_enable_capture(self.pg_interfaces)
851         self.pg_start()
852         rx = self.pg0.get_capture(1)
853
854         #
855         # Disable PG1
856         #
857         self.pg1.unconfig_ip4()
858
859         #
860         # PG1 does not forward IP traffic
861         #
862         self.send_and_assert_no_replies(self.pg1, pu, "IP disabled")
863         self.send_and_assert_no_replies(self.pg1, pm, "IP disabled")
864
865
866 class TestIPSubNets(VppTestCase):
867     """ IPv4 Subnets """
868
869     @classmethod
870     def setUpClass(cls):
871         super(TestIPSubNets, cls).setUpClass()
872
873     @classmethod
874     def tearDownClass(cls):
875         super(TestIPSubNets, cls).tearDownClass()
876
877     def setUp(self):
878         super(TestIPSubNets, self).setUp()
879
880         # create a 2 pg interfaces
881         self.create_pg_interfaces(range(2))
882
883         # pg0 we will use to experiment
884         self.pg0.admin_up()
885
886         # pg1 is setup normally
887         self.pg1.admin_up()
888         self.pg1.config_ip4()
889         self.pg1.resolve_arp()
890
891     def tearDown(self):
892         super(TestIPSubNets, self).tearDown()
893         for i in self.pg_interfaces:
894             i.admin_down()
895
896     def test_ip_sub_nets(self):
897         """ IP Sub Nets """
898
899         #
900         # Configure a covering route to forward so we know
901         # when we are dropping
902         #
903         cover_route = VppIpRoute(self, "10.0.0.0", 8,
904                                  [VppRoutePath(self.pg1.remote_ip4,
905                                                self.pg1.sw_if_index)])
906         cover_route.add_vpp_config()
907
908         p = (Ether(src=self.pg1.remote_mac,
909                    dst=self.pg1.local_mac) /
910              IP(dst="10.10.10.10", src=self.pg0.local_ip4) /
911              UDP(sport=1234, dport=1234) /
912              Raw(b'\xa5' * 100))
913
914         self.pg1.add_stream(p)
915         self.pg_enable_capture(self.pg_interfaces)
916         self.pg_start()
917         rx = self.pg1.get_capture(1)
918
919         #
920         # Configure some non-/24 subnets on an IP interface
921         #
922         ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10")
923
924         self.vapi.sw_interface_add_del_address(
925             sw_if_index=self.pg0.sw_if_index,
926             prefix=VppIpPrefix("10.10.10.10", 16).encode())
927
928         pn = (Ether(src=self.pg1.remote_mac,
929                     dst=self.pg1.local_mac) /
930               IP(dst="10.10.0.0", src=self.pg0.local_ip4) /
931               UDP(sport=1234, dport=1234) /
932               Raw(b'\xa5' * 100))
933         pb = (Ether(src=self.pg1.remote_mac,
934                     dst=self.pg1.local_mac) /
935               IP(dst="10.10.255.255", src=self.pg0.local_ip4) /
936               UDP(sport=1234, dport=1234) /
937               Raw(b'\xa5' * 100))
938
939         self.send_and_assert_no_replies(self.pg1, pn, "IP Network address")
940         self.send_and_assert_no_replies(self.pg1, pb, "IP Broadcast address")
941
942         # remove the sub-net and we are forwarding via the cover again
943         self.vapi.sw_interface_add_del_address(
944             sw_if_index=self.pg0.sw_if_index,
945             prefix=VppIpPrefix("10.10.10.10", 16).encode(), is_add=0)
946
947         self.pg1.add_stream(pn)
948         self.pg_enable_capture(self.pg_interfaces)
949         self.pg_start()
950         rx = self.pg1.get_capture(1)
951         self.pg1.add_stream(pb)
952         self.pg_enable_capture(self.pg_interfaces)
953         self.pg_start()
954         rx = self.pg1.get_capture(1)
955
956         #
957         # A /31 is a special case where the 'other-side' is an attached host
958         # packets to that peer generate ARP requests
959         #
960         ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10")
961
962         self.vapi.sw_interface_add_del_address(
963             sw_if_index=self.pg0.sw_if_index,
964             prefix=VppIpPrefix("10.10.10.10", 31).encode())
965
966         pn = (Ether(src=self.pg1.remote_mac,
967                     dst=self.pg1.local_mac) /
968               IP(dst="10.10.10.11", src=self.pg0.local_ip4) /
969               UDP(sport=1234, dport=1234) /
970               Raw(b'\xa5' * 100))
971
972         self.pg1.add_stream(pn)
973         self.pg_enable_capture(self.pg_interfaces)
974         self.pg_start()
975         rx = self.pg0.get_capture(1)
976         rx[ARP]
977
978         # remove the sub-net and we are forwarding via the cover again
979         self.vapi.sw_interface_add_del_address(
980             sw_if_index=self.pg0.sw_if_index,
981             prefix=VppIpPrefix("10.10.10.10", 31).encode(), is_add=0)
982
983         self.pg1.add_stream(pn)
984         self.pg_enable_capture(self.pg_interfaces)
985         self.pg_start()
986         rx = self.pg1.get_capture(1)
987
988
989 class TestIPLoadBalance(VppTestCase):
990     """ IPv4 Load-Balancing """
991
992     @classmethod
993     def setUpClass(cls):
994         super(TestIPLoadBalance, cls).setUpClass()
995
996     @classmethod
997     def tearDownClass(cls):
998         super(TestIPLoadBalance, cls).tearDownClass()
999
1000     def setUp(self):
1001         super(TestIPLoadBalance, self).setUp()
1002
1003         self.create_pg_interfaces(range(5))
1004         mpls_tbl = VppMplsTable(self, 0)
1005         mpls_tbl.add_vpp_config()
1006
1007         for i in self.pg_interfaces:
1008             i.admin_up()
1009             i.config_ip4()
1010             i.resolve_arp()
1011             i.enable_mpls()
1012
1013     def tearDown(self):
1014         for i in self.pg_interfaces:
1015             i.disable_mpls()
1016             i.unconfig_ip4()
1017             i.admin_down()
1018         super(TestIPLoadBalance, self).tearDown()
1019
1020     def send_and_expect_load_balancing(self, input, pkts, outputs):
1021         input.add_stream(pkts)
1022         self.pg_enable_capture(self.pg_interfaces)
1023         self.pg_start()
1024         rxs = []
1025         for oo in outputs:
1026             rx = oo._get_capture(1)
1027             self.assertNotEqual(0, len(rx))
1028             for r in rx:
1029                 rxs.append(r)
1030         return rxs
1031
1032     def send_and_expect_one_itf(self, input, pkts, itf):
1033         input.add_stream(pkts)
1034         self.pg_enable_capture(self.pg_interfaces)
1035         self.pg_start()
1036         rx = itf.get_capture(len(pkts))
1037
1038     def test_ip_load_balance(self):
1039         """ IP Load-Balancing """
1040
1041         #
1042         # An array of packets that differ only in the destination port
1043         #
1044         port_ip_pkts = []
1045         port_mpls_pkts = []
1046
1047         #
1048         # An array of packets that differ only in the source address
1049         #
1050         src_ip_pkts = []
1051         src_mpls_pkts = []
1052
1053         for ii in range(NUM_PKTS):
1054             port_ip_hdr = (IP(dst="10.0.0.1", src="20.0.0.1") /
1055                            UDP(sport=1234, dport=1234 + ii) /
1056                            Raw(b'\xa5' * 100))
1057             port_ip_pkts.append((Ether(src=self.pg0.remote_mac,
1058                                        dst=self.pg0.local_mac) /
1059                                  port_ip_hdr))
1060             port_mpls_pkts.append((Ether(src=self.pg0.remote_mac,
1061                                          dst=self.pg0.local_mac) /
1062                                    MPLS(label=66, ttl=2) /
1063                                    port_ip_hdr))
1064
1065             src_ip_hdr = (IP(dst="10.0.0.1", src="20.0.0.%d" % ii) /
1066                           UDP(sport=1234, dport=1234) /
1067                           Raw(b'\xa5' * 100))
1068             src_ip_pkts.append((Ether(src=self.pg0.remote_mac,
1069                                       dst=self.pg0.local_mac) /
1070                                 src_ip_hdr))
1071             src_mpls_pkts.append((Ether(src=self.pg0.remote_mac,
1072                                         dst=self.pg0.local_mac) /
1073                                   MPLS(label=66, ttl=2) /
1074                                   src_ip_hdr))
1075
1076         route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
1077                                     [VppRoutePath(self.pg1.remote_ip4,
1078                                                   self.pg1.sw_if_index),
1079                                      VppRoutePath(self.pg2.remote_ip4,
1080                                                   self.pg2.sw_if_index)])
1081         route_10_0_0_1.add_vpp_config()
1082
1083         binding = VppMplsIpBind(self, 66, "10.0.0.1", 32)
1084         binding.add_vpp_config()
1085
1086         #
1087         # inject the packet on pg0 - expect load-balancing across the 2 paths
1088         #  - since the default hash config is to use IP src,dst and port
1089         #    src,dst
1090         # We are not going to ensure equal amounts of packets across each link,
1091         # since the hash algorithm is statistical and therefore this can never
1092         # be guaranteed. But with 64 different packets we do expect some
1093         # balancing. So instead just ensure there is traffic on each link.
1094         #
1095         self.send_and_expect_load_balancing(self.pg0, port_ip_pkts,
1096                                             [self.pg1, self.pg2])
1097         self.send_and_expect_load_balancing(self.pg0, src_ip_pkts,
1098                                             [self.pg1, self.pg2])
1099         self.send_and_expect_load_balancing(self.pg0, port_mpls_pkts,
1100                                             [self.pg1, self.pg2])
1101         self.send_and_expect_load_balancing(self.pg0, src_mpls_pkts,
1102                                             [self.pg1, self.pg2])
1103
1104         #
1105         # change the flow hash config so it's only IP src,dst
1106         #  - now only the stream with differing source address will
1107         #    load-balance
1108         #
1109         self.vapi.set_ip_flow_hash(vrf_id=0, src=1, dst=1, sport=0, dport=0)
1110
1111         self.send_and_expect_load_balancing(self.pg0, src_ip_pkts,
1112                                             [self.pg1, self.pg2])
1113         self.send_and_expect_load_balancing(self.pg0, src_mpls_pkts,
1114                                             [self.pg1, self.pg2])
1115
1116         self.send_and_expect_one_itf(self.pg0, port_ip_pkts, self.pg2)
1117
1118         #
1119         # change the flow hash config back to defaults
1120         #
1121         self.vapi.set_ip_flow_hash(vrf_id=0, src=1, dst=1, sport=1, dport=1)
1122
1123         #
1124         # Recursive prefixes
1125         #  - testing that 2 stages of load-balancing occurs and there is no
1126         #    polarisation (i.e. only 2 of 4 paths are used)
1127         #
1128         port_pkts = []
1129         src_pkts = []
1130
1131         for ii in range(257):
1132             port_pkts.append((Ether(src=self.pg0.remote_mac,
1133                                     dst=self.pg0.local_mac) /
1134                               IP(dst="1.1.1.1", src="20.0.0.1") /
1135                               UDP(sport=1234, dport=1234 + ii) /
1136                               Raw(b'\xa5' * 100)))
1137             src_pkts.append((Ether(src=self.pg0.remote_mac,
1138                                    dst=self.pg0.local_mac) /
1139                              IP(dst="1.1.1.1", src="20.0.0.%d" % ii) /
1140                              UDP(sport=1234, dport=1234) /
1141                              Raw(b'\xa5' * 100)))
1142
1143         route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
1144                                     [VppRoutePath(self.pg3.remote_ip4,
1145                                                   self.pg3.sw_if_index),
1146                                      VppRoutePath(self.pg4.remote_ip4,
1147                                                   self.pg4.sw_if_index)])
1148         route_10_0_0_2.add_vpp_config()
1149
1150         route_1_1_1_1 = VppIpRoute(self, "1.1.1.1", 32,
1151                                    [VppRoutePath("10.0.0.2", 0xffffffff),
1152                                     VppRoutePath("10.0.0.1", 0xffffffff)])
1153         route_1_1_1_1.add_vpp_config()
1154
1155         #
1156         # inject the packet on pg0 - expect load-balancing across all 4 paths
1157         #
1158         self.vapi.cli("clear trace")
1159         self.send_and_expect_load_balancing(self.pg0, port_pkts,
1160                                             [self.pg1, self.pg2,
1161                                              self.pg3, self.pg4])
1162         self.send_and_expect_load_balancing(self.pg0, src_pkts,
1163                                             [self.pg1, self.pg2,
1164                                              self.pg3, self.pg4])
1165
1166         #
1167         # bring down pg1 expect LB to adjust to use only those that are pu
1168         #
1169         self.pg1.link_down()
1170
1171         rx = self.send_and_expect_load_balancing(self.pg0, src_pkts,
1172                                                  [self.pg2, self.pg3,
1173                                                   self.pg4])
1174         self.assertEqual(len(src_pkts), len(rx))
1175
1176         #
1177         # bring down pg2 expect LB to adjust to use only those that are pu
1178         #
1179         self.pg2.link_down()
1180
1181         rx = self.send_and_expect_load_balancing(self.pg0, src_pkts,
1182                                                  [self.pg3, self.pg4])
1183         self.assertEqual(len(src_pkts), len(rx))
1184
1185         #
1186         # bring the links back up - expect LB over all again
1187         #
1188         self.pg1.link_up()
1189         self.pg2.link_up()
1190
1191         rx = self.send_and_expect_load_balancing(self.pg0, src_pkts,
1192                                                  [self.pg1, self.pg2,
1193                                                   self.pg3, self.pg4])
1194         self.assertEqual(len(src_pkts), len(rx))
1195
1196         #
1197         # The same link-up/down but this time admin state
1198         #
1199         self.pg1.admin_down()
1200         self.pg2.admin_down()
1201         rx = self.send_and_expect_load_balancing(self.pg0, src_pkts,
1202                                                  [self.pg3, self.pg4])
1203         self.assertEqual(len(src_pkts), len(rx))
1204         self.pg1.admin_up()
1205         self.pg2.admin_up()
1206         self.pg1.resolve_arp()
1207         self.pg2.resolve_arp()
1208         rx = self.send_and_expect_load_balancing(self.pg0, src_pkts,
1209                                                  [self.pg1, self.pg2,
1210                                                   self.pg3, self.pg4])
1211         self.assertEqual(len(src_pkts), len(rx))
1212
1213         #
1214         # Recursive prefixes
1215         #  - testing that 2 stages of load-balancing, no choices
1216         #
1217         port_pkts = []
1218
1219         for ii in range(257):
1220             port_pkts.append((Ether(src=self.pg0.remote_mac,
1221                                     dst=self.pg0.local_mac) /
1222                               IP(dst="1.1.1.2", src="20.0.0.2") /
1223                               UDP(sport=1234, dport=1234 + ii) /
1224                               Raw(b'\xa5' * 100)))
1225
1226         route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1227                                     [VppRoutePath(self.pg3.remote_ip4,
1228                                                   self.pg3.sw_if_index)])
1229         route_10_0_0_3.add_vpp_config()
1230
1231         route_1_1_1_2 = VppIpRoute(self, "1.1.1.2", 32,
1232                                    [VppRoutePath("10.0.0.3", 0xffffffff)])
1233         route_1_1_1_2.add_vpp_config()
1234
1235         #
1236         # inject the packet on pg0 - rx only on via routes output interface
1237         #
1238         self.vapi.cli("clear trace")
1239         self.send_and_expect_one_itf(self.pg0, port_pkts, self.pg3)
1240
1241         #
1242         # Add a LB route in the presence of a down link - expect no
1243         # packets over the down link
1244         #
1245         self.pg3.link_down()
1246
1247         route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1248                                     [VppRoutePath(self.pg3.remote_ip4,
1249                                                   self.pg3.sw_if_index),
1250                                      VppRoutePath(self.pg4.remote_ip4,
1251                                                   self.pg4.sw_if_index)])
1252         route_10_0_0_3.add_vpp_config()
1253
1254         port_pkts = []
1255         for ii in range(257):
1256             port_pkts.append(Ether(src=self.pg0.remote_mac,
1257                                    dst=self.pg0.local_mac) /
1258                              IP(dst="10.0.0.3", src="20.0.0.2") /
1259                              UDP(sport=1234, dport=1234 + ii) /
1260                              Raw(b'\xa5' * 100))
1261
1262         self.send_and_expect_one_itf(self.pg0, port_pkts, self.pg4)
1263
1264         # bring the link back up
1265         self.pg3.link_up()
1266
1267         rx = self.send_and_expect_load_balancing(self.pg0, port_pkts,
1268                                                  [self.pg3, self.pg4])
1269         self.assertEqual(len(src_pkts), len(rx))
1270
1271
1272 class TestIPVlan0(VppTestCase):
1273     """ IPv4 VLAN-0 """
1274
1275     @classmethod
1276     def setUpClass(cls):
1277         super(TestIPVlan0, cls).setUpClass()
1278
1279     @classmethod
1280     def tearDownClass(cls):
1281         super(TestIPVlan0, cls).tearDownClass()
1282
1283     def setUp(self):
1284         super(TestIPVlan0, self).setUp()
1285
1286         self.create_pg_interfaces(range(2))
1287         mpls_tbl = VppMplsTable(self, 0)
1288         mpls_tbl.add_vpp_config()
1289
1290         for i in self.pg_interfaces:
1291             i.admin_up()
1292             i.config_ip4()
1293             i.resolve_arp()
1294             i.enable_mpls()
1295
1296     def tearDown(self):
1297         for i in self.pg_interfaces:
1298             i.disable_mpls()
1299             i.unconfig_ip4()
1300             i.admin_down()
1301         super(TestIPVlan0, self).tearDown()
1302
1303     def test_ip_vlan_0(self):
1304         """ IP VLAN-0 """
1305
1306         pkts = (Ether(src=self.pg0.remote_mac,
1307                       dst=self.pg0.local_mac) /
1308                 Dot1Q(vlan=0) /
1309                 IP(dst=self.pg1.remote_ip4,
1310                    src=self.pg0.remote_ip4) /
1311                 UDP(sport=1234, dport=1234) /
1312                 Raw(b'\xa5' * 100)) * NUM_PKTS
1313
1314         #
1315         # Expect that packets sent on VLAN-0 are forwarded on the
1316         # main interface.
1317         #
1318         self.send_and_expect(self.pg0, pkts, self.pg1)
1319
1320
1321 class TestIPPunt(VppTestCase):
1322     """ IPv4 Punt Police/Redirect """
1323
1324     @classmethod
1325     def setUpClass(cls):
1326         super(TestIPPunt, cls).setUpClass()
1327
1328     @classmethod
1329     def tearDownClass(cls):
1330         super(TestIPPunt, cls).tearDownClass()
1331
1332     def setUp(self):
1333         super(TestIPPunt, self).setUp()
1334
1335         self.create_pg_interfaces(range(4))
1336
1337         for i in self.pg_interfaces:
1338             i.admin_up()
1339             i.config_ip4()
1340             i.resolve_arp()
1341
1342     def tearDown(self):
1343         super(TestIPPunt, self).tearDown()
1344         for i in self.pg_interfaces:
1345             i.unconfig_ip4()
1346             i.admin_down()
1347
1348     def test_ip_punt(self):
1349         """ IP punt police and redirect """
1350
1351         # use UDP packet that have a port we need to explicitly
1352         # register to get punted.
1353         pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
1354         af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
1355         udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
1356         punt_udp = {
1357             'type': pt_l4,
1358             'punt': {
1359                 'l4': {
1360                     'af': af_ip4,
1361                     'protocol': udp_proto,
1362                     'port': 1234,
1363                 }
1364             }
1365         }
1366
1367         self.vapi.set_punt(is_add=1, punt=punt_udp)
1368
1369         p = (Ether(src=self.pg0.remote_mac,
1370                    dst=self.pg0.local_mac) /
1371              IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
1372              UDP(sport=1234, dport=1234) /
1373              Raw(b'\xa5' * 100))
1374
1375         pkts = p * 1025
1376
1377         #
1378         # Configure a punt redirect via pg1.
1379         #
1380         nh_addr = self.pg1.remote_ip4
1381         self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
1382                                    self.pg1.sw_if_index,
1383                                    nh_addr)
1384
1385         self.send_and_expect(self.pg0, pkts, self.pg1)
1386
1387         #
1388         # add a policer
1389         #
1390         policer = self.vapi.policer_add_del(b"ip4-punt", 400, 0, 10, 0,
1391                                             rate_type=1)
1392         self.vapi.ip_punt_police(policer.policer_index)
1393
1394         self.vapi.cli("clear trace")
1395         self.pg0.add_stream(pkts)
1396         self.pg_enable_capture(self.pg_interfaces)
1397         self.pg_start()
1398
1399         #
1400         # the number of packet received should be greater than 0,
1401         # but not equal to the number sent, since some were policed
1402         #
1403         rx = self.pg1._get_capture(1)
1404         self.assertGreater(len(rx), 0)
1405         self.assertLess(len(rx), len(pkts))
1406
1407         #
1408         # remove the policer. back to full rx
1409         #
1410         self.vapi.ip_punt_police(policer.policer_index, is_add=0)
1411         self.vapi.policer_add_del(b"ip4-punt", 400, 0, 10, 0,
1412                                   rate_type=1, is_add=0)
1413         self.send_and_expect(self.pg0, pkts, self.pg1)
1414
1415         #
1416         # remove the redirect. expect full drop.
1417         #
1418         self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
1419                                    self.pg1.sw_if_index,
1420                                    nh_addr,
1421                                    is_add=0)
1422         self.send_and_assert_no_replies(self.pg0, pkts,
1423                                         "IP no punt config")
1424
1425         #
1426         # Add a redirect that is not input port selective
1427         #
1428         self.vapi.ip_punt_redirect(0xffffffff,
1429                                    self.pg1.sw_if_index,
1430                                    nh_addr)
1431         self.send_and_expect(self.pg0, pkts, self.pg1)
1432
1433         self.vapi.ip_punt_redirect(0xffffffff,
1434                                    self.pg1.sw_if_index,
1435                                    nh_addr,
1436                                    is_add=0)
1437
1438     def test_ip_punt_dump(self):
1439         """ IP4 punt redirect dump"""
1440
1441         #
1442         # Configure a punt redirects
1443         #
1444         nh_address = self.pg3.remote_ip4
1445         self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
1446                                    self.pg3.sw_if_index,
1447                                    nh_address)
1448         self.vapi.ip_punt_redirect(self.pg1.sw_if_index,
1449                                    self.pg3.sw_if_index,
1450                                    nh_address)
1451         self.vapi.ip_punt_redirect(self.pg2.sw_if_index,
1452                                    self.pg3.sw_if_index,
1453                                    '0.0.0.0')
1454
1455         #
1456         # Dump pg0 punt redirects
1457         #
1458         punts = self.vapi.ip_punt_redirect_dump(self.pg0.sw_if_index)
1459         for p in punts:
1460             self.assertEqual(p.punt.rx_sw_if_index, self.pg0.sw_if_index)
1461
1462         #
1463         # Dump punt redirects for all interfaces
1464         #
1465         punts = self.vapi.ip_punt_redirect_dump(0xffffffff)
1466         self.assertEqual(len(punts), 3)
1467         for p in punts:
1468             self.assertEqual(p.punt.tx_sw_if_index, self.pg3.sw_if_index)
1469         self.assertNotEqual(punts[1].punt.nh, self.pg3.remote_ip4)
1470         self.assertEqual(str(punts[2].punt.nh), '0.0.0.0')
1471
1472
1473 class TestIPDeag(VppTestCase):
1474     """ IPv4 Deaggregate Routes """
1475
1476     @classmethod
1477     def setUpClass(cls):
1478         super(TestIPDeag, cls).setUpClass()
1479
1480     @classmethod
1481     def tearDownClass(cls):
1482         super(TestIPDeag, cls).tearDownClass()
1483
1484     def setUp(self):
1485         super(TestIPDeag, self).setUp()
1486
1487         self.create_pg_interfaces(range(3))
1488
1489         for i in self.pg_interfaces:
1490             i.admin_up()
1491             i.config_ip4()
1492             i.resolve_arp()
1493
1494     def tearDown(self):
1495         super(TestIPDeag, self).tearDown()
1496         for i in self.pg_interfaces:
1497             i.unconfig_ip4()
1498             i.admin_down()
1499
1500     def test_ip_deag(self):
1501         """ IP Deag Routes """
1502
1503         #
1504         # Create a table to be used for:
1505         #  1 - another destination address lookup
1506         #  2 - a source address lookup
1507         #
1508         table_dst = VppIpTable(self, 1)
1509         table_src = VppIpTable(self, 2)
1510         table_dst.add_vpp_config()
1511         table_src.add_vpp_config()
1512
1513         #
1514         # Add a route in the default table to point to a deag/
1515         # second lookup in each of these tables
1516         #
1517         route_to_dst = VppIpRoute(self, "1.1.1.1", 32,
1518                                   [VppRoutePath("0.0.0.0",
1519                                                 0xffffffff,
1520                                                 nh_table_id=1)])
1521         route_to_src = VppIpRoute(
1522             self, "1.1.1.2", 32,
1523             [VppRoutePath("0.0.0.0",
1524                           0xffffffff,
1525                           nh_table_id=2,
1526                           type=FibPathType.FIB_PATH_TYPE_SOURCE_LOOKUP)])
1527         route_to_dst.add_vpp_config()
1528         route_to_src.add_vpp_config()
1529
1530         #
1531         # packets to these destination are dropped, since they'll
1532         # hit the respective default routes in the second table
1533         #
1534         p_dst = (Ether(src=self.pg0.remote_mac,
1535                        dst=self.pg0.local_mac) /
1536                  IP(src="5.5.5.5", dst="1.1.1.1") /
1537                  TCP(sport=1234, dport=1234) /
1538                  Raw(b'\xa5' * 100))
1539         p_src = (Ether(src=self.pg0.remote_mac,
1540                        dst=self.pg0.local_mac) /
1541                  IP(src="2.2.2.2", dst="1.1.1.2") /
1542                  TCP(sport=1234, dport=1234) /
1543                  Raw(b'\xa5' * 100))
1544         pkts_dst = p_dst * 257
1545         pkts_src = p_src * 257
1546
1547         self.send_and_assert_no_replies(self.pg0, pkts_dst,
1548                                         "IP in dst table")
1549         self.send_and_assert_no_replies(self.pg0, pkts_src,
1550                                         "IP in src table")
1551
1552         #
1553         # add a route in the dst table to forward via pg1
1554         #
1555         route_in_dst = VppIpRoute(self, "1.1.1.1", 32,
1556                                   [VppRoutePath(self.pg1.remote_ip4,
1557                                                 self.pg1.sw_if_index)],
1558                                   table_id=1)
1559         route_in_dst.add_vpp_config()
1560
1561         self.send_and_expect(self.pg0, pkts_dst, self.pg1)
1562
1563         #
1564         # add a route in the src table to forward via pg2
1565         #
1566         route_in_src = VppIpRoute(self, "2.2.2.2", 32,
1567                                   [VppRoutePath(self.pg2.remote_ip4,
1568                                                 self.pg2.sw_if_index)],
1569                                   table_id=2)
1570         route_in_src.add_vpp_config()
1571         self.send_and_expect(self.pg0, pkts_src, self.pg2)
1572
1573         #
1574         # loop in the lookup DP
1575         #
1576         route_loop = VppIpRoute(self, "2.2.2.3", 32,
1577                                 [VppRoutePath("0.0.0.0",
1578                                               0xffffffff,
1579                                               nh_table_id=0)])
1580         route_loop.add_vpp_config()
1581
1582         p_l = (Ether(src=self.pg0.remote_mac,
1583                      dst=self.pg0.local_mac) /
1584                IP(src="2.2.2.4", dst="2.2.2.3") /
1585                TCP(sport=1234, dport=1234) /
1586                Raw(b'\xa5' * 100))
1587
1588         self.send_and_assert_no_replies(self.pg0, p_l * 257,
1589                                         "IP lookup loop")
1590
1591
1592 class TestIPInput(VppTestCase):
1593     """ IPv4 Input Exceptions """
1594
1595     @classmethod
1596     def setUpClass(cls):
1597         super(TestIPInput, cls).setUpClass()
1598
1599     @classmethod
1600     def tearDownClass(cls):
1601         super(TestIPInput, cls).tearDownClass()
1602
1603     def setUp(self):
1604         super(TestIPInput, self).setUp()
1605
1606         self.create_pg_interfaces(range(2))
1607
1608         for i in self.pg_interfaces:
1609             i.admin_up()
1610             i.config_ip4()
1611             i.resolve_arp()
1612
1613     def tearDown(self):
1614         super(TestIPInput, self).tearDown()
1615         for i in self.pg_interfaces:
1616             i.unconfig_ip4()
1617             i.admin_down()
1618
1619     def test_ip_input(self):
1620         """ IP Input Exceptions """
1621
1622         # i can't find a way in scapy to construct an IP packet
1623         # with a length less than the IP header length
1624
1625         #
1626         # Packet too short - this is forwarded
1627         #
1628         p_short = (Ether(src=self.pg0.remote_mac,
1629                          dst=self.pg0.local_mac) /
1630                    IP(src=self.pg0.remote_ip4,
1631                       dst=self.pg1.remote_ip4,
1632                       len=40) /
1633                    UDP(sport=1234, dport=1234) /
1634                    Raw(b'\xa5' * 100))
1635
1636         rx = self.send_and_expect(self.pg0, p_short * NUM_PKTS, self.pg1)
1637
1638         #
1639         # Packet too long - this is dropped
1640         #
1641         p_long = (Ether(src=self.pg0.remote_mac,
1642                         dst=self.pg0.local_mac) /
1643                   IP(src=self.pg0.remote_ip4,
1644                      dst=self.pg1.remote_ip4,
1645                      len=400) /
1646                   UDP(sport=1234, dport=1234) /
1647                   Raw(b'\xa5' * 100))
1648
1649         rx = self.send_and_assert_no_replies(self.pg0, p_long * NUM_PKTS,
1650                                              "too long")
1651
1652         #
1653         # bad chksum - this is dropped
1654         #
1655         p_chksum = (Ether(src=self.pg0.remote_mac,
1656                           dst=self.pg0.local_mac) /
1657                     IP(src=self.pg0.remote_ip4,
1658                        dst=self.pg1.remote_ip4,
1659                        chksum=400) /
1660                     UDP(sport=1234, dport=1234) /
1661                     Raw(b'\xa5' * 100))
1662
1663         rx = self.send_and_assert_no_replies(self.pg0, p_chksum * NUM_PKTS,
1664                                              "bad checksum")
1665
1666         #
1667         # bad version - this is dropped
1668         #
1669         p_ver = (Ether(src=self.pg0.remote_mac,
1670                        dst=self.pg0.local_mac) /
1671                  IP(src=self.pg0.remote_ip4,
1672                     dst=self.pg1.remote_ip4,
1673                     version=3) /
1674                  UDP(sport=1234, dport=1234) /
1675                  Raw(b'\xa5' * 100))
1676
1677         rx = self.send_and_assert_no_replies(self.pg0, p_ver * NUM_PKTS,
1678                                              "funky version")
1679
1680         #
1681         # fragment offset 1 - this is dropped
1682         #
1683         p_frag = (Ether(src=self.pg0.remote_mac,
1684                         dst=self.pg0.local_mac) /
1685                   IP(src=self.pg0.remote_ip4,
1686                      dst=self.pg1.remote_ip4,
1687                      frag=1) /
1688                   UDP(sport=1234, dport=1234) /
1689                   Raw(b'\xa5' * 100))
1690
1691         rx = self.send_and_assert_no_replies(self.pg0, p_frag * NUM_PKTS,
1692                                              "frag offset")
1693
1694         #
1695         # TTL expired packet
1696         #
1697         p_ttl = (Ether(src=self.pg0.remote_mac,
1698                        dst=self.pg0.local_mac) /
1699                  IP(src=self.pg0.remote_ip4,
1700                     dst=self.pg1.remote_ip4,
1701                     ttl=1) /
1702                  UDP(sport=1234, dport=1234) /
1703                  Raw(b'\xa5' * 100))
1704
1705         rx = self.send_and_expect(self.pg0, p_ttl * NUM_PKTS, self.pg0)
1706
1707         rx = rx[0]
1708         icmp = rx[ICMP]
1709
1710         self.assertEqual(icmptypes[icmp.type], "time-exceeded")
1711         self.assertEqual(icmpcodes[icmp.type][icmp.code],
1712                          "ttl-zero-during-transit")
1713         self.assertEqual(icmp.src, self.pg0.remote_ip4)
1714         self.assertEqual(icmp.dst, self.pg1.remote_ip4)
1715
1716         #
1717         # MTU exceeded
1718         #
1719         p_mtu = (Ether(src=self.pg0.remote_mac,
1720                        dst=self.pg0.local_mac) /
1721                  IP(src=self.pg0.remote_ip4,
1722                     dst=self.pg1.remote_ip4,
1723                     ttl=10, flags='DF') /
1724                  UDP(sport=1234, dport=1234) /
1725                  Raw(b'\xa5' * 2000))
1726
1727         self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1500, 0, 0, 0])
1728
1729         rx = self.send_and_expect(self.pg0, p_mtu * NUM_PKTS, self.pg0)
1730         rx = rx[0]
1731         icmp = rx[ICMP]
1732
1733         self.assertEqual(icmptypes[icmp.type], "dest-unreach")
1734         self.assertEqual(icmpcodes[icmp.type][icmp.code],
1735                          "fragmentation-needed")
1736         self.assertEqual(icmp.src, self.pg0.remote_ip4)
1737         self.assertEqual(icmp.dst, self.pg1.remote_ip4)
1738
1739         self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2500, 0, 0, 0])
1740         rx = self.send_and_expect(self.pg0, p_mtu * NUM_PKTS, self.pg1)
1741
1742         # Reset MTU for subsequent tests
1743         self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [9000, 0, 0, 0])
1744
1745         #
1746         # source address 0.0.0.0 and 25.255.255.255 and for-us
1747         #
1748         p_s0 = (Ether(src=self.pg0.remote_mac,
1749                       dst=self.pg0.local_mac) /
1750                 IP(src="0.0.0.0",
1751                    dst=self.pg0.local_ip4) /
1752                 ICMP(id=4, seq=4) /
1753                 Raw(load=b'\x0a' * 18))
1754         rx = self.send_and_assert_no_replies(self.pg0, p_s0 * 17)
1755
1756         p_s0 = (Ether(src=self.pg0.remote_mac,
1757                       dst=self.pg0.local_mac) /
1758                 IP(src="255.255.255.255",
1759                    dst=self.pg0.local_ip4) /
1760                 ICMP(id=4, seq=4) /
1761                 Raw(load=b'\x0a' * 18))
1762         rx = self.send_and_assert_no_replies(self.pg0, p_s0 * 17)
1763
1764
1765 class TestIPDirectedBroadcast(VppTestCase):
1766     """ IPv4 Directed Broadcast """
1767
1768     @classmethod
1769     def setUpClass(cls):
1770         super(TestIPDirectedBroadcast, cls).setUpClass()
1771
1772     @classmethod
1773     def tearDownClass(cls):
1774         super(TestIPDirectedBroadcast, cls).tearDownClass()
1775
1776     def setUp(self):
1777         super(TestIPDirectedBroadcast, self).setUp()
1778
1779         self.create_pg_interfaces(range(2))
1780
1781         for i in self.pg_interfaces:
1782             i.admin_up()
1783
1784     def tearDown(self):
1785         super(TestIPDirectedBroadcast, self).tearDown()
1786         for i in self.pg_interfaces:
1787             i.admin_down()
1788
1789     def test_ip_input(self):
1790         """ IP Directed Broadcast """
1791
1792         #
1793         # set the directed broadcast on pg0 first, then config IP4 addresses
1794         # for pg1 directed broadcast is always disabled
1795         self.vapi.sw_interface_set_ip_directed_broadcast(
1796             self.pg0.sw_if_index, 1)
1797
1798         p0 = (Ether(src=self.pg1.remote_mac,
1799                     dst=self.pg1.local_mac) /
1800               IP(src="1.1.1.1",
1801                  dst=self.pg0._local_ip4_bcast) /
1802               UDP(sport=1234, dport=1234) /
1803               Raw(b'\xa5' * 2000))
1804         p1 = (Ether(src=self.pg0.remote_mac,
1805                     dst=self.pg0.local_mac) /
1806               IP(src="1.1.1.1",
1807                  dst=self.pg1._local_ip4_bcast) /
1808               UDP(sport=1234, dport=1234) /
1809               Raw(b'\xa5' * 2000))
1810
1811         self.pg0.config_ip4()
1812         self.pg0.resolve_arp()
1813         self.pg1.config_ip4()
1814         self.pg1.resolve_arp()
1815
1816         #
1817         # test packet is L2 broadcast
1818         #
1819         rx = self.send_and_expect(self.pg1, p0 * NUM_PKTS, self.pg0)
1820         self.assertTrue(rx[0][Ether].dst, "ff:ff:ff:ff:ff:ff")
1821
1822         self.send_and_assert_no_replies(self.pg0, p1 * NUM_PKTS,
1823                                         "directed broadcast disabled")
1824
1825         #
1826         # toggle directed broadcast on pg0
1827         #
1828         self.vapi.sw_interface_set_ip_directed_broadcast(
1829             self.pg0.sw_if_index, 0)
1830         self.send_and_assert_no_replies(self.pg1, p0 * NUM_PKTS,
1831                                         "directed broadcast disabled")
1832
1833         self.vapi.sw_interface_set_ip_directed_broadcast(
1834             self.pg0.sw_if_index, 1)
1835         rx = self.send_and_expect(self.pg1, p0 * NUM_PKTS, self.pg0)
1836
1837         self.pg0.unconfig_ip4()
1838         self.pg1.unconfig_ip4()
1839
1840
1841 class TestIPLPM(VppTestCase):
1842     """ IPv4 longest Prefix Match """
1843
1844     @classmethod
1845     def setUpClass(cls):
1846         super(TestIPLPM, cls).setUpClass()
1847
1848     @classmethod
1849     def tearDownClass(cls):
1850         super(TestIPLPM, cls).tearDownClass()
1851
1852     def setUp(self):
1853         super(TestIPLPM, self).setUp()
1854
1855         self.create_pg_interfaces(range(4))
1856
1857         for i in self.pg_interfaces:
1858             i.admin_up()
1859             i.config_ip4()
1860             i.resolve_arp()
1861
1862     def tearDown(self):
1863         super(TestIPLPM, self).tearDown()
1864         for i in self.pg_interfaces:
1865             i.admin_down()
1866             i.unconfig_ip4()
1867
1868     def test_ip_lpm(self):
1869         """ IP longest Prefix Match """
1870
1871         s_24 = VppIpRoute(self, "10.1.2.0", 24,
1872                           [VppRoutePath(self.pg1.remote_ip4,
1873                                         self.pg1.sw_if_index)])
1874         s_24.add_vpp_config()
1875         s_8 = VppIpRoute(self, "10.0.0.0", 8,
1876                          [VppRoutePath(self.pg2.remote_ip4,
1877                                        self.pg2.sw_if_index)])
1878         s_8.add_vpp_config()
1879
1880         p_8 = (Ether(src=self.pg0.remote_mac,
1881                      dst=self.pg0.local_mac) /
1882                IP(src="1.1.1.1",
1883                   dst="10.1.1.1") /
1884                UDP(sport=1234, dport=1234) /
1885                Raw(b'\xa5' * 2000))
1886         p_24 = (Ether(src=self.pg0.remote_mac,
1887                       dst=self.pg0.local_mac) /
1888                 IP(src="1.1.1.1",
1889                    dst="10.1.2.1") /
1890                 UDP(sport=1234, dport=1234) /
1891                 Raw(b'\xa5' * 2000))
1892
1893         self.logger.info(self.vapi.cli("sh ip fib mtrie"))
1894         rx = self.send_and_expect(self.pg0, p_8 * NUM_PKTS, self.pg2)
1895         rx = self.send_and_expect(self.pg0, p_24 * NUM_PKTS, self.pg1)
1896
1897
1898 class TestIPv4Frag(VppTestCase):
1899     """ IPv4 fragmentation """
1900
1901     @classmethod
1902     def setUpClass(cls):
1903         super(TestIPv4Frag, cls).setUpClass()
1904
1905         cls.create_pg_interfaces([0, 1])
1906         cls.src_if = cls.pg0
1907         cls.dst_if = cls.pg1
1908
1909         # setup all interfaces
1910         for i in cls.pg_interfaces:
1911             i.admin_up()
1912             i.config_ip4()
1913             i.resolve_arp()
1914
1915     @classmethod
1916     def tearDownClass(cls):
1917         super(TestIPv4Frag, cls).tearDownClass()
1918
1919     def test_frag_large_packets(self):
1920         """ Fragmentation of large packets """
1921
1922         self.vapi.cli("adjacency counters enable")
1923
1924         p = (Ether(dst=self.src_if.local_mac, src=self.src_if.remote_mac) /
1925              IP(src=self.src_if.remote_ip4, dst=self.dst_if.remote_ip4) /
1926              UDP(sport=1234, dport=5678) / Raw())
1927         self.extend_packet(p, 6000, "abcde")
1928         saved_payload = p[Raw].load
1929
1930         nbr = VppNeighbor(self,
1931                           self.dst_if.sw_if_index,
1932                           self.dst_if.remote_mac,
1933                           self.dst_if.remote_ip4).add_vpp_config()
1934
1935         # Force fragmentation by setting MTU of output interface
1936         # lower than packet size
1937         self.vapi.sw_interface_set_mtu(self.dst_if.sw_if_index,
1938                                        [5000, 0, 0, 0])
1939
1940         self.pg_enable_capture()
1941         self.src_if.add_stream(p)
1942         self.pg_start()
1943
1944         # Expecting 3 fragments because size of created fragments currently
1945         # cannot be larger then VPP buffer size (which is 2048)
1946         packets = self.dst_if.get_capture(3)
1947
1948         # we should show 3 packets thru the neighbor
1949         self.assertEqual(3, nbr.get_stats()['packets'])
1950
1951         # Assume VPP sends the fragments in order
1952         payload = b''
1953         for p in packets:
1954             payload_offset = p.frag * 8
1955             if payload_offset > 0:
1956                 payload_offset -= 8  # UDP header is not in payload
1957             self.assert_equal(payload_offset, len(payload))
1958             payload += p[Raw].load
1959         self.assert_equal(payload, saved_payload, "payload")
1960
1961
1962 if __name__ == '__main__':
1963     unittest.main(testRunner=VppTestRunner)