12 from struct import unpack, unpack_from
15 import unittest2 as unittest
19 from util import ppp, ppc
20 from re import compile
22 from scapy.packet import Raw
23 from scapy.layers.l2 import Ether
24 from scapy.layers.inet import IP, UDP, ICMP
25 from scapy.layers.ipsec import ESP
26 import scapy.layers.inet6 as inet6
27 from scapy.layers.inet6 import IPv6, ICMPv6DestUnreach
28 from scapy.contrib.ospf import OSPF_Hdr, OSPFv3_Hello
29 from framework import tag_fixme_vpp_workers
30 from framework import VppTestCase, VppTestRunner
32 from vpp_ip import DpoProto
33 from vpp_ip_route import VppIpRoute, VppRoutePath
34 from vpp_ipsec import VppIpsecSA, VppIpsecTunProtect, VppIpsecInterface
35 from vpp_papi import VppEnum
40 class serverSocketThread(threading.Thread):
41 """Socket server thread"""
43 def __init__(self, threadID, sockName):
44 threading.Thread.__init__(self)
45 self.threadID = threadID
46 self.sockName = sockName
49 self.stop_running = False
52 # Wait for some packets on socket
55 data = self.sock.recv(65536)
57 # punt socket metadata
58 # packet_desc = data[0:8]
61 self.rx_pkts.append(Ether(data[8:]))
64 # nothing to receive, stop running or sleep a little
73 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
75 os.unlink(self.sockName)
78 self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 65536)
79 self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 65536)
80 fcntl.fcntl(self.sock, fcntl.F_SETFL, os.O_NONBLOCK)
81 self.sock.bind(self.sockName)
86 self.stop_running = True
87 threading.Thread.join(self)
92 class TestPuntSocket(VppTestCase):
95 ports = [1111, 2222, 3333, 4444]
97 # FIXME: nr_packets > 3 results in failure
98 # nr_packets = 3 makes the test unstable
103 super(TestPuntSocket, cls).setUpClass()
106 def tearDownClass(cls):
107 super(TestPuntSocket, cls).tearDownClass()
110 def setUpConstants(cls):
111 cls.extra_vpp_punt_config = [
115 cls.tempdir + "/socket_punt",
118 super(TestPuntSocket, cls).setUpConstants()
121 super(TestPuntSocket, self).setUp()
124 self.create_pg_interfaces(range(2))
125 for i in self.pg_interfaces:
129 del self.sock_servers[:]
130 super(TestPuntSocket, self).tearDown()
132 def socket_client_create(self, sock_name, id=None):
133 thread = serverSocketThread(id, sock_name)
134 self.sock_servers.append(thread)
138 def socket_client_close(self):
140 for thread in self.sock_servers:
141 rx_pkts += thread.close()
144 def verify_port(self, pr, vpr):
145 self.assertEqual(vpr.punt.type, pr["type"])
146 self.assertEqual(vpr.punt.punt.l4.port, pr["punt"]["l4"]["port"])
147 self.assertEqual(vpr.punt.punt.l4.protocol, pr["punt"]["l4"]["protocol"])
148 self.assertEqual(vpr.punt.punt.l4.af, pr["punt"]["l4"]["af"])
150 def verify_exception(self, pr, vpr):
151 self.assertEqual(vpr.punt.type, pr["type"])
152 self.assertEqual(vpr.punt.punt.exception.id, pr["punt"]["exception"]["id"])
154 def verify_ip_proto(self, pr, vpr):
155 self.assertEqual(vpr.punt.type, pr["type"])
156 self.assertEqual(vpr.punt.punt.ip_proto.af, pr["punt"]["ip_proto"]["af"])
158 vpr.punt.punt.ip_proto.protocol, pr["punt"]["ip_proto"]["protocol"]
161 def verify_udp_pkts(self, rxs, n_rx, port):
164 self.assertTrue(rx.haslayer(UDP))
165 if rx[UDP].dport == port:
167 self.assertEqual(n_match, n_rx)
170 def set_port(pr, port):
171 pr["punt"]["l4"]["port"] = port
175 def set_reason(pr, reason):
176 pr["punt"]["exception"]["id"] = reason
181 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
182 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
183 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
184 punt_l4 = {"type": pt_l4, "punt": {"l4": {"af": af_ip4, "protocol": udp_proto}}}
189 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
190 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
191 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
192 punt_l4 = {"type": pt_l4, "punt": {"l4": {"af": af_ip6, "protocol": udp_proto}}}
196 class TestIP4PuntSocket(TestPuntSocket):
197 """Punt Socket for IPv4 UDP"""
201 super(TestIP4PuntSocket, cls).setUpClass()
204 def tearDownClass(cls):
205 super(TestIP4PuntSocket, cls).tearDownClass()
208 super(TestIP4PuntSocket, self).setUp()
210 for i in self.pg_interfaces:
215 super(TestIP4PuntSocket, self).tearDown()
216 for i in self.pg_interfaces:
220 def test_punt_socket_dump(self):
221 """Punt socket registration/deregistration"""
223 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
224 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
225 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
227 punts = self.vapi.punt_socket_dump(type=pt_l4)
228 self.assertEqual(len(punts), 0)
231 # configure a punt socket
233 punt_l4 = mk_vpp_cfg4()
235 self.vapi.punt_socket_register(
236 set_port(punt_l4, 1111), "%s/socket_punt_1111" % self.tempdir
238 self.vapi.punt_socket_register(
239 set_port(punt_l4, 2222), "%s/socket_punt_2222" % self.tempdir
241 punts = self.vapi.punt_socket_dump(type=pt_l4)
242 self.assertEqual(len(punts), 2)
243 self.verify_port(set_port(punt_l4, 1111), punts[0])
244 self.verify_port(set_port(punt_l4, 2222), punts[1])
247 # deregister a punt socket
249 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
250 punts = self.vapi.punt_socket_dump(type=pt_l4)
251 self.assertEqual(len(punts), 1)
254 # configure a punt socket again
256 self.vapi.punt_socket_register(
257 set_port(punt_l4, 1111), "%s/socket_punt_1111" % self.tempdir
259 self.vapi.punt_socket_register(
260 set_port(punt_l4, 3333), "%s/socket_punt_3333" % self.tempdir
262 punts = self.vapi.punt_socket_dump(type=pt_l4)
263 self.assertEqual(len(punts), 3)
265 self.logger.info(self.vapi.cli("sh punt sock reg"))
268 # deregister all punt socket
270 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
271 self.vapi.punt_socket_deregister(set_port(punt_l4, 2222))
272 self.vapi.punt_socket_deregister(set_port(punt_l4, 3333))
273 punts = self.vapi.punt_socket_dump(type=pt_l4)
274 self.assertEqual(len(punts), 0)
276 def test_punt_socket_traffic_single_port_single_socket(self):
277 """Punt socket traffic single port single socket"""
280 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
281 punt_l4 = set_port(mk_vpp_cfg4(), port)
284 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
285 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
286 / UDP(sport=9876, dport=port)
290 pkts = p * self.nr_packets
292 punts = self.vapi.punt_socket_dump(type=pt_l4)
293 self.assertEqual(len(punts), 0)
296 # expect ICMP - port unreachable for all packets
298 rx = self.send_and_expect_some(self.pg0, pkts, self.pg0)
301 self.assertEqual(int(p[IP].proto), 1) # ICMP
302 self.assertEqual(int(p[ICMP].code), 3) # unreachable
305 # configure a punt socket
307 self.socket_client_create("%s/socket_%d" % (self.tempdir, port))
308 self.vapi.punt_socket_register(punt_l4, "%s/socket_%d" % (self.tempdir, port))
309 punts = self.vapi.punt_socket_dump(type=pt_l4)
310 self.assertEqual(len(punts), 1)
313 # expect punt socket and no packets on pg0
315 self.send_and_assert_no_replies(self.pg0, pkts)
316 rx = self.socket_client_close()
317 self.verify_udp_pkts(rx, len(pkts), port)
320 # remove punt socket. expect ICMP - port unreachable for all packets
322 self.vapi.punt_socket_deregister(punt_l4)
323 punts = self.vapi.punt_socket_dump(type=pt_l4)
324 self.assertEqual(len(punts), 0)
326 rx = self.send_and_expect_some(self.pg0, pkts, self.pg0)
328 self.assertEqual(int(p[IP].proto), 1) # ICMP
329 self.assertEqual(int(p[ICMP].code), 3) # unreachable
331 def test_punt_socket_traffic_multi_ports_multi_sockets(self):
332 """Punt socket traffic multi ports and multi sockets"""
334 punt_l4 = mk_vpp_cfg4()
336 # configuration for each UDP port
340 # create stream of packets for each port
342 for port in self.ports:
343 # choose port from port list
347 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
348 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
349 / UDP(sport=9876, dport=port)
352 cfgs[port]["pkts"] = pkt * self.nr_packets
353 cfgs[port]["port"] = port
354 cfgs[port]["vpp"] = copy.deepcopy(set_port(punt_l4, port))
356 # configure punt sockets
357 cfgs[port]["sock"] = self.socket_client_create(
358 "%s/socket_%d" % (self.tempdir, port)
360 self.vapi.punt_socket_register(
361 cfgs[port]["vpp"], "%s/socket_%d" % (self.tempdir, port)
365 # send the packets that get punted
367 for cfg in cfgs.values():
368 self.send_and_assert_no_replies(self.pg0, cfg["pkts"])
371 # test that we got the excepted packets on the expected socket
373 for cfg in cfgs.values():
374 rx = cfg["sock"].close()
375 self.verify_udp_pkts(rx, len(cfg["pkts"]), cfg["port"])
376 self.vapi.punt_socket_deregister(cfg["vpp"])
378 def test_punt_socket_traffic_multi_ports_single_socket(self):
379 """Punt socket traffic multi ports and single socket"""
381 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
382 punt_l4 = mk_vpp_cfg4()
385 # create stream of packets with each port
388 for port in self.ports:
389 # choose port from port list
391 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
392 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
393 / UDP(sport=9876, dport=port)
396 pkts += pkt * self.nr_packets
399 # configure a punt socket
401 self.socket_client_create("%s/socket_multi" % self.tempdir)
403 self.vapi.punt_socket_register(
404 set_port(punt_l4, p), "%s/socket_multi" % self.tempdir
406 punts = self.vapi.punt_socket_dump(type=pt_l4)
407 self.assertEqual(len(punts), len(self.ports))
410 # expect punt socket and no packets on pg0
412 self.send_and_assert_no_replies(self.pg0, pkts)
413 self.logger.info(self.vapi.cli("show trace"))
414 rx = self.socket_client_close()
417 self.verify_udp_pkts(rx, self.nr_packets, p)
418 self.vapi.punt_socket_deregister(set_port(punt_l4, p))
419 punts = self.vapi.punt_socket_dump(type=pt_l4)
420 self.assertEqual(len(punts), 0)
423 class TestIP6PuntSocket(TestPuntSocket):
424 """Punt Socket for IPv6 UDP"""
428 super(TestIP6PuntSocket, cls).setUpClass()
431 def tearDownClass(cls):
432 super(TestIP6PuntSocket, cls).tearDownClass()
435 super(TestIP6PuntSocket, self).setUp()
437 for i in self.pg_interfaces:
442 super(TestIP6PuntSocket, self).tearDown()
443 for i in self.pg_interfaces:
447 def test_punt_socket_dump(self):
448 """Punt socket registration"""
450 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
451 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
452 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
454 # configure a punt socket
456 punt_l4 = {"type": pt_l4, "punt": {"l4": {"af": af_ip6, "protocol": udp_proto}}}
458 punts = self.vapi.punt_socket_dump(type=pt_l4)
459 self.assertEqual(len(punts), 0)
462 # configure a punt socket
464 self.vapi.punt_socket_register(
465 set_port(punt_l4, 1111), "%s/socket_1111" % self.tempdir
467 self.vapi.punt_socket_register(
468 set_port(punt_l4, 2222), "%s/socket_2222" % self.tempdir
470 punts = self.vapi.punt_socket_dump(type=pt_l4)
471 self.assertEqual(len(punts), 2)
472 self.verify_port(set_port(punt_l4, 1111), punts[0])
473 self.verify_port(set_port(punt_l4, 2222), punts[1])
476 # deregister a punt socket
478 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
479 punts = self.vapi.punt_socket_dump(type=pt_l4)
480 self.assertEqual(len(punts), 1)
483 # configure a punt socket again
485 self.vapi.punt_socket_register(
486 set_port(punt_l4, 1111), "%s/socket_1111" % self.tempdir
488 punts = self.vapi.punt_socket_dump(type=pt_l4)
489 self.assertEqual(len(punts), 2)
492 # deregister all punt socket
494 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
495 self.vapi.punt_socket_deregister(set_port(punt_l4, 2222))
496 self.vapi.punt_socket_deregister(set_port(punt_l4, 3333))
497 punts = self.vapi.punt_socket_dump(type=pt_l4)
498 self.assertEqual(len(punts), 0)
500 def test_punt_socket_traffic_single_port_single_socket(self):
501 """Punt socket traffic single port single socket"""
504 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
505 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
506 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
512 "protocol": udp_proto,
519 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
520 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
521 / inet6.UDP(sport=9876, dport=port)
525 pkts = p * self.nr_packets
527 punts = self.vapi.punt_socket_dump(type=pt_l4)
528 self.assertEqual(len(punts), 0)
531 # expect ICMPv6 - destination unreachable for all packets
533 self.vapi.cli("clear trace")
534 self.pg0.add_stream(pkts)
535 self.pg_enable_capture(self.pg_interfaces)
537 # FIXME - when punt socket deregister is implemented
538 # rx = self.pg0.get_capture(self.nr_packets)
540 # self.assertEqual(int(p[IPv6].nh), 58) # ICMPv6
541 # self.assertEqual(int(p[ICMPv6DestUnreach].code),4) # unreachable
544 # configure a punt socket
546 self.socket_client_create("%s/socket_%d" % (self.tempdir, port))
547 self.vapi.punt_socket_register(punt_l4, "%s/socket_%d" % (self.tempdir, port))
548 punts = self.vapi.punt_socket_dump(type=pt_l4)
549 self.assertEqual(len(punts), 1)
552 # expect punt socket and no packets on pg0
554 self.vapi.cli("clear errors")
555 self.vapi.cli("clear trace")
556 self.pg0.add_stream(pkts)
557 self.pg_enable_capture(self.pg_interfaces)
559 self.pg0.get_capture(0)
560 self.logger.info(self.vapi.cli("show trace"))
561 rx = self.socket_client_close()
562 self.verify_udp_pkts(rx, len(pkts), port)
565 # remove punt socket. expect ICMP - dest. unreachable for all packets
567 self.vapi.punt_socket_deregister(punt_l4)
568 punts = self.vapi.punt_socket_dump(type=pt_l4)
569 self.assertEqual(len(punts), 0)
570 self.pg0.add_stream(pkts)
571 self.pg_enable_capture(self.pg_interfaces)
573 # FIXME - when punt socket deregister is implemented
574 # self.pg0.get_capture(nr_packets)
576 def test_punt_socket_traffic_multi_ports_multi_sockets(self):
577 """Punt socket traffic multi ports and multi sockets"""
579 punt_l4 = mk_vpp_cfg6()
581 # configuration for each UDP port
585 # create stream of packets for each port
587 for port in self.ports:
588 # choose port from port list
592 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
593 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
594 / UDP(sport=9876, dport=port)
597 cfgs[port]["pkts"] = pkt * self.nr_packets
598 cfgs[port]["port"] = port
599 cfgs[port]["vpp"] = copy.deepcopy(set_port(punt_l4, port))
601 # configure punt sockets
602 cfgs[port]["sock"] = self.socket_client_create(
603 "%s/socket_%d" % (self.tempdir, port)
605 self.vapi.punt_socket_register(
606 cfgs[port]["vpp"], "%s/socket_%d" % (self.tempdir, port)
610 # send the packets that get punted
612 for cfg in cfgs.values():
613 self.send_and_assert_no_replies(self.pg0, cfg["pkts"])
616 # test that we got the excepted packets on the expected socket
618 for cfg in cfgs.values():
619 rx = cfg["sock"].close()
620 self.verify_udp_pkts(rx, len(cfg["pkts"]), cfg["port"])
621 self.vapi.punt_socket_deregister(cfg["vpp"])
623 def test_punt_socket_traffic_multi_ports_single_socket(self):
624 """Punt socket traffic multi ports and single socket"""
626 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
627 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
628 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
634 "protocol": udp_proto,
640 # create stream of packets with each port
643 for port in self.ports:
644 # choose port from port list
646 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
647 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
648 / UDP(sport=9876, dport=port)
651 pkts += pkt * self.nr_packets
656 punts = self.vapi.punt_socket_dump(type=pt_l4)
657 self.assertEqual(len(punts), 0)
660 # configure a punt socket
662 self.socket_client_create("%s/socket_multi" % self.tempdir)
664 self.vapi.punt_socket_register(
665 set_port(punt_l4, p), "%s/socket_multi" % self.tempdir
667 punts = self.vapi.punt_socket_dump(type=pt_l4)
668 self.assertEqual(len(punts), len(self.ports))
671 # expect punt socket and no packets on pg0
673 self.vapi.cli("clear errors")
674 self.vapi.cli("clear trace")
675 self.pg0.add_stream(pkts)
676 self.pg_enable_capture(self.pg_interfaces)
678 # give a chance to punt socket to collect all packets
680 self.pg0.get_capture(0)
681 rx = self.socket_client_close()
684 self.verify_udp_pkts(rx, self.nr_packets, p)
685 self.vapi.punt_socket_deregister(set_port(punt_l4, p))
686 punts = self.vapi.punt_socket_dump(type=pt_l4)
687 self.assertEqual(len(punts), 0)
690 class TestExceptionPuntSocket(TestPuntSocket):
691 """Punt Socket for Exceptions"""
695 super(TestExceptionPuntSocket, cls).setUpClass()
698 def tearDownClass(cls):
699 super(TestExceptionPuntSocket, cls).tearDownClass()
702 super(TestExceptionPuntSocket, self).setUp()
704 self.create_pg_interfaces(range(2))
705 for i in self.pg_interfaces:
710 super(TestExceptionPuntSocket, self).tearDown()
711 for i in self.pg_interfaces:
715 def test_registration(self):
716 """Punt socket registration/deregistration"""
718 pt_ex = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_EXCEPTION
720 punts = self.vapi.punt_socket_dump(type=pt_ex)
721 self.assertEqual(len(punts), 0)
724 # configure a punt socket
726 punt_ex = {"type": pt_ex, "punt": {"exception": {}}}
728 self.vapi.punt_socket_register(
729 set_reason(punt_ex, 1), "%s/socket_punt_1" % self.tempdir
731 self.vapi.punt_socket_register(
732 set_reason(punt_ex, 2), "%s/socket_punt_2" % self.tempdir
734 punts = self.vapi.punt_socket_dump(type=pt_ex)
735 self.assertEqual(len(punts), 2)
736 self.verify_exception(set_reason(punt_ex, 1), punts[0])
737 self.verify_exception(set_reason(punt_ex, 2), punts[1])
740 # deregister a punt socket
742 self.vapi.punt_socket_deregister(set_reason(punt_ex, 1))
743 punts = self.vapi.punt_socket_dump(type=pt_ex)
744 self.assertEqual(len(punts), 1)
747 # configure a punt socket again
749 self.vapi.punt_socket_register(
750 set_reason(punt_ex, 1), "%s/socket_punt_1" % self.tempdir
752 self.vapi.punt_socket_register(
753 set_reason(punt_ex, 3), "%s/socket_punt_3" % self.tempdir
755 punts = self.vapi.punt_socket_dump(type=pt_ex)
756 self.assertEqual(len(punts), 3)
758 self.logger.info(self.vapi.cli("sh punt sock reg exception"))
761 # deregister all punt socket
763 self.vapi.punt_socket_deregister(set_reason(punt_ex, 1))
764 self.vapi.punt_socket_deregister(set_reason(punt_ex, 2))
765 self.vapi.punt_socket_deregister(set_reason(punt_ex, 3))
766 punts = self.vapi.punt_socket_dump(type=pt_ex)
767 self.assertEqual(len(punts), 0)
769 def verify_esp_pkts(self, rxs, n_sent, spi, has_udp):
770 self.assertEqual(len(rxs), n_sent)
772 self.assertTrue(rx.haslayer(IP))
773 self.assertTrue(rx.haslayer(ESP))
774 self.assertEqual(rx[ESP].spi, spi)
776 self.assertTrue(rx.haslayer(UDP))
778 def test_traffic(self):
779 """Punt socket traffic"""
782 pt_ex = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_EXCEPTION
783 punt_ex = {"type": pt_ex, "punt": {"exception": {}}}
786 # we're dealing with IPSec tunnels punting for no-such-tunnel
787 # (SPI=0 goes to ikev2)
790 cfgs["ipsec4-no-such-tunnel"] = {"spi": 99, "udp": False, "itf": self.pg0}
793 # find the VPP ID for these punt exception reasin
795 rs = self.vapi.punt_reason_dump()
800 if r.reason.name == key:
801 cfgs[key]["id"] = r.reason.id
802 cfgs[key]["vpp"] = copy.deepcopy(
803 set_reason(punt_ex, cfgs[key]["id"])
808 # configure punt sockets
810 for cfg in cfgs.values():
811 cfg["sock"] = self.socket_client_create(
812 "%s/socket_%d" % (self.tempdir, cfg["id"])
814 self.vapi.punt_socket_register(
815 cfg["vpp"], "%s/socket_%d" % (self.tempdir, cfg["id"])
819 # create packet streams for 'no-such-tunnel' exception
821 for cfg in cfgs.values():
822 pkt = Ether(src=cfg["itf"].remote_mac, dst=cfg["itf"].local_mac) / IP(
823 src=cfg["itf"].remote_ip4, dst=cfg["itf"].local_ip4
826 pkt = pkt / UDP(sport=666, dport=4500)
827 pkt = pkt / ESP(spi=cfg["spi"], seq=3) / Raw(b"\xa5" * 100)
831 # send packets for each SPI we expect to be punted
833 for cfg in cfgs.values():
834 self.send_and_assert_no_replies(cfg["itf"], cfg["pkts"])
837 # verify the punted packets arrived on the associated socket
839 for cfg in cfgs.values():
840 rx = cfg["sock"].close()
841 self.verify_esp_pkts(rx, len(cfg["pkts"]), cfg["spi"], cfg["udp"])
844 # add some tunnels, make sure it still punts
846 tun = VppIpsecInterface(self).add_vpp_config()
851 (VppEnum.vl_api_ipsec_integ_alg_t.IPSEC_API_INTEG_ALG_SHA1_96),
853 (VppEnum.vl_api_ipsec_crypto_alg_t.IPSEC_API_CRYPTO_ALG_AES_CBC_128),
863 (VppEnum.vl_api_ipsec_integ_alg_t.IPSEC_API_INTEG_ALG_SHA1_96),
865 (VppEnum.vl_api_ipsec_crypto_alg_t.IPSEC_API_CRYPTO_ALG_AES_CBC_128),
871 protect = VppIpsecTunProtect(self, tun, sa_out, [sa_in]).add_vpp_config()
874 # send packets for each SPI we expect to be punted
876 for cfg in cfgs.values():
877 self.send_and_assert_no_replies(cfg["itf"], cfg["pkts"])
880 # verify the punted packets arrived on the associated socket
882 for cfg in cfgs.values():
883 rx = cfg["sock"].close()
884 self.verify_esp_pkts(rx, len(cfg["pkts"]), cfg["spi"], cfg["udp"])
888 for cfg in cfgs.values():
889 self.vapi.punt_socket_deregister(cfg["vpp"])
892 class TestIpProtoPuntSocket(TestPuntSocket):
893 """Punt Socket for IP packets"""
897 super(TestIpProtoPuntSocket, cls).setUpClass()
900 def tearDownClass(cls):
901 super(TestIpProtoPuntSocket, cls).tearDownClass()
904 super(TestIpProtoPuntSocket, self).setUp()
906 for i in self.pg_interfaces:
911 super(TestIpProtoPuntSocket, self).tearDown()
912 for i in self.pg_interfaces:
916 def test_registration(self):
917 """Punt socket registration/deregistration"""
919 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
920 pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
921 proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
922 proto_eigrp = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_EIGRP
924 punts = self.vapi.punt_socket_dump(type=pt_ip)
925 self.assertEqual(len(punts), 0)
928 # configure a punt socket
932 "punt": {"ip_proto": {"af": af_ip4, "protocol": proto_ospf}},
936 "punt": {"ip_proto": {"af": af_ip4, "protocol": proto_eigrp}},
939 self.vapi.punt_socket_register(punt_ospf, "%s/socket_punt_1" % self.tempdir)
940 self.vapi.punt_socket_register(punt_eigrp, "%s/socket_punt_2" % self.tempdir)
941 self.logger.info(self.vapi.cli("sh punt sock reg ip"))
942 punts = self.vapi.punt_socket_dump(type=pt_ip)
943 self.assertEqual(len(punts), 2)
944 self.verify_ip_proto(punt_ospf, punts[0])
945 self.verify_ip_proto(punt_eigrp, punts[1])
948 # deregister a punt socket
950 self.vapi.punt_socket_deregister(punt_ospf)
951 punts = self.vapi.punt_socket_dump(type=pt_ip)
952 self.assertEqual(len(punts), 1)
955 # configure a punt socket again
957 self.vapi.punt_socket_register(punt_ospf, "%s/socket_punt_3" % self.tempdir)
958 punts = self.vapi.punt_socket_dump(type=pt_ip)
959 self.assertEqual(len(punts), 2)
961 self.logger.info(self.vapi.cli("sh punt sock reg exception"))
964 # deregister all punt socket
966 self.vapi.punt_socket_deregister(punt_eigrp)
967 self.vapi.punt_socket_deregister(punt_ospf)
968 punts = self.vapi.punt_socket_dump(type=pt_ip)
969 self.assertEqual(len(punts), 0)
971 def verify_ospf_pkts(self, rxs, n_sent):
972 self.assertEqual(len(rxs), n_sent)
974 self.assertTrue(rx.haslayer(OSPF_Hdr))
976 def test_traffic(self):
977 """Punt socket traffic"""
979 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
980 pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
981 proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
984 # configure a punt socket to capture OSPF packets
988 "punt": {"ip_proto": {"af": af_ip4, "protocol": proto_ospf}},
992 # create packet streams and configure a punt sockets
995 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
996 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
1002 sock = self.socket_client_create("%s/socket_1" % self.tempdir)
1003 self.vapi.punt_socket_register(punt_ospf, "%s/socket_1" % self.tempdir)
1006 # send packets for each SPI we expect to be punted
1008 self.send_and_assert_no_replies(self.pg0, pkts)
1011 # verify the punted packets arrived on the associated socket
1014 self.verify_ospf_pkts(rx, len(pkts))
1015 self.vapi.punt_socket_deregister(punt_ospf)
1018 @tag_fixme_vpp_workers
1019 class TestPunt(VppTestCase):
1020 """Exception Punt Test Case"""
1023 def setUpClass(cls):
1024 super(TestPunt, cls).setUpClass()
1027 def tearDownClass(cls):
1028 super(TestPunt, cls).tearDownClass()
1031 super(TestPunt, self).setUp()
1033 self.create_pg_interfaces(range(4))
1035 for i in self.pg_interfaces:
1043 for i in self.pg_interfaces:
1047 super(TestPunt, self).tearDown()
1049 def test_punt(self):
1050 """Exception Path testing"""
1053 # dump the punt registered reasons
1054 # search for a few we know should be there
1056 rs = self.vapi.punt_reason_dump()
1059 "ipsec6-no-such-tunnel",
1060 "ipsec4-no-such-tunnel",
1061 "ipsec4-spi-o-udp-0",
1064 for reason in reasons:
1067 if r.reason.name == reason:
1070 self.assertTrue(found)
1073 # Using the test CLI we will hook in a exception path to
1074 # send ACL deny packets out of pg0 and pg1.
1075 # the ACL is src,dst = 1.1.1.1,1.1.1.2
1077 ip_1_1_1_2 = VppIpRoute(
1081 [VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index)],
1083 ip_1_1_1_2.add_vpp_config()
1084 ip_1_2 = VppIpRoute(
1090 self.pg3.remote_ip6,
1091 self.pg3.sw_if_index,
1092 proto=DpoProto.DPO_PROTO_IP6,
1096 ip_1_2.add_vpp_config()
1099 Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac)
1100 / IP(src="1.1.1.1", dst="1.1.1.2")
1101 / UDP(sport=1234, dport=1234)
1102 / Raw(b"\xa5" * 100)
1105 Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac)
1106 / IPv6(src="1::1", dst="1::2")
1107 / UDP(sport=1234, dport=1234)
1108 / Raw(b"\xa5" * 100)
1110 self.send_and_expect(self.pg2, p4 * 1, self.pg3)
1111 self.send_and_expect(self.pg2, p6 * 1, self.pg3)
1114 # apply the punting features
1116 self.vapi.cli("test punt pg2")
1119 # dump the punt reasons to learn the IDs assigned
1121 rs = self.vapi.punt_reason_dump(reason={"name": "reason-v4"})
1122 r4 = rs[0].reason.id
1123 rs = self.vapi.punt_reason_dump(reason={"name": "reason-v6"})
1124 r6 = rs[0].reason.id
1129 self.send_and_assert_no_replies(self.pg2, p4 * NUM_PKTS)
1130 self.send_and_assert_no_replies(self.pg2, p6 * NUM_PKTS)
1134 # 1 - node error counters
1135 # 2 - per-reason counters
1136 # 2, 3 are the index of the assigned punt reason
1138 stats = self.statistics.get_err_counter("/err/punt-dispatch/No registrations")
1139 self.assertEqual(stats, 2 * NUM_PKTS)
1141 stats = self.statistics.get_counter("/net/punt")
1142 self.assertEqual(stats[0][r4]["packets"], NUM_PKTS)
1143 self.assertEqual(stats[0][r6]["packets"], NUM_PKTS)
1146 # use the test CLI to test a client that punts exception
1147 # packets out of pg0
1149 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip4)
1150 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip6)
1152 rx4s = self.send_and_expect(self.pg2, p4 * NUM_PKTS, self.pg0)
1153 rx6s = self.send_and_expect(self.pg2, p6 * NUM_PKTS, self.pg0)
1156 # check the packets come out IP unmodified but destined to pg0 host
1159 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1160 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1161 self.assertEqual(p4[IP].dst, rx[IP].dst)
1162 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1164 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1165 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1166 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1167 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1169 stats = self.statistics.get_counter("/net/punt")
1170 self.assertEqual(stats[0][r4]["packets"], 2 * NUM_PKTS)
1171 self.assertEqual(stats[0][r6]["packets"], 2 * NUM_PKTS)
1174 # add another registration for the same reason to send packets
1177 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip4)
1178 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip6)
1180 self.vapi.cli("clear trace")
1181 self.pg2.add_stream(p4 * NUM_PKTS)
1182 self.pg_enable_capture(self.pg_interfaces)
1185 rxd = self.pg0.get_capture(NUM_PKTS)
1187 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1188 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1189 self.assertEqual(p4[IP].dst, rx[IP].dst)
1190 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1191 rxd = self.pg1.get_capture(NUM_PKTS)
1193 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1194 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1195 self.assertEqual(p4[IP].dst, rx[IP].dst)
1196 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1198 self.vapi.cli("clear trace")
1199 self.pg2.add_stream(p6 * NUM_PKTS)
1200 self.pg_enable_capture(self.pg_interfaces)
1203 rxd = self.pg0.get_capture(NUM_PKTS)
1205 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1206 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1207 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1208 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1209 rxd = self.pg1.get_capture(NUM_PKTS)
1211 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1212 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1213 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1214 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1216 stats = self.statistics.get_counter("/net/punt")
1217 self.assertEqual(stats[0][r4]["packets"], 3 * NUM_PKTS)
1218 self.assertEqual(stats[0][r6]["packets"], 3 * NUM_PKTS)
1220 self.logger.info(self.vapi.cli("show vlib graph punt-dispatch"))
1221 self.logger.info(self.vapi.cli("show punt client"))
1222 self.logger.info(self.vapi.cli("show punt reason"))
1223 self.logger.info(self.vapi.cli("show punt stats"))
1224 self.logger.info(self.vapi.cli("show punt db"))
1227 if __name__ == "__main__":
1228 unittest.main(testRunner=VppTestRunner)