make_test: add icmp packet size sweep and icmp echo tests
[vpp.git] / test / test_ip4.py
1 #!/usr/bin/env python
2 import random
3 import socket
4 import unittest
5
6 from framework import VppTestCase, VppTestRunner
7 from vpp_sub_interface import VppSubInterface, VppDot1QSubint, VppDot1ADSubint
8 from vpp_ip_route import VppIpRoute, VppRoutePath, VppIpMRoute, \
9     VppMRoutePath, MRouteItfFlags, MRouteEntryFlags, VppMplsIpBind, \
10     VppMplsTable, VppIpTable
11
12 from scapy.packet import Raw
13 from scapy.layers.l2 import Ether, Dot1Q, ARP
14 from scapy.layers.inet import IP, UDP, TCP, ICMP, icmptypes, icmpcodes
15 from util import ppp
16 from scapy.contrib.mpls import MPLS
17
18
19 class TestIPv4(VppTestCase):
20     """ IPv4 Test Case """
21
22     def setUp(self):
23         """
24         Perform test setup before test case.
25
26         **Config:**
27             - create 3 pg interfaces
28                 - untagged pg0 interface
29                 - Dot1Q subinterface on pg1
30                 - Dot1AD subinterface on pg2
31             - setup interfaces:
32                 - put it into UP state
33                 - set IPv4 addresses
34                 - resolve neighbor address using ARP
35             - configure 200 fib entries
36
37         :ivar list interfaces: pg interfaces and subinterfaces.
38         :ivar dict flows: IPv4 packet flows in test.
39         """
40         super(TestIPv4, self).setUp()
41
42         # create 3 pg interfaces
43         self.create_pg_interfaces(range(3))
44
45         # create 2 subinterfaces for pg1 and pg2
46         self.sub_interfaces = [
47             VppDot1QSubint(self, self.pg1, 100),
48             VppDot1ADSubint(self, self.pg2, 200, 300, 400)]
49
50         # packet flows mapping pg0 -> pg1.sub, pg2.sub, etc.
51         self.flows = dict()
52         self.flows[self.pg0] = [self.pg1.sub_if, self.pg2.sub_if]
53         self.flows[self.pg1.sub_if] = [self.pg0, self.pg2.sub_if]
54         self.flows[self.pg2.sub_if] = [self.pg0, self.pg1.sub_if]
55
56         # packet sizes
57         self.pg_if_packet_sizes = [64, 1500, 9020]
58
59         self.interfaces = list(self.pg_interfaces)
60         self.interfaces.extend(self.sub_interfaces)
61
62         # setup all interfaces
63         for i in self.interfaces:
64             i.admin_up()
65             i.config_ip4()
66             i.resolve_arp()
67
68         # config 2M FIB entries
69         self.config_fib_entries(200)
70
71     def tearDown(self):
72         """Run standard test teardown and log ``show ip arp``."""
73         super(TestIPv4, self).tearDown()
74         if not self.vpp_dead:
75             self.logger.info(self.vapi.cli("show ip arp"))
76             # info(self.vapi.cli("show ip fib"))  # many entries
77
78     def config_fib_entries(self, count):
79         """For each interface add to the FIB table *count* routes to
80         "10.0.0.1/32" destination with interface's local address as next-hop
81         address.
82
83         :param int count: Number of FIB entries.
84
85         - *TODO:* check if the next-hop address shouldn't be remote address
86           instead of local address.
87         """
88         n_int = len(self.interfaces)
89         percent = 0
90         counter = 0.0
91         dest_addr = socket.inet_pton(socket.AF_INET, "10.0.0.1")
92         dest_addr_len = 32
93         for i in self.interfaces:
94             next_hop_address = i.local_ip4n
95             for j in range(count / n_int):
96                 self.vapi.ip_add_del_route(
97                     dest_addr, dest_addr_len, next_hop_address)
98                 counter += 1
99                 if counter / count * 100 > percent:
100                     self.logger.info("Configure %d FIB entries .. %d%% done" %
101                                      (count, percent))
102                     percent += 1
103
104     def modify_packet(self, src_if, packet_size, pkt):
105         """Add load, set destination IP and extend packet to required packet
106         size for defined interface.
107
108         :param VppInterface src_if: Interface to create packet for.
109         :param int packet_size: Required packet size.
110         :param Scapy pkt: Packet to be modified.
111         """
112         dst_if_idx = packet_size / 10 % 2
113         dst_if = self.flows[src_if][dst_if_idx]
114         info = self.create_packet_info(src_if, dst_if)
115         payload = self.info_to_payload(info)
116         p = pkt/Raw(payload)
117         p[IP].dst = dst_if.remote_ip4
118         info.data = p.copy()
119         if isinstance(src_if, VppSubInterface):
120             p = src_if.add_dot1_layer(p)
121         self.extend_packet(p, packet_size)
122
123         return p
124
125     def create_stream(self, src_if):
126         """Create input packet stream for defined interface.
127
128         :param VppInterface src_if: Interface to create packet stream for.
129         """
130         hdr_ext = 4 if isinstance(src_if, VppSubInterface) else 0
131         pkt_tmpl = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
132                     IP(src=src_if.remote_ip4) /
133                     UDP(sport=1234, dport=1234))
134
135         pkts = [self.modify_packet(src_if, i, pkt_tmpl)
136                 for i in xrange(self.pg_if_packet_sizes[0],
137                                 self.pg_if_packet_sizes[1], 10)]
138         pkts_b = [self.modify_packet(src_if, i, pkt_tmpl)
139                   for i in xrange(self.pg_if_packet_sizes[1] + hdr_ext,
140                                   self.pg_if_packet_sizes[2] + hdr_ext, 50)]
141         pkts.extend(pkts_b)
142
143         return pkts
144
145     def verify_capture(self, dst_if, capture):
146         """Verify captured input packet stream for defined interface.
147
148         :param VppInterface dst_if: Interface to verify captured packet stream
149             for.
150         :param list capture: Captured packet stream.
151         """
152         self.logger.info("Verifying capture on interface %s" % dst_if.name)
153         last_info = dict()
154         for i in self.interfaces:
155             last_info[i.sw_if_index] = None
156         is_sub_if = False
157         dst_sw_if_index = dst_if.sw_if_index
158         if hasattr(dst_if, 'parent'):
159             is_sub_if = True
160         for packet in capture:
161             if is_sub_if:
162                 # Check VLAN tags and Ethernet header
163                 packet = dst_if.remove_dot1_layer(packet)
164             self.assertTrue(Dot1Q not in packet)
165             try:
166                 ip = packet[IP]
167                 udp = packet[UDP]
168                 payload_info = self.payload_to_info(str(packet[Raw]))
169                 packet_index = payload_info.index
170                 self.assertEqual(payload_info.dst, dst_sw_if_index)
171                 self.logger.debug(
172                     "Got packet on port %s: src=%u (id=%u)" %
173                     (dst_if.name, payload_info.src, packet_index))
174                 next_info = self.get_next_packet_info_for_interface2(
175                     payload_info.src, dst_sw_if_index,
176                     last_info[payload_info.src])
177                 last_info[payload_info.src] = next_info
178                 self.assertTrue(next_info is not None)
179                 self.assertEqual(packet_index, next_info.index)
180                 saved_packet = next_info.data
181                 # Check standard fields
182                 self.assertEqual(ip.src, saved_packet[IP].src)
183                 self.assertEqual(ip.dst, saved_packet[IP].dst)
184                 self.assertEqual(udp.sport, saved_packet[UDP].sport)
185                 self.assertEqual(udp.dport, saved_packet[UDP].dport)
186             except:
187                 self.logger.error(ppp("Unexpected or invalid packet:", packet))
188                 raise
189         for i in self.interfaces:
190             remaining_packet = self.get_next_packet_info_for_interface2(
191                 i.sw_if_index, dst_sw_if_index, last_info[i.sw_if_index])
192             self.assertTrue(remaining_packet is None,
193                             "Interface %s: Packet expected from interface %s "
194                             "didn't arrive" % (dst_if.name, i.name))
195
196     def test_fib(self):
197         """ IPv4 FIB test
198
199         Test scenario:
200
201             - Create IPv4 stream for pg0 interface
202             - Create IPv4 tagged streams for pg1's and pg2's sub-interface.
203             - Send and verify received packets on each interface.
204         """
205
206         pkts = self.create_stream(self.pg0)
207         self.pg0.add_stream(pkts)
208
209         for i in self.sub_interfaces:
210             pkts = self.create_stream(i)
211             i.parent.add_stream(pkts)
212
213         self.pg_enable_capture(self.pg_interfaces)
214         self.pg_start()
215
216         pkts = self.pg0.get_capture()
217         self.verify_capture(self.pg0, pkts)
218
219         for i in self.sub_interfaces:
220             pkts = i.parent.get_capture()
221             self.verify_capture(i, pkts)
222
223
224 class TestICMPEcho(VppTestCase):
225     """ ICMP Echo Test Case """
226
227     def setUp(self):
228         super(TestICMPEcho, 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(TestICMPEcho, self).tearDown()
240         for i in self.pg_interfaces:
241             i.unconfig_ip4()
242             i.admin_down()
243
244     def test_icmp_echo(self):
245         """ VPP replies to ICMP Echo Request
246
247         Test scenario:
248
249             - Receive ICMP Echo Request message on pg0 interface.
250             - Check outgoing ICMP Echo Reply message on pg0 interface.
251         """
252
253         icmp_id = 0xb
254         icmp_seq = 5
255         icmp_load = '\x0a' * 18
256         p_echo_request = (Ether(src=self.pg0.remote_mac,
257                                 dst=self.pg0.local_mac) /
258                           IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
259                           ICMP(id=icmp_id, seq=icmp_seq) /
260                           Raw(load=icmp_load))
261
262         self.pg0.add_stream(p_echo_request)
263         self.pg_enable_capture(self.pg_interfaces)
264         self.pg_start()
265
266         rx = self.pg0.get_capture(1)
267         rx = rx[0]
268         ether = rx[Ether]
269         ipv4 = rx[IP]
270         icmp = rx[ICMP]
271
272         self.assertEqual(ether.src, self.pg0.local_mac)
273         self.assertEqual(ether.dst, self.pg0.remote_mac)
274
275         self.assertEqual(ipv4.src, self.pg0.local_ip4)
276         self.assertEqual(ipv4.dst, self.pg0.remote_ip4)
277
278         self.assertEqual(icmptypes[icmp.type], "echo-reply")
279         self.assertEqual(icmp.id, icmp_id)
280         self.assertEqual(icmp.seq, icmp_seq)
281         self.assertEqual(icmp[Raw].load, icmp_load)
282
283
284 class TestIPv4FibCrud(VppTestCase):
285     """ FIB - add/update/delete - ip4 routes
286
287     Test scenario:
288         - add 1k,
289         - del 100,
290         - add new 1k,
291         - del 1.5k
292
293     ..note:: Python API is too slow to add many routes, needs replacement.
294     """
295
296     def config_fib_many_to_one(self, start_dest_addr, next_hop_addr, count):
297         """
298
299         :param start_dest_addr:
300         :param next_hop_addr:
301         :param count:
302         :return list: added ips with 32 prefix
303         """
304         added_ips = []
305         dest_addr = int(socket.inet_pton(socket.AF_INET,
306                                          start_dest_addr).encode('hex'),
307                         16)
308         dest_addr_len = 32
309         n_next_hop_addr = socket.inet_pton(socket.AF_INET, next_hop_addr)
310         for _ in range(count):
311             n_dest_addr = '{:08x}'.format(dest_addr).decode('hex')
312             self.vapi.ip_add_del_route(n_dest_addr, dest_addr_len,
313                                        n_next_hop_addr)
314             added_ips.append(socket.inet_ntoa(n_dest_addr))
315             dest_addr += 1
316         return added_ips
317
318     def unconfig_fib_many_to_one(self, start_dest_addr, next_hop_addr, count):
319
320         removed_ips = []
321         dest_addr = int(socket.inet_pton(socket.AF_INET,
322                                          start_dest_addr).encode('hex'),
323                         16)
324         dest_addr_len = 32
325         n_next_hop_addr = socket.inet_pton(socket.AF_INET, next_hop_addr)
326         for _ in range(count):
327             n_dest_addr = '{:08x}'.format(dest_addr).decode('hex')
328             self.vapi.ip_add_del_route(n_dest_addr, dest_addr_len,
329                                        n_next_hop_addr, is_add=0)
330             removed_ips.append(socket.inet_ntoa(n_dest_addr))
331             dest_addr += 1
332         return removed_ips
333
334     def create_stream(self, src_if, dst_if, dst_ips, count):
335         pkts = []
336
337         for _ in range(count):
338             dst_addr = random.choice(dst_ips)
339             info = self.create_packet_info(src_if, dst_if)
340             payload = self.info_to_payload(info)
341             p = (Ether(dst=src_if.local_mac, src=src_if.remote_mac) /
342                  IP(src=src_if.remote_ip4, dst=dst_addr) /
343                  UDP(sport=1234, dport=1234) /
344                  Raw(payload))
345             info.data = p.copy()
346             self.extend_packet(p, random.choice(self.pg_if_packet_sizes))
347             pkts.append(p)
348
349         return pkts
350
351     def _find_ip_match(self, find_in, pkt):
352         for p in find_in:
353             if self.payload_to_info(str(p[Raw])) == \
354                     self.payload_to_info(str(pkt[Raw])):
355                 if p[IP].src != pkt[IP].src:
356                     break
357                 if p[IP].dst != pkt[IP].dst:
358                     break
359                 if p[UDP].sport != pkt[UDP].sport:
360                     break
361                 if p[UDP].dport != pkt[UDP].dport:
362                     break
363                 return p
364         return None
365
366     @staticmethod
367     def _match_route_detail(route_detail, ip, address_length=32, table_id=0):
368         if route_detail.address == socket.inet_pton(socket.AF_INET, ip):
369             if route_detail.table_id != table_id:
370                 return False
371             elif route_detail.address_length != address_length:
372                 return False
373             else:
374                 return True
375         else:
376             return False
377
378     def verify_capture(self, dst_interface, received_pkts, expected_pkts):
379         self.assertEqual(len(received_pkts), len(expected_pkts))
380         to_verify = list(expected_pkts)
381         for p in received_pkts:
382             self.assertEqual(p.src, dst_interface.local_mac)
383             self.assertEqual(p.dst, dst_interface.remote_mac)
384             x = self._find_ip_match(to_verify, p)
385             to_verify.remove(x)
386         self.assertListEqual(to_verify, [])
387
388     def verify_route_dump(self, fib_dump, ips):
389
390         def _ip_in_route_dump(ip, fib_dump):
391             return next((route for route in fib_dump
392                          if self._match_route_detail(route, ip)),
393                         False)
394
395         for ip in ips:
396             self.assertTrue(_ip_in_route_dump(ip, fib_dump),
397                             'IP {} is not in fib dump.'.format(ip))
398
399     def verify_not_in_route_dump(self, fib_dump, ips):
400
401         def _ip_in_route_dump(ip, fib_dump):
402             return next((route for route in fib_dump
403                          if self._match_route_detail(route, ip)),
404                         False)
405
406         for ip in ips:
407             self.assertFalse(_ip_in_route_dump(ip, fib_dump),
408                              'IP {} is in fib dump.'.format(ip))
409
410     @classmethod
411     def setUpClass(cls):
412         """
413         #. Create and initialize 3 pg interfaces.
414         #. initialize class attributes configured_routes and deleted_routes
415            to store information between tests.
416         """
417         super(TestIPv4FibCrud, cls).setUpClass()
418
419         try:
420             # create 3 pg interfaces
421             cls.create_pg_interfaces(range(3))
422
423             cls.interfaces = list(cls.pg_interfaces)
424
425             # setup all interfaces
426             for i in cls.interfaces:
427                 i.admin_up()
428                 i.config_ip4()
429                 i.resolve_arp()
430
431             cls.configured_routes = []
432             cls.deleted_routes = []
433             cls.pg_if_packet_sizes = [64, 512, 1518, 9018]
434
435         except Exception:
436             super(TestIPv4FibCrud, cls).tearDownClass()
437             raise
438
439     def setUp(self):
440         super(TestIPv4FibCrud, self).setUp()
441         self.reset_packet_infos()
442
443     def test_1_add_routes(self):
444         """ Add 1k routes
445
446         - add 100 routes check with traffic script.
447         """
448         # config 1M FIB entries
449         self.configured_routes.extend(self.config_fib_many_to_one(
450             "10.0.0.0", self.pg0.remote_ip4, 100))
451
452         fib_dump = self.vapi.ip_fib_dump()
453         self.verify_route_dump(fib_dump, self.configured_routes)
454
455         self.stream_1 = self.create_stream(
456             self.pg1, self.pg0, self.configured_routes, 100)
457         self.stream_2 = self.create_stream(
458             self.pg2, self.pg0, self.configured_routes, 100)
459         self.pg1.add_stream(self.stream_1)
460         self.pg2.add_stream(self.stream_2)
461
462         self.pg_enable_capture(self.pg_interfaces)
463         self.pg_start()
464
465         pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
466         self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
467
468     def test_2_del_routes(self):
469         """ Delete 100 routes
470
471         - delete 10 routes check with traffic script.
472         """
473         self.deleted_routes.extend(self.unconfig_fib_many_to_one(
474             "10.0.0.10", self.pg0.remote_ip4, 10))
475         for x in self.deleted_routes:
476             self.configured_routes.remove(x)
477
478         fib_dump = self.vapi.ip_fib_dump()
479         self.verify_route_dump(fib_dump, self.configured_routes)
480
481         self.stream_1 = self.create_stream(
482             self.pg1, self.pg0, self.configured_routes, 100)
483         self.stream_2 = self.create_stream(
484             self.pg2, self.pg0, self.configured_routes, 100)
485         self.stream_3 = self.create_stream(
486             self.pg1, self.pg0, self.deleted_routes, 100)
487         self.stream_4 = self.create_stream(
488             self.pg2, self.pg0, self.deleted_routes, 100)
489         self.pg1.add_stream(self.stream_1 + self.stream_3)
490         self.pg2.add_stream(self.stream_2 + self.stream_4)
491         self.pg_enable_capture(self.pg_interfaces)
492         self.pg_start()
493
494         pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
495         self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
496
497     def test_3_add_new_routes(self):
498         """ Add 1k routes
499
500         - re-add 5 routes check with traffic script.
501         - add 100 routes check with traffic script.
502         """
503         tmp = self.config_fib_many_to_one(
504             "10.0.0.10", self.pg0.remote_ip4, 5)
505         self.configured_routes.extend(tmp)
506         for x in tmp:
507             self.deleted_routes.remove(x)
508
509         self.configured_routes.extend(self.config_fib_many_to_one(
510             "10.0.1.0", self.pg0.remote_ip4, 100))
511
512         fib_dump = self.vapi.ip_fib_dump()
513         self.verify_route_dump(fib_dump, self.configured_routes)
514
515         self.stream_1 = self.create_stream(
516             self.pg1, self.pg0, self.configured_routes, 300)
517         self.stream_2 = self.create_stream(
518             self.pg2, self.pg0, self.configured_routes, 300)
519         self.stream_3 = self.create_stream(
520             self.pg1, self.pg0, self.deleted_routes, 100)
521         self.stream_4 = self.create_stream(
522             self.pg2, self.pg0, self.deleted_routes, 100)
523
524         self.pg1.add_stream(self.stream_1 + self.stream_3)
525         self.pg2.add_stream(self.stream_2 + self.stream_4)
526         self.pg_enable_capture(self.pg_interfaces)
527         self.pg_start()
528
529         pkts = self.pg0.get_capture(len(self.stream_1) + len(self.stream_2))
530         self.verify_capture(self.pg0, pkts, self.stream_1 + self.stream_2)
531
532     def test_4_del_routes(self):
533         """ Delete 1.5k routes
534
535         - delete 5 routes check with traffic script.
536         - add 100 routes check with traffic script.
537         """
538         self.deleted_routes.extend(self.unconfig_fib_many_to_one(
539             "10.0.0.0", self.pg0.remote_ip4, 15))
540         self.deleted_routes.extend(self.unconfig_fib_many_to_one(
541             "10.0.0.20", self.pg0.remote_ip4, 85))
542         self.deleted_routes.extend(self.unconfig_fib_many_to_one(
543             "10.0.1.0", self.pg0.remote_ip4, 100))
544         fib_dump = self.vapi.ip_fib_dump()
545         self.verify_not_in_route_dump(fib_dump, self.deleted_routes)
546
547
548 class TestIPNull(VppTestCase):
549     """ IPv4 routes via NULL """
550
551     def setUp(self):
552         super(TestIPNull, self).setUp()
553
554         # create 2 pg interfaces
555         self.create_pg_interfaces(range(1))
556
557         for i in self.pg_interfaces:
558             i.admin_up()
559             i.config_ip4()
560             i.resolve_arp()
561
562     def tearDown(self):
563         super(TestIPNull, self).tearDown()
564         for i in self.pg_interfaces:
565             i.unconfig_ip4()
566             i.admin_down()
567
568     def test_ip_null(self):
569         """ IP NULL route """
570
571         #
572         # A route via IP NULL that will reply with ICMP unreachables
573         #
574         ip_unreach = VppIpRoute(self, "10.0.0.1", 32, [], is_unreach=1)
575         ip_unreach.add_vpp_config()
576
577         p_unreach = (Ether(src=self.pg0.remote_mac,
578                            dst=self.pg0.local_mac) /
579                      IP(src=self.pg0.remote_ip4, dst="10.0.0.1") /
580                      UDP(sport=1234, dport=1234) /
581                      Raw('\xa5' * 100))
582
583         self.pg0.add_stream(p_unreach)
584         self.pg_enable_capture(self.pg_interfaces)
585         self.pg_start()
586
587         rx = self.pg0.get_capture(1)
588         rx = rx[0]
589         icmp = rx[ICMP]
590
591         self.assertEqual(icmptypes[icmp.type], "dest-unreach")
592         self.assertEqual(icmpcodes[icmp.type][icmp.code], "host-unreachable")
593         self.assertEqual(icmp.src, self.pg0.remote_ip4)
594         self.assertEqual(icmp.dst, "10.0.0.1")
595
596         #
597         # ICMP replies are rate limited. so sit and spin.
598         #
599         self.sleep(1)
600
601         #
602         # A route via IP NULL that will reply with ICMP prohibited
603         #
604         ip_prohibit = VppIpRoute(self, "10.0.0.2", 32, [], is_prohibit=1)
605         ip_prohibit.add_vpp_config()
606
607         p_prohibit = (Ether(src=self.pg0.remote_mac,
608                             dst=self.pg0.local_mac) /
609                       IP(src=self.pg0.remote_ip4, dst="10.0.0.2") /
610                       UDP(sport=1234, dport=1234) /
611                       Raw('\xa5' * 100))
612
613         self.pg0.add_stream(p_prohibit)
614         self.pg_enable_capture(self.pg_interfaces)
615         self.pg_start()
616
617         rx = self.pg0.get_capture(1)
618
619         rx = rx[0]
620         icmp = rx[ICMP]
621
622         self.assertEqual(icmptypes[icmp.type], "dest-unreach")
623         self.assertEqual(icmpcodes[icmp.type][icmp.code], "host-prohibited")
624         self.assertEqual(icmp.src, self.pg0.remote_ip4)
625         self.assertEqual(icmp.dst, "10.0.0.2")
626
627
628 class TestIPDisabled(VppTestCase):
629     """ IPv4 disabled """
630
631     def setUp(self):
632         super(TestIPDisabled, self).setUp()
633
634         # create 2 pg interfaces
635         self.create_pg_interfaces(range(2))
636
637         # PG0 is IP enalbed
638         self.pg0.admin_up()
639         self.pg0.config_ip4()
640         self.pg0.resolve_arp()
641
642         # PG 1 is not IP enabled
643         self.pg1.admin_up()
644
645     def tearDown(self):
646         super(TestIPDisabled, self).tearDown()
647         for i in self.pg_interfaces:
648             i.unconfig_ip4()
649             i.admin_down()
650
651     def test_ip_disabled(self):
652         """ IP Disabled """
653
654         #
655         # An (S,G).
656         # one accepting interface, pg0, 2 forwarding interfaces
657         #
658         route_232_1_1_1 = VppIpMRoute(
659             self,
660             "0.0.0.0",
661             "232.1.1.1", 32,
662             MRouteEntryFlags.MFIB_ENTRY_FLAG_NONE,
663             [VppMRoutePath(self.pg1.sw_if_index,
664                            MRouteItfFlags.MFIB_ITF_FLAG_ACCEPT),
665              VppMRoutePath(self.pg0.sw_if_index,
666                            MRouteItfFlags.MFIB_ITF_FLAG_FORWARD)])
667         route_232_1_1_1.add_vpp_config()
668
669         pu = (Ether(src=self.pg1.remote_mac,
670                     dst=self.pg1.local_mac) /
671               IP(src="10.10.10.10", dst=self.pg0.remote_ip4) /
672               UDP(sport=1234, dport=1234) /
673               Raw('\xa5' * 100))
674         pm = (Ether(src=self.pg1.remote_mac,
675                     dst=self.pg1.local_mac) /
676               IP(src="10.10.10.10", dst="232.1.1.1") /
677               UDP(sport=1234, dport=1234) /
678               Raw('\xa5' * 100))
679
680         #
681         # PG1 does not forward IP traffic
682         #
683         self.send_and_assert_no_replies(self.pg1, pu, "IP disabled")
684         self.send_and_assert_no_replies(self.pg1, pm, "IP disabled")
685
686         #
687         # IP enable PG1
688         #
689         self.pg1.config_ip4()
690
691         #
692         # Now we get packets through
693         #
694         self.pg1.add_stream(pu)
695         self.pg_enable_capture(self.pg_interfaces)
696         self.pg_start()
697         rx = self.pg0.get_capture(1)
698
699         self.pg1.add_stream(pm)
700         self.pg_enable_capture(self.pg_interfaces)
701         self.pg_start()
702         rx = self.pg0.get_capture(1)
703
704         #
705         # Disable PG1
706         #
707         self.pg1.unconfig_ip4()
708
709         #
710         # PG1 does not forward IP traffic
711         #
712         self.send_and_assert_no_replies(self.pg1, pu, "IP disabled")
713         self.send_and_assert_no_replies(self.pg1, pm, "IP disabled")
714
715
716 class TestIPSubNets(VppTestCase):
717     """ IPv4 Subnets """
718
719     def setUp(self):
720         super(TestIPSubNets, self).setUp()
721
722         # create a 2 pg interfaces
723         self.create_pg_interfaces(range(2))
724
725         # pg0 we will use to experiemnt
726         self.pg0.admin_up()
727
728         # pg1 is setup normally
729         self.pg1.admin_up()
730         self.pg1.config_ip4()
731         self.pg1.resolve_arp()
732
733     def tearDown(self):
734         super(TestIPSubNets, self).tearDown()
735         for i in self.pg_interfaces:
736             i.admin_down()
737
738     def test_ip_sub_nets(self):
739         """ IP Sub Nets """
740
741         #
742         # Configure a covering route to forward so we know
743         # when we are dropping
744         #
745         cover_route = VppIpRoute(self, "10.0.0.0", 8,
746                                  [VppRoutePath(self.pg1.remote_ip4,
747                                                self.pg1.sw_if_index)])
748         cover_route.add_vpp_config()
749
750         p = (Ether(src=self.pg1.remote_mac,
751                    dst=self.pg1.local_mac) /
752              IP(dst="10.10.10.10", src=self.pg0.local_ip4) /
753              UDP(sport=1234, dport=1234) /
754              Raw('\xa5' * 100))
755
756         self.pg1.add_stream(p)
757         self.pg_enable_capture(self.pg_interfaces)
758         self.pg_start()
759         rx = self.pg1.get_capture(1)
760
761         #
762         # Configure some non-/24 subnets on an IP interface
763         #
764         ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10")
765
766         self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
767                                                ip_addr_n,
768                                                16)
769
770         pn = (Ether(src=self.pg1.remote_mac,
771                     dst=self.pg1.local_mac) /
772               IP(dst="10.10.0.0", src=self.pg0.local_ip4) /
773               UDP(sport=1234, dport=1234) /
774               Raw('\xa5' * 100))
775         pb = (Ether(src=self.pg1.remote_mac,
776                     dst=self.pg1.local_mac) /
777               IP(dst="10.10.255.255", src=self.pg0.local_ip4) /
778               UDP(sport=1234, dport=1234) /
779               Raw('\xa5' * 100))
780
781         self.send_and_assert_no_replies(self.pg1, pn, "IP Network address")
782         self.send_and_assert_no_replies(self.pg1, pb, "IP Broadcast address")
783
784         # remove the sub-net and we are forwarding via the cover again
785         self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
786                                                ip_addr_n,
787                                                16,
788                                                is_add=0)
789         self.pg1.add_stream(pn)
790         self.pg_enable_capture(self.pg_interfaces)
791         self.pg_start()
792         rx = self.pg1.get_capture(1)
793         self.pg1.add_stream(pb)
794         self.pg_enable_capture(self.pg_interfaces)
795         self.pg_start()
796         rx = self.pg1.get_capture(1)
797
798         #
799         # A /31 is a special case where the 'other-side' is an attached host
800         # packets to that peer generate ARP requests
801         #
802         ip_addr_n = socket.inet_pton(socket.AF_INET, "10.10.10.10")
803
804         self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
805                                                ip_addr_n,
806                                                31)
807
808         pn = (Ether(src=self.pg1.remote_mac,
809                     dst=self.pg1.local_mac) /
810               IP(dst="10.10.10.11", src=self.pg0.local_ip4) /
811               UDP(sport=1234, dport=1234) /
812               Raw('\xa5' * 100))
813
814         self.pg1.add_stream(pn)
815         self.pg_enable_capture(self.pg_interfaces)
816         self.pg_start()
817         rx = self.pg0.get_capture(1)
818         rx[ARP]
819
820         # remove the sub-net and we are forwarding via the cover again
821         self.vapi.sw_interface_add_del_address(self.pg0.sw_if_index,
822                                                ip_addr_n,
823                                                31,
824                                                is_add=0)
825         self.pg1.add_stream(pn)
826         self.pg_enable_capture(self.pg_interfaces)
827         self.pg_start()
828         rx = self.pg1.get_capture(1)
829
830
831 class TestIPLoadBalance(VppTestCase):
832     """ IPv4 Load-Balancing """
833
834     def setUp(self):
835         super(TestIPLoadBalance, self).setUp()
836
837         self.create_pg_interfaces(range(5))
838         mpls_tbl = VppMplsTable(self, 0)
839         mpls_tbl.add_vpp_config()
840
841         for i in self.pg_interfaces:
842             i.admin_up()
843             i.config_ip4()
844             i.resolve_arp()
845             i.enable_mpls()
846
847     def tearDown(self):
848         for i in self.pg_interfaces:
849             i.disable_mpls()
850             i.unconfig_ip4()
851             i.admin_down()
852         super(TestIPLoadBalance, self).tearDown()
853
854     def send_and_expect_load_balancing(self, input, pkts, outputs):
855         input.add_stream(pkts)
856         self.pg_enable_capture(self.pg_interfaces)
857         self.pg_start()
858         for oo in outputs:
859             rx = oo._get_capture(1)
860             self.assertNotEqual(0, len(rx))
861
862     def send_and_expect_one_itf(self, input, pkts, itf):
863         input.add_stream(pkts)
864         self.pg_enable_capture(self.pg_interfaces)
865         self.pg_start()
866         rx = itf.get_capture(len(pkts))
867
868     def test_ip_load_balance(self):
869         """ IP Load-Balancing """
870
871         #
872         # An array of packets that differ only in the destination port
873         #
874         port_ip_pkts = []
875         port_mpls_pkts = []
876
877         #
878         # An array of packets that differ only in the source address
879         #
880         src_ip_pkts = []
881         src_mpls_pkts = []
882
883         for ii in range(65):
884             port_ip_hdr = (IP(dst="10.0.0.1", src="20.0.0.1") /
885                            UDP(sport=1234, dport=1234 + ii) /
886                            Raw('\xa5' * 100))
887             port_ip_pkts.append((Ether(src=self.pg0.remote_mac,
888                                        dst=self.pg0.local_mac) /
889                                  port_ip_hdr))
890             port_mpls_pkts.append((Ether(src=self.pg0.remote_mac,
891                                          dst=self.pg0.local_mac) /
892                                    MPLS(label=66, ttl=2) /
893                                    port_ip_hdr))
894
895             src_ip_hdr = (IP(dst="10.0.0.1", src="20.0.0.%d" % ii) /
896                           UDP(sport=1234, dport=1234) /
897                           Raw('\xa5' * 100))
898             src_ip_pkts.append((Ether(src=self.pg0.remote_mac,
899                                       dst=self.pg0.local_mac) /
900                                 src_ip_hdr))
901             src_mpls_pkts.append((Ether(src=self.pg0.remote_mac,
902                                         dst=self.pg0.local_mac) /
903                                   MPLS(label=66, ttl=2) /
904                                   src_ip_hdr))
905
906         route_10_0_0_1 = VppIpRoute(self, "10.0.0.1", 32,
907                                     [VppRoutePath(self.pg1.remote_ip4,
908                                                   self.pg1.sw_if_index),
909                                      VppRoutePath(self.pg2.remote_ip4,
910                                                   self.pg2.sw_if_index)])
911         route_10_0_0_1.add_vpp_config()
912
913         binding = VppMplsIpBind(self, 66, "10.0.0.1", 32)
914         binding.add_vpp_config()
915
916         #
917         # inject the packet on pg0 - expect load-balancing across the 2 paths
918         #  - since the default hash config is to use IP src,dst and port
919         #    src,dst
920         # We are not going to ensure equal amounts of packets across each link,
921         # since the hash algorithm is statistical and therefore this can never
922         # be guaranteed. But wuth 64 different packets we do expect some
923         # balancing. So instead just ensure there is traffic on each link.
924         #
925         self.send_and_expect_load_balancing(self.pg0, port_ip_pkts,
926                                             [self.pg1, self.pg2])
927         self.send_and_expect_load_balancing(self.pg0, src_ip_pkts,
928                                             [self.pg1, self.pg2])
929         self.send_and_expect_load_balancing(self.pg0, port_mpls_pkts,
930                                             [self.pg1, self.pg2])
931         self.send_and_expect_load_balancing(self.pg0, src_mpls_pkts,
932                                             [self.pg1, self.pg2])
933
934         #
935         # change the flow hash config so it's only IP src,dst
936         #  - now only the stream with differing source address will
937         #    load-balance
938         #
939         self.vapi.set_ip_flow_hash(0, src=1, dst=1, sport=0, dport=0)
940
941         self.send_and_expect_load_balancing(self.pg0, src_ip_pkts,
942                                             [self.pg1, self.pg2])
943         self.send_and_expect_load_balancing(self.pg0, src_mpls_pkts,
944                                             [self.pg1, self.pg2])
945
946         self.send_and_expect_one_itf(self.pg0, port_ip_pkts, self.pg2)
947
948         #
949         # change the flow hash config back to defaults
950         #
951         self.vapi.set_ip_flow_hash(0, src=1, dst=1, sport=1, dport=1)
952
953         #
954         # Recursive prefixes
955         #  - testing that 2 stages of load-balancing occurs and there is no
956         #    polarisation (i.e. only 2 of 4 paths are used)
957         #
958         port_pkts = []
959         src_pkts = []
960
961         for ii in range(257):
962             port_pkts.append((Ether(src=self.pg0.remote_mac,
963                                     dst=self.pg0.local_mac) /
964                               IP(dst="1.1.1.1", src="20.0.0.1") /
965                               UDP(sport=1234, dport=1234 + ii) /
966                               Raw('\xa5' * 100)))
967             src_pkts.append((Ether(src=self.pg0.remote_mac,
968                                    dst=self.pg0.local_mac) /
969                              IP(dst="1.1.1.1", src="20.0.0.%d" % ii) /
970                              UDP(sport=1234, dport=1234) /
971                              Raw('\xa5' * 100)))
972
973         route_10_0_0_2 = VppIpRoute(self, "10.0.0.2", 32,
974                                     [VppRoutePath(self.pg3.remote_ip4,
975                                                   self.pg3.sw_if_index),
976                                      VppRoutePath(self.pg4.remote_ip4,
977                                                   self.pg4.sw_if_index)])
978         route_10_0_0_2.add_vpp_config()
979
980         route_1_1_1_1 = VppIpRoute(self, "1.1.1.1", 32,
981                                    [VppRoutePath("10.0.0.2", 0xffffffff),
982                                     VppRoutePath("10.0.0.1", 0xffffffff)])
983         route_1_1_1_1.add_vpp_config()
984
985         #
986         # inject the packet on pg0 - expect load-balancing across all 4 paths
987         #
988         self.vapi.cli("clear trace")
989         self.send_and_expect_load_balancing(self.pg0, port_pkts,
990                                             [self.pg1, self.pg2,
991                                              self.pg3, self.pg4])
992         self.send_and_expect_load_balancing(self.pg0, src_pkts,
993                                             [self.pg1, self.pg2,
994                                              self.pg3, self.pg4])
995
996         #
997         # Recursive prefixes
998         #  - testing that 2 stages of load-balancing, no choices
999         #
1000         port_pkts = []
1001
1002         for ii in range(257):
1003             port_pkts.append((Ether(src=self.pg0.remote_mac,
1004                                     dst=self.pg0.local_mac) /
1005                               IP(dst="1.1.1.2", src="20.0.0.2") /
1006                               UDP(sport=1234, dport=1234 + ii) /
1007                               Raw('\xa5' * 100)))
1008
1009         route_10_0_0_3 = VppIpRoute(self, "10.0.0.3", 32,
1010                                     [VppRoutePath(self.pg3.remote_ip4,
1011                                                   self.pg3.sw_if_index)])
1012         route_10_0_0_3.add_vpp_config()
1013
1014         route_1_1_1_2 = VppIpRoute(self, "1.1.1.2", 32,
1015                                    [VppRoutePath("10.0.0.3", 0xffffffff)])
1016         route_1_1_1_2.add_vpp_config()
1017
1018         #
1019         # inject the packet on pg0 - expect load-balancing across all 4 paths
1020         #
1021         self.vapi.cli("clear trace")
1022         self.send_and_expect_one_itf(self.pg0, port_pkts, self.pg3)
1023
1024
1025 class TestIPVlan0(VppTestCase):
1026     """ IPv4 VLAN-0 """
1027
1028     def setUp(self):
1029         super(TestIPVlan0, self).setUp()
1030
1031         self.create_pg_interfaces(range(2))
1032         mpls_tbl = VppMplsTable(self, 0)
1033         mpls_tbl.add_vpp_config()
1034
1035         for i in self.pg_interfaces:
1036             i.admin_up()
1037             i.config_ip4()
1038             i.resolve_arp()
1039             i.enable_mpls()
1040
1041     def tearDown(self):
1042         for i in self.pg_interfaces:
1043             i.disable_mpls()
1044             i.unconfig_ip4()
1045             i.admin_down()
1046         super(TestIPVlan0, self).tearDown()
1047
1048     def test_ip_vlan_0(self):
1049         """ IP VLAN-0 """
1050
1051         pkts = (Ether(src=self.pg0.remote_mac,
1052                       dst=self.pg0.local_mac) /
1053                 Dot1Q(vlan=0) /
1054                 IP(dst=self.pg1.remote_ip4,
1055                    src=self.pg0.remote_ip4) /
1056                 UDP(sport=1234, dport=1234) /
1057                 Raw('\xa5' * 100)) * 65
1058
1059         #
1060         # Expect that packets sent on VLAN-0 are forwarded on the
1061         # main interface.
1062         #
1063         self.send_and_expect(self.pg0, pkts, self.pg1)
1064
1065
1066 class TestIPPunt(VppTestCase):
1067     """ IPv4 Punt Police/Redirect """
1068
1069     def setUp(self):
1070         super(TestIPPunt, self).setUp()
1071
1072         self.create_pg_interfaces(range(2))
1073
1074         for i in self.pg_interfaces:
1075             i.admin_up()
1076             i.config_ip4()
1077             i.resolve_arp()
1078
1079     def tearDown(self):
1080         super(TestIPPunt, self).tearDown()
1081         for i in self.pg_interfaces:
1082             i.unconfig_ip4()
1083             i.admin_down()
1084
1085     def test_ip_punt(self):
1086         """ IP punt police and redirect """
1087
1088         p = (Ether(src=self.pg0.remote_mac,
1089                    dst=self.pg0.local_mac) /
1090              IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
1091              TCP(sport=1234, dport=1234) /
1092              Raw('\xa5' * 100))
1093
1094         pkts = p * 1025
1095
1096         #
1097         # Configure a punt redirect via pg1.
1098         #
1099         nh_addr = socket.inet_pton(socket.AF_INET,
1100                                    self.pg1.remote_ip4)
1101         self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
1102                                    self.pg1.sw_if_index,
1103                                    nh_addr)
1104
1105         self.send_and_expect(self.pg0, pkts, self.pg1)
1106
1107         #
1108         # add a policer
1109         #
1110         policer = self.vapi.policer_add_del("ip4-punt", 400, 0, 10, 0,
1111                                             rate_type=1)
1112         self.vapi.ip_punt_police(policer.policer_index)
1113
1114         self.vapi.cli("clear trace")
1115         self.pg0.add_stream(pkts)
1116         self.pg_enable_capture(self.pg_interfaces)
1117         self.pg_start()
1118
1119         #
1120         # the number of packet recieved should be greater than 0,
1121         # but not equal to the number sent, since some were policed
1122         #
1123         rx = self.pg1._get_capture(1)
1124         self.assertTrue(len(rx) > 0)
1125         self.assertTrue(len(rx) < len(pkts))
1126
1127         #
1128         # remove the poilcer. back to full rx
1129         #
1130         self.vapi.ip_punt_police(policer.policer_index, is_add=0)
1131         self.vapi.policer_add_del("ip4-punt", 400, 0, 10, 0,
1132                                   rate_type=1, is_add=0)
1133         self.send_and_expect(self.pg0, pkts, self.pg1)
1134
1135         #
1136         # remove the redirect. expect full drop.
1137         #
1138         self.vapi.ip_punt_redirect(self.pg0.sw_if_index,
1139                                    self.pg1.sw_if_index,
1140                                    nh_addr,
1141                                    is_add=0)
1142         self.send_and_assert_no_replies(self.pg0, pkts,
1143                                         "IP no punt config")
1144
1145         #
1146         # Add a redirect that is not input port selective
1147         #
1148         self.vapi.ip_punt_redirect(0xffffffff,
1149                                    self.pg1.sw_if_index,
1150                                    nh_addr)
1151         self.send_and_expect(self.pg0, pkts, self.pg1)
1152
1153         self.vapi.ip_punt_redirect(0xffffffff,
1154                                    self.pg1.sw_if_index,
1155                                    nh_addr,
1156                                    is_add=0)
1157
1158
1159 class TestIPDeag(VppTestCase):
1160     """ IPv4 Deaggregate Routes """
1161
1162     def setUp(self):
1163         super(TestIPDeag, self).setUp()
1164
1165         self.create_pg_interfaces(range(3))
1166
1167         for i in self.pg_interfaces:
1168             i.admin_up()
1169             i.config_ip4()
1170             i.resolve_arp()
1171
1172     def tearDown(self):
1173         super(TestIPDeag, self).tearDown()
1174         for i in self.pg_interfaces:
1175             i.unconfig_ip4()
1176             i.admin_down()
1177
1178     def test_ip_deag(self):
1179         """ IP Deag Routes """
1180
1181         #
1182         # Create a table to be used for:
1183         #  1 - another destination address lookup
1184         #  2 - a source address lookup
1185         #
1186         table_dst = VppIpTable(self, 1)
1187         table_src = VppIpTable(self, 2)
1188         table_dst.add_vpp_config()
1189         table_src.add_vpp_config()
1190
1191         #
1192         # Add a route in the default table to point to a deag/
1193         # second lookup in each of these tables
1194         #
1195         route_to_dst = VppIpRoute(self, "1.1.1.1", 32,
1196                                   [VppRoutePath("0.0.0.0",
1197                                                 0xffffffff,
1198                                                 nh_table_id=1)])
1199         route_to_src = VppIpRoute(self, "1.1.1.2", 32,
1200                                   [VppRoutePath("0.0.0.0",
1201                                                 0xffffffff,
1202                                                 nh_table_id=2,
1203                                                 is_source_lookup=1)])
1204         route_to_dst.add_vpp_config()
1205         route_to_src.add_vpp_config()
1206
1207         #
1208         # packets to these destination are dropped, since they'll
1209         # hit the respective default routes in the second table
1210         #
1211         p_dst = (Ether(src=self.pg0.remote_mac,
1212                        dst=self.pg0.local_mac) /
1213                  IP(src="5.5.5.5", dst="1.1.1.1") /
1214                  TCP(sport=1234, dport=1234) /
1215                  Raw('\xa5' * 100))
1216         p_src = (Ether(src=self.pg0.remote_mac,
1217                        dst=self.pg0.local_mac) /
1218                  IP(src="2.2.2.2", dst="1.1.1.2") /
1219                  TCP(sport=1234, dport=1234) /
1220                  Raw('\xa5' * 100))
1221         pkts_dst = p_dst * 257
1222         pkts_src = p_src * 257
1223
1224         self.send_and_assert_no_replies(self.pg0, pkts_dst,
1225                                         "IP in dst table")
1226         self.send_and_assert_no_replies(self.pg0, pkts_src,
1227                                         "IP in src table")
1228
1229         #
1230         # add a route in the dst table to forward via pg1
1231         #
1232         route_in_dst = VppIpRoute(self, "1.1.1.1", 32,
1233                                   [VppRoutePath(self.pg1.remote_ip4,
1234                                                 self.pg1.sw_if_index)],
1235                                   table_id=1)
1236         route_in_dst.add_vpp_config()
1237         self.send_and_expect(self.pg0, pkts_dst, self.pg1)
1238
1239         #
1240         # add a route in the src table to forward via pg2
1241         #
1242         route_in_src = VppIpRoute(self, "2.2.2.2", 32,
1243                                   [VppRoutePath(self.pg2.remote_ip4,
1244                                                 self.pg2.sw_if_index)],
1245                                   table_id=2)
1246         route_in_src.add_vpp_config()
1247         self.send_and_expect(self.pg0, pkts_src, self.pg2)
1248
1249
1250 class TestIPInput(VppTestCase):
1251     """ IPv4 Input Exceptions """
1252
1253     def setUp(self):
1254         super(TestIPInput, self).setUp()
1255
1256         self.create_pg_interfaces(range(2))
1257
1258         for i in self.pg_interfaces:
1259             i.admin_up()
1260             i.config_ip4()
1261             i.resolve_arp()
1262
1263     def tearDown(self):
1264         super(TestIPInput, self).tearDown()
1265         for i in self.pg_interfaces:
1266             i.unconfig_ip4()
1267             i.admin_down()
1268
1269     def test_ip_input(self):
1270         """ IP Input Exceptions """
1271
1272         # i can't find a way in scapy to construct an IP packet
1273         # with a length less than the IP header length
1274
1275         #
1276         # Packet too short - this is forwarded
1277         #
1278         p_short = (Ether(src=self.pg0.remote_mac,
1279                          dst=self.pg0.local_mac) /
1280                    IP(src=self.pg0.remote_ip4,
1281                       dst=self.pg1.remote_ip4,
1282                       len=40) /
1283                    UDP(sport=1234, dport=1234) /
1284                    Raw('\xa5' * 100))
1285
1286         rx = self.send_and_expect(self.pg0, p_short * 65, self.pg1)
1287
1288         #
1289         # Packet too long - this is dropped
1290         #
1291         p_long = (Ether(src=self.pg0.remote_mac,
1292                         dst=self.pg0.local_mac) /
1293                   IP(src=self.pg0.remote_ip4,
1294                      dst=self.pg1.remote_ip4,
1295                      len=400) /
1296                   UDP(sport=1234, dport=1234) /
1297                   Raw('\xa5' * 100))
1298
1299         rx = self.send_and_assert_no_replies(self.pg0, p_long * 65,
1300                                              "too long")
1301
1302         #
1303         # bad chksum - this is dropped
1304         #
1305         p_chksum = (Ether(src=self.pg0.remote_mac,
1306                           dst=self.pg0.local_mac) /
1307                     IP(src=self.pg0.remote_ip4,
1308                        dst=self.pg1.remote_ip4,
1309                        chksum=400) /
1310                     UDP(sport=1234, dport=1234) /
1311                     Raw('\xa5' * 100))
1312
1313         rx = self.send_and_assert_no_replies(self.pg0, p_chksum * 65,
1314                                              "bad checksum")
1315
1316         #
1317         # bad version - this is dropped
1318         #
1319         p_ver = (Ether(src=self.pg0.remote_mac,
1320                        dst=self.pg0.local_mac) /
1321                  IP(src=self.pg0.remote_ip4,
1322                     dst=self.pg1.remote_ip4,
1323                     version=3) /
1324                  UDP(sport=1234, dport=1234) /
1325                  Raw('\xa5' * 100))
1326
1327         rx = self.send_and_assert_no_replies(self.pg0, p_ver * 65,
1328                                              "funky version")
1329
1330         #
1331         # fragment offset 1 - this is dropped
1332         #
1333         p_frag = (Ether(src=self.pg0.remote_mac,
1334                         dst=self.pg0.local_mac) /
1335                   IP(src=self.pg0.remote_ip4,
1336                      dst=self.pg1.remote_ip4,
1337                      frag=1) /
1338                   UDP(sport=1234, dport=1234) /
1339                   Raw('\xa5' * 100))
1340
1341         rx = self.send_and_assert_no_replies(self.pg0, p_frag * 65,
1342                                              "frag offset")
1343
1344         #
1345         # TTL expired packet
1346         #
1347         p_ttl = (Ether(src=self.pg0.remote_mac,
1348                        dst=self.pg0.local_mac) /
1349                  IP(src=self.pg0.remote_ip4,
1350                     dst=self.pg1.remote_ip4,
1351                     ttl=1) /
1352                  UDP(sport=1234, dport=1234) /
1353                  Raw('\xa5' * 100))
1354
1355         rx = self.send_and_expect(self.pg0, p_ttl * 65, self.pg0)
1356
1357         rx = rx[0]
1358         icmp = rx[ICMP]
1359
1360         self.assertEqual(icmptypes[icmp.type], "time-exceeded")
1361         self.assertEqual(icmpcodes[icmp.type][icmp.code],
1362                          "ttl-zero-during-transit")
1363         self.assertEqual(icmp.src, self.pg0.remote_ip4)
1364         self.assertEqual(icmp.dst, self.pg1.remote_ip4)
1365
1366         #
1367         # MTU exceeded
1368         #
1369         p_mtu = (Ether(src=self.pg0.remote_mac,
1370                        dst=self.pg0.local_mac) /
1371                  IP(src=self.pg0.remote_ip4,
1372                     dst=self.pg1.remote_ip4,
1373                     ttl=10, flags='DF') /
1374                  UDP(sport=1234, dport=1234) /
1375                  Raw('\xa5' * 2000))
1376
1377         self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [1500, 0, 0, 0])
1378
1379         rx = self.send_and_expect(self.pg0, p_mtu * 65, self.pg0)
1380         rx = rx[0]
1381         icmp = rx[ICMP]
1382
1383         self.assertEqual(icmptypes[icmp.type], "dest-unreach")
1384         self.assertEqual(icmpcodes[icmp.type][icmp.code],
1385                          "fragmentation-needed")
1386         self.assertEqual(icmp.src, self.pg0.remote_ip4)
1387         self.assertEqual(icmp.dst, self.pg1.remote_ip4)
1388
1389         self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [2500, 0, 0, 0])
1390         rx = self.send_and_expect(self.pg0, p_mtu * 65, self.pg1)
1391
1392         # Reset MTU for subsequent tests
1393         self.vapi.sw_interface_set_mtu(self.pg1.sw_if_index, [9000, 0, 0, 0])
1394
1395 if __name__ == '__main__':
1396     unittest.main(testRunner=VppTestRunner)