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