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