12 import unittest2 as unittest
16 from scapy.packet import Raw
17 from scapy.layers.l2 import Ether
18 from scapy.layers.l2 import Dot1Q
19 from scapy.layers.inet import IP, UDP, ICMP
20 from scapy.layers.ipsec import ESP
21 import scapy.layers.inet6 as inet6
22 from scapy.layers.inet6 import IPv6
23 from scapy.contrib.ospf import OSPF_Hdr, OSPFv3_Hello
24 from framework import VppTestCase
25 from asfframework import VppTestRunner, tag_fixme_vpp_workers
26 from vpp_sub_interface import VppDot1QSubint
28 from vpp_ip import DpoProto
29 from vpp_ip_route import VppIpRoute, VppRoutePath
30 from vpp_ipsec import VppIpsecSA, VppIpsecTunProtect, VppIpsecInterface
31 from vpp_papi import VppEnum
36 class serverSocketThread(threading.Thread):
37 """Socket server thread"""
39 def __init__(self, threadID, sockName):
40 threading.Thread.__init__(self)
41 self.threadID = threadID
42 self.sockName = sockName
45 self.stop_running = False
48 # Wait for some packets on socket
51 data = self.sock.recv(65536)
53 # punt socket metadata
54 # packet_desc = data[0:8]
57 self.rx_pkts.append(Ether(data[8:]))
59 if e.errno == errno.EAGAIN:
60 # nothing to receive, stop running or sleep a little
69 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
71 os.unlink(self.sockName)
74 self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 65536)
75 self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 65536)
76 fcntl.fcntl(self.sock, fcntl.F_SETFL, os.O_NONBLOCK)
77 self.sock.bind(self.sockName)
82 self.stop_running = True
83 threading.Thread.join(self)
88 class TestPuntSocket(VppTestCase):
91 ports = [1111, 2222, 3333, 4444]
93 # FIXME: nr_packets > 3 results in failure
94 # nr_packets = 3 makes the test unstable
99 super(TestPuntSocket, cls).setUpClass()
102 def tearDownClass(cls):
103 super(TestPuntSocket, cls).tearDownClass()
106 def setUpConstants(cls):
107 cls.extra_vpp_config = [
111 cls.tempdir + "/socket_punt",
114 super(TestPuntSocket, cls).setUpConstants()
117 super(TestPuntSocket, self).setUp()
120 self.create_pg_interfaces(range(2))
121 for i in self.pg_interfaces:
125 del self.sock_servers[:]
126 super(TestPuntSocket, self).tearDown()
128 def socket_client_create(self, sock_name, id=None):
129 thread = serverSocketThread(id, sock_name)
130 self.sock_servers.append(thread)
134 def socket_client_close(self):
136 for thread in self.sock_servers:
137 rx_pkts += thread.close()
140 def verify_port(self, pr, vpr):
141 self.assertEqual(vpr.punt.type, pr["type"])
142 self.assertEqual(vpr.punt.punt.l4.port, pr["punt"]["l4"]["port"])
143 self.assertEqual(vpr.punt.punt.l4.protocol, pr["punt"]["l4"]["protocol"])
144 self.assertEqual(vpr.punt.punt.l4.af, pr["punt"]["l4"]["af"])
146 def verify_exception(self, pr, vpr):
147 self.assertEqual(vpr.punt.type, pr["type"])
148 self.assertEqual(vpr.punt.punt.exception.id, pr["punt"]["exception"]["id"])
150 def verify_ip_proto(self, pr, vpr):
151 self.assertEqual(vpr.punt.type, pr["type"])
152 self.assertEqual(vpr.punt.punt.ip_proto.af, pr["punt"]["ip_proto"]["af"])
154 vpr.punt.punt.ip_proto.protocol, pr["punt"]["ip_proto"]["protocol"]
157 def verify_udp_pkts(self, rxs, n_rx, port):
160 self.assertTrue(rx.haslayer(UDP))
161 if rx[UDP].dport == port:
163 self.assertEqual(n_match, n_rx)
166 def set_port(pr, port):
167 pr["punt"]["l4"]["port"] = port
171 def set_reason(pr, reason):
172 pr["punt"]["exception"]["id"] = reason
177 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
178 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
179 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
180 punt_l4 = {"type": pt_l4, "punt": {"l4": {"af": af_ip4, "protocol": udp_proto}}}
185 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
186 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
187 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
188 punt_l4 = {"type": pt_l4, "punt": {"l4": {"af": af_ip6, "protocol": udp_proto}}}
192 class TestIP4PuntSocket(TestPuntSocket):
193 """Punt Socket for IPv4 UDP"""
197 super(TestIP4PuntSocket, cls).setUpClass()
200 def tearDownClass(cls):
201 super(TestIP4PuntSocket, cls).tearDownClass()
204 super(TestIP4PuntSocket, self).setUp()
206 for i in self.pg_interfaces:
211 super(TestIP4PuntSocket, self).tearDown()
212 for i in self.pg_interfaces:
216 def test_punt_socket_dump(self):
217 """Punt socket registration/deregistration"""
219 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
220 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
221 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
223 punts = self.vapi.punt_socket_dump(type=pt_l4)
224 self.assertEqual(len(punts), 0)
227 # configure a punt socket
229 punt_l4 = mk_vpp_cfg4()
231 self.vapi.punt_socket_register(
232 set_port(punt_l4, 1111), "%s/socket_punt_1111" % self.tempdir
234 self.vapi.punt_socket_register(
235 set_port(punt_l4, 2222), "%s/socket_punt_2222" % self.tempdir
237 punts = self.vapi.punt_socket_dump(type=pt_l4)
238 self.assertEqual(len(punts), 2)
239 self.verify_port(set_port(punt_l4, 1111), punts[0])
240 self.verify_port(set_port(punt_l4, 2222), punts[1])
243 # deregister a punt socket
245 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
246 punts = self.vapi.punt_socket_dump(type=pt_l4)
247 self.assertEqual(len(punts), 1)
250 # configure a punt socket again
252 self.vapi.punt_socket_register(
253 set_port(punt_l4, 1111), "%s/socket_punt_1111" % self.tempdir
255 self.vapi.punt_socket_register(
256 set_port(punt_l4, 3333), "%s/socket_punt_3333" % self.tempdir
258 punts = self.vapi.punt_socket_dump(type=pt_l4)
259 self.assertEqual(len(punts), 3)
261 self.logger.info(self.vapi.cli("sh punt sock reg"))
264 # deregister all punt socket
266 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
267 self.vapi.punt_socket_deregister(set_port(punt_l4, 2222))
268 self.vapi.punt_socket_deregister(set_port(punt_l4, 3333))
269 punts = self.vapi.punt_socket_dump(type=pt_l4)
270 self.assertEqual(len(punts), 0)
272 def test_punt_socket_traffic_single_port_single_socket(self):
273 """Punt socket traffic single port single socket"""
276 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
277 punt_l4 = set_port(mk_vpp_cfg4(), port)
280 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
281 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
282 / UDP(sport=9876, dport=port)
286 pkts = p * self.nr_packets
288 punts = self.vapi.punt_socket_dump(type=pt_l4)
289 self.assertEqual(len(punts), 0)
292 # expect ICMP - port unreachable for all packets
294 rx = self.send_and_expect_some(self.pg0, pkts, self.pg0)
297 self.assertEqual(int(p[IP].proto), 1) # ICMP
298 self.assertEqual(int(p[ICMP].code), 3) # unreachable
301 # configure a punt socket
303 self.socket_client_create("%s/socket_%d" % (self.tempdir, port))
304 self.vapi.punt_socket_register(punt_l4, "%s/socket_%d" % (self.tempdir, port))
305 punts = self.vapi.punt_socket_dump(type=pt_l4)
306 self.assertEqual(len(punts), 1)
309 # expect punt socket and no packets on pg0
311 self.send_and_assert_no_replies(self.pg0, pkts)
312 rx = self.socket_client_close()
313 self.verify_udp_pkts(rx, len(pkts), port)
316 # remove punt socket. expect ICMP - port unreachable for all packets
318 self.vapi.punt_socket_deregister(punt_l4)
319 punts = self.vapi.punt_socket_dump(type=pt_l4)
320 self.assertEqual(len(punts), 0)
322 rx = self.send_and_expect_some(self.pg0, pkts, self.pg0)
324 self.assertEqual(int(p[IP].proto), 1) # ICMP
325 self.assertEqual(int(p[ICMP].code), 3) # unreachable
327 def test_punt_socket_traffic_multi_ports_multi_sockets(self):
328 """Punt socket traffic multi ports and multi sockets"""
330 punt_l4 = mk_vpp_cfg4()
332 # configuration for each UDP port
336 # create stream of packets for each port
338 for port in self.ports:
339 # choose port from port list
343 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
344 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
345 / UDP(sport=9876, dport=port)
348 cfgs[port]["pkts"] = pkt * self.nr_packets
349 cfgs[port]["port"] = port
350 cfgs[port]["vpp"] = copy.deepcopy(set_port(punt_l4, port))
352 # configure punt sockets
353 cfgs[port]["sock"] = self.socket_client_create(
354 "%s/socket_%d" % (self.tempdir, port)
356 self.vapi.punt_socket_register(
357 cfgs[port]["vpp"], "%s/socket_%d" % (self.tempdir, port)
361 # send the packets that get punted
363 for cfg in cfgs.values():
364 self.send_and_assert_no_replies(self.pg0, cfg["pkts"])
367 # test that we got the excepted packets on the expected socket
369 for cfg in cfgs.values():
370 rx = cfg["sock"].close()
371 self.verify_udp_pkts(rx, len(cfg["pkts"]), cfg["port"])
372 self.vapi.punt_socket_deregister(cfg["vpp"])
374 def test_punt_socket_traffic_multi_ports_single_socket(self):
375 """Punt socket traffic multi ports and single socket"""
377 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
378 punt_l4 = mk_vpp_cfg4()
381 # create stream of packets with each port
384 for port in self.ports:
385 # choose port from port list
387 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
388 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
389 / UDP(sport=9876, dport=port)
392 pkts += pkt * self.nr_packets
395 # configure a punt socket
397 self.socket_client_create("%s/socket_multi" % self.tempdir)
399 self.vapi.punt_socket_register(
400 set_port(punt_l4, p), "%s/socket_multi" % self.tempdir
402 punts = self.vapi.punt_socket_dump(type=pt_l4)
403 self.assertEqual(len(punts), len(self.ports))
406 # expect punt socket and no packets on pg0
408 self.send_and_assert_no_replies(self.pg0, pkts)
409 self.logger.info(self.vapi.cli("show trace"))
410 rx = self.socket_client_close()
413 self.verify_udp_pkts(rx, self.nr_packets, p)
414 self.vapi.punt_socket_deregister(set_port(punt_l4, p))
415 punts = self.vapi.punt_socket_dump(type=pt_l4)
416 self.assertEqual(len(punts), 0)
419 class TestIP6PuntSocket(TestPuntSocket):
420 """Punt Socket for IPv6 UDP"""
424 super(TestIP6PuntSocket, cls).setUpClass()
427 def tearDownClass(cls):
428 super(TestIP6PuntSocket, cls).tearDownClass()
431 super(TestIP6PuntSocket, self).setUp()
433 for i in self.pg_interfaces:
438 super(TestIP6PuntSocket, self).tearDown()
439 for i in self.pg_interfaces:
443 def test_punt_socket_dump(self):
444 """Punt socket registration"""
446 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
447 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
448 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
450 # configure a punt socket
452 punt_l4 = {"type": pt_l4, "punt": {"l4": {"af": af_ip6, "protocol": udp_proto}}}
454 punts = self.vapi.punt_socket_dump(type=pt_l4)
455 self.assertEqual(len(punts), 0)
458 # configure a punt socket
460 self.vapi.punt_socket_register(
461 set_port(punt_l4, 1111), "%s/socket_1111" % self.tempdir
463 self.vapi.punt_socket_register(
464 set_port(punt_l4, 2222), "%s/socket_2222" % self.tempdir
466 punts = self.vapi.punt_socket_dump(type=pt_l4)
467 self.assertEqual(len(punts), 2)
468 self.verify_port(set_port(punt_l4, 1111), punts[0])
469 self.verify_port(set_port(punt_l4, 2222), punts[1])
472 # deregister a punt socket
474 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
475 punts = self.vapi.punt_socket_dump(type=pt_l4)
476 self.assertEqual(len(punts), 1)
479 # configure a punt socket again
481 self.vapi.punt_socket_register(
482 set_port(punt_l4, 1111), "%s/socket_1111" % self.tempdir
484 punts = self.vapi.punt_socket_dump(type=pt_l4)
485 self.assertEqual(len(punts), 2)
488 # deregister all punt socket
490 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
491 self.vapi.punt_socket_deregister(set_port(punt_l4, 2222))
492 self.vapi.punt_socket_deregister(set_port(punt_l4, 3333))
493 punts = self.vapi.punt_socket_dump(type=pt_l4)
494 self.assertEqual(len(punts), 0)
496 def test_punt_socket_traffic_single_port_single_socket(self):
497 """Punt socket traffic single port single socket"""
500 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
501 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
502 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
508 "protocol": udp_proto,
515 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
516 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
517 / inet6.UDP(sport=9876, dport=port)
521 pkts = p * self.nr_packets
523 punts = self.vapi.punt_socket_dump(type=pt_l4)
524 self.assertEqual(len(punts), 0)
527 # expect ICMPv6 - destination unreachable for all packets
529 self.vapi.cli("clear trace")
530 self.pg0.add_stream(pkts)
531 self.pg_enable_capture(self.pg_interfaces)
533 # FIXME - when punt socket deregister is implemented
534 # rx = self.pg0.get_capture(self.nr_packets)
536 # self.assertEqual(int(p[IPv6].nh), 58) # ICMPv6
537 # self.assertEqual(int(p[ICMPv6DestUnreach].code),4) # unreachable
540 # configure a punt socket
542 self.socket_client_create("%s/socket_%d" % (self.tempdir, port))
543 self.vapi.punt_socket_register(punt_l4, "%s/socket_%d" % (self.tempdir, port))
544 punts = self.vapi.punt_socket_dump(type=pt_l4)
545 self.assertEqual(len(punts), 1)
548 # expect punt socket and no packets on pg0
550 self.vapi.cli("clear errors")
551 self.vapi.cli("clear trace")
552 self.pg0.add_stream(pkts)
553 self.pg_enable_capture(self.pg_interfaces)
555 self.pg0.get_capture(0)
556 self.logger.info(self.vapi.cli("show trace"))
557 rx = self.socket_client_close()
558 self.verify_udp_pkts(rx, len(pkts), port)
561 # remove punt socket. expect ICMP - dest. unreachable for all packets
563 self.vapi.punt_socket_deregister(punt_l4)
564 punts = self.vapi.punt_socket_dump(type=pt_l4)
565 self.assertEqual(len(punts), 0)
566 self.pg0.add_stream(pkts)
567 self.pg_enable_capture(self.pg_interfaces)
569 # FIXME - when punt socket deregister is implemented
570 # self.pg0.get_capture(nr_packets)
572 def test_punt_socket_traffic_multi_ports_multi_sockets(self):
573 """Punt socket traffic multi ports and multi sockets"""
575 punt_l4 = mk_vpp_cfg6()
577 # configuration for each UDP port
581 # create stream of packets for each port
583 for port in self.ports:
584 # choose port from port list
588 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
589 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
590 / UDP(sport=9876, dport=port)
593 cfgs[port]["pkts"] = pkt * self.nr_packets
594 cfgs[port]["port"] = port
595 cfgs[port]["vpp"] = copy.deepcopy(set_port(punt_l4, port))
597 # configure punt sockets
598 cfgs[port]["sock"] = self.socket_client_create(
599 "%s/socket_%d" % (self.tempdir, port)
601 self.vapi.punt_socket_register(
602 cfgs[port]["vpp"], "%s/socket_%d" % (self.tempdir, port)
606 # send the packets that get punted
608 for cfg in cfgs.values():
609 self.send_and_assert_no_replies(self.pg0, cfg["pkts"])
612 # test that we got the excepted packets on the expected socket
614 for cfg in cfgs.values():
615 rx = cfg["sock"].close()
616 self.verify_udp_pkts(rx, len(cfg["pkts"]), cfg["port"])
617 self.vapi.punt_socket_deregister(cfg["vpp"])
619 def test_punt_socket_traffic_multi_ports_single_socket(self):
620 """Punt socket traffic multi ports and single socket"""
622 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
623 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
624 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
630 "protocol": udp_proto,
636 # create stream of packets with each port
639 for port in self.ports:
640 # choose port from port list
642 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
643 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
644 / UDP(sport=9876, dport=port)
647 pkts += pkt * self.nr_packets
652 punts = self.vapi.punt_socket_dump(type=pt_l4)
653 self.assertEqual(len(punts), 0)
656 # configure a punt socket
658 self.socket_client_create("%s/socket_multi" % self.tempdir)
660 self.vapi.punt_socket_register(
661 set_port(punt_l4, p), "%s/socket_multi" % self.tempdir
663 punts = self.vapi.punt_socket_dump(type=pt_l4)
664 self.assertEqual(len(punts), len(self.ports))
667 # expect punt socket and no packets on pg0
669 self.vapi.cli("clear errors")
670 self.vapi.cli("clear trace")
671 self.pg0.add_stream(pkts)
672 self.pg_enable_capture(self.pg_interfaces)
674 # give a chance to punt socket to collect all packets
676 self.pg0.get_capture(0)
677 rx = self.socket_client_close()
680 self.verify_udp_pkts(rx, self.nr_packets, p)
681 self.vapi.punt_socket_deregister(set_port(punt_l4, p))
682 punts = self.vapi.punt_socket_dump(type=pt_l4)
683 self.assertEqual(len(punts), 0)
686 class TestExceptionPuntSocket(TestPuntSocket):
687 """Punt Socket for Exceptions"""
691 super(TestExceptionPuntSocket, cls).setUpClass()
694 def tearDownClass(cls):
695 super(TestExceptionPuntSocket, cls).tearDownClass()
698 super(TestExceptionPuntSocket, self).setUp()
700 self.create_pg_interfaces(range(2))
701 for i in self.pg_interfaces:
706 super(TestExceptionPuntSocket, self).tearDown()
707 for i in self.pg_interfaces:
711 def test_registration(self):
712 """Punt socket registration/deregistration"""
714 pt_ex = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_EXCEPTION
716 punts = self.vapi.punt_socket_dump(type=pt_ex)
717 self.assertEqual(len(punts), 0)
720 # configure a punt socket
722 punt_ex = {"type": pt_ex, "punt": {"exception": {}}}
724 self.vapi.punt_socket_register(
725 set_reason(punt_ex, 1), "%s/socket_punt_1" % self.tempdir
727 self.vapi.punt_socket_register(
728 set_reason(punt_ex, 2), "%s/socket_punt_2" % self.tempdir
730 punts = self.vapi.punt_socket_dump(type=pt_ex)
731 self.assertEqual(len(punts), 2)
732 self.verify_exception(set_reason(punt_ex, 1), punts[0])
733 self.verify_exception(set_reason(punt_ex, 2), punts[1])
736 # deregister a punt socket
738 self.vapi.punt_socket_deregister(set_reason(punt_ex, 1))
739 punts = self.vapi.punt_socket_dump(type=pt_ex)
740 self.assertEqual(len(punts), 1)
743 # configure a punt socket again
745 self.vapi.punt_socket_register(
746 set_reason(punt_ex, 1), "%s/socket_punt_1" % self.tempdir
748 self.vapi.punt_socket_register(
749 set_reason(punt_ex, 3), "%s/socket_punt_3" % self.tempdir
751 punts = self.vapi.punt_socket_dump(type=pt_ex)
752 self.assertEqual(len(punts), 3)
754 self.logger.info(self.vapi.cli("sh punt sock reg exception"))
757 # deregister all punt socket
759 self.vapi.punt_socket_deregister(set_reason(punt_ex, 1))
760 self.vapi.punt_socket_deregister(set_reason(punt_ex, 2))
761 self.vapi.punt_socket_deregister(set_reason(punt_ex, 3))
762 punts = self.vapi.punt_socket_dump(type=pt_ex)
763 self.assertEqual(len(punts), 0)
765 def verify_esp_pkts(self, rxs, n_sent, spi, has_udp):
766 self.assertEqual(len(rxs), n_sent)
768 self.assertTrue(rx.haslayer(IP))
769 self.assertTrue(rx.haslayer(ESP))
770 self.assertEqual(rx[ESP].spi, spi)
772 self.assertTrue(rx.haslayer(UDP))
774 def test_traffic(self):
775 """Punt socket traffic"""
778 pt_ex = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_EXCEPTION
779 punt_ex = {"type": pt_ex, "punt": {"exception": {}}}
782 # we're dealing with IPSec tunnels punting for no-such-tunnel
783 # (SPI=0 goes to ikev2)
786 cfgs["ipsec4-no-such-tunnel"] = {"spi": 99, "udp": False, "itf": self.pg0}
789 # find the VPP ID for these punt exception reasin
791 rs = self.vapi.punt_reason_dump()
796 if r.reason.name == key:
797 cfgs[key]["id"] = r.reason.id
798 cfgs[key]["vpp"] = copy.deepcopy(
799 set_reason(punt_ex, cfgs[key]["id"])
804 # configure punt sockets
806 for cfg in cfgs.values():
807 cfg["sock"] = self.socket_client_create(
808 "%s/socket_%d" % (self.tempdir, cfg["id"])
810 self.vapi.punt_socket_register(
811 cfg["vpp"], "%s/socket_%d" % (self.tempdir, cfg["id"])
815 # create packet streams for 'no-such-tunnel' exception
817 for cfg in cfgs.values():
818 pkt = Ether(src=cfg["itf"].remote_mac, dst=cfg["itf"].local_mac) / IP(
819 src=cfg["itf"].remote_ip4, dst=cfg["itf"].local_ip4
822 pkt = pkt / UDP(sport=666, dport=4500)
823 pkt = pkt / ESP(spi=cfg["spi"], seq=3) / Raw(b"\xa5" * 100)
827 # send packets for each SPI we expect to be punted
829 for cfg in cfgs.values():
830 self.send_and_assert_no_replies(cfg["itf"], cfg["pkts"])
833 # verify the punted packets arrived on the associated socket
835 for cfg in cfgs.values():
836 rx = cfg["sock"].close()
837 self.verify_esp_pkts(rx, len(cfg["pkts"]), cfg["spi"], cfg["udp"])
840 # add some tunnels, make sure it still punts
842 tun = VppIpsecInterface(self).add_vpp_config()
847 (VppEnum.vl_api_ipsec_integ_alg_t.IPSEC_API_INTEG_ALG_SHA1_96),
849 (VppEnum.vl_api_ipsec_crypto_alg_t.IPSEC_API_CRYPTO_ALG_AES_CBC_128),
859 (VppEnum.vl_api_ipsec_integ_alg_t.IPSEC_API_INTEG_ALG_SHA1_96),
861 (VppEnum.vl_api_ipsec_crypto_alg_t.IPSEC_API_CRYPTO_ALG_AES_CBC_128),
867 protect = VppIpsecTunProtect(self, tun, sa_out, [sa_in]).add_vpp_config()
870 # send packets for each SPI we expect to be punted
872 for cfg in cfgs.values():
873 self.send_and_assert_no_replies(cfg["itf"], cfg["pkts"])
876 # verify the punted packets arrived on the associated socket
878 for cfg in cfgs.values():
879 rx = cfg["sock"].close()
880 self.verify_esp_pkts(rx, len(cfg["pkts"]), cfg["spi"], cfg["udp"])
884 for cfg in cfgs.values():
885 self.vapi.punt_socket_deregister(cfg["vpp"])
888 class TestIpProtoPuntSocket(TestPuntSocket):
889 """Punt Socket for IP packets"""
893 super(TestIpProtoPuntSocket, cls).setUpClass()
896 def tearDownClass(cls):
897 super(TestIpProtoPuntSocket, cls).tearDownClass()
900 super(TestIpProtoPuntSocket, self).setUp()
902 for i in self.pg_interfaces:
907 super(TestIpProtoPuntSocket, self).tearDown()
908 for i in self.pg_interfaces:
912 def test_registration(self):
913 """Punt socket registration/deregistration"""
915 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
916 pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
917 proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
918 proto_eigrp = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_EIGRP
920 punts = self.vapi.punt_socket_dump(type=pt_ip)
921 self.assertEqual(len(punts), 0)
924 # configure a punt socket
928 "punt": {"ip_proto": {"af": af_ip4, "protocol": proto_ospf}},
932 "punt": {"ip_proto": {"af": af_ip4, "protocol": proto_eigrp}},
935 self.vapi.punt_socket_register(punt_ospf, "%s/socket_punt_1" % self.tempdir)
936 self.vapi.punt_socket_register(punt_eigrp, "%s/socket_punt_2" % self.tempdir)
937 self.logger.info(self.vapi.cli("sh punt sock reg ip"))
938 punts = self.vapi.punt_socket_dump(type=pt_ip)
939 self.assertEqual(len(punts), 2)
940 self.verify_ip_proto(punt_ospf, punts[0])
941 self.verify_ip_proto(punt_eigrp, punts[1])
944 # deregister a punt socket
946 self.vapi.punt_socket_deregister(punt_ospf)
947 punts = self.vapi.punt_socket_dump(type=pt_ip)
948 self.assertEqual(len(punts), 1)
951 # configure a punt socket again
953 self.vapi.punt_socket_register(punt_ospf, "%s/socket_punt_3" % self.tempdir)
954 punts = self.vapi.punt_socket_dump(type=pt_ip)
955 self.assertEqual(len(punts), 2)
957 self.logger.info(self.vapi.cli("sh punt sock reg exception"))
960 # deregister all punt socket
962 self.vapi.punt_socket_deregister(punt_eigrp)
963 self.vapi.punt_socket_deregister(punt_ospf)
964 punts = self.vapi.punt_socket_dump(type=pt_ip)
965 self.assertEqual(len(punts), 0)
967 def verify_ospf_pkts(self, rxs, n_sent):
968 self.assertEqual(len(rxs), n_sent)
970 self.assertTrue(rx.haslayer(OSPF_Hdr))
972 def test_traffic(self):
973 """Punt socket traffic"""
975 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
976 pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
977 proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
980 # configure a punt socket to capture OSPF packets
984 "punt": {"ip_proto": {"af": af_ip4, "protocol": proto_ospf}},
988 # create packet streams and configure a punt sockets
991 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
992 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
998 sock = self.socket_client_create("%s/socket_1" % self.tempdir)
999 self.vapi.punt_socket_register(punt_ospf, "%s/socket_1" % self.tempdir)
1002 # send packets for each SPI we expect to be punted
1004 self.send_and_assert_no_replies(self.pg0, pkts)
1007 # verify the punted packets arrived on the associated socket
1010 self.verify_ospf_pkts(rx, len(pkts))
1011 self.vapi.punt_socket_deregister(punt_ospf)
1014 class TestDot1QPuntSocket(TestPuntSocket):
1015 """Punt Socket for 802.1Q (dot1q)"""
1018 super(TestDot1QPuntSocket, self).setUp()
1020 for i in self.pg_interfaces:
1026 super(TestDot1QPuntSocket, self).tearDown()
1027 for i in self.pg_interfaces:
1031 def test_dot1q_header_punt(self):
1032 """Punt socket traffic with Dot1q header"""
1034 port = self.ports[0]
1035 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
1036 punt_l4 = set_port(mk_vpp_cfg4(), port)
1041 # Create a subinterface with the VLAN ID
1042 subif = VppDot1QSubint(self, self.pg0, vlan_id)
1046 # Configure an IP address on the subinterface
1047 subif_ip4 = subif.local_ip4
1050 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1051 / Dot1Q(vlan=vlan_id)
1052 / IP(src=self.pg0.remote_ip4, dst=subif_ip4)
1053 / UDP(sport=9876, dport=port)
1054 / Raw(b"\xa5" * 100)
1057 pkts = p * self.nr_packets
1059 # Expect ICMP - port unreachable for all packets
1060 rx = self.send_and_expect_some(self.pg0, pkts, self.pg0)
1063 self.assertEqual(int(p[IP].proto), 1) # ICMP
1064 self.assertEqual(int(p[ICMP].code), 3) # unreachable
1066 # Configure a punt socket
1067 self.socket_client_create("%s/socket_%d" % (self.tempdir, port))
1068 self.vapi.punt_socket_register(punt_l4, "%s/socket_%d" % (self.tempdir, port))
1069 punts = self.vapi.punt_socket_dump(type=pt_l4)
1070 self.assertEqual(len(punts), 1)
1072 # Expect punt socket and no packets on pg0
1073 self.send_and_assert_no_replies(self.pg0, pkts)
1074 rx = self.socket_client_close()
1075 self.logger.info("RXPKT")
1076 self.logger.info(rx)
1077 self.verify_udp_pkts(rx, len(pkts), port)
1079 self.assertEqual(pkt[Ether].src, self.pg0.remote_mac)
1080 self.assertEqual(pkt[Ether].dst, self.pg0.local_mac)
1081 self.assertEqual(pkt[Dot1Q].vlan, 100)
1083 # Remove punt socket. Expect ICMP - port unreachable for all packets
1084 self.vapi.punt_socket_deregister(punt_l4)
1085 punts = self.vapi.punt_socket_dump(type=pt_l4)
1086 self.assertEqual(len(punts), 0)
1088 rx = self.send_and_expect_some(self.pg0, pkts, self.pg0)
1090 self.assertEqual(int(p[IP].proto), 1) # ICMP
1091 self.assertEqual(int(p[ICMP].code), 3) # unreachable
1094 @tag_fixme_vpp_workers
1095 class TestPunt(VppTestCase):
1096 """Exception Punt Test Case"""
1099 def setUpClass(cls):
1100 super(TestPunt, cls).setUpClass()
1103 def tearDownClass(cls):
1104 super(TestPunt, cls).tearDownClass()
1107 super(TestPunt, self).setUp()
1109 self.create_pg_interfaces(range(4))
1111 for i in self.pg_interfaces:
1119 for i in self.pg_interfaces:
1123 super(TestPunt, self).tearDown()
1125 def test_punt(self):
1126 """Exception Path testing"""
1129 # dump the punt registered reasons
1130 # search for a few we know should be there
1132 rs = self.vapi.punt_reason_dump()
1135 "ipsec6-no-such-tunnel",
1136 "ipsec4-no-such-tunnel",
1137 "ipsec4-spi-o-udp-0",
1140 for reason in reasons:
1143 if r.reason.name == reason:
1146 self.assertTrue(found)
1149 # Using the test CLI we will hook in a exception path to
1150 # send ACL deny packets out of pg0 and pg1.
1151 # the ACL is src,dst = 1.1.1.1,1.1.1.2
1153 ip_1_1_1_2 = VppIpRoute(
1157 [VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index)],
1159 ip_1_1_1_2.add_vpp_config()
1160 ip_1_2 = VppIpRoute(
1166 self.pg3.remote_ip6,
1167 self.pg3.sw_if_index,
1168 proto=DpoProto.DPO_PROTO_IP6,
1172 ip_1_2.add_vpp_config()
1175 Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac)
1176 / IP(src="1.1.1.1", dst="1.1.1.2")
1177 / UDP(sport=1234, dport=1234)
1178 / Raw(b"\xa5" * 100)
1181 Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac)
1182 / IPv6(src="1::1", dst="1::2")
1183 / UDP(sport=1234, dport=1234)
1184 / Raw(b"\xa5" * 100)
1186 self.send_and_expect(self.pg2, p4 * 1, self.pg3)
1187 self.send_and_expect(self.pg2, p6 * 1, self.pg3)
1190 # apply the punting features
1192 self.vapi.cli("test punt pg2")
1195 # dump the punt reasons to learn the IDs assigned
1197 rs = self.vapi.punt_reason_dump(reason={"name": "reason-v4"})
1198 r4 = rs[0].reason.id
1199 rs = self.vapi.punt_reason_dump(reason={"name": "reason-v6"})
1200 r6 = rs[0].reason.id
1205 self.send_and_assert_no_replies(self.pg2, p4 * NUM_PKTS)
1206 self.send_and_assert_no_replies(self.pg2, p6 * NUM_PKTS)
1210 # 1 - node error counters
1211 # 2 - per-reason counters
1212 # 2, 3 are the index of the assigned punt reason
1214 stats = self.statistics.get_err_counter("/err/punt-dispatch/No registrations")
1215 self.assertEqual(stats, 2 * NUM_PKTS)
1217 stats = self.statistics.get_counter("/net/punt")
1218 self.assertEqual(stats[0][r4]["packets"], NUM_PKTS)
1219 self.assertEqual(stats[0][r6]["packets"], NUM_PKTS)
1222 # use the test CLI to test a client that punts exception
1223 # packets out of pg0
1225 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip4)
1226 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip6)
1228 rx4s = self.send_and_expect(self.pg2, p4 * NUM_PKTS, self.pg0)
1229 rx6s = self.send_and_expect(self.pg2, p6 * NUM_PKTS, self.pg0)
1232 # check the packets come out IP unmodified but destined to pg0 host
1235 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1236 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1237 self.assertEqual(p4[IP].dst, rx[IP].dst)
1238 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1240 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1241 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1242 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1243 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1245 stats = self.statistics.get_counter("/net/punt")
1246 self.assertEqual(stats[0][r4]["packets"], 2 * NUM_PKTS)
1247 self.assertEqual(stats[0][r6]["packets"], 2 * NUM_PKTS)
1250 # add another registration for the same reason to send packets
1253 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip4)
1254 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip6)
1256 self.vapi.cli("clear trace")
1257 self.pg2.add_stream(p4 * NUM_PKTS)
1258 self.pg_enable_capture(self.pg_interfaces)
1261 rxd = self.pg0.get_capture(NUM_PKTS)
1263 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1264 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1265 self.assertEqual(p4[IP].dst, rx[IP].dst)
1266 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1267 rxd = self.pg1.get_capture(NUM_PKTS)
1269 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1270 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1271 self.assertEqual(p4[IP].dst, rx[IP].dst)
1272 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1274 self.vapi.cli("clear trace")
1275 self.pg2.add_stream(p6 * NUM_PKTS)
1276 self.pg_enable_capture(self.pg_interfaces)
1279 rxd = self.pg0.get_capture(NUM_PKTS)
1281 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1282 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1283 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1284 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1285 rxd = self.pg1.get_capture(NUM_PKTS)
1287 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1288 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1289 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1290 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1292 stats = self.statistics.get_counter("/net/punt")
1293 self.assertEqual(stats[0][r4]["packets"], 3 * NUM_PKTS)
1294 self.assertEqual(stats[0][r6]["packets"], 3 * NUM_PKTS)
1296 self.logger.info(self.vapi.cli("show vlib graph punt-dispatch"))
1297 self.logger.info(self.vapi.cli("show punt client"))
1298 self.logger.info(self.vapi.cli("show punt reason"))
1299 self.logger.info(self.vapi.cli("show punt stats"))
1300 self.logger.info(self.vapi.cli("show punt db"))
1303 if __name__ == "__main__":
1304 unittest.main(testRunner=VppTestRunner)