12 from struct import unpack, unpack_from
15 import unittest2 as unittest
19 from util import ppp, ppc
20 from re import compile
22 from scapy.packet import Raw
23 from scapy.layers.l2 import Ether
24 from scapy.layers.inet import IP, UDP, ICMP
25 from scapy.layers.ipsec import ESP
26 import scapy.layers.inet6 as inet6
27 from scapy.layers.inet6 import IPv6, ICMPv6DestUnreach
28 from scapy.contrib.ospf import OSPF_Hdr, OSPFv3_Hello
29 from framework import VppTestCase, VppTestRunner
31 from vpp_ip import DpoProto
32 from vpp_ip_route import VppIpRoute, VppRoutePath
33 from vpp_papi import VppEnum
34 from vpp_ipsec_tun_interface import VppIpsecTunInterface
39 class serverSocketThread(threading.Thread):
40 """ Socket server thread"""
42 def __init__(self, threadID, sockName):
43 threading.Thread.__init__(self)
44 self.threadID = threadID
45 self.sockName = sockName
48 self.keep_running = True
51 # Wait for some packets on socket
52 while self.keep_running:
54 data = self.sock.recv(65536)
56 # punt socket metadata
57 # packet_desc = data[0:8]
60 self.rx_pkts.append(Ether(data[8:]))
63 # nothing to receive, sleep a little
70 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
72 os.unlink(self.sockName)
75 self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 65536)
76 self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 65536)
77 fcntl.fcntl(self.sock, fcntl.F_SETFL, os.O_NONBLOCK)
78 self.sock.bind(self.sockName)
84 self.keep_running = False
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_punt_config = [
108 "punt", "{", "socket", cls.tempdir+"/socket_punt", "}"]
109 super(TestPuntSocket, cls).setUpConstants()
112 super(TestPuntSocket, self).setUp()
115 self.create_pg_interfaces(range(2))
116 for i in self.pg_interfaces:
120 del self.sock_servers[:]
121 super(TestPuntSocket, self).tearDown()
123 def socket_client_create(self, sock_name, id=None):
124 thread = serverSocketThread(id, sock_name)
125 self.sock_servers.append(thread)
129 def socket_client_close(self):
131 for thread in self.sock_servers:
132 rx_pkts += thread.close()
136 def verify_port(self, pr, vpr):
137 self.assertEqual(vpr.punt.type, pr['type'])
138 self.assertEqual(vpr.punt.punt.l4.port,
139 pr['punt']['l4']['port'])
140 self.assertEqual(vpr.punt.punt.l4.protocol,
141 pr['punt']['l4']['protocol'])
142 self.assertEqual(vpr.punt.punt.l4.af,
143 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,
148 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,
153 pr['punt']['ip_proto']['af'])
154 self.assertEqual(vpr.punt.punt.ip_proto.protocol,
155 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
185 'protocol': udp_proto
193 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
194 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
195 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
201 'protocol': udp_proto
208 class TestIP4PuntSocket(TestPuntSocket):
209 """ Punt Socket for IPv4 UDP """
213 super(TestIP4PuntSocket, cls).setUpClass()
216 def tearDownClass(cls):
217 super(TestIP4PuntSocket, cls).tearDownClass()
220 super(TestIP4PuntSocket, self).setUp()
222 for i in self.pg_interfaces:
227 super(TestIP4PuntSocket, self).tearDown()
228 for i in self.pg_interfaces:
232 def test_punt_socket_dump(self):
233 """ Punt socket registration/deregistration"""
235 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
236 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
237 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
239 punts = self.vapi.punt_socket_dump(type=pt_l4)
240 self.assertEqual(len(punts), 0)
243 # configure a punt socket
245 punt_l4 = mk_vpp_cfg4()
247 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
248 "%s/socket_punt_1111" % self.tempdir)
249 self.vapi.punt_socket_register(set_port(punt_l4, 2222),
250 "%s/socket_punt_2222" % self.tempdir)
251 punts = self.vapi.punt_socket_dump(type=pt_l4)
252 self.assertEqual(len(punts), 2)
253 self.verify_port(set_port(punt_l4, 1111), punts[0])
254 self.verify_port(set_port(punt_l4, 2222), punts[1])
257 # deregister a punt socket
259 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
260 punts = self.vapi.punt_socket_dump(type=pt_l4)
261 self.assertEqual(len(punts), 1)
264 # configure a punt socket again
266 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
267 "%s/socket_punt_1111" % self.tempdir)
268 self.vapi.punt_socket_register(set_port(punt_l4, 3333),
269 "%s/socket_punt_3333" % self.tempdir)
270 punts = self.vapi.punt_socket_dump(type=pt_l4)
271 self.assertEqual(len(punts), 3)
273 self.logger.info(self.vapi.cli("sh punt sock reg"))
276 # deregister all punt socket
278 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
279 self.vapi.punt_socket_deregister(set_port(punt_l4, 2222))
280 self.vapi.punt_socket_deregister(set_port(punt_l4, 3333))
281 punts = self.vapi.punt_socket_dump(type=pt_l4)
282 self.assertEqual(len(punts), 0)
284 def test_punt_socket_traffic_single_port_single_socket(self):
285 """ Punt socket traffic single port single socket"""
288 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
289 punt_l4 = set_port(mk_vpp_cfg4(), port)
291 p = (Ether(src=self.pg0.remote_mac,
292 dst=self.pg0.local_mac) /
293 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
294 UDP(sport=9876, dport=port) /
297 pkts = p * self.nr_packets
299 punts = self.vapi.punt_socket_dump(type=pt_l4)
300 self.assertEqual(len(punts), 0)
303 # expect ICMP - port unreachable for all packets
305 rx = self.send_and_expect(self.pg0, pkts, self.pg0)
308 self.assertEqual(int(p[IP].proto), 1) # ICMP
309 self.assertEqual(int(p[ICMP].code), 3) # unreachable
312 # configure a punt socket
314 self.socket_client_create("%s/socket_%d" % (self.tempdir, port))
315 self.vapi.punt_socket_register(punt_l4, "%s/socket_%d" %
316 (self.tempdir, port))
317 punts = self.vapi.punt_socket_dump(type=pt_l4)
318 self.assertEqual(len(punts), 1)
321 # expect punt socket and no packets on pg0
323 self.send_and_assert_no_replies(self.pg0, pkts)
324 rx = self.socket_client_close()
325 self.verify_udp_pkts(rx, len(pkts), port)
328 # remove punt socket. expect ICMP - port unreachable for all packets
330 self.vapi.punt_socket_deregister(punt_l4)
331 punts = self.vapi.punt_socket_dump(type=pt_l4)
332 self.assertEqual(len(punts), 0)
334 rx = self.send_and_expect(self.pg0, pkts, self.pg0)
336 self.assertEqual(int(p[IP].proto), 1) # ICMP
337 self.assertEqual(int(p[ICMP].code), 3) # unreachable
339 def test_punt_socket_traffic_multi_ports_multi_sockets(self):
340 """ Punt socket traffic multi ports and multi sockets"""
342 punt_l4 = mk_vpp_cfg4()
344 # configuration for each UDP port
348 # create stream of packets for each port
350 for port in self.ports:
351 # choose port from port list
354 pkt = (Ether(src=self.pg0.remote_mac,
355 dst=self.pg0.local_mac) /
356 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
357 UDP(sport=9876, dport=port) /
359 cfgs[port]['pkts'] = pkt * self.nr_packets
360 cfgs[port]['port'] = port
361 cfgs[port]['vpp'] = copy.deepcopy(set_port(punt_l4, port))
363 # configure punt sockets
364 cfgs[port]['sock'] = self.socket_client_create(
365 "%s/socket_%d" % (self.tempdir, port))
366 self.vapi.punt_socket_register(
368 "%s/socket_%d" % (self.tempdir, port))
371 # send the packets that get punted
373 for cfg in cfgs.values():
374 self.send_and_assert_no_replies(self.pg0, cfg['pkts'])
377 # test that we got the excepted packets on the expected socket
379 for cfg in cfgs.values():
380 rx = cfg['sock'].close()
381 self.verify_udp_pkts(rx, len(cfg['pkts']), cfg['port'])
382 self.vapi.punt_socket_deregister(cfg['vpp'])
384 def test_punt_socket_traffic_multi_ports_single_socket(self):
385 """ Punt socket traffic multi ports and single socket"""
387 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
388 punt_l4 = mk_vpp_cfg4()
391 # create stream of packets with each port
394 for port in self.ports:
395 # choose port from port list
396 pkt = (Ether(src=self.pg0.remote_mac,
397 dst=self.pg0.local_mac) /
398 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
399 UDP(sport=9876, dport=port) /
401 pkts += pkt * self.nr_packets
404 # configure a punt socket
406 self.socket_client_create("%s/socket_multi" % self.tempdir)
408 self.vapi.punt_socket_register(set_port(punt_l4, p),
409 "%s/socket_multi" % self.tempdir)
410 punts = self.vapi.punt_socket_dump(type=pt_l4)
411 self.assertEqual(len(punts), len(self.ports))
414 # expect punt socket and no packets on pg0
416 self.send_and_assert_no_replies(self.pg0, pkts)
417 self.logger.info(self.vapi.cli("show trace"))
418 rx = self.socket_client_close()
421 self.verify_udp_pkts(rx, self.nr_packets, p)
422 self.vapi.punt_socket_deregister(set_port(punt_l4, p))
423 punts = self.vapi.punt_socket_dump(type=pt_l4)
424 self.assertEqual(len(punts), 0)
427 class TestIP6PuntSocket(TestPuntSocket):
428 """ Punt Socket for IPv6 UDP """
432 super(TestIP6PuntSocket, cls).setUpClass()
435 def tearDownClass(cls):
436 super(TestIP6PuntSocket, cls).tearDownClass()
439 super(TestIP6PuntSocket, self).setUp()
441 for i in self.pg_interfaces:
446 super(TestIP6PuntSocket, self).tearDown()
447 for i in self.pg_interfaces:
451 def test_punt_socket_dump(self):
452 """ Punt socket registration """
454 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
455 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
456 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
458 # configure a punt socket
465 'protocol': udp_proto
470 punts = self.vapi.punt_socket_dump(type=pt_l4)
471 self.assertEqual(len(punts), 0)
474 # configure a punt socket
476 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
477 "%s/socket_1111" % self.tempdir)
478 self.vapi.punt_socket_register(set_port(punt_l4, 2222),
479 "%s/socket_2222" % self.tempdir)
480 punts = self.vapi.punt_socket_dump(type=pt_l4)
481 self.assertEqual(len(punts), 2)
482 self.verify_port(set_port(punt_l4, 1111), punts[0])
483 self.verify_port(set_port(punt_l4, 2222), punts[1])
486 # deregister a punt socket
488 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
489 punts = self.vapi.punt_socket_dump(type=pt_l4)
490 self.assertEqual(len(punts), 1)
493 # configure a punt socket again
495 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
496 "%s/socket_1111" % self.tempdir)
497 punts = self.vapi.punt_socket_dump(type=pt_l4)
498 self.assertEqual(len(punts), 2)
501 # deregister all punt socket
503 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
504 self.vapi.punt_socket_deregister(set_port(punt_l4, 2222))
505 self.vapi.punt_socket_deregister(set_port(punt_l4, 3333))
506 punts = self.vapi.punt_socket_dump(type=pt_l4)
507 self.assertEqual(len(punts), 0)
509 def test_punt_socket_traffic_single_port_single_socket(self):
510 """ Punt socket traffic single port single socket"""
513 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
514 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
515 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
521 'protocol': udp_proto,
527 p = (Ether(src=self.pg0.remote_mac,
528 dst=self.pg0.local_mac) /
529 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
530 inet6.UDP(sport=9876, dport=port) /
533 pkts = p * self.nr_packets
535 punts = self.vapi.punt_socket_dump(type=pt_l4)
536 self.assertEqual(len(punts), 0)
539 # expect ICMPv6 - destination unreachable for all packets
541 self.vapi.cli("clear trace")
542 self.pg0.add_stream(pkts)
543 self.pg_enable_capture(self.pg_interfaces)
545 # FIXME - when punt socket deregister is implemented
546 # rx = self.pg0.get_capture(self.nr_packets)
548 # self.assertEqual(int(p[IPv6].nh), 58) # ICMPv6
549 # self.assertEqual(int(p[ICMPv6DestUnreach].code),4) # unreachable
552 # configure a punt socket
554 self.socket_client_create("%s/socket_%d" % (self.tempdir, port))
555 self.vapi.punt_socket_register(punt_l4, "%s/socket_%d" %
556 (self.tempdir, port))
557 punts = self.vapi.punt_socket_dump(type=pt_l4)
558 self.assertEqual(len(punts), 1)
561 # expect punt socket and no packets on pg0
563 self.vapi.cli("clear errors")
564 self.vapi.cli("clear trace")
565 self.pg0.add_stream(pkts)
566 self.pg_enable_capture(self.pg_interfaces)
568 self.pg0.get_capture(0)
569 self.logger.info(self.vapi.cli("show trace"))
570 rx = self.socket_client_close()
571 self.verify_udp_pkts(rx, len(pkts), port)
574 # remove punt socket. expect ICMP - dest. unreachable for all packets
576 self.vapi.punt_socket_deregister(punt_l4)
577 punts = self.vapi.punt_socket_dump(type=pt_l4)
578 self.assertEqual(len(punts), 0)
579 self.pg0.add_stream(pkts)
580 self.pg_enable_capture(self.pg_interfaces)
582 # FIXME - when punt socket deregister is implemented
583 # self.pg0.get_capture(nr_packets)
585 def test_punt_socket_traffic_multi_ports_multi_sockets(self):
586 """ Punt socket traffic multi ports and multi sockets"""
588 punt_l4 = mk_vpp_cfg6()
590 # configuration for each UDP port
594 # create stream of packets for each port
596 for port in self.ports:
597 # choose port from port list
600 pkt = (Ether(src=self.pg0.remote_mac,
601 dst=self.pg0.local_mac) /
602 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
603 UDP(sport=9876, dport=port) /
605 cfgs[port]['pkts'] = pkt * self.nr_packets
606 cfgs[port]['port'] = port
607 cfgs[port]['vpp'] = copy.deepcopy(set_port(punt_l4, port))
609 # configure punt sockets
610 cfgs[port]['sock'] = self.socket_client_create(
611 "%s/socket_%d" % (self.tempdir, port))
612 self.vapi.punt_socket_register(
614 "%s/socket_%d" % (self.tempdir, port))
617 # send the packets that get punted
619 for cfg in cfgs.values():
620 self.send_and_assert_no_replies(self.pg0, cfg['pkts'])
623 # test that we got the excepted packets on the expected socket
625 for cfg in cfgs.values():
626 rx = cfg['sock'].close()
627 self.verify_udp_pkts(rx, len(cfg['pkts']), cfg['port'])
628 self.vapi.punt_socket_deregister(cfg['vpp'])
630 def test_punt_socket_traffic_multi_ports_single_socket(self):
631 """ Punt socket traffic multi ports and single socket"""
633 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
634 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
635 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
641 'protocol': udp_proto,
647 # create stream of packets with each port
650 for port in self.ports:
651 # choose port from port list
652 pkt = (Ether(src=self.pg0.remote_mac,
653 dst=self.pg0.local_mac) /
654 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
655 UDP(sport=9876, dport=port) /
657 pkts += pkt * self.nr_packets
662 punts = self.vapi.punt_socket_dump(type=pt_l4)
663 self.assertEqual(len(punts), 0)
666 # configure a punt socket
668 self.socket_client_create("%s/socket_multi" % self.tempdir)
670 self.vapi.punt_socket_register(set_port(punt_l4, p),
671 "%s/socket_multi" % self.tempdir)
672 punts = self.vapi.punt_socket_dump(type=pt_l4)
673 self.assertEqual(len(punts), len(self.ports))
676 # expect punt socket and no packets on pg0
678 self.vapi.cli("clear errors")
679 self.vapi.cli("clear trace")
680 self.pg0.add_stream(pkts)
681 self.pg_enable_capture(self.pg_interfaces)
683 # give a chance to punt socket to collect all packets
685 self.pg0.get_capture(0)
686 rx = self.socket_client_close()
689 self.verify_udp_pkts(rx, self.nr_packets, p)
690 self.vapi.punt_socket_deregister(set_port(punt_l4, p))
691 punts = self.vapi.punt_socket_dump(type=pt_l4)
692 self.assertEqual(len(punts), 0)
695 class TestExceptionPuntSocket(TestPuntSocket):
696 """ Punt Socket for Exceptions """
700 super(TestExceptionPuntSocket, cls).setUpClass()
703 def tearDownClass(cls):
704 super(TestExceptionPuntSocket, cls).tearDownClass()
707 super(TestExceptionPuntSocket, self).setUp()
709 self.create_pg_interfaces(range(2))
710 for i in self.pg_interfaces:
715 super(TestExceptionPuntSocket, self).tearDown()
716 for i in self.pg_interfaces:
720 def test_registration(self):
721 """ Punt socket registration/deregistration"""
723 pt_ex = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_EXCEPTION
725 punts = self.vapi.punt_socket_dump(type=pt_ex)
726 self.assertEqual(len(punts), 0)
729 # configure a punt socket
738 self.vapi.punt_socket_register(set_reason(punt_ex, 1),
739 "%s/socket_punt_1" % self.tempdir)
740 self.vapi.punt_socket_register(set_reason(punt_ex, 2),
741 "%s/socket_punt_2" % self.tempdir)
742 punts = self.vapi.punt_socket_dump(type=pt_ex)
743 self.assertEqual(len(punts), 2)
744 self.verify_exception(set_reason(punt_ex, 1), punts[0])
745 self.verify_exception(set_reason(punt_ex, 2), punts[1])
748 # deregister a punt socket
750 self.vapi.punt_socket_deregister(set_reason(punt_ex, 1))
751 punts = self.vapi.punt_socket_dump(type=pt_ex)
752 self.assertEqual(len(punts), 1)
755 # configure a punt socket again
757 self.vapi.punt_socket_register(set_reason(punt_ex, 1),
758 "%s/socket_punt_1" % self.tempdir)
759 self.vapi.punt_socket_register(set_reason(punt_ex, 3),
760 "%s/socket_punt_3" % self.tempdir)
761 punts = self.vapi.punt_socket_dump(type=pt_ex)
762 self.assertEqual(len(punts), 3)
764 self.logger.info(self.vapi.cli("sh punt sock reg exception"))
767 # deregister all punt socket
769 self.vapi.punt_socket_deregister(set_reason(punt_ex, 1))
770 self.vapi.punt_socket_deregister(set_reason(punt_ex, 2))
771 self.vapi.punt_socket_deregister(set_reason(punt_ex, 3))
772 punts = self.vapi.punt_socket_dump(type=pt_ex)
773 self.assertEqual(len(punts), 0)
775 def verify_esp_pkts(self, rxs, n_sent, spi, has_udp):
776 self.assertEqual(len(rxs), n_sent)
778 self.assertTrue(rx.haslayer(IP))
779 self.assertTrue(rx.haslayer(ESP))
780 self.assertEqual(rx[ESP].spi, spi)
782 self.assertTrue(rx.haslayer(UDP))
784 def test_traffic(self):
785 """ Punt socket traffic """
788 pt_ex = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_EXCEPTION
797 # we're dealing with IPSec tunnels punting for no-such-tunnel
798 # (SPI=0 goes to ikev2)
801 cfgs['ipsec4-no-such-tunnel'] = {'spi': 99,
806 # find the VPP ID for these punt exception reasin
808 rs = self.vapi.punt_reason_dump()
813 if r.reason.name == key:
814 cfgs[key]['id'] = r.reason.id
815 cfgs[key]['vpp'] = copy.deepcopy(
821 # configure punt sockets
823 for cfg in cfgs.values():
824 cfg['sock'] = self.socket_client_create("%s/socket_%d" %
825 (self.tempdir, cfg['id']))
826 self.vapi.punt_socket_register(
827 cfg['vpp'], "%s/socket_%d" % (self.tempdir, cfg['id']))
830 # create packet streams for 'no-such-tunnel' exception
832 for cfg in cfgs.values():
833 pkt = (Ether(src=cfg['itf'].remote_mac,
834 dst=cfg['itf'].local_mac) /
835 IP(src=cfg['itf'].remote_ip4,
836 dst=cfg['itf'].local_ip4))
838 pkt = pkt / UDP(sport=666, dport=4500)
839 pkt = (pkt / ESP(spi=cfg['spi'], seq=3) /
844 # send packets for each SPI we expect to be punted
846 for cfg in cfgs.values():
847 self.send_and_assert_no_replies(cfg['itf'], cfg['pkts'])
850 # verify the punted packets arrived on the associated socket
852 for cfg in cfgs.values():
853 rx = cfg['sock'].close()
854 self.verify_esp_pkts(rx, len(cfg['pkts']),
855 cfg['spi'], cfg['udp'])
858 # add some tunnels, make sure it still punts
860 VppIpsecTunInterface(self, self.pg0, 1000, 1000,
861 (VppEnum.vl_api_ipsec_crypto_alg_t.
862 IPSEC_API_CRYPTO_ALG_AES_CBC_128),
865 (VppEnum.vl_api_ipsec_integ_alg_t.
866 IPSEC_API_INTEG_ALG_SHA1_96),
868 b"0123456701234567").add_vpp_config()
869 VppIpsecTunInterface(self, self.pg1, 1000, 1000,
870 (VppEnum.vl_api_ipsec_crypto_alg_t.
871 IPSEC_API_CRYPTO_ALG_AES_CBC_128),
874 (VppEnum.vl_api_ipsec_integ_alg_t.
875 IPSEC_API_INTEG_ALG_SHA1_96),
878 udp_encap=True).add_vpp_config()
881 # send packets for each SPI we expect to be punted
883 for cfg in cfgs.values():
884 self.send_and_assert_no_replies(cfg['itf'], cfg['pkts'])
887 # verify the punted packets arrived on the associated socket
889 for cfg in cfgs.values():
890 rx = cfg['sock'].close()
891 self.verify_esp_pkts(rx, len(cfg['pkts']),
892 cfg['spi'], cfg['udp'])
896 for cfg in cfgs.values():
897 self.vapi.punt_socket_deregister(cfg['vpp'])
900 class TestIpProtoPuntSocket(TestPuntSocket):
901 """ Punt Socket for IP packets """
905 super(TestIpProtoPuntSocket, cls).setUpClass()
908 def tearDownClass(cls):
909 super(TestIpProtoPuntSocket, cls).tearDownClass()
912 super(TestIpProtoPuntSocket, self).setUp()
914 for i in self.pg_interfaces:
919 super(TestIpProtoPuntSocket, self).tearDown()
920 for i in self.pg_interfaces:
924 def test_registration(self):
925 """ Punt socket registration/deregistration"""
927 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
928 pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
929 proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
930 proto_eigrp = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_EIGRP
932 punts = self.vapi.punt_socket_dump(type=pt_ip)
933 self.assertEqual(len(punts), 0)
936 # configure a punt socket
943 'protocol': proto_ospf
952 'protocol': proto_eigrp
957 self.vapi.punt_socket_register(punt_ospf,
958 "%s/socket_punt_1" % self.tempdir)
959 self.vapi.punt_socket_register(punt_eigrp,
960 "%s/socket_punt_2" % self.tempdir)
961 self.logger.info(self.vapi.cli("sh punt sock reg ip"))
962 punts = self.vapi.punt_socket_dump(type=pt_ip)
963 self.assertEqual(len(punts), 2)
964 self.verify_ip_proto(punt_ospf, punts[0])
965 self.verify_ip_proto(punt_eigrp, punts[1])
968 # deregister a punt socket
970 self.vapi.punt_socket_deregister(punt_ospf)
971 punts = self.vapi.punt_socket_dump(type=pt_ip)
972 self.assertEqual(len(punts), 1)
975 # configure a punt socket again
977 self.vapi.punt_socket_register(punt_ospf,
978 "%s/socket_punt_3" % self.tempdir)
979 punts = self.vapi.punt_socket_dump(type=pt_ip)
980 self.assertEqual(len(punts), 2)
982 self.logger.info(self.vapi.cli("sh punt sock reg exception"))
985 # deregister all punt socket
987 self.vapi.punt_socket_deregister(punt_eigrp)
988 self.vapi.punt_socket_deregister(punt_ospf)
989 punts = self.vapi.punt_socket_dump(type=pt_ip)
990 self.assertEqual(len(punts), 0)
992 def verify_ospf_pkts(self, rxs, n_sent):
993 self.assertEqual(len(rxs), n_sent)
995 self.assertTrue(rx.haslayer(OSPF_Hdr))
997 def test_traffic(self):
998 """ Punt socket traffic """
1000 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
1001 pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
1002 proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
1005 # configure a punt socket to capture OSPF packets
1012 'protocol': proto_ospf
1018 # create packet streams and configure a punt sockets
1020 pkt = (Ether(src=self.pg0.remote_mac,
1021 dst=self.pg0.local_mac) /
1022 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
1027 sock = self.socket_client_create("%s/socket_1" % self.tempdir)
1028 self.vapi.punt_socket_register(
1029 punt_ospf, "%s/socket_1" % self.tempdir)
1032 # send packets for each SPI we expect to be punted
1034 self.send_and_assert_no_replies(self.pg0, pkts)
1037 # verify the punted packets arrived on the associated socket
1040 self.verify_ospf_pkts(rx, len(pkts))
1041 self.vapi.punt_socket_deregister(punt_ospf)
1044 class TestPunt(VppTestCase):
1045 """ Exception Punt Test Case """
1048 def setUpClass(cls):
1049 super(TestPunt, cls).setUpClass()
1052 def tearDownClass(cls):
1053 super(TestPunt, cls).tearDownClass()
1056 super(TestPunt, self).setUp()
1058 self.create_pg_interfaces(range(4))
1060 for i in self.pg_interfaces:
1068 for i in self.pg_interfaces:
1072 super(TestPunt, self).tearDown()
1074 def test_punt(self):
1075 """ Exception Path testing """
1078 # dump the punt registered reasons
1079 # search for a few we know should be there
1081 rs = self.vapi.punt_reason_dump()
1083 reasons = ["ipsec6-no-such-tunnel",
1084 "ipsec4-no-such-tunnel",
1085 "ipsec4-spi-o-udp-0"]
1087 for reason in reasons:
1090 if r.reason.name == reason:
1093 self.assertTrue(found)
1096 # Using the test CLI we will hook in a exception path to
1097 # send ACL deny packets out of pg0 and pg1.
1098 # the ACL is src,dst = 1.1.1.1,1.1.1.2
1100 ip_1_1_1_2 = VppIpRoute(self, "1.1.1.2", 32,
1101 [VppRoutePath(self.pg3.remote_ip4,
1102 self.pg3.sw_if_index)])
1103 ip_1_1_1_2.add_vpp_config()
1104 ip_1_2 = VppIpRoute(self, "1::2", 128,
1105 [VppRoutePath(self.pg3.remote_ip6,
1106 self.pg3.sw_if_index,
1107 proto=DpoProto.DPO_PROTO_IP6)])
1108 ip_1_2.add_vpp_config()
1110 p4 = (Ether(src=self.pg2.remote_mac,
1111 dst=self.pg2.local_mac) /
1112 IP(src="1.1.1.1", dst="1.1.1.2") /
1113 UDP(sport=1234, dport=1234) /
1115 p6 = (Ether(src=self.pg2.remote_mac,
1116 dst=self.pg2.local_mac) /
1117 IPv6(src="1::1", dst="1::2") /
1118 UDP(sport=1234, dport=1234) /
1120 self.send_and_expect(self.pg2, p4*1, self.pg3)
1121 self.send_and_expect(self.pg2, p6*1, self.pg3)
1124 # apply the punting features
1126 self.vapi.cli("test punt pg2")
1129 # dump the punt reasons to learn the IDs assigned
1131 rs = self.vapi.punt_reason_dump(reason={'name': "reason-v4"})
1132 r4 = rs[0].reason.id
1133 rs = self.vapi.punt_reason_dump(reason={'name': "reason-v6"})
1134 r6 = rs[0].reason.id
1139 self.send_and_assert_no_replies(self.pg2, p4*NUM_PKTS)
1140 self.send_and_assert_no_replies(self.pg2, p6*NUM_PKTS)
1144 # 1 - node error counters
1145 # 2 - per-reason counters
1146 # 2, 3 are the index of the assigned punt reason
1148 stats = self.statistics.get_err_counter(
1149 "/err/punt-dispatch/No registrations")
1150 self.assertEqual(stats, 2*NUM_PKTS)
1152 stats = self.statistics.get_counter("/net/punt")
1153 self.assertEqual(stats[0][r4]['packets'], NUM_PKTS)
1154 self.assertEqual(stats[0][r6]['packets'], NUM_PKTS)
1157 # use the test CLI to test a client that punts exception
1158 # packets out of pg0
1160 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip4)
1161 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip6)
1163 rx4s = self.send_and_expect(self.pg2, p4*NUM_PKTS, self.pg0)
1164 rx6s = self.send_and_expect(self.pg2, p6*NUM_PKTS, self.pg0)
1167 # check the packets come out IP unmodified but destined to pg0 host
1170 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1171 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1172 self.assertEqual(p4[IP].dst, rx[IP].dst)
1173 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1175 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1176 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1177 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1178 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1180 stats = self.statistics.get_counter("/net/punt")
1181 self.assertEqual(stats[0][r4]['packets'], 2*NUM_PKTS)
1182 self.assertEqual(stats[0][r6]['packets'], 2*NUM_PKTS)
1185 # add another registration for the same reason to send packets
1188 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip4)
1189 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip6)
1191 self.vapi.cli("clear trace")
1192 self.pg2.add_stream(p4 * NUM_PKTS)
1193 self.pg_enable_capture(self.pg_interfaces)
1196 rxd = self.pg0.get_capture(NUM_PKTS)
1198 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1199 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1200 self.assertEqual(p4[IP].dst, rx[IP].dst)
1201 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1202 rxd = self.pg1.get_capture(NUM_PKTS)
1204 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1205 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1206 self.assertEqual(p4[IP].dst, rx[IP].dst)
1207 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1209 self.vapi.cli("clear trace")
1210 self.pg2.add_stream(p6 * NUM_PKTS)
1211 self.pg_enable_capture(self.pg_interfaces)
1214 rxd = self.pg0.get_capture(NUM_PKTS)
1216 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1217 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1218 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1219 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1220 rxd = self.pg1.get_capture(NUM_PKTS)
1222 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1223 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1224 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1225 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1227 stats = self.statistics.get_counter("/net/punt")
1228 self.assertEqual(stats[0][r4]['packets'], 3*NUM_PKTS)
1229 self.assertEqual(stats[0][r6]['packets'], 3*NUM_PKTS)
1231 self.logger.info(self.vapi.cli("show vlib graph punt-dispatch"))
1232 self.logger.info(self.vapi.cli("show punt client"))
1233 self.logger.info(self.vapi.cli("show punt reason"))
1234 self.logger.info(self.vapi.cli("show punt stats"))
1235 self.logger.info(self.vapi.cli("show punt db"))
1238 if __name__ == '__main__':
1239 unittest.main(testRunner=VppTestRunner)