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