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