11 import unittest2 as unittest
15 from scapy.packet import Raw
16 from scapy.layers.l2 import Ether
17 from scapy.layers.l2 import Dot1Q
18 from scapy.layers.inet import IP, UDP, ICMP
19 from scapy.layers.ipsec import ESP
20 import scapy.layers.inet6 as inet6
21 from scapy.layers.inet6 import IPv6
22 from scapy.contrib.ospf import OSPF_Hdr, OSPFv3_Hello
23 from framework import VppTestCase
24 from asfframework import VppTestRunner, tag_fixme_vpp_workers
25 from vpp_sub_interface import VppDot1QSubint
27 from vpp_ip import DpoProto
28 from vpp_ip_route import VppIpRoute, VppRoutePath
29 from vpp_ipsec import VppIpsecSA, VppIpsecTunProtect, VppIpsecInterface
30 from vpp_papi import VppEnum
35 class serverSocketThread(threading.Thread):
36 """Socket server thread"""
38 def __init__(self, threadID, sockName):
39 threading.Thread.__init__(self)
40 self.threadID = threadID
41 self.sockName = sockName
44 self.stop_running = False
47 # Wait for some packets on socket
50 data = self.sock.recv(65536)
52 # punt socket metadata
53 # packet_desc = data[0:8]
56 self.rx_pkts.append(Ether(data[8:]))
59 # nothing to receive, stop running or sleep a little
68 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
70 os.unlink(self.sockName)
73 self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 65536)
74 self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 65536)
75 fcntl.fcntl(self.sock, fcntl.F_SETFL, os.O_NONBLOCK)
76 self.sock.bind(self.sockName)
81 self.stop_running = True
82 threading.Thread.join(self)
87 class TestPuntSocket(VppTestCase):
90 ports = [1111, 2222, 3333, 4444]
92 # FIXME: nr_packets > 3 results in failure
93 # nr_packets = 3 makes the test unstable
98 super(TestPuntSocket, cls).setUpClass()
101 def tearDownClass(cls):
102 super(TestPuntSocket, cls).tearDownClass()
105 def setUpConstants(cls):
106 cls.extra_vpp_config = [
110 cls.tempdir + "/socket_punt",
113 super(TestPuntSocket, cls).setUpConstants()
116 super(TestPuntSocket, self).setUp()
119 self.create_pg_interfaces(range(2))
120 for i in self.pg_interfaces:
124 del self.sock_servers[:]
125 super(TestPuntSocket, self).tearDown()
127 def socket_client_create(self, sock_name, id=None):
128 thread = serverSocketThread(id, sock_name)
129 self.sock_servers.append(thread)
133 def socket_client_close(self):
135 for thread in self.sock_servers:
136 rx_pkts += thread.close()
139 def verify_port(self, pr, vpr):
140 self.assertEqual(vpr.punt.type, pr["type"])
141 self.assertEqual(vpr.punt.punt.l4.port, pr["punt"]["l4"]["port"])
142 self.assertEqual(vpr.punt.punt.l4.protocol, pr["punt"]["l4"]["protocol"])
143 self.assertEqual(vpr.punt.punt.l4.af, pr["punt"]["l4"]["af"])
145 def verify_exception(self, pr, vpr):
146 self.assertEqual(vpr.punt.type, pr["type"])
147 self.assertEqual(vpr.punt.punt.exception.id, pr["punt"]["exception"]["id"])
149 def verify_ip_proto(self, pr, vpr):
150 self.assertEqual(vpr.punt.type, pr["type"])
151 self.assertEqual(vpr.punt.punt.ip_proto.af, pr["punt"]["ip_proto"]["af"])
153 vpr.punt.punt.ip_proto.protocol, pr["punt"]["ip_proto"]["protocol"]
156 def verify_udp_pkts(self, rxs, n_rx, port):
159 self.assertTrue(rx.haslayer(UDP))
160 if rx[UDP].dport == port:
162 self.assertEqual(n_match, n_rx)
165 def set_port(pr, port):
166 pr["punt"]["l4"]["port"] = port
170 def set_reason(pr, reason):
171 pr["punt"]["exception"]["id"] = reason
176 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
177 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
178 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
179 punt_l4 = {"type": pt_l4, "punt": {"l4": {"af": af_ip4, "protocol": udp_proto}}}
184 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
185 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
186 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
187 punt_l4 = {"type": pt_l4, "punt": {"l4": {"af": af_ip6, "protocol": udp_proto}}}
191 class TestIP4PuntSocket(TestPuntSocket):
192 """Punt Socket for IPv4 UDP"""
196 super(TestIP4PuntSocket, cls).setUpClass()
199 def tearDownClass(cls):
200 super(TestIP4PuntSocket, cls).tearDownClass()
203 super(TestIP4PuntSocket, self).setUp()
205 for i in self.pg_interfaces:
210 super(TestIP4PuntSocket, self).tearDown()
211 for i in self.pg_interfaces:
215 def test_punt_socket_dump(self):
216 """Punt socket registration/deregistration"""
218 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
219 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
220 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
222 punts = self.vapi.punt_socket_dump(type=pt_l4)
223 self.assertEqual(len(punts), 0)
226 # configure a punt socket
228 punt_l4 = mk_vpp_cfg4()
230 self.vapi.punt_socket_register(
231 set_port(punt_l4, 1111), "%s/socket_punt_1111" % self.tempdir
233 self.vapi.punt_socket_register(
234 set_port(punt_l4, 2222), "%s/socket_punt_2222" % self.tempdir
236 punts = self.vapi.punt_socket_dump(type=pt_l4)
237 self.assertEqual(len(punts), 2)
238 self.verify_port(set_port(punt_l4, 1111), punts[0])
239 self.verify_port(set_port(punt_l4, 2222), punts[1])
242 # deregister a punt socket
244 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
245 punts = self.vapi.punt_socket_dump(type=pt_l4)
246 self.assertEqual(len(punts), 1)
249 # configure a punt socket again
251 self.vapi.punt_socket_register(
252 set_port(punt_l4, 1111), "%s/socket_punt_1111" % self.tempdir
254 self.vapi.punt_socket_register(
255 set_port(punt_l4, 3333), "%s/socket_punt_3333" % self.tempdir
257 punts = self.vapi.punt_socket_dump(type=pt_l4)
258 self.assertEqual(len(punts), 3)
260 self.logger.info(self.vapi.cli("sh punt sock reg"))
263 # deregister all punt socket
265 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
266 self.vapi.punt_socket_deregister(set_port(punt_l4, 2222))
267 self.vapi.punt_socket_deregister(set_port(punt_l4, 3333))
268 punts = self.vapi.punt_socket_dump(type=pt_l4)
269 self.assertEqual(len(punts), 0)
271 def test_punt_socket_traffic_single_port_single_socket(self):
272 """Punt socket traffic single port single socket"""
275 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
276 punt_l4 = set_port(mk_vpp_cfg4(), port)
279 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
280 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
281 / UDP(sport=9876, dport=port)
285 pkts = p * self.nr_packets
287 punts = self.vapi.punt_socket_dump(type=pt_l4)
288 self.assertEqual(len(punts), 0)
291 # expect ICMP - port unreachable for all packets
293 rx = self.send_and_expect_some(self.pg0, pkts, self.pg0)
296 self.assertEqual(int(p[IP].proto), 1) # ICMP
297 self.assertEqual(int(p[ICMP].code), 3) # unreachable
300 # configure a punt socket
302 self.socket_client_create("%s/socket_%d" % (self.tempdir, port))
303 self.vapi.punt_socket_register(punt_l4, "%s/socket_%d" % (self.tempdir, port))
304 punts = self.vapi.punt_socket_dump(type=pt_l4)
305 self.assertEqual(len(punts), 1)
308 # expect punt socket and no packets on pg0
310 self.send_and_assert_no_replies(self.pg0, pkts)
311 rx = self.socket_client_close()
312 self.verify_udp_pkts(rx, len(pkts), port)
315 # remove punt socket. expect ICMP - port unreachable for all packets
317 self.vapi.punt_socket_deregister(punt_l4)
318 punts = self.vapi.punt_socket_dump(type=pt_l4)
319 self.assertEqual(len(punts), 0)
321 rx = self.send_and_expect_some(self.pg0, pkts, self.pg0)
323 self.assertEqual(int(p[IP].proto), 1) # ICMP
324 self.assertEqual(int(p[ICMP].code), 3) # unreachable
326 def test_punt_socket_traffic_multi_ports_multi_sockets(self):
327 """Punt socket traffic multi ports and multi sockets"""
329 punt_l4 = mk_vpp_cfg4()
331 # configuration for each UDP port
335 # create stream of packets for each port
337 for port in self.ports:
338 # choose port from port list
342 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
343 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
344 / UDP(sport=9876, dport=port)
347 cfgs[port]["pkts"] = pkt * self.nr_packets
348 cfgs[port]["port"] = port
349 cfgs[port]["vpp"] = copy.deepcopy(set_port(punt_l4, port))
351 # configure punt sockets
352 cfgs[port]["sock"] = self.socket_client_create(
353 "%s/socket_%d" % (self.tempdir, port)
355 self.vapi.punt_socket_register(
356 cfgs[port]["vpp"], "%s/socket_%d" % (self.tempdir, port)
360 # send the packets that get punted
362 for cfg in cfgs.values():
363 self.send_and_assert_no_replies(self.pg0, cfg["pkts"])
366 # test that we got the excepted packets on the expected socket
368 for cfg in cfgs.values():
369 rx = cfg["sock"].close()
370 self.verify_udp_pkts(rx, len(cfg["pkts"]), cfg["port"])
371 self.vapi.punt_socket_deregister(cfg["vpp"])
373 def test_punt_socket_traffic_multi_ports_single_socket(self):
374 """Punt socket traffic multi ports and single socket"""
376 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
377 punt_l4 = mk_vpp_cfg4()
380 # create stream of packets with each port
383 for port in self.ports:
384 # choose port from port list
386 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
387 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
388 / UDP(sport=9876, dport=port)
391 pkts += pkt * self.nr_packets
394 # configure a punt socket
396 self.socket_client_create("%s/socket_multi" % self.tempdir)
398 self.vapi.punt_socket_register(
399 set_port(punt_l4, p), "%s/socket_multi" % self.tempdir
401 punts = self.vapi.punt_socket_dump(type=pt_l4)
402 self.assertEqual(len(punts), len(self.ports))
405 # expect punt socket and no packets on pg0
407 self.send_and_assert_no_replies(self.pg0, pkts)
408 self.logger.info(self.vapi.cli("show trace"))
409 rx = self.socket_client_close()
412 self.verify_udp_pkts(rx, self.nr_packets, p)
413 self.vapi.punt_socket_deregister(set_port(punt_l4, p))
414 punts = self.vapi.punt_socket_dump(type=pt_l4)
415 self.assertEqual(len(punts), 0)
418 class TestIP6PuntSocket(TestPuntSocket):
419 """Punt Socket for IPv6 UDP"""
423 super(TestIP6PuntSocket, cls).setUpClass()
426 def tearDownClass(cls):
427 super(TestIP6PuntSocket, cls).tearDownClass()
430 super(TestIP6PuntSocket, self).setUp()
432 for i in self.pg_interfaces:
437 super(TestIP6PuntSocket, self).tearDown()
438 for i in self.pg_interfaces:
442 def test_punt_socket_dump(self):
443 """Punt socket registration"""
445 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
446 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
447 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
449 # configure a punt socket
451 punt_l4 = {"type": pt_l4, "punt": {"l4": {"af": af_ip6, "protocol": udp_proto}}}
453 punts = self.vapi.punt_socket_dump(type=pt_l4)
454 self.assertEqual(len(punts), 0)
457 # configure a punt socket
459 self.vapi.punt_socket_register(
460 set_port(punt_l4, 1111), "%s/socket_1111" % self.tempdir
462 self.vapi.punt_socket_register(
463 set_port(punt_l4, 2222), "%s/socket_2222" % self.tempdir
465 punts = self.vapi.punt_socket_dump(type=pt_l4)
466 self.assertEqual(len(punts), 2)
467 self.verify_port(set_port(punt_l4, 1111), punts[0])
468 self.verify_port(set_port(punt_l4, 2222), punts[1])
471 # deregister a punt socket
473 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
474 punts = self.vapi.punt_socket_dump(type=pt_l4)
475 self.assertEqual(len(punts), 1)
478 # configure a punt socket again
480 self.vapi.punt_socket_register(
481 set_port(punt_l4, 1111), "%s/socket_1111" % self.tempdir
483 punts = self.vapi.punt_socket_dump(type=pt_l4)
484 self.assertEqual(len(punts), 2)
487 # deregister all punt socket
489 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
490 self.vapi.punt_socket_deregister(set_port(punt_l4, 2222))
491 self.vapi.punt_socket_deregister(set_port(punt_l4, 3333))
492 punts = self.vapi.punt_socket_dump(type=pt_l4)
493 self.assertEqual(len(punts), 0)
495 def test_punt_socket_traffic_single_port_single_socket(self):
496 """Punt socket traffic single port single socket"""
499 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
500 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
501 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
507 "protocol": udp_proto,
514 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
515 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
516 / inet6.UDP(sport=9876, dport=port)
520 pkts = p * self.nr_packets
522 punts = self.vapi.punt_socket_dump(type=pt_l4)
523 self.assertEqual(len(punts), 0)
526 # expect ICMPv6 - destination unreachable for all packets
528 self.vapi.cli("clear trace")
529 self.pg0.add_stream(pkts)
530 self.pg_enable_capture(self.pg_interfaces)
532 # FIXME - when punt socket deregister is implemented
533 # rx = self.pg0.get_capture(self.nr_packets)
535 # self.assertEqual(int(p[IPv6].nh), 58) # ICMPv6
536 # self.assertEqual(int(p[ICMPv6DestUnreach].code),4) # unreachable
539 # configure a punt socket
541 self.socket_client_create("%s/socket_%d" % (self.tempdir, port))
542 self.vapi.punt_socket_register(punt_l4, "%s/socket_%d" % (self.tempdir, port))
543 punts = self.vapi.punt_socket_dump(type=pt_l4)
544 self.assertEqual(len(punts), 1)
547 # expect punt socket and no packets on pg0
549 self.vapi.cli("clear errors")
550 self.vapi.cli("clear trace")
551 self.pg0.add_stream(pkts)
552 self.pg_enable_capture(self.pg_interfaces)
554 self.pg0.get_capture(0)
555 self.logger.info(self.vapi.cli("show trace"))
556 rx = self.socket_client_close()
557 self.verify_udp_pkts(rx, len(pkts), port)
560 # remove punt socket. expect ICMP - dest. unreachable for all packets
562 self.vapi.punt_socket_deregister(punt_l4)
563 punts = self.vapi.punt_socket_dump(type=pt_l4)
564 self.assertEqual(len(punts), 0)
565 self.pg0.add_stream(pkts)
566 self.pg_enable_capture(self.pg_interfaces)
568 # FIXME - when punt socket deregister is implemented
569 # self.pg0.get_capture(nr_packets)
571 def test_punt_socket_traffic_multi_ports_multi_sockets(self):
572 """Punt socket traffic multi ports and multi sockets"""
574 punt_l4 = mk_vpp_cfg6()
576 # configuration for each UDP port
580 # create stream of packets for each port
582 for port in self.ports:
583 # choose port from port list
587 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
588 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
589 / UDP(sport=9876, dport=port)
592 cfgs[port]["pkts"] = pkt * self.nr_packets
593 cfgs[port]["port"] = port
594 cfgs[port]["vpp"] = copy.deepcopy(set_port(punt_l4, port))
596 # configure punt sockets
597 cfgs[port]["sock"] = self.socket_client_create(
598 "%s/socket_%d" % (self.tempdir, port)
600 self.vapi.punt_socket_register(
601 cfgs[port]["vpp"], "%s/socket_%d" % (self.tempdir, port)
605 # send the packets that get punted
607 for cfg in cfgs.values():
608 self.send_and_assert_no_replies(self.pg0, cfg["pkts"])
611 # test that we got the excepted packets on the expected socket
613 for cfg in cfgs.values():
614 rx = cfg["sock"].close()
615 self.verify_udp_pkts(rx, len(cfg["pkts"]), cfg["port"])
616 self.vapi.punt_socket_deregister(cfg["vpp"])
618 def test_punt_socket_traffic_multi_ports_single_socket(self):
619 """Punt socket traffic multi ports and single socket"""
621 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
622 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
623 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
629 "protocol": udp_proto,
635 # create stream of packets with each port
638 for port in self.ports:
639 # choose port from port list
641 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
642 / IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6)
643 / UDP(sport=9876, dport=port)
646 pkts += pkt * self.nr_packets
651 punts = self.vapi.punt_socket_dump(type=pt_l4)
652 self.assertEqual(len(punts), 0)
655 # configure a punt socket
657 self.socket_client_create("%s/socket_multi" % self.tempdir)
659 self.vapi.punt_socket_register(
660 set_port(punt_l4, p), "%s/socket_multi" % self.tempdir
662 punts = self.vapi.punt_socket_dump(type=pt_l4)
663 self.assertEqual(len(punts), len(self.ports))
666 # expect punt socket and no packets on pg0
668 self.vapi.cli("clear errors")
669 self.vapi.cli("clear trace")
670 self.pg0.add_stream(pkts)
671 self.pg_enable_capture(self.pg_interfaces)
673 # give a chance to punt socket to collect all packets
675 self.pg0.get_capture(0)
676 rx = self.socket_client_close()
679 self.verify_udp_pkts(rx, self.nr_packets, p)
680 self.vapi.punt_socket_deregister(set_port(punt_l4, p))
681 punts = self.vapi.punt_socket_dump(type=pt_l4)
682 self.assertEqual(len(punts), 0)
685 class TestExceptionPuntSocket(TestPuntSocket):
686 """Punt Socket for Exceptions"""
690 super(TestExceptionPuntSocket, cls).setUpClass()
693 def tearDownClass(cls):
694 super(TestExceptionPuntSocket, cls).tearDownClass()
697 super(TestExceptionPuntSocket, self).setUp()
699 self.create_pg_interfaces(range(2))
700 for i in self.pg_interfaces:
705 super(TestExceptionPuntSocket, self).tearDown()
706 for i in self.pg_interfaces:
710 def test_registration(self):
711 """Punt socket registration/deregistration"""
713 pt_ex = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_EXCEPTION
715 punts = self.vapi.punt_socket_dump(type=pt_ex)
716 self.assertEqual(len(punts), 0)
719 # configure a punt socket
721 punt_ex = {"type": pt_ex, "punt": {"exception": {}}}
723 self.vapi.punt_socket_register(
724 set_reason(punt_ex, 1), "%s/socket_punt_1" % self.tempdir
726 self.vapi.punt_socket_register(
727 set_reason(punt_ex, 2), "%s/socket_punt_2" % self.tempdir
729 punts = self.vapi.punt_socket_dump(type=pt_ex)
730 self.assertEqual(len(punts), 2)
731 self.verify_exception(set_reason(punt_ex, 1), punts[0])
732 self.verify_exception(set_reason(punt_ex, 2), punts[1])
735 # deregister a punt socket
737 self.vapi.punt_socket_deregister(set_reason(punt_ex, 1))
738 punts = self.vapi.punt_socket_dump(type=pt_ex)
739 self.assertEqual(len(punts), 1)
742 # configure a punt socket again
744 self.vapi.punt_socket_register(
745 set_reason(punt_ex, 1), "%s/socket_punt_1" % self.tempdir
747 self.vapi.punt_socket_register(
748 set_reason(punt_ex, 3), "%s/socket_punt_3" % self.tempdir
750 punts = self.vapi.punt_socket_dump(type=pt_ex)
751 self.assertEqual(len(punts), 3)
753 self.logger.info(self.vapi.cli("sh punt sock reg exception"))
756 # deregister all punt socket
758 self.vapi.punt_socket_deregister(set_reason(punt_ex, 1))
759 self.vapi.punt_socket_deregister(set_reason(punt_ex, 2))
760 self.vapi.punt_socket_deregister(set_reason(punt_ex, 3))
761 punts = self.vapi.punt_socket_dump(type=pt_ex)
762 self.assertEqual(len(punts), 0)
764 def verify_esp_pkts(self, rxs, n_sent, spi, has_udp):
765 self.assertEqual(len(rxs), n_sent)
767 self.assertTrue(rx.haslayer(IP))
768 self.assertTrue(rx.haslayer(ESP))
769 self.assertEqual(rx[ESP].spi, spi)
771 self.assertTrue(rx.haslayer(UDP))
773 def test_traffic(self):
774 """Punt socket traffic"""
777 pt_ex = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_EXCEPTION
778 punt_ex = {"type": pt_ex, "punt": {"exception": {}}}
781 # we're dealing with IPSec tunnels punting for no-such-tunnel
782 # (SPI=0 goes to ikev2)
785 cfgs["ipsec4-no-such-tunnel"] = {"spi": 99, "udp": False, "itf": self.pg0}
788 # find the VPP ID for these punt exception reasin
790 rs = self.vapi.punt_reason_dump()
795 if r.reason.name == key:
796 cfgs[key]["id"] = r.reason.id
797 cfgs[key]["vpp"] = copy.deepcopy(
798 set_reason(punt_ex, cfgs[key]["id"])
803 # configure punt sockets
805 for cfg in cfgs.values():
806 cfg["sock"] = self.socket_client_create(
807 "%s/socket_%d" % (self.tempdir, cfg["id"])
809 self.vapi.punt_socket_register(
810 cfg["vpp"], "%s/socket_%d" % (self.tempdir, cfg["id"])
814 # create packet streams for 'no-such-tunnel' exception
816 for cfg in cfgs.values():
817 pkt = Ether(src=cfg["itf"].remote_mac, dst=cfg["itf"].local_mac) / IP(
818 src=cfg["itf"].remote_ip4, dst=cfg["itf"].local_ip4
821 pkt = pkt / UDP(sport=666, dport=4500)
822 pkt = pkt / ESP(spi=cfg["spi"], seq=3) / Raw(b"\xa5" * 100)
826 # send packets for each SPI we expect to be punted
828 for cfg in cfgs.values():
829 self.send_and_assert_no_replies(cfg["itf"], cfg["pkts"])
832 # verify the punted packets arrived on the associated socket
834 for cfg in cfgs.values():
835 rx = cfg["sock"].close()
836 self.verify_esp_pkts(rx, len(cfg["pkts"]), cfg["spi"], cfg["udp"])
839 # add some tunnels, make sure it still punts
841 tun = VppIpsecInterface(self).add_vpp_config()
846 (VppEnum.vl_api_ipsec_integ_alg_t.IPSEC_API_INTEG_ALG_SHA1_96),
848 (VppEnum.vl_api_ipsec_crypto_alg_t.IPSEC_API_CRYPTO_ALG_AES_CBC_128),
858 (VppEnum.vl_api_ipsec_integ_alg_t.IPSEC_API_INTEG_ALG_SHA1_96),
860 (VppEnum.vl_api_ipsec_crypto_alg_t.IPSEC_API_CRYPTO_ALG_AES_CBC_128),
866 protect = VppIpsecTunProtect(self, tun, sa_out, [sa_in]).add_vpp_config()
869 # send packets for each SPI we expect to be punted
871 for cfg in cfgs.values():
872 self.send_and_assert_no_replies(cfg["itf"], cfg["pkts"])
875 # verify the punted packets arrived on the associated socket
877 for cfg in cfgs.values():
878 rx = cfg["sock"].close()
879 self.verify_esp_pkts(rx, len(cfg["pkts"]), cfg["spi"], cfg["udp"])
883 for cfg in cfgs.values():
884 self.vapi.punt_socket_deregister(cfg["vpp"])
887 class TestIpProtoPuntSocket(TestPuntSocket):
888 """Punt Socket for IP packets"""
892 super(TestIpProtoPuntSocket, cls).setUpClass()
895 def tearDownClass(cls):
896 super(TestIpProtoPuntSocket, cls).tearDownClass()
899 super(TestIpProtoPuntSocket, self).setUp()
901 for i in self.pg_interfaces:
906 super(TestIpProtoPuntSocket, self).tearDown()
907 for i in self.pg_interfaces:
911 def test_registration(self):
912 """Punt socket registration/deregistration"""
914 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
915 pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
916 proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
917 proto_eigrp = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_EIGRP
919 punts = self.vapi.punt_socket_dump(type=pt_ip)
920 self.assertEqual(len(punts), 0)
923 # configure a punt socket
927 "punt": {"ip_proto": {"af": af_ip4, "protocol": proto_ospf}},
931 "punt": {"ip_proto": {"af": af_ip4, "protocol": proto_eigrp}},
934 self.vapi.punt_socket_register(punt_ospf, "%s/socket_punt_1" % self.tempdir)
935 self.vapi.punt_socket_register(punt_eigrp, "%s/socket_punt_2" % self.tempdir)
936 self.logger.info(self.vapi.cli("sh punt sock reg ip"))
937 punts = self.vapi.punt_socket_dump(type=pt_ip)
938 self.assertEqual(len(punts), 2)
939 self.verify_ip_proto(punt_ospf, punts[0])
940 self.verify_ip_proto(punt_eigrp, punts[1])
943 # deregister a punt socket
945 self.vapi.punt_socket_deregister(punt_ospf)
946 punts = self.vapi.punt_socket_dump(type=pt_ip)
947 self.assertEqual(len(punts), 1)
950 # configure a punt socket again
952 self.vapi.punt_socket_register(punt_ospf, "%s/socket_punt_3" % self.tempdir)
953 punts = self.vapi.punt_socket_dump(type=pt_ip)
954 self.assertEqual(len(punts), 2)
956 self.logger.info(self.vapi.cli("sh punt sock reg exception"))
959 # deregister all punt socket
961 self.vapi.punt_socket_deregister(punt_eigrp)
962 self.vapi.punt_socket_deregister(punt_ospf)
963 punts = self.vapi.punt_socket_dump(type=pt_ip)
964 self.assertEqual(len(punts), 0)
966 def verify_ospf_pkts(self, rxs, n_sent):
967 self.assertEqual(len(rxs), n_sent)
969 self.assertTrue(rx.haslayer(OSPF_Hdr))
971 def test_traffic(self):
972 """Punt socket traffic"""
974 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
975 pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
976 proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
979 # configure a punt socket to capture OSPF packets
983 "punt": {"ip_proto": {"af": af_ip4, "protocol": proto_ospf}},
987 # create packet streams and configure a punt sockets
990 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
991 / IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4)
997 sock = self.socket_client_create("%s/socket_1" % self.tempdir)
998 self.vapi.punt_socket_register(punt_ospf, "%s/socket_1" % self.tempdir)
1001 # send packets for each SPI we expect to be punted
1003 self.send_and_assert_no_replies(self.pg0, pkts)
1006 # verify the punted packets arrived on the associated socket
1009 self.verify_ospf_pkts(rx, len(pkts))
1010 self.vapi.punt_socket_deregister(punt_ospf)
1013 class TestDot1QPuntSocket(TestPuntSocket):
1014 """Punt Socket for 802.1Q (dot1q)"""
1017 super(TestDot1QPuntSocket, self).setUp()
1019 for i in self.pg_interfaces:
1025 super(TestDot1QPuntSocket, self).tearDown()
1026 for i in self.pg_interfaces:
1030 def test_dot1q_header_punt(self):
1031 """Punt socket traffic with Dot1q header"""
1033 port = self.ports[0]
1034 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
1035 punt_l4 = set_port(mk_vpp_cfg4(), port)
1040 # Create a subinterface with the VLAN ID
1041 subif = VppDot1QSubint(self, self.pg0, vlan_id)
1045 # Configure an IP address on the subinterface
1046 subif_ip4 = subif.local_ip4
1049 Ether(src=self.pg0.remote_mac, dst=self.pg0.local_mac)
1050 / Dot1Q(vlan=vlan_id)
1051 / IP(src=self.pg0.remote_ip4, dst=subif_ip4)
1052 / UDP(sport=9876, dport=port)
1053 / Raw(b"\xa5" * 100)
1056 pkts = p * self.nr_packets
1058 # Expect ICMP - port unreachable for all packets
1059 rx = self.send_and_expect_some(self.pg0, pkts, self.pg0)
1062 self.assertEqual(int(p[IP].proto), 1) # ICMP
1063 self.assertEqual(int(p[ICMP].code), 3) # unreachable
1065 # Configure a punt socket
1066 self.socket_client_create("%s/socket_%d" % (self.tempdir, port))
1067 self.vapi.punt_socket_register(punt_l4, "%s/socket_%d" % (self.tempdir, port))
1068 punts = self.vapi.punt_socket_dump(type=pt_l4)
1069 self.assertEqual(len(punts), 1)
1071 # Expect punt socket and no packets on pg0
1072 self.send_and_assert_no_replies(self.pg0, pkts)
1073 rx = self.socket_client_close()
1074 self.logger.info("RXPKT")
1075 self.logger.info(rx)
1076 self.verify_udp_pkts(rx, len(pkts), port)
1078 self.assertEqual(pkt[Ether].src, self.pg0.remote_mac)
1079 self.assertEqual(pkt[Ether].dst, self.pg0.local_mac)
1080 self.assertEqual(pkt[Dot1Q].vlan, 100)
1082 # Remove punt socket. Expect ICMP - port unreachable for all packets
1083 self.vapi.punt_socket_deregister(punt_l4)
1084 punts = self.vapi.punt_socket_dump(type=pt_l4)
1085 self.assertEqual(len(punts), 0)
1087 rx = self.send_and_expect_some(self.pg0, pkts, self.pg0)
1089 self.assertEqual(int(p[IP].proto), 1) # ICMP
1090 self.assertEqual(int(p[ICMP].code), 3) # unreachable
1093 @tag_fixme_vpp_workers
1094 class TestPunt(VppTestCase):
1095 """Exception Punt Test Case"""
1098 def setUpClass(cls):
1099 super(TestPunt, cls).setUpClass()
1102 def tearDownClass(cls):
1103 super(TestPunt, cls).tearDownClass()
1106 super(TestPunt, self).setUp()
1108 self.create_pg_interfaces(range(4))
1110 for i in self.pg_interfaces:
1118 for i in self.pg_interfaces:
1122 super(TestPunt, self).tearDown()
1124 def test_punt(self):
1125 """Exception Path testing"""
1128 # dump the punt registered reasons
1129 # search for a few we know should be there
1131 rs = self.vapi.punt_reason_dump()
1134 "ipsec6-no-such-tunnel",
1135 "ipsec4-no-such-tunnel",
1136 "ipsec4-spi-o-udp-0",
1139 for reason in reasons:
1142 if r.reason.name == reason:
1145 self.assertTrue(found)
1148 # Using the test CLI we will hook in a exception path to
1149 # send ACL deny packets out of pg0 and pg1.
1150 # the ACL is src,dst = 1.1.1.1,1.1.1.2
1152 ip_1_1_1_2 = VppIpRoute(
1156 [VppRoutePath(self.pg3.remote_ip4, self.pg3.sw_if_index)],
1158 ip_1_1_1_2.add_vpp_config()
1159 ip_1_2 = VppIpRoute(
1165 self.pg3.remote_ip6,
1166 self.pg3.sw_if_index,
1167 proto=DpoProto.DPO_PROTO_IP6,
1171 ip_1_2.add_vpp_config()
1174 Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac)
1175 / IP(src="1.1.1.1", dst="1.1.1.2")
1176 / UDP(sport=1234, dport=1234)
1177 / Raw(b"\xa5" * 100)
1180 Ether(src=self.pg2.remote_mac, dst=self.pg2.local_mac)
1181 / IPv6(src="1::1", dst="1::2")
1182 / UDP(sport=1234, dport=1234)
1183 / Raw(b"\xa5" * 100)
1185 self.send_and_expect(self.pg2, p4 * 1, self.pg3)
1186 self.send_and_expect(self.pg2, p6 * 1, self.pg3)
1189 # apply the punting features
1191 self.vapi.cli("test punt pg2")
1194 # dump the punt reasons to learn the IDs assigned
1196 rs = self.vapi.punt_reason_dump(reason={"name": "reason-v4"})
1197 r4 = rs[0].reason.id
1198 rs = self.vapi.punt_reason_dump(reason={"name": "reason-v6"})
1199 r6 = rs[0].reason.id
1204 self.send_and_assert_no_replies(self.pg2, p4 * NUM_PKTS)
1205 self.send_and_assert_no_replies(self.pg2, p6 * NUM_PKTS)
1209 # 1 - node error counters
1210 # 2 - per-reason counters
1211 # 2, 3 are the index of the assigned punt reason
1213 stats = self.statistics.get_err_counter("/err/punt-dispatch/No registrations")
1214 self.assertEqual(stats, 2 * NUM_PKTS)
1216 stats = self.statistics.get_counter("/net/punt")
1217 self.assertEqual(stats[0][r4]["packets"], NUM_PKTS)
1218 self.assertEqual(stats[0][r6]["packets"], NUM_PKTS)
1221 # use the test CLI to test a client that punts exception
1222 # packets out of pg0
1224 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip4)
1225 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip6)
1227 rx4s = self.send_and_expect(self.pg2, p4 * NUM_PKTS, self.pg0)
1228 rx6s = self.send_and_expect(self.pg2, p6 * NUM_PKTS, self.pg0)
1231 # check the packets come out IP unmodified but destined to pg0 host
1234 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1235 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1236 self.assertEqual(p4[IP].dst, rx[IP].dst)
1237 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1239 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1240 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1241 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1242 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1244 stats = self.statistics.get_counter("/net/punt")
1245 self.assertEqual(stats[0][r4]["packets"], 2 * NUM_PKTS)
1246 self.assertEqual(stats[0][r6]["packets"], 2 * NUM_PKTS)
1249 # add another registration for the same reason to send packets
1252 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip4)
1253 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip6)
1255 self.vapi.cli("clear trace")
1256 self.pg2.add_stream(p4 * NUM_PKTS)
1257 self.pg_enable_capture(self.pg_interfaces)
1260 rxd = self.pg0.get_capture(NUM_PKTS)
1262 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1263 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1264 self.assertEqual(p4[IP].dst, rx[IP].dst)
1265 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1266 rxd = self.pg1.get_capture(NUM_PKTS)
1268 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1269 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1270 self.assertEqual(p4[IP].dst, rx[IP].dst)
1271 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1273 self.vapi.cli("clear trace")
1274 self.pg2.add_stream(p6 * NUM_PKTS)
1275 self.pg_enable_capture(self.pg_interfaces)
1278 rxd = self.pg0.get_capture(NUM_PKTS)
1280 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1281 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1282 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1283 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1284 rxd = self.pg1.get_capture(NUM_PKTS)
1286 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1287 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1288 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1289 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1291 stats = self.statistics.get_counter("/net/punt")
1292 self.assertEqual(stats[0][r4]["packets"], 3 * NUM_PKTS)
1293 self.assertEqual(stats[0][r6]["packets"], 3 * NUM_PKTS)
1295 self.logger.info(self.vapi.cli("show vlib graph punt-dispatch"))
1296 self.logger.info(self.vapi.cli("show punt client"))
1297 self.logger.info(self.vapi.cli("show punt reason"))
1298 self.logger.info(self.vapi.cli("show punt stats"))
1299 self.logger.info(self.vapi.cli("show punt db"))
1302 if __name__ == "__main__":
1303 unittest.main(testRunner=VppTestRunner)