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