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.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
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
42 class serverSocketThread(threading.Thread):
43 """Socket server thread"""
45 def __init__(self, threadID, sockName):
46 threading.Thread.__init__(self)
47 self.threadID = threadID
48 self.sockName = sockName
51 self.stop_running = False
54 # Wait for some packets on socket
57 data = self.sock.recv(65536)
59 # punt socket metadata
60 # packet_desc = data[0:8]
63 self.rx_pkts.append(Ether(data[8:]))
66 # nothing to receive, stop running or sleep a little
75 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
77 os.unlink(self.sockName)
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)
88 self.stop_running = True
89 threading.Thread.join(self)
94 class TestPuntSocket(VppTestCase):
97 ports = [1111, 2222, 3333, 4444]
99 # FIXME: nr_packets > 3 results in failure
100 # nr_packets = 3 makes the test unstable
105 super(TestPuntSocket, cls).setUpClass()
108 def tearDownClass(cls):
109 super(TestPuntSocket, cls).tearDownClass()
112 def setUpConstants(cls):
113 cls.extra_vpp_config = [
117 cls.tempdir + "/socket_punt",
120 super(TestPuntSocket, cls).setUpConstants()
123 super(TestPuntSocket, self).setUp()
126 self.create_pg_interfaces(range(2))
127 for i in self.pg_interfaces:
131 del self.sock_servers[:]
132 super(TestPuntSocket, self).tearDown()
134 def socket_client_create(self, sock_name, id=None):
135 thread = serverSocketThread(id, sock_name)
136 self.sock_servers.append(thread)
140 def socket_client_close(self):
142 for thread in self.sock_servers:
143 rx_pkts += thread.close()
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"])
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"])
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"])
160 vpr.punt.punt.ip_proto.protocol, pr["punt"]["ip_proto"]["protocol"]
163 def verify_udp_pkts(self, rxs, n_rx, port):
166 self.assertTrue(rx.haslayer(UDP))
167 if rx[UDP].dport == port:
169 self.assertEqual(n_match, n_rx)
172 def set_port(pr, port):
173 pr["punt"]["l4"]["port"] = port
177 def set_reason(pr, reason):
178 pr["punt"]["exception"]["id"] = reason
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}}}
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}}}
198 class TestIP4PuntSocket(TestPuntSocket):
199 """Punt Socket for IPv4 UDP"""
203 super(TestIP4PuntSocket, cls).setUpClass()
206 def tearDownClass(cls):
207 super(TestIP4PuntSocket, cls).tearDownClass()
210 super(TestIP4PuntSocket, self).setUp()
212 for i in self.pg_interfaces:
217 super(TestIP4PuntSocket, self).tearDown()
218 for i in self.pg_interfaces:
222 def test_punt_socket_dump(self):
223 """Punt socket registration/deregistration"""
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
229 punts = self.vapi.punt_socket_dump(type=pt_l4)
230 self.assertEqual(len(punts), 0)
233 # configure a punt socket
235 punt_l4 = mk_vpp_cfg4()
237 self.vapi.punt_socket_register(
238 set_port(punt_l4, 1111), "%s/socket_punt_1111" % self.tempdir
240 self.vapi.punt_socket_register(
241 set_port(punt_l4, 2222), "%s/socket_punt_2222" % self.tempdir
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])
249 # deregister a punt socket
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)
256 # configure a punt socket again
258 self.vapi.punt_socket_register(
259 set_port(punt_l4, 1111), "%s/socket_punt_1111" % self.tempdir
261 self.vapi.punt_socket_register(
262 set_port(punt_l4, 3333), "%s/socket_punt_3333" % self.tempdir
264 punts = self.vapi.punt_socket_dump(type=pt_l4)
265 self.assertEqual(len(punts), 3)
267 self.logger.info(self.vapi.cli("sh punt sock reg"))
270 # deregister all punt socket
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)
278 def test_punt_socket_traffic_single_port_single_socket(self):
279 """Punt socket traffic single port single socket"""
282 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
283 punt_l4 = set_port(mk_vpp_cfg4(), port)
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)
292 pkts = p * self.nr_packets
294 punts = self.vapi.punt_socket_dump(type=pt_l4)
295 self.assertEqual(len(punts), 0)
298 # expect ICMP - port unreachable for all packets
300 rx = self.send_and_expect_some(self.pg0, pkts, self.pg0)
303 self.assertEqual(int(p[IP].proto), 1) # ICMP
304 self.assertEqual(int(p[ICMP].code), 3) # unreachable
307 # configure a punt socket
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)
315 # expect punt socket and no packets on pg0
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)
322 # remove punt socket. expect ICMP - port unreachable for all packets
324 self.vapi.punt_socket_deregister(punt_l4)
325 punts = self.vapi.punt_socket_dump(type=pt_l4)
326 self.assertEqual(len(punts), 0)
328 rx = self.send_and_expect_some(self.pg0, pkts, self.pg0)
330 self.assertEqual(int(p[IP].proto), 1) # ICMP
331 self.assertEqual(int(p[ICMP].code), 3) # unreachable
333 def test_punt_socket_traffic_multi_ports_multi_sockets(self):
334 """Punt socket traffic multi ports and multi sockets"""
336 punt_l4 = mk_vpp_cfg4()
338 # configuration for each UDP port
342 # create stream of packets for each port
344 for port in self.ports:
345 # choose port from port list
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)
354 cfgs[port]["pkts"] = pkt * self.nr_packets
355 cfgs[port]["port"] = port
356 cfgs[port]["vpp"] = copy.deepcopy(set_port(punt_l4, port))
358 # configure punt sockets
359 cfgs[port]["sock"] = self.socket_client_create(
360 "%s/socket_%d" % (self.tempdir, port)
362 self.vapi.punt_socket_register(
363 cfgs[port]["vpp"], "%s/socket_%d" % (self.tempdir, port)
367 # send the packets that get punted
369 for cfg in cfgs.values():
370 self.send_and_assert_no_replies(self.pg0, cfg["pkts"])
373 # test that we got the excepted packets on the expected socket
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"])
380 def test_punt_socket_traffic_multi_ports_single_socket(self):
381 """Punt socket traffic multi ports and single socket"""
383 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
384 punt_l4 = mk_vpp_cfg4()
387 # create stream of packets with each port
390 for port in self.ports:
391 # choose port from port list
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)
398 pkts += pkt * self.nr_packets
401 # configure a punt socket
403 self.socket_client_create("%s/socket_multi" % self.tempdir)
405 self.vapi.punt_socket_register(
406 set_port(punt_l4, p), "%s/socket_multi" % self.tempdir
408 punts = self.vapi.punt_socket_dump(type=pt_l4)
409 self.assertEqual(len(punts), len(self.ports))
412 # expect punt socket and no packets on pg0
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()
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)
425 class TestIP6PuntSocket(TestPuntSocket):
426 """Punt Socket for IPv6 UDP"""
430 super(TestIP6PuntSocket, cls).setUpClass()
433 def tearDownClass(cls):
434 super(TestIP6PuntSocket, cls).tearDownClass()
437 super(TestIP6PuntSocket, self).setUp()
439 for i in self.pg_interfaces:
444 super(TestIP6PuntSocket, self).tearDown()
445 for i in self.pg_interfaces:
449 def test_punt_socket_dump(self):
450 """Punt socket registration"""
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
456 # configure a punt socket
458 punt_l4 = {"type": pt_l4, "punt": {"l4": {"af": af_ip6, "protocol": udp_proto}}}
460 punts = self.vapi.punt_socket_dump(type=pt_l4)
461 self.assertEqual(len(punts), 0)
464 # configure a punt socket
466 self.vapi.punt_socket_register(
467 set_port(punt_l4, 1111), "%s/socket_1111" % self.tempdir
469 self.vapi.punt_socket_register(
470 set_port(punt_l4, 2222), "%s/socket_2222" % self.tempdir
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])
478 # deregister a punt socket
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)
485 # configure a punt socket again
487 self.vapi.punt_socket_register(
488 set_port(punt_l4, 1111), "%s/socket_1111" % self.tempdir
490 punts = self.vapi.punt_socket_dump(type=pt_l4)
491 self.assertEqual(len(punts), 2)
494 # deregister all punt socket
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)
502 def test_punt_socket_traffic_single_port_single_socket(self):
503 """Punt socket traffic single port single socket"""
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
514 "protocol": udp_proto,
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)
527 pkts = p * self.nr_packets
529 punts = self.vapi.punt_socket_dump(type=pt_l4)
530 self.assertEqual(len(punts), 0)
533 # expect ICMPv6 - destination unreachable for all packets
535 self.vapi.cli("clear trace")
536 self.pg0.add_stream(pkts)
537 self.pg_enable_capture(self.pg_interfaces)
539 # FIXME - when punt socket deregister is implemented
540 # rx = self.pg0.get_capture(self.nr_packets)
542 # self.assertEqual(int(p[IPv6].nh), 58) # ICMPv6
543 # self.assertEqual(int(p[ICMPv6DestUnreach].code),4) # unreachable
546 # configure a punt socket
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)
554 # expect punt socket and no packets on pg0
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)
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)
567 # remove punt socket. expect ICMP - dest. unreachable for all packets
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)
575 # FIXME - when punt socket deregister is implemented
576 # self.pg0.get_capture(nr_packets)
578 def test_punt_socket_traffic_multi_ports_multi_sockets(self):
579 """Punt socket traffic multi ports and multi sockets"""
581 punt_l4 = mk_vpp_cfg6()
583 # configuration for each UDP port
587 # create stream of packets for each port
589 for port in self.ports:
590 # choose port from port list
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)
599 cfgs[port]["pkts"] = pkt * self.nr_packets
600 cfgs[port]["port"] = port
601 cfgs[port]["vpp"] = copy.deepcopy(set_port(punt_l4, port))
603 # configure punt sockets
604 cfgs[port]["sock"] = self.socket_client_create(
605 "%s/socket_%d" % (self.tempdir, port)
607 self.vapi.punt_socket_register(
608 cfgs[port]["vpp"], "%s/socket_%d" % (self.tempdir, port)
612 # send the packets that get punted
614 for cfg in cfgs.values():
615 self.send_and_assert_no_replies(self.pg0, cfg["pkts"])
618 # test that we got the excepted packets on the expected socket
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"])
625 def test_punt_socket_traffic_multi_ports_single_socket(self):
626 """Punt socket traffic multi ports and single socket"""
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
636 "protocol": udp_proto,
642 # create stream of packets with each port
645 for port in self.ports:
646 # choose port from port list
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)
653 pkts += pkt * self.nr_packets
658 punts = self.vapi.punt_socket_dump(type=pt_l4)
659 self.assertEqual(len(punts), 0)
662 # configure a punt socket
664 self.socket_client_create("%s/socket_multi" % self.tempdir)
666 self.vapi.punt_socket_register(
667 set_port(punt_l4, p), "%s/socket_multi" % self.tempdir
669 punts = self.vapi.punt_socket_dump(type=pt_l4)
670 self.assertEqual(len(punts), len(self.ports))
673 # expect punt socket and no packets on pg0
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)
680 # give a chance to punt socket to collect all packets
682 self.pg0.get_capture(0)
683 rx = self.socket_client_close()
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)
692 class TestExceptionPuntSocket(TestPuntSocket):
693 """Punt Socket for Exceptions"""
697 super(TestExceptionPuntSocket, cls).setUpClass()
700 def tearDownClass(cls):
701 super(TestExceptionPuntSocket, cls).tearDownClass()
704 super(TestExceptionPuntSocket, self).setUp()
706 self.create_pg_interfaces(range(2))
707 for i in self.pg_interfaces:
712 super(TestExceptionPuntSocket, self).tearDown()
713 for i in self.pg_interfaces:
717 def test_registration(self):
718 """Punt socket registration/deregistration"""
720 pt_ex = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_EXCEPTION
722 punts = self.vapi.punt_socket_dump(type=pt_ex)
723 self.assertEqual(len(punts), 0)
726 # configure a punt socket
728 punt_ex = {"type": pt_ex, "punt": {"exception": {}}}
730 self.vapi.punt_socket_register(
731 set_reason(punt_ex, 1), "%s/socket_punt_1" % self.tempdir
733 self.vapi.punt_socket_register(
734 set_reason(punt_ex, 2), "%s/socket_punt_2" % self.tempdir
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])
742 # deregister a punt socket
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)
749 # configure a punt socket again
751 self.vapi.punt_socket_register(
752 set_reason(punt_ex, 1), "%s/socket_punt_1" % self.tempdir
754 self.vapi.punt_socket_register(
755 set_reason(punt_ex, 3), "%s/socket_punt_3" % self.tempdir
757 punts = self.vapi.punt_socket_dump(type=pt_ex)
758 self.assertEqual(len(punts), 3)
760 self.logger.info(self.vapi.cli("sh punt sock reg exception"))
763 # deregister all punt socket
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)
771 def verify_esp_pkts(self, rxs, n_sent, spi, has_udp):
772 self.assertEqual(len(rxs), n_sent)
774 self.assertTrue(rx.haslayer(IP))
775 self.assertTrue(rx.haslayer(ESP))
776 self.assertEqual(rx[ESP].spi, spi)
778 self.assertTrue(rx.haslayer(UDP))
780 def test_traffic(self):
781 """Punt socket traffic"""
784 pt_ex = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_EXCEPTION
785 punt_ex = {"type": pt_ex, "punt": {"exception": {}}}
788 # we're dealing with IPSec tunnels punting for no-such-tunnel
789 # (SPI=0 goes to ikev2)
792 cfgs["ipsec4-no-such-tunnel"] = {"spi": 99, "udp": False, "itf": self.pg0}
795 # find the VPP ID for these punt exception reasin
797 rs = self.vapi.punt_reason_dump()
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"])
810 # configure punt sockets
812 for cfg in cfgs.values():
813 cfg["sock"] = self.socket_client_create(
814 "%s/socket_%d" % (self.tempdir, cfg["id"])
816 self.vapi.punt_socket_register(
817 cfg["vpp"], "%s/socket_%d" % (self.tempdir, cfg["id"])
821 # create packet streams for 'no-such-tunnel' exception
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
828 pkt = pkt / UDP(sport=666, dport=4500)
829 pkt = pkt / ESP(spi=cfg["spi"], seq=3) / Raw(b"\xa5" * 100)
833 # send packets for each SPI we expect to be punted
835 for cfg in cfgs.values():
836 self.send_and_assert_no_replies(cfg["itf"], cfg["pkts"])
839 # verify the punted packets arrived on the associated socket
841 for cfg in cfgs.values():
842 rx = cfg["sock"].close()
843 self.verify_esp_pkts(rx, len(cfg["pkts"]), cfg["spi"], cfg["udp"])
846 # add some tunnels, make sure it still punts
848 tun = VppIpsecInterface(self).add_vpp_config()
853 (VppEnum.vl_api_ipsec_integ_alg_t.IPSEC_API_INTEG_ALG_SHA1_96),
855 (VppEnum.vl_api_ipsec_crypto_alg_t.IPSEC_API_CRYPTO_ALG_AES_CBC_128),
865 (VppEnum.vl_api_ipsec_integ_alg_t.IPSEC_API_INTEG_ALG_SHA1_96),
867 (VppEnum.vl_api_ipsec_crypto_alg_t.IPSEC_API_CRYPTO_ALG_AES_CBC_128),
873 protect = VppIpsecTunProtect(self, tun, sa_out, [sa_in]).add_vpp_config()
876 # send packets for each SPI we expect to be punted
878 for cfg in cfgs.values():
879 self.send_and_assert_no_replies(cfg["itf"], cfg["pkts"])
882 # verify the punted packets arrived on the associated socket
884 for cfg in cfgs.values():
885 rx = cfg["sock"].close()
886 self.verify_esp_pkts(rx, len(cfg["pkts"]), cfg["spi"], cfg["udp"])
890 for cfg in cfgs.values():
891 self.vapi.punt_socket_deregister(cfg["vpp"])
894 class TestIpProtoPuntSocket(TestPuntSocket):
895 """Punt Socket for IP packets"""
899 super(TestIpProtoPuntSocket, cls).setUpClass()
902 def tearDownClass(cls):
903 super(TestIpProtoPuntSocket, cls).tearDownClass()
906 super(TestIpProtoPuntSocket, self).setUp()
908 for i in self.pg_interfaces:
913 super(TestIpProtoPuntSocket, self).tearDown()
914 for i in self.pg_interfaces:
918 def test_registration(self):
919 """Punt socket registration/deregistration"""
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
926 punts = self.vapi.punt_socket_dump(type=pt_ip)
927 self.assertEqual(len(punts), 0)
930 # configure a punt socket
934 "punt": {"ip_proto": {"af": af_ip4, "protocol": proto_ospf}},
938 "punt": {"ip_proto": {"af": af_ip4, "protocol": proto_eigrp}},
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])
950 # deregister a punt socket
952 self.vapi.punt_socket_deregister(punt_ospf)
953 punts = self.vapi.punt_socket_dump(type=pt_ip)
954 self.assertEqual(len(punts), 1)
957 # configure a punt socket again
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)
963 self.logger.info(self.vapi.cli("sh punt sock reg exception"))
966 # deregister all punt socket
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)
973 def verify_ospf_pkts(self, rxs, n_sent):
974 self.assertEqual(len(rxs), n_sent)
976 self.assertTrue(rx.haslayer(OSPF_Hdr))
978 def test_traffic(self):
979 """Punt socket traffic"""
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
986 # configure a punt socket to capture OSPF packets
990 "punt": {"ip_proto": {"af": af_ip4, "protocol": proto_ospf}},
994 # create packet streams and configure a punt sockets
997 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
998 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
1004 sock = self.socket_client_create("%s/socket_1" % self.tempdir)
1005 self.vapi.punt_socket_register(punt_ospf, "%s/socket_1" % self.tempdir)
1008 # send packets for each SPI we expect to be punted
1010 self.send_and_assert_no_replies(self.pg0, pkts)
1013 # verify the punted packets arrived on the associated socket
1016 self.verify_ospf_pkts(rx, len(pkts))
1017 self.vapi.punt_socket_deregister(punt_ospf)
1020 class TestDot1QPuntSocket(TestPuntSocket):
1021 """Punt Socket for 802.1Q (dot1q)"""
1024 super(TestDot1QPuntSocket, self).setUp()
1026 for i in self.pg_interfaces:
1032 super(TestDot1QPuntSocket, self).tearDown()
1033 for i in self.pg_interfaces:
1037 def test_dot1q_header_punt(self):
1038 """Punt socket traffic with Dot1q header"""
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)
1047 # Create a subinterface with the VLAN ID
1048 subif = VppDot1QSubint(self, self.pg0, vlan_id)
1052 # Configure an IP address on the subinterface
1053 subif_ip4 = subif.local_ip4
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)
1063 pkts = p * self.nr_packets
1065 # Expect ICMP - port unreachable for all packets
1066 rx = self.send_and_expect_some(self.pg0, pkts, self.pg0)
1069 self.assertEqual(int(p[IP].proto), 1) # ICMP
1070 self.assertEqual(int(p[ICMP].code), 3) # unreachable
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)
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)
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)
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)
1094 rx = self.send_and_expect_some(self.pg0, pkts, self.pg0)
1096 self.assertEqual(int(p[IP].proto), 1) # ICMP
1097 self.assertEqual(int(p[ICMP].code), 3) # unreachable
1100 @tag_fixme_vpp_workers
1101 class TestPunt(VppTestCase):
1102 """Exception Punt Test Case"""
1105 def setUpClass(cls):
1106 super(TestPunt, cls).setUpClass()
1109 def tearDownClass(cls):
1110 super(TestPunt, cls).tearDownClass()
1113 super(TestPunt, self).setUp()
1115 self.create_pg_interfaces(range(4))
1117 for i in self.pg_interfaces:
1125 for i in self.pg_interfaces:
1129 super(TestPunt, self).tearDown()
1131 def test_punt(self):
1132 """Exception Path testing"""
1135 # dump the punt registered reasons
1136 # search for a few we know should be there
1138 rs = self.vapi.punt_reason_dump()
1141 "ipsec6-no-such-tunnel",
1142 "ipsec4-no-such-tunnel",
1143 "ipsec4-spi-o-udp-0",
1146 for reason in reasons:
1149 if r.reason.name == reason:
1152 self.assertTrue(found)
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
1159 ip_1_1_1_2 = VppIpRoute(
1163 [VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index)],
1165 ip_1_1_1_2.add_vpp_config()
1166 ip_1_2 = VppIpRoute(
1172 self.pg3.remote_ip6,
1173 self.pg3.sw_if_index,
1174 proto=DpoProto.DPO_PROTO_IP6,
1178 ip_1_2.add_vpp_config()
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)
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)
1192 self.send_and_expect(self.pg2, p4 * 1, self.pg3)
1193 self.send_and_expect(self.pg2, p6 * 1, self.pg3)
1196 # apply the punting features
1198 self.vapi.cli("test punt pg2")
1201 # dump the punt reasons to learn the IDs assigned
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
1211 self.send_and_assert_no_replies(self.pg2, p4 * NUM_PKTS)
1212 self.send_and_assert_no_replies(self.pg2, p6 * NUM_PKTS)
1216 # 1 - node error counters
1217 # 2 - per-reason counters
1218 # 2, 3 are the index of the assigned punt reason
1220 stats = self.statistics.get_err_counter("/err/punt-dispatch/No registrations")
1221 self.assertEqual(stats, 2 * NUM_PKTS)
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)
1228 # use the test CLI to test a client that punts exception
1229 # packets out of pg0
1231 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip4)
1232 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip6)
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)
1238 # check the packets come out IP unmodified but destined to pg0 host
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)
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)
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)
1256 # add another registration for the same reason to send packets
1259 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip4)
1260 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip6)
1262 self.vapi.cli("clear trace")
1263 self.pg2.add_stream(p4 * NUM_PKTS)
1264 self.pg_enable_capture(self.pg_interfaces)
1267 rxd = self.pg0.get_capture(NUM_PKTS)
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)
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)
1280 self.vapi.cli("clear trace")
1281 self.pg2.add_stream(p6 * NUM_PKTS)
1282 self.pg_enable_capture(self.pg_interfaces)
1285 rxd = self.pg0.get_capture(NUM_PKTS)
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)
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)
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)
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"))
1309 if __name__ == "__main__":
1310 unittest.main(testRunner=VppTestRunner)