e6829d42bb3cc3684f66f9bef39f5123dabed27e
[vpp.git] / test / test_punt.py
1 #!/usr/bin/env python3
2 import random
3 import socket
4 import os
5 import threading
6 import copy
7 import fcntl
8 import time
9
10 try:
11     import unittest2 as unittest
12 except ImportError:
13     import unittest
14
15 from scapy.packet import Raw
16 from scapy.layers.l2 import Ether
17 from scapy.layers.l2 import Dot1Q
18 from scapy.layers.inet import IP, UDP, ICMP
19 from scapy.layers.ipsec import ESP
20 import scapy.layers.inet6 as inet6
21 from scapy.layers.inet6 import IPv6
22 from scapy.contrib.ospf import OSPF_Hdr, OSPFv3_Hello
23 from framework import VppTestCase
24 from asfframework import VppTestRunner, tag_fixme_vpp_workers
25 from vpp_sub_interface import VppDot1QSubint
26
27 from vpp_ip import DpoProto
28 from vpp_ip_route import VppIpRoute, VppRoutePath
29 from vpp_ipsec import VppIpsecSA, VppIpsecTunProtect, VppIpsecInterface
30 from vpp_papi import VppEnum
31
32 NUM_PKTS = 67
33
34
35 class serverSocketThread(threading.Thread):
36     """Socket server thread"""
37
38     def __init__(self, threadID, sockName):
39         threading.Thread.__init__(self)
40         self.threadID = threadID
41         self.sockName = sockName
42         self.sock = None
43         self.rx_pkts = []
44         self.stop_running = False
45
46     def rx_packets(self):
47         # Wait for some packets on socket
48         while True:
49             try:
50                 data = self.sock.recv(65536)
51
52                 # punt socket metadata
53                 # packet_desc = data[0:8]
54
55                 # Ethernet
56                 self.rx_pkts.append(Ether(data[8:]))
57             except IOError as e:
58                 if e.errno == 11:
59                     # nothing to receive, stop running or sleep a little
60                     if self.stop_running:
61                         break
62                     time.sleep(0.1)
63                     pass
64                 else:
65                     raise
66
67     def run(self):
68         self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
69         try:
70             os.unlink(self.sockName)
71         except:
72             pass
73         self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 65536)
74         self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 65536)
75         fcntl.fcntl(self.sock, fcntl.F_SETFL, os.O_NONBLOCK)
76         self.sock.bind(self.sockName)
77
78         self.rx_packets()
79
80     def close(self):
81         self.stop_running = True
82         threading.Thread.join(self)
83         self.sock.close()
84         return self.rx_pkts
85
86
87 class TestPuntSocket(VppTestCase):
88     """Punt Socket"""
89
90     ports = [1111, 2222, 3333, 4444]
91     sock_servers = list()
92     # FIXME: nr_packets > 3 results in failure
93     # nr_packets = 3 makes the test unstable
94     nr_packets = 2
95
96     @classmethod
97     def setUpClass(cls):
98         super(TestPuntSocket, cls).setUpClass()
99
100     @classmethod
101     def tearDownClass(cls):
102         super(TestPuntSocket, cls).tearDownClass()
103
104     @classmethod
105     def setUpConstants(cls):
106         cls.extra_vpp_config = [
107             "punt",
108             "{",
109             "socket",
110             cls.tempdir + "/socket_punt",
111             "}",
112         ]
113         super(TestPuntSocket, cls).setUpConstants()
114
115     def setUp(self):
116         super(TestPuntSocket, self).setUp()
117         random.seed()
118
119         self.create_pg_interfaces(range(2))
120         for i in self.pg_interfaces:
121             i.admin_up()
122
123     def tearDown(self):
124         del self.sock_servers[:]
125         super(TestPuntSocket, self).tearDown()
126
127     def socket_client_create(self, sock_name, id=None):
128         thread = serverSocketThread(id, sock_name)
129         self.sock_servers.append(thread)
130         thread.start()
131         return thread
132
133     def socket_client_close(self):
134         rx_pkts = []
135         for thread in self.sock_servers:
136             rx_pkts += thread.close()
137         return rx_pkts
138
139     def verify_port(self, pr, vpr):
140         self.assertEqual(vpr.punt.type, pr["type"])
141         self.assertEqual(vpr.punt.punt.l4.port, pr["punt"]["l4"]["port"])
142         self.assertEqual(vpr.punt.punt.l4.protocol, pr["punt"]["l4"]["protocol"])
143         self.assertEqual(vpr.punt.punt.l4.af, pr["punt"]["l4"]["af"])
144
145     def verify_exception(self, pr, vpr):
146         self.assertEqual(vpr.punt.type, pr["type"])
147         self.assertEqual(vpr.punt.punt.exception.id, pr["punt"]["exception"]["id"])
148
149     def verify_ip_proto(self, pr, vpr):
150         self.assertEqual(vpr.punt.type, pr["type"])
151         self.assertEqual(vpr.punt.punt.ip_proto.af, pr["punt"]["ip_proto"]["af"])
152         self.assertEqual(
153             vpr.punt.punt.ip_proto.protocol, pr["punt"]["ip_proto"]["protocol"]
154         )
155
156     def verify_udp_pkts(self, rxs, n_rx, port):
157         n_match = 0
158         for rx in rxs:
159             self.assertTrue(rx.haslayer(UDP))
160             if rx[UDP].dport == port:
161                 n_match += 1
162         self.assertEqual(n_match, n_rx)
163
164
165 def set_port(pr, port):
166     pr["punt"]["l4"]["port"] = port
167     return pr
168
169
170 def set_reason(pr, reason):
171     pr["punt"]["exception"]["id"] = reason
172     return pr
173
174
175 def mk_vpp_cfg4():
176     pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
177     af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
178     udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
179     punt_l4 = {"type": pt_l4, "punt": {"l4": {"af": af_ip4, "protocol": udp_proto}}}
180     return punt_l4
181
182
183 def mk_vpp_cfg6():
184     pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
185     af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
186     udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
187     punt_l4 = {"type": pt_l4, "punt": {"l4": {"af": af_ip6, "protocol": udp_proto}}}
188     return punt_l4
189
190
191 class TestIP4PuntSocket(TestPuntSocket):
192     """Punt Socket for IPv4 UDP"""
193
194     @classmethod
195     def setUpClass(cls):
196         super(TestIP4PuntSocket, cls).setUpClass()
197
198     @classmethod
199     def tearDownClass(cls):
200         super(TestIP4PuntSocket, cls).tearDownClass()
201
202     def setUp(self):
203         super(TestIP4PuntSocket, self).setUp()
204
205         for i in self.pg_interfaces:
206             i.config_ip4()
207             i.resolve_arp()
208
209     def tearDown(self):
210         super(TestIP4PuntSocket, self).tearDown()
211         for i in self.pg_interfaces:
212             i.unconfig_ip4()
213             i.admin_down()
214
215     def test_punt_socket_dump(self):
216         """Punt socket registration/deregistration"""
217
218         pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
219         af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
220         udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
221
222         punts = self.vapi.punt_socket_dump(type=pt_l4)
223         self.assertEqual(len(punts), 0)
224
225         #
226         # configure a punt socket
227         #
228         punt_l4 = mk_vpp_cfg4()
229
230         self.vapi.punt_socket_register(
231             set_port(punt_l4, 1111), "%s/socket_punt_1111" % self.tempdir
232         )
233         self.vapi.punt_socket_register(
234             set_port(punt_l4, 2222), "%s/socket_punt_2222" % self.tempdir
235         )
236         punts = self.vapi.punt_socket_dump(type=pt_l4)
237         self.assertEqual(len(punts), 2)
238         self.verify_port(set_port(punt_l4, 1111), punts[0])
239         self.verify_port(set_port(punt_l4, 2222), punts[1])
240
241         #
242         # deregister a punt socket
243         #
244         self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
245         punts = self.vapi.punt_socket_dump(type=pt_l4)
246         self.assertEqual(len(punts), 1)
247
248         #
249         # configure a punt socket again
250         #
251         self.vapi.punt_socket_register(
252             set_port(punt_l4, 1111), "%s/socket_punt_1111" % self.tempdir
253         )
254         self.vapi.punt_socket_register(
255             set_port(punt_l4, 3333), "%s/socket_punt_3333" % self.tempdir
256         )
257         punts = self.vapi.punt_socket_dump(type=pt_l4)
258         self.assertEqual(len(punts), 3)
259
260         self.logger.info(self.vapi.cli("sh punt sock reg"))
261
262         #
263         # deregister all punt socket
264         #
265         self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
266         self.vapi.punt_socket_deregister(set_port(punt_l4, 2222))
267         self.vapi.punt_socket_deregister(set_port(punt_l4, 3333))
268         punts = self.vapi.punt_socket_dump(type=pt_l4)
269         self.assertEqual(len(punts), 0)
270
271     def test_punt_socket_traffic_single_port_single_socket(self):
272         """Punt socket traffic single port single socket"""
273
274         port = self.ports[0]
275         pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
276         punt_l4 = set_port(mk_vpp_cfg4(), port)
277
278         p = (
279             Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
280             / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
281             / UDP(sport=9876, dport=port)
282             / Raw(b"\xa5" * 100)
283         )
284
285         pkts = p * self.nr_packets
286
287         punts = self.vapi.punt_socket_dump(type=pt_l4)
288         self.assertEqual(len(punts), 0)
289
290         #
291         # expect ICMP - port unreachable for all packets
292         #
293         rx = self.send_and_expect_some(self.pg0, pkts, self.pg0)
294
295         for p in rx:
296             self.assertEqual(int(p[IP].proto), 1)  # ICMP
297             self.assertEqual(int(p[ICMP].code), 3)  # unreachable
298
299         #
300         # configure a punt socket
301         #
302         self.socket_client_create("%s/socket_%d" % (self.tempdir, port))
303         self.vapi.punt_socket_register(punt_l4, "%s/socket_%d" % (self.tempdir, port))
304         punts = self.vapi.punt_socket_dump(type=pt_l4)
305         self.assertEqual(len(punts), 1)
306
307         #
308         # expect punt socket and no packets on pg0
309         #
310         self.send_and_assert_no_replies(self.pg0, pkts)
311         rx = self.socket_client_close()
312         self.verify_udp_pkts(rx, len(pkts), port)
313
314         #
315         # remove punt socket. expect ICMP - port unreachable for all packets
316         #
317         self.vapi.punt_socket_deregister(punt_l4)
318         punts = self.vapi.punt_socket_dump(type=pt_l4)
319         self.assertEqual(len(punts), 0)
320
321         rx = self.send_and_expect_some(self.pg0, pkts, self.pg0)
322         for p in rx:
323             self.assertEqual(int(p[IP].proto), 1)  # ICMP
324             self.assertEqual(int(p[ICMP].code), 3)  # unreachable
325
326     def test_punt_socket_traffic_multi_ports_multi_sockets(self):
327         """Punt socket traffic multi ports and multi sockets"""
328
329         punt_l4 = mk_vpp_cfg4()
330
331         # configuration for each UDP port
332         cfgs = dict()
333
334         #
335         # create stream of packets for each port
336         #
337         for port in self.ports:
338             # choose port from port list
339             cfgs[port] = {}
340
341             pkt = (
342                 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
343                 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
344                 / UDP(sport=9876, dport=port)
345                 / Raw(b"\xa5" * 100)
346             )
347             cfgs[port]["pkts"] = pkt * self.nr_packets
348             cfgs[port]["port"] = port
349             cfgs[port]["vpp"] = copy.deepcopy(set_port(punt_l4, port))
350
351             # configure punt sockets
352             cfgs[port]["sock"] = self.socket_client_create(
353                 "%s/socket_%d" % (self.tempdir, port)
354             )
355             self.vapi.punt_socket_register(
356                 cfgs[port]["vpp"], "%s/socket_%d" % (self.tempdir, port)
357             )
358
359         #
360         # send the packets that get punted
361         #
362         for cfg in cfgs.values():
363             self.send_and_assert_no_replies(self.pg0, cfg["pkts"])
364
365         #
366         # test that we got the excepted packets on the expected socket
367         #
368         for cfg in cfgs.values():
369             rx = cfg["sock"].close()
370             self.verify_udp_pkts(rx, len(cfg["pkts"]), cfg["port"])
371             self.vapi.punt_socket_deregister(cfg["vpp"])
372
373     def test_punt_socket_traffic_multi_ports_single_socket(self):
374         """Punt socket traffic multi ports and single socket"""
375
376         pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
377         punt_l4 = mk_vpp_cfg4()
378
379         #
380         # create stream of packets with each port
381         #
382         pkts = []
383         for port in self.ports:
384             # choose port from port list
385             pkt = (
386                 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
387                 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
388                 / UDP(sport=9876, dport=port)
389                 / Raw(b"\xa5" * 100)
390             )
391             pkts += pkt * self.nr_packets
392
393         #
394         # configure a punt socket
395         #
396         self.socket_client_create("%s/socket_multi" % self.tempdir)
397         for p in self.ports:
398             self.vapi.punt_socket_register(
399                 set_port(punt_l4, p), "%s/socket_multi" % self.tempdir
400             )
401         punts = self.vapi.punt_socket_dump(type=pt_l4)
402         self.assertEqual(len(punts), len(self.ports))
403
404         #
405         # expect punt socket and no packets on pg0
406         #
407         self.send_and_assert_no_replies(self.pg0, pkts)
408         self.logger.info(self.vapi.cli("show trace"))
409         rx = self.socket_client_close()
410
411         for p in self.ports:
412             self.verify_udp_pkts(rx, self.nr_packets, p)
413             self.vapi.punt_socket_deregister(set_port(punt_l4, p))
414         punts = self.vapi.punt_socket_dump(type=pt_l4)
415         self.assertEqual(len(punts), 0)
416
417
418 class TestIP6PuntSocket(TestPuntSocket):
419     """Punt Socket for IPv6 UDP"""
420
421     @classmethod
422     def setUpClass(cls):
423         super(TestIP6PuntSocket, cls).setUpClass()
424
425     @classmethod
426     def tearDownClass(cls):
427         super(TestIP6PuntSocket, cls).tearDownClass()
428
429     def setUp(self):
430         super(TestIP6PuntSocket, self).setUp()
431
432         for i in self.pg_interfaces:
433             i.config_ip6()
434             i.resolve_ndp()
435
436     def tearDown(self):
437         super(TestIP6PuntSocket, self).tearDown()
438         for i in self.pg_interfaces:
439             i.unconfig_ip6()
440             i.admin_down()
441
442     def test_punt_socket_dump(self):
443         """Punt socket registration"""
444
445         pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
446         af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
447         udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
448         #
449         # configure a punt socket
450         #
451         punt_l4 = {"type": pt_l4, "punt": {"l4": {"af": af_ip6, "protocol": udp_proto}}}
452
453         punts = self.vapi.punt_socket_dump(type=pt_l4)
454         self.assertEqual(len(punts), 0)
455
456         #
457         # configure a punt socket
458         #
459         self.vapi.punt_socket_register(
460             set_port(punt_l4, 1111), "%s/socket_1111" % self.tempdir
461         )
462         self.vapi.punt_socket_register(
463             set_port(punt_l4, 2222), "%s/socket_2222" % self.tempdir
464         )
465         punts = self.vapi.punt_socket_dump(type=pt_l4)
466         self.assertEqual(len(punts), 2)
467         self.verify_port(set_port(punt_l4, 1111), punts[0])
468         self.verify_port(set_port(punt_l4, 2222), punts[1])
469
470         #
471         # deregister a punt socket
472         #
473         self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
474         punts = self.vapi.punt_socket_dump(type=pt_l4)
475         self.assertEqual(len(punts), 1)
476
477         #
478         # configure a punt socket again
479         #
480         self.vapi.punt_socket_register(
481             set_port(punt_l4, 1111), "%s/socket_1111" % self.tempdir
482         )
483         punts = self.vapi.punt_socket_dump(type=pt_l4)
484         self.assertEqual(len(punts), 2)
485
486         #
487         # deregister all punt socket
488         #
489         self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
490         self.vapi.punt_socket_deregister(set_port(punt_l4, 2222))
491         self.vapi.punt_socket_deregister(set_port(punt_l4, 3333))
492         punts = self.vapi.punt_socket_dump(type=pt_l4)
493         self.assertEqual(len(punts), 0)
494
495     def test_punt_socket_traffic_single_port_single_socket(self):
496         """Punt socket traffic single port single socket"""
497
498         port = self.ports[0]
499         pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
500         af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
501         udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
502         punt_l4 = {
503             "type": pt_l4,
504             "punt": {
505                 "l4": {
506                     "af": af_ip6,
507                     "protocol": udp_proto,
508                     "port": port,
509                 }
510             },
511         }
512
513         p = (
514             Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
515             / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
516             / inet6.UDP(sport=9876, dport=port)
517             / Raw(b"\xa5" * 100)
518         )
519
520         pkts = p * self.nr_packets
521
522         punts = self.vapi.punt_socket_dump(type=pt_l4)
523         self.assertEqual(len(punts), 0)
524
525         #
526         # expect ICMPv6 - destination unreachable for all packets
527         #
528         self.vapi.cli("clear trace")
529         self.pg0.add_stream(pkts)
530         self.pg_enable_capture(self.pg_interfaces)
531         self.pg_start()
532         # FIXME - when punt socket deregister is implemented
533         # rx = self.pg0.get_capture(self.nr_packets)
534         # for p in rx:
535         #     self.assertEqual(int(p[IPv6].nh), 58)                # ICMPv6
536         #     self.assertEqual(int(p[ICMPv6DestUnreach].code),4)  # unreachable
537
538         #
539         # configure a punt socket
540         #
541         self.socket_client_create("%s/socket_%d" % (self.tempdir, port))
542         self.vapi.punt_socket_register(punt_l4, "%s/socket_%d" % (self.tempdir, port))
543         punts = self.vapi.punt_socket_dump(type=pt_l4)
544         self.assertEqual(len(punts), 1)
545
546         #
547         # expect punt socket and no packets on pg0
548         #
549         self.vapi.cli("clear errors")
550         self.vapi.cli("clear trace")
551         self.pg0.add_stream(pkts)
552         self.pg_enable_capture(self.pg_interfaces)
553         self.pg_start()
554         self.pg0.get_capture(0)
555         self.logger.info(self.vapi.cli("show trace"))
556         rx = self.socket_client_close()
557         self.verify_udp_pkts(rx, len(pkts), port)
558
559         #
560         # remove punt socket. expect ICMP - dest. unreachable for all packets
561         #
562         self.vapi.punt_socket_deregister(punt_l4)
563         punts = self.vapi.punt_socket_dump(type=pt_l4)
564         self.assertEqual(len(punts), 0)
565         self.pg0.add_stream(pkts)
566         self.pg_enable_capture(self.pg_interfaces)
567         self.pg_start()
568         # FIXME - when punt socket deregister is implemented
569         # self.pg0.get_capture(nr_packets)
570
571     def test_punt_socket_traffic_multi_ports_multi_sockets(self):
572         """Punt socket traffic multi ports and multi sockets"""
573
574         punt_l4 = mk_vpp_cfg6()
575
576         # configuration for each UDP port
577         cfgs = dict()
578
579         #
580         # create stream of packets for each port
581         #
582         for port in self.ports:
583             # choose port from port list
584             cfgs[port] = {}
585
586             pkt = (
587                 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
588                 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
589                 / UDP(sport=9876, dport=port)
590                 / Raw(b"\xa5" * 100)
591             )
592             cfgs[port]["pkts"] = pkt * self.nr_packets
593             cfgs[port]["port"] = port
594             cfgs[port]["vpp"] = copy.deepcopy(set_port(punt_l4, port))
595
596             # configure punt sockets
597             cfgs[port]["sock"] = self.socket_client_create(
598                 "%s/socket_%d" % (self.tempdir, port)
599             )
600             self.vapi.punt_socket_register(
601                 cfgs[port]["vpp"], "%s/socket_%d" % (self.tempdir, port)
602             )
603
604         #
605         # send the packets that get punted
606         #
607         for cfg in cfgs.values():
608             self.send_and_assert_no_replies(self.pg0, cfg["pkts"])
609
610         #
611         # test that we got the excepted packets on the expected socket
612         #
613         for cfg in cfgs.values():
614             rx = cfg["sock"].close()
615             self.verify_udp_pkts(rx, len(cfg["pkts"]), cfg["port"])
616             self.vapi.punt_socket_deregister(cfg["vpp"])
617
618     def test_punt_socket_traffic_multi_ports_single_socket(self):
619         """Punt socket traffic multi ports and single socket"""
620
621         pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
622         af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
623         udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
624         punt_l4 = {
625             "type": pt_l4,
626             "punt": {
627                 "l4": {
628                     "af": af_ip6,
629                     "protocol": udp_proto,
630                 }
631             },
632         }
633
634         #
635         # create stream of packets with each port
636         #
637         pkts = []
638         for port in self.ports:
639             # choose port from port list
640             pkt = (
641                 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
642                 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
643                 / UDP(sport=9876, dport=port)
644                 / Raw(b"\xa5" * 100)
645             )
646             pkts += pkt * self.nr_packets
647
648         #
649         # no punt socket
650         #
651         punts = self.vapi.punt_socket_dump(type=pt_l4)
652         self.assertEqual(len(punts), 0)
653
654         #
655         # configure a punt socket
656         #
657         self.socket_client_create("%s/socket_multi" % self.tempdir)
658         for p in self.ports:
659             self.vapi.punt_socket_register(
660                 set_port(punt_l4, p), "%s/socket_multi" % self.tempdir
661             )
662         punts = self.vapi.punt_socket_dump(type=pt_l4)
663         self.assertEqual(len(punts), len(self.ports))
664
665         #
666         # expect punt socket and no packets on pg0
667         #
668         self.vapi.cli("clear errors")
669         self.vapi.cli("clear trace")
670         self.pg0.add_stream(pkts)
671         self.pg_enable_capture(self.pg_interfaces)
672         self.pg_start()
673         # give a chance to punt socket to collect all packets
674         self.sleep(1)
675         self.pg0.get_capture(0)
676         rx = self.socket_client_close()
677
678         for p in self.ports:
679             self.verify_udp_pkts(rx, self.nr_packets, p)
680             self.vapi.punt_socket_deregister(set_port(punt_l4, p))
681         punts = self.vapi.punt_socket_dump(type=pt_l4)
682         self.assertEqual(len(punts), 0)
683
684
685 class TestExceptionPuntSocket(TestPuntSocket):
686     """Punt Socket for Exceptions"""
687
688     @classmethod
689     def setUpClass(cls):
690         super(TestExceptionPuntSocket, cls).setUpClass()
691
692     @classmethod
693     def tearDownClass(cls):
694         super(TestExceptionPuntSocket, cls).tearDownClass()
695
696     def setUp(self):
697         super(TestExceptionPuntSocket, self).setUp()
698
699         self.create_pg_interfaces(range(2))
700         for i in self.pg_interfaces:
701             i.config_ip4()
702             i.resolve_arp()
703
704     def tearDown(self):
705         super(TestExceptionPuntSocket, self).tearDown()
706         for i in self.pg_interfaces:
707             i.unconfig_ip4()
708             i.admin_down()
709
710     def test_registration(self):
711         """Punt socket registration/deregistration"""
712
713         pt_ex = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_EXCEPTION
714
715         punts = self.vapi.punt_socket_dump(type=pt_ex)
716         self.assertEqual(len(punts), 0)
717
718         #
719         # configure a punt socket
720         #
721         punt_ex = {"type": pt_ex, "punt": {"exception": {}}}
722
723         self.vapi.punt_socket_register(
724             set_reason(punt_ex, 1), "%s/socket_punt_1" % self.tempdir
725         )
726         self.vapi.punt_socket_register(
727             set_reason(punt_ex, 2), "%s/socket_punt_2" % self.tempdir
728         )
729         punts = self.vapi.punt_socket_dump(type=pt_ex)
730         self.assertEqual(len(punts), 2)
731         self.verify_exception(set_reason(punt_ex, 1), punts[0])
732         self.verify_exception(set_reason(punt_ex, 2), punts[1])
733
734         #
735         # deregister a punt socket
736         #
737         self.vapi.punt_socket_deregister(set_reason(punt_ex, 1))
738         punts = self.vapi.punt_socket_dump(type=pt_ex)
739         self.assertEqual(len(punts), 1)
740
741         #
742         # configure a punt socket again
743         #
744         self.vapi.punt_socket_register(
745             set_reason(punt_ex, 1), "%s/socket_punt_1" % self.tempdir
746         )
747         self.vapi.punt_socket_register(
748             set_reason(punt_ex, 3), "%s/socket_punt_3" % self.tempdir
749         )
750         punts = self.vapi.punt_socket_dump(type=pt_ex)
751         self.assertEqual(len(punts), 3)
752
753         self.logger.info(self.vapi.cli("sh punt sock reg exception"))
754
755         #
756         # deregister all punt socket
757         #
758         self.vapi.punt_socket_deregister(set_reason(punt_ex, 1))
759         self.vapi.punt_socket_deregister(set_reason(punt_ex, 2))
760         self.vapi.punt_socket_deregister(set_reason(punt_ex, 3))
761         punts = self.vapi.punt_socket_dump(type=pt_ex)
762         self.assertEqual(len(punts), 0)
763
764     def verify_esp_pkts(self, rxs, n_sent, spi, has_udp):
765         self.assertEqual(len(rxs), n_sent)
766         for rx in rxs:
767             self.assertTrue(rx.haslayer(IP))
768             self.assertTrue(rx.haslayer(ESP))
769             self.assertEqual(rx[ESP].spi, spi)
770             if has_udp:
771                 self.assertTrue(rx.haslayer(UDP))
772
773     def test_traffic(self):
774         """Punt socket traffic"""
775
776         port = self.ports[0]
777         pt_ex = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_EXCEPTION
778         punt_ex = {"type": pt_ex, "punt": {"exception": {}}}
779
780         #
781         # we're dealing with IPSec tunnels punting for no-such-tunnel
782         # (SPI=0 goes to ikev2)
783         #
784         cfgs = dict()
785         cfgs["ipsec4-no-such-tunnel"] = {"spi": 99, "udp": False, "itf": self.pg0}
786
787         #
788         # find the VPP ID for these punt exception reasin
789         #
790         rs = self.vapi.punt_reason_dump()
791         for key in cfgs:
792             for r in rs:
793                 print(r.reason.name)
794                 print(key)
795                 if r.reason.name == key:
796                     cfgs[key]["id"] = r.reason.id
797                     cfgs[key]["vpp"] = copy.deepcopy(
798                         set_reason(punt_ex, cfgs[key]["id"])
799                     )
800                     break
801
802         #
803         # configure punt sockets
804         #
805         for cfg in cfgs.values():
806             cfg["sock"] = self.socket_client_create(
807                 "%s/socket_%d" % (self.tempdir, cfg["id"])
808             )
809             self.vapi.punt_socket_register(
810                 cfg["vpp"], "%s/socket_%d" % (self.tempdir, cfg["id"])
811             )
812
813         #
814         # create packet streams for 'no-such-tunnel' exception
815         #
816         for cfg in cfgs.values():
817             pkt = Ether(src=cfg["itf"].remote_mac, dst=cfg["itf"].local_mac) / IP(
818                 src=cfg["itf"].remote_ip4, dst=cfg["itf"].local_ip4
819             )
820             if cfg["udp"]:
821                 pkt = pkt / UDP(sport=666, dport=4500)
822             pkt = pkt / ESP(spi=cfg["spi"], seq=3) / Raw(b"\xa5" * 100)
823             cfg["pkts"] = [pkt]
824
825         #
826         # send packets for each SPI we expect to be punted
827         #
828         for cfg in cfgs.values():
829             self.send_and_assert_no_replies(cfg["itf"], cfg["pkts"])
830
831         #
832         # verify the punted packets arrived on the associated socket
833         #
834         for cfg in cfgs.values():
835             rx = cfg["sock"].close()
836             self.verify_esp_pkts(rx, len(cfg["pkts"]), cfg["spi"], cfg["udp"])
837
838         #
839         # add some tunnels, make sure it still punts
840         #
841         tun = VppIpsecInterface(self).add_vpp_config()
842         sa_in = VppIpsecSA(
843             self,
844             11,
845             11,
846             (VppEnum.vl_api_ipsec_integ_alg_t.IPSEC_API_INTEG_ALG_SHA1_96),
847             b"0123456701234567",
848             (VppEnum.vl_api_ipsec_crypto_alg_t.IPSEC_API_CRYPTO_ALG_AES_CBC_128),
849             b"0123456701234567",
850             50,
851             self.pg0.local_ip4,
852             self.pg0.remote_ip4,
853         ).add_vpp_config()
854         sa_out = VppIpsecSA(
855             self,
856             22,
857             22,
858             (VppEnum.vl_api_ipsec_integ_alg_t.IPSEC_API_INTEG_ALG_SHA1_96),
859             b"0123456701234567",
860             (VppEnum.vl_api_ipsec_crypto_alg_t.IPSEC_API_CRYPTO_ALG_AES_CBC_128),
861             b"0123456701234567",
862             50,
863             self.pg0.local_ip4,
864             self.pg0.remote_ip4,
865         ).add_vpp_config()
866         protect = VppIpsecTunProtect(self, tun, sa_out, [sa_in]).add_vpp_config()
867
868         #
869         # send packets for each SPI we expect to be punted
870         #
871         for cfg in cfgs.values():
872             self.send_and_assert_no_replies(cfg["itf"], cfg["pkts"])
873
874         #
875         # verify the punted packets arrived on the associated socket
876         #
877         for cfg in cfgs.values():
878             rx = cfg["sock"].close()
879             self.verify_esp_pkts(rx, len(cfg["pkts"]), cfg["spi"], cfg["udp"])
880         #
881         # socket deregister
882         #
883         for cfg in cfgs.values():
884             self.vapi.punt_socket_deregister(cfg["vpp"])
885
886
887 class TestIpProtoPuntSocket(TestPuntSocket):
888     """Punt Socket for IP packets"""
889
890     @classmethod
891     def setUpClass(cls):
892         super(TestIpProtoPuntSocket, cls).setUpClass()
893
894     @classmethod
895     def tearDownClass(cls):
896         super(TestIpProtoPuntSocket, cls).tearDownClass()
897
898     def setUp(self):
899         super(TestIpProtoPuntSocket, self).setUp()
900
901         for i in self.pg_interfaces:
902             i.config_ip4()
903             i.resolve_arp()
904
905     def tearDown(self):
906         super(TestIpProtoPuntSocket, self).tearDown()
907         for i in self.pg_interfaces:
908             i.unconfig_ip4()
909             i.admin_down()
910
911     def test_registration(self):
912         """Punt socket registration/deregistration"""
913
914         af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
915         pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
916         proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
917         proto_eigrp = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_EIGRP
918
919         punts = self.vapi.punt_socket_dump(type=pt_ip)
920         self.assertEqual(len(punts), 0)
921
922         #
923         # configure a punt socket
924         #
925         punt_ospf = {
926             "type": pt_ip,
927             "punt": {"ip_proto": {"af": af_ip4, "protocol": proto_ospf}},
928         }
929         punt_eigrp = {
930             "type": pt_ip,
931             "punt": {"ip_proto": {"af": af_ip4, "protocol": proto_eigrp}},
932         }
933
934         self.vapi.punt_socket_register(punt_ospf, "%s/socket_punt_1" % self.tempdir)
935         self.vapi.punt_socket_register(punt_eigrp, "%s/socket_punt_2" % self.tempdir)
936         self.logger.info(self.vapi.cli("sh punt sock reg ip"))
937         punts = self.vapi.punt_socket_dump(type=pt_ip)
938         self.assertEqual(len(punts), 2)
939         self.verify_ip_proto(punt_ospf, punts[0])
940         self.verify_ip_proto(punt_eigrp, punts[1])
941
942         #
943         # deregister a punt socket
944         #
945         self.vapi.punt_socket_deregister(punt_ospf)
946         punts = self.vapi.punt_socket_dump(type=pt_ip)
947         self.assertEqual(len(punts), 1)
948
949         #
950         # configure a punt socket again
951         #
952         self.vapi.punt_socket_register(punt_ospf, "%s/socket_punt_3" % self.tempdir)
953         punts = self.vapi.punt_socket_dump(type=pt_ip)
954         self.assertEqual(len(punts), 2)
955
956         self.logger.info(self.vapi.cli("sh punt sock reg exception"))
957
958         #
959         # deregister all punt socket
960         #
961         self.vapi.punt_socket_deregister(punt_eigrp)
962         self.vapi.punt_socket_deregister(punt_ospf)
963         punts = self.vapi.punt_socket_dump(type=pt_ip)
964         self.assertEqual(len(punts), 0)
965
966     def verify_ospf_pkts(self, rxs, n_sent):
967         self.assertEqual(len(rxs), n_sent)
968         for rx in rxs:
969             self.assertTrue(rx.haslayer(OSPF_Hdr))
970
971     def test_traffic(self):
972         """Punt socket traffic"""
973
974         af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
975         pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
976         proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
977
978         #
979         # configure a punt socket to capture OSPF packets
980         #
981         punt_ospf = {
982             "type": pt_ip,
983             "punt": {"ip_proto": {"af": af_ip4, "protocol": proto_ospf}},
984         }
985
986         #
987         # create packet streams and configure a punt sockets
988         #
989         pkt = (
990             Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
991             / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
992             / OSPF_Hdr()
993             / OSPFv3_Hello()
994         )
995         pkts = pkt * 7
996
997         sock = self.socket_client_create("%s/socket_1" % self.tempdir)
998         self.vapi.punt_socket_register(punt_ospf, "%s/socket_1" % self.tempdir)
999
1000         #
1001         # send packets for each SPI we expect to be punted
1002         #
1003         self.send_and_assert_no_replies(self.pg0, pkts)
1004
1005         #
1006         # verify the punted packets arrived on the associated socket
1007         #
1008         rx = sock.close()
1009         self.verify_ospf_pkts(rx, len(pkts))
1010         self.vapi.punt_socket_deregister(punt_ospf)
1011
1012
1013 class TestDot1QPuntSocket(TestPuntSocket):
1014     """Punt Socket for 802.1Q (dot1q)"""
1015
1016     def setUp(self):
1017         super(TestDot1QPuntSocket, self).setUp()
1018
1019         for i in self.pg_interfaces:
1020             i.admin_up()
1021             i.config_ip4()
1022             i.resolve_arp()
1023
1024     def tearDown(self):
1025         super(TestDot1QPuntSocket, self).tearDown()
1026         for i in self.pg_interfaces:
1027             i.unconfig_ip4()
1028             i.admin_down()
1029
1030     def test_dot1q_header_punt(self):
1031         """Punt socket traffic with Dot1q header"""
1032
1033         port = self.ports[0]
1034         pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
1035         punt_l4 = set_port(mk_vpp_cfg4(), port)
1036
1037         # VLAN ID
1038         vlan_id = 100
1039
1040         # Create a subinterface with the VLAN ID
1041         subif = VppDot1QSubint(self, self.pg0, vlan_id)
1042         subif.admin_up()
1043         subif.config_ip4()
1044
1045         # Configure an IP address on the subinterface
1046         subif_ip4 = subif.local_ip4
1047
1048         p = (
1049             Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1050             / Dot1Q(vlan=vlan_id)
1051             / IP(src=self.pg0.remote_ip4, dst=subif_ip4)
1052             / UDP(sport=9876, dport=port)
1053             / Raw(b"\xa5" * 100)
1054         )
1055
1056         pkts = p * self.nr_packets
1057
1058         # Expect ICMP - port unreachable for all packets
1059         rx = self.send_and_expect_some(self.pg0, pkts, self.pg0)
1060
1061         for p in rx:
1062             self.assertEqual(int(p[IP].proto), 1)  # ICMP
1063             self.assertEqual(int(p[ICMP].code), 3)  # unreachable
1064
1065         # Configure a punt socket
1066         self.socket_client_create("%s/socket_%d" % (self.tempdir, port))
1067         self.vapi.punt_socket_register(punt_l4, "%s/socket_%d" % (self.tempdir, port))
1068         punts = self.vapi.punt_socket_dump(type=pt_l4)
1069         self.assertEqual(len(punts), 1)
1070
1071         # Expect punt socket and no packets on pg0
1072         self.send_and_assert_no_replies(self.pg0, pkts)
1073         rx = self.socket_client_close()
1074         self.logger.info("RXPKT")
1075         self.logger.info(rx)
1076         self.verify_udp_pkts(rx, len(pkts), port)
1077         for pkt in rx:
1078             self.assertEqual(pkt[Ether].src, self.pg0.remote_mac)
1079             self.assertEqual(pkt[Ether].dst, self.pg0.local_mac)
1080             self.assertEqual(pkt[Dot1Q].vlan, 100)
1081
1082         # Remove punt socket. Expect ICMP - port unreachable for all packets
1083         self.vapi.punt_socket_deregister(punt_l4)
1084         punts = self.vapi.punt_socket_dump(type=pt_l4)
1085         self.assertEqual(len(punts), 0)
1086
1087         rx = self.send_and_expect_some(self.pg0, pkts, self.pg0)
1088         for p in rx:
1089             self.assertEqual(int(p[IP].proto), 1)  # ICMP
1090             self.assertEqual(int(p[ICMP].code), 3)  # unreachable
1091
1092
1093 @tag_fixme_vpp_workers
1094 class TestPunt(VppTestCase):
1095     """Exception Punt Test Case"""
1096
1097     @classmethod
1098     def setUpClass(cls):
1099         super(TestPunt, cls).setUpClass()
1100
1101     @classmethod
1102     def tearDownClass(cls):
1103         super(TestPunt, cls).tearDownClass()
1104
1105     def setUp(self):
1106         super(TestPunt, self).setUp()
1107
1108         self.create_pg_interfaces(range(4))
1109
1110         for i in self.pg_interfaces:
1111             i.admin_up()
1112             i.config_ip4()
1113             i.resolve_arp()
1114             i.config_ip6()
1115             i.resolve_ndp()
1116
1117     def tearDown(self):
1118         for i in self.pg_interfaces:
1119             i.unconfig_ip4()
1120             i.unconfig_ip6()
1121             i.admin_down()
1122         super(TestPunt, self).tearDown()
1123
1124     def test_punt(self):
1125         """Exception Path testing"""
1126
1127         #
1128         # dump the punt registered reasons
1129         #  search for a few we know should be there
1130         #
1131         rs = self.vapi.punt_reason_dump()
1132
1133         reasons = [
1134             "ipsec6-no-such-tunnel",
1135             "ipsec4-no-such-tunnel",
1136             "ipsec4-spi-o-udp-0",
1137         ]
1138
1139         for reason in reasons:
1140             found = False
1141             for r in rs:
1142                 if r.reason.name == reason:
1143                     found = True
1144                     break
1145             self.assertTrue(found)
1146
1147         #
1148         # Using the test CLI we will hook in a exception path to
1149         # send ACL deny packets out of pg0 and pg1.
1150         # the ACL is src,dst = 1.1.1.1,1.1.1.2
1151         #
1152         ip_1_1_1_2 = VppIpRoute(
1153             self,
1154             "1.1.1.2",
1155             32,
1156             [VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index)],
1157         )
1158         ip_1_1_1_2.add_vpp_config()
1159         ip_1_2 = VppIpRoute(
1160             self,
1161             "1::2",
1162             128,
1163             [
1164                 VppRoutePath(
1165                     self.pg3.remote_ip6,
1166                     self.pg3.sw_if_index,
1167                     proto=DpoProto.DPO_PROTO_IP6,
1168                 )
1169             ],
1170         )
1171         ip_1_2.add_vpp_config()
1172
1173         p4 = (
1174             Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac)
1175             / IP(src="1.1.1.1", dst="1.1.1.2")
1176             / UDP(sport=1234, dport=1234)
1177             / Raw(b"\xa5" * 100)
1178         )
1179         p6 = (
1180             Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac)
1181             / IPv6(src="1::1", dst="1::2")
1182             / UDP(sport=1234, dport=1234)
1183             / Raw(b"\xa5" * 100)
1184         )
1185         self.send_and_expect(self.pg2, p4 * 1, self.pg3)
1186         self.send_and_expect(self.pg2, p6 * 1, self.pg3)
1187
1188         #
1189         # apply the punting features
1190         #
1191         self.vapi.cli("test punt pg2")
1192
1193         #
1194         # dump the punt reasons to learn the IDs assigned
1195         #
1196         rs = self.vapi.punt_reason_dump(reason={"name": "reason-v4"})
1197         r4 = rs[0].reason.id
1198         rs = self.vapi.punt_reason_dump(reason={"name": "reason-v6"})
1199         r6 = rs[0].reason.id
1200
1201         #
1202         # pkts now dropped
1203         #
1204         self.send_and_assert_no_replies(self.pg2, p4 * NUM_PKTS)
1205         self.send_and_assert_no_replies(self.pg2, p6 * NUM_PKTS)
1206
1207         #
1208         # Check state:
1209         #  1 - node error counters
1210         #  2 - per-reason counters
1211         #    2, 3 are the index of the assigned punt reason
1212         #
1213         stats = self.statistics.get_err_counter("/err/punt-dispatch/No registrations")
1214         self.assertEqual(stats, 2 * NUM_PKTS)
1215
1216         stats = self.statistics.get_counter("/net/punt")
1217         self.assertEqual(stats[0][r4]["packets"], NUM_PKTS)
1218         self.assertEqual(stats[0][r6]["packets"], NUM_PKTS)
1219
1220         #
1221         # use the test CLI to test a client that punts exception
1222         # packets out of pg0
1223         #
1224         self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip4)
1225         self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip6)
1226
1227         rx4s = self.send_and_expect(self.pg2, p4 * NUM_PKTS, self.pg0)
1228         rx6s = self.send_and_expect(self.pg2, p6 * NUM_PKTS, self.pg0)
1229
1230         #
1231         # check the packets come out IP unmodified but destined to pg0 host
1232         #
1233         for rx in rx4s:
1234             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1235             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1236             self.assertEqual(p4[IP].dst, rx[IP].dst)
1237             self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1238         for rx in rx6s:
1239             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1240             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1241             self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1242             self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1243
1244         stats = self.statistics.get_counter("/net/punt")
1245         self.assertEqual(stats[0][r4]["packets"], 2 * NUM_PKTS)
1246         self.assertEqual(stats[0][r6]["packets"], 2 * NUM_PKTS)
1247
1248         #
1249         # add another registration for the same reason to send packets
1250         # out of pg1
1251         #
1252         self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip4)
1253         self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip6)
1254
1255         self.vapi.cli("clear trace")
1256         self.pg2.add_stream(p4 * NUM_PKTS)
1257         self.pg_enable_capture(self.pg_interfaces)
1258         self.pg_start()
1259
1260         rxd = self.pg0.get_capture(NUM_PKTS)
1261         for rx in rxd:
1262             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1263             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1264             self.assertEqual(p4[IP].dst, rx[IP].dst)
1265             self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1266         rxd = self.pg1.get_capture(NUM_PKTS)
1267         for rx in rxd:
1268             self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1269             self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1270             self.assertEqual(p4[IP].dst, rx[IP].dst)
1271             self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1272
1273         self.vapi.cli("clear trace")
1274         self.pg2.add_stream(p6 * NUM_PKTS)
1275         self.pg_enable_capture(self.pg_interfaces)
1276         self.pg_start()
1277
1278         rxd = self.pg0.get_capture(NUM_PKTS)
1279         for rx in rxd:
1280             self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1281             self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1282             self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1283             self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1284         rxd = self.pg1.get_capture(NUM_PKTS)
1285         for rx in rxd:
1286             self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1287             self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1288             self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1289             self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1290
1291         stats = self.statistics.get_counter("/net/punt")
1292         self.assertEqual(stats[0][r4]["packets"], 3 * NUM_PKTS)
1293         self.assertEqual(stats[0][r6]["packets"], 3 * NUM_PKTS)
1294
1295         self.logger.info(self.vapi.cli("show vlib graph punt-dispatch"))
1296         self.logger.info(self.vapi.cli("show punt client"))
1297         self.logger.info(self.vapi.cli("show punt reason"))
1298         self.logger.info(self.vapi.cli("show punt stats"))
1299         self.logger.info(self.vapi.cli("show punt db"))
1300
1301
1302 if __name__ == "__main__":
1303     unittest.main(testRunner=VppTestRunner)