9 from struct import unpack, unpack_from
12 import unittest2 as unittest
16 from util import ppp, ppc
17 from re import compile
19 from scapy.packet import Raw
20 from scapy.layers.l2 import Ether
21 from scapy.layers.inet import IP, UDP, ICMP
22 from scapy.layers.ipsec import ESP
23 import scapy.layers.inet6 as inet6
24 from scapy.layers.inet6 import IPv6, ICMPv6DestUnreach
25 from scapy.contrib.ospf import OSPF_Hdr, OSPFv3_Hello
27 from framework import VppTestCase, VppTestRunner
29 from vpp_ip import DpoProto
30 from vpp_ip_route import VppIpRoute, VppRoutePath
31 from vpp_papi import VppEnum
32 from vpp_ipsec_tun_interface import VppIpsecTunInterface
37 class serverSocketThread(threading.Thread):
38 """ Socket server thread"""
40 def __init__(self, threadID, sockName):
41 threading.Thread.__init__(self)
42 self.threadID = threadID
43 self.sockName = sockName
48 # 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 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
61 os.unlink(self.sockName)
64 self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 65536)
65 self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 65536)
66 self.sock.bind(self.sockName)
75 class TestPuntSocket(VppTestCase):
78 ports = [1111, 2222, 3333, 4444]
84 super(TestPuntSocket, cls).setUpClass()
87 def tearDownClass(cls):
88 super(TestPuntSocket, cls).tearDownClass()
91 def setUpConstants(cls):
92 cls.extra_vpp_punt_config = [
93 "punt", "{", "socket", cls.tempdir+"/socket_punt", "}"]
94 super(TestPuntSocket, cls).setUpConstants()
97 super(TestPuntSocket, self).setUp()
100 self.create_pg_interfaces(range(2))
101 for i in self.pg_interfaces:
105 del self.sock_servers[:]
106 super(TestPuntSocket, self).tearDown()
108 def socket_client_create(self, sock_name, id=None):
109 thread = serverSocketThread(id, sock_name)
110 self.sock_servers.append(thread)
114 def socket_client_close(self):
116 for thread in self.sock_servers:
117 rx_pkts += thread.close()
120 def verify_port(self, pr, vpr):
121 self.assertEqual(vpr.punt.type, pr['type'])
122 self.assertEqual(vpr.punt.punt.l4.port,
123 pr['punt']['l4']['port'])
124 self.assertEqual(vpr.punt.punt.l4.protocol,
125 pr['punt']['l4']['protocol'])
126 self.assertEqual(vpr.punt.punt.l4.af,
127 pr['punt']['l4']['af'])
129 def verify_exception(self, pr, vpr):
130 self.assertEqual(vpr.punt.type, pr['type'])
131 self.assertEqual(vpr.punt.punt.exception.id,
132 pr['punt']['exception']['id'])
134 def verify_ip_proto(self, pr, vpr):
135 self.assertEqual(vpr.punt.type, pr['type'])
136 self.assertEqual(vpr.punt.punt.ip_proto.af,
137 pr['punt']['ip_proto']['af'])
138 self.assertEqual(vpr.punt.punt.ip_proto.protocol,
139 pr['punt']['ip_proto']['protocol'])
141 def verify_udp_pkts(self, rxs, n_rx, port):
144 self.assertTrue(rx.haslayer(UDP))
145 if rx[UDP].dport == port:
147 self.assertEqual(n_match, n_rx)
150 def set_port(pr, port):
151 pr['punt']['l4']['port'] = port
155 def set_reason(pr, reason):
156 pr['punt']['exception']['id'] = reason
161 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
162 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
163 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
169 'protocol': udp_proto
177 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
178 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
179 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
185 '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(set_port(punt_l4, 1111),
232 b"%s/socket_punt_1111" %
233 six.ensure_binary(self.tempdir))
234 self.vapi.punt_socket_register(set_port(punt_l4, 2222),
235 b"%s/socket_punt_2222" %
236 six.ensure_binary(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(set_port(punt_l4, 1111),
253 b"%s/socket_punt_1111" %
254 six.ensure_binary(self.tempdir))
255 self.vapi.punt_socket_register(set_port(punt_l4, 3333),
256 b"%s/socket_punt_3333" %
257 six.ensure_binary(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)
279 p = (Ether(src=self.pg0.remote_mac,
280 dst=self.pg0.local_mac) /
281 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
282 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(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(b"%s/socket_%d" % (
303 six.ensure_binary(self.tempdir), port))
304 self.vapi.punt_socket_register(punt_l4, b"%s/socket_%d" % (
305 six.ensure_binary(self.tempdir), port))
306 punts = self.vapi.punt_socket_dump(type=pt_l4)
307 self.assertEqual(len(punts), 1)
310 # expect punt socket and no packets on pg0
312 self.send_and_assert_no_replies(self.pg0, pkts)
313 rx = self.socket_client_close()
314 self.verify_udp_pkts(rx, len(pkts), port)
317 # remove punt socket. expect ICMP - port unreachable for all packets
319 self.vapi.punt_socket_deregister(punt_l4)
320 punts = self.vapi.punt_socket_dump(type=pt_l4)
321 self.assertEqual(len(punts), 0)
323 rx = self.send_and_expect(self.pg0, pkts, self.pg0)
325 self.assertEqual(int(p[IP].proto), 1) # ICMP
326 self.assertEqual(int(p[ICMP].code), 3) # unreachable
328 def test_punt_socket_traffic_multi_ports_multi_sockets(self):
329 """ Punt socket traffic multi ports and multi sockets"""
331 punt_l4 = mk_vpp_cfg4()
333 # configuration for each UDP port
337 # create stream of packets for each port
339 for port in self.ports:
340 # choose port from port list
343 pkt = (Ether(src=self.pg0.remote_mac,
344 dst=self.pg0.local_mac) /
345 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
346 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 b"%s/socket_%d" % (six.ensure_binary(self.tempdir), port))
355 self.vapi.punt_socket_register(
357 b"%s/socket_%d" % (six.ensure_binary(self.tempdir),
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
386 pkt = (Ether(src=self.pg0.remote_mac,
387 dst=self.pg0.local_mac) /
388 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
389 UDP(sport=9876, dport=port) /
391 pkts += pkt * self.nr_packets
394 # configure a punt socket
396 self.socket_client_create(b"%s/socket_multi" %
397 six.ensure_binary(self.tempdir))
399 self.vapi.punt_socket_register(set_port(punt_l4, p),
401 six.ensure_binary(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
457 'protocol': udp_proto
462 punts = self.vapi.punt_socket_dump(type=pt_l4)
463 self.assertEqual(len(punts), 0)
466 # configure a punt socket
468 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
470 six.ensure_binary(self.tempdir))
471 self.vapi.punt_socket_register(set_port(punt_l4, 2222),
473 six.ensure_binary(self.tempdir))
474 punts = self.vapi.punt_socket_dump(type=pt_l4)
475 self.assertEqual(len(punts), 2)
476 self.verify_port(set_port(punt_l4, 1111), punts[0])
477 self.verify_port(set_port(punt_l4, 2222), punts[1])
480 # deregister a punt socket
482 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
483 punts = self.vapi.punt_socket_dump(type=pt_l4)
484 self.assertEqual(len(punts), 1)
487 # configure a punt socket again
489 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
491 six.ensure_binary(self.tempdir))
492 punts = self.vapi.punt_socket_dump(type=pt_l4)
493 self.assertEqual(len(punts), 2)
496 # deregister all punt socket
498 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
499 self.vapi.punt_socket_deregister(set_port(punt_l4, 2222))
500 self.vapi.punt_socket_deregister(set_port(punt_l4, 3333))
501 punts = self.vapi.punt_socket_dump(type=pt_l4)
502 self.assertEqual(len(punts), 0)
504 def test_punt_socket_traffic_single_port_single_socket(self):
505 """ Punt socket traffic single port single socket"""
508 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
509 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
510 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
516 'protocol': udp_proto,
522 p = (Ether(src=self.pg0.remote_mac,
523 dst=self.pg0.local_mac) /
524 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
525 inet6.UDP(sport=9876, dport=port) /
528 pkts = p * self.nr_packets
530 punts = self.vapi.punt_socket_dump(type=pt_l4)
531 self.assertEqual(len(punts), 0)
534 # expect ICMPv6 - destination unreachable for all packets
536 self.vapi.cli("clear trace")
537 self.pg0.add_stream(pkts)
538 self.pg_enable_capture(self.pg_interfaces)
540 # FIXME - when punt socket deregister is implemented
541 # rx = self.pg0.get_capture(self.nr_packets)
543 # self.assertEqual(int(p[IPv6].nh), 58) # ICMPv6
544 # self.assertEqual(int(p[ICMPv6DestUnreach].code),4) # unreachable
547 # configure a punt socket
549 self.socket_client_create(b"%s/socket_%d" % (
550 six.ensure_binary(self.tempdir), port))
551 self.vapi.punt_socket_register(punt_l4, b"%s/socket_%d" % (
552 six.ensure_binary(self.tempdir), port))
553 punts = self.vapi.punt_socket_dump(type=pt_l4)
554 self.assertEqual(len(punts), 1)
557 # expect punt socket and no packets on pg0
559 self.vapi.cli("clear errors")
560 self.vapi.cli("clear trace")
561 self.pg0.add_stream(pkts)
562 self.pg_enable_capture(self.pg_interfaces)
564 self.pg0.get_capture(0)
565 self.logger.info(self.vapi.cli("show trace"))
566 rx = self.socket_client_close()
567 self.verify_udp_pkts(rx, len(pkts), port)
570 # remove punt socket. expect ICMP - dest. unreachable for all packets
572 self.vapi.punt_socket_deregister(punt_l4)
573 punts = self.vapi.punt_socket_dump(type=pt_l4)
574 self.assertEqual(len(punts), 0)
575 self.pg0.add_stream(pkts)
576 self.pg_enable_capture(self.pg_interfaces)
578 # FIXME - when punt socket deregister is implemented
579 # self.pg0.get_capture(nr_packets)
581 def test_punt_socket_traffic_multi_ports_multi_sockets(self):
582 """ Punt socket traffic multi ports and multi sockets"""
584 punt_l4 = mk_vpp_cfg6()
586 # configuration for each UDP port
590 # create stream of packets for each port
592 for port in self.ports:
593 # choose port from port list
596 pkt = (Ether(src=self.pg0.remote_mac,
597 dst=self.pg0.local_mac) /
598 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
599 UDP(sport=9876, dport=port) /
601 cfgs[port]['pkts'] = pkt * self.nr_packets
602 cfgs[port]['port'] = port
603 cfgs[port]['vpp'] = copy.deepcopy(set_port(punt_l4, port))
605 # configure punt sockets
606 cfgs[port]['sock'] = self.socket_client_create(
607 b"%s/socket_%d" % (six.ensure_binary(self.tempdir), port))
608 self.vapi.punt_socket_register(
610 b"%s/socket_%d" % (six.ensure_binary(self.tempdir),
614 # send the packets that get punted
616 for cfg in cfgs.values():
617 self.send_and_assert_no_replies(self.pg0, cfg['pkts'])
620 # test that we got the excepted packets on the expected socket
622 for cfg in cfgs.values():
623 rx = cfg['sock'].close()
624 self.verify_udp_pkts(rx, len(cfg['pkts']), cfg['port'])
625 self.vapi.punt_socket_deregister(cfg['vpp'])
627 def test_punt_socket_traffic_multi_ports_single_socket(self):
628 """ Punt socket traffic multi ports and single socket"""
630 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
631 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
632 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
638 'protocol': udp_proto,
644 # create stream of packets with each port
647 for port in self.ports:
648 # choose port from port list
649 pkt = (Ether(src=self.pg0.remote_mac,
650 dst=self.pg0.local_mac) /
651 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
652 UDP(sport=9876, dport=port) /
654 pkts += pkt * self.nr_packets
659 punts = self.vapi.punt_socket_dump(type=pt_l4)
660 self.assertEqual(len(punts), 0)
663 # configure a punt socket
665 self.socket_client_create(b"%s/socket_multi" %
666 six.ensure_binary(self.tempdir))
668 self.vapi.punt_socket_register(set_port(punt_l4, p),
670 six.ensure_binary(self.tempdir))
671 punts = self.vapi.punt_socket_dump(type=pt_l4)
672 self.assertEqual(len(punts), len(self.ports))
675 # expect punt socket and no packets on pg0
677 self.vapi.cli("clear errors")
678 self.vapi.cli("clear trace")
679 self.pg0.add_stream(pkts)
680 self.pg_enable_capture(self.pg_interfaces)
682 self.pg0.get_capture(0)
683 rx = self.socket_client_close()
686 self.verify_udp_pkts(rx, self.nr_packets, p)
687 self.vapi.punt_socket_deregister(set_port(punt_l4, p))
688 punts = self.vapi.punt_socket_dump(type=pt_l4)
689 self.assertEqual(len(punts), 0)
692 class TestExceptionPuntSocket(TestPuntSocket):
693 """ Punt Socket for Exceptions """
697 super(TestExceptionPuntSocket, cls).setUpClass()
700 def tearDownClass(cls):
701 super(TestExceptionPuntSocket, cls).tearDownClass()
704 super(TestExceptionPuntSocket, self).setUp()
706 for i in self.pg_interfaces:
711 super(TestExceptionPuntSocket, self).tearDown()
712 for i in self.pg_interfaces:
716 def test_registration(self):
717 """ Punt socket registration/deregistration"""
719 pt_ex = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_EXCEPTION
721 punts = self.vapi.punt_socket_dump(type=pt_ex)
722 self.assertEqual(len(punts), 0)
725 # configure a punt socket
734 self.vapi.punt_socket_register(set_reason(punt_ex, 1),
735 b"%s/socket_punt_1" %
736 six.ensure_binary(self.tempdir))
737 self.vapi.punt_socket_register(set_reason(punt_ex, 2),
738 b"%s/socket_punt_2" %
739 six.ensure_binary(self.tempdir))
740 punts = self.vapi.punt_socket_dump(type=pt_ex)
741 self.assertEqual(len(punts), 2)
742 self.verify_exception(set_reason(punt_ex, 1), punts[0])
743 self.verify_exception(set_reason(punt_ex, 2), punts[1])
746 # deregister a punt socket
748 self.vapi.punt_socket_deregister(set_reason(punt_ex, 1))
749 punts = self.vapi.punt_socket_dump(type=pt_ex)
750 self.assertEqual(len(punts), 1)
753 # configure a punt socket again
755 self.vapi.punt_socket_register(set_reason(punt_ex, 1),
756 b"%s/socket_punt_1" %
757 six.ensure_binary(self.tempdir))
758 self.vapi.punt_socket_register(set_reason(punt_ex, 3),
759 b"%s/socket_punt_3" %
760 six.ensure_binary(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):
776 self.assertEqual(len(rxs), n_sent)
778 self.assertTrue(rx.haslayer(ESP))
779 self.assertEqual(rx[ESP].spi, spi)
781 def test_traffic(self):
782 """ Punt socket traffic """
785 pt_ex = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_EXCEPTION
794 # we need an IPSec tunnel for this to work otherwise ESP gets dropped
795 # due to unknown IP proto
797 VppIpsecTunInterface(self, self.pg0, 1000, 1000,
798 (VppEnum.vl_api_ipsec_crypto_alg_t.
799 IPSEC_API_CRYPTO_ALG_AES_CBC_128),
802 (VppEnum.vl_api_ipsec_integ_alg_t.
803 IPSEC_API_INTEG_ALG_SHA1_96),
805 "0123456701234567").add_vpp_config()
808 # we're dealing with IPSec tunnels punting for no-such-tunnel
812 cfgs['ipsec4-no-such-tunnel'] = {'spi': 99}
813 cfgs['ipsec4-spi-0'] = {'spi': 0}
816 # find the VPP ID for these punt exception reasin
818 rs = self.vapi.punt_reason_dump()
821 if r.reason.name == key:
822 cfgs[key]['id'] = r.reason.id
823 cfgs[key]['vpp'] = copy.deepcopy(
829 # create packet streams and configure a punt sockets
831 for cfg in cfgs.values():
832 pkt = (Ether(src=self.pg0.remote_mac,
833 dst=self.pg0.local_mac) /
834 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
835 ESP(spi=cfg['spi'], seq=3) /
837 cfg['pkts'] = pkt * self.nr_packets
839 cfg['sock'] = self.socket_client_create(b"%s/socket_%d" % (
840 six.ensure_binary(self.tempdir), cfg['id']))
841 self.vapi.punt_socket_register(
843 b"%s/socket_%d" % (six.ensure_binary(self.tempdir),
847 # send packets for each SPI we expect to be punted
849 for cfg in cfgs.values():
850 self.send_and_assert_no_replies(self.pg0, cfg['pkts'])
853 # verify the punted packets arrived on the associated socket
855 for cfg in cfgs.values():
856 rx = cfg['sock'].close()
857 self.verify_esp_pkts(rx, len(cfg['pkts']), cfg['spi'])
858 self.vapi.punt_socket_deregister(cfg['vpp'])
861 class TestIpProtoPuntSocket(TestPuntSocket):
862 """ Punt Socket for IP packets """
866 super(TestIpProtoPuntSocket, cls).setUpClass()
869 def tearDownClass(cls):
870 super(TestIpProtoPuntSocket, cls).tearDownClass()
873 super(TestIpProtoPuntSocket, self).setUp()
875 for i in self.pg_interfaces:
880 super(TestIpProtoPuntSocket, self).tearDown()
881 for i in self.pg_interfaces:
885 def test_registration(self):
886 """ Punt socket registration/deregistration"""
888 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
889 pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
890 proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
891 proto_eigrp = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_EIGRP
893 punts = self.vapi.punt_socket_dump(type=pt_ip)
894 self.assertEqual(len(punts), 0)
897 # configure a punt socket
904 'protocol': proto_ospf
913 'protocol': proto_eigrp
918 self.vapi.punt_socket_register(punt_ospf,
919 b"%s/socket_punt_1" %
920 six.ensure_binary(self.tempdir))
921 self.vapi.punt_socket_register(punt_eigrp,
922 b"%s/socket_punt_2" %
923 six.ensure_binary(self.tempdir))
924 self.logger.info(self.vapi.cli("sh punt sock reg ip"))
925 punts = self.vapi.punt_socket_dump(type=pt_ip)
926 self.assertEqual(len(punts), 2)
927 self.verify_ip_proto(punt_ospf, punts[0])
928 self.verify_ip_proto(punt_eigrp, punts[1])
931 # deregister a punt socket
933 self.vapi.punt_socket_deregister(punt_ospf)
934 punts = self.vapi.punt_socket_dump(type=pt_ip)
935 self.assertEqual(len(punts), 1)
938 # configure a punt socket again
940 self.vapi.punt_socket_register(punt_ospf,
941 b"%s/socket_punt_3" %
942 six.ensure_binary(self.tempdir))
943 punts = self.vapi.punt_socket_dump(type=pt_ip)
944 self.assertEqual(len(punts), 2)
946 self.logger.info(self.vapi.cli("sh punt sock reg exception"))
949 # deregister all punt socket
951 self.vapi.punt_socket_deregister(punt_eigrp)
952 self.vapi.punt_socket_deregister(punt_ospf)
953 punts = self.vapi.punt_socket_dump(type=pt_ip)
954 self.assertEqual(len(punts), 0)
956 def verify_ospf_pkts(self, rxs, n_sent):
957 self.assertEqual(len(rxs), n_sent)
959 self.assertTrue(rx.haslayer(OSPF_Hdr))
961 def test_traffic(self):
962 """ Punt socket traffic """
964 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
965 pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
966 proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
969 # configure a punt socket to capture OSPF packets
976 'protocol': proto_ospf
982 # create packet streams and configure a punt sockets
984 pkt = (Ether(src=self.pg0.remote_mac,
985 dst=self.pg0.local_mac) /
986 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
991 sock = self.socket_client_create(b"%s/socket_1" % (
992 six.ensure_binary(self.tempdir)))
993 self.vapi.punt_socket_register(
995 b"%s/socket_1" % (six.ensure_binary(self.tempdir)))
998 # send packets for each SPI we expect to be punted
1000 self.send_and_assert_no_replies(self.pg0, pkts)
1003 # verify the punted packets arrived on the associated socket
1006 self.verify_ospf_pkts(rx, len(pkts))
1007 self.vapi.punt_socket_deregister(punt_ospf)
1010 class TestPunt(VppTestCase):
1011 """ Exception Punt Test Case """
1014 def setUpClass(cls):
1015 super(TestPunt, cls).setUpClass()
1018 def tearDownClass(cls):
1019 super(TestPunt, cls).tearDownClass()
1022 super(TestPunt, self).setUp()
1024 self.create_pg_interfaces(range(4))
1026 for i in self.pg_interfaces:
1034 for i in self.pg_interfaces:
1039 super(TestPunt, self).tearDown()
1041 def test_punt(self):
1042 """ Exception Path testing """
1045 # Using the test CLI we will hook in a exception path to
1046 # send ACL deny packets out of pg0 and pg1.
1047 # the ACL is src,dst = 1.1.1.1,1.1.1.2
1049 ip_1_1_1_2 = VppIpRoute(self, "1.1.1.2", 32,
1050 [VppRoutePath(self.pg3.remote_ip4,
1051 self.pg3.sw_if_index)])
1052 ip_1_1_1_2.add_vpp_config()
1053 ip_1_2 = VppIpRoute(self, "1::2", 128,
1054 [VppRoutePath(self.pg3.remote_ip6,
1055 self.pg3.sw_if_index,
1056 proto=DpoProto.DPO_PROTO_IP6)],
1058 ip_1_2.add_vpp_config()
1060 p4 = (Ether(src=self.pg2.remote_mac,
1061 dst=self.pg2.local_mac) /
1062 IP(src="1.1.1.1", dst="1.1.1.2") /
1063 UDP(sport=1234, dport=1234) /
1065 p6 = (Ether(src=self.pg2.remote_mac,
1066 dst=self.pg2.local_mac) /
1067 IPv6(src="1::1", dst="1::2") /
1068 UDP(sport=1234, dport=1234) /
1070 self.send_and_expect(self.pg2, p4*1, self.pg3)
1071 self.send_and_expect(self.pg2, p6*1, self.pg3)
1074 # apply the punting features
1076 self.vapi.cli("test punt pg2")
1081 self.send_and_assert_no_replies(self.pg2, p4*NUM_PKTS)
1082 self.send_and_assert_no_replies(self.pg2, p6*NUM_PKTS)
1086 # 1 - node error counters
1087 # 2 - per-reason counters
1088 # 2, 3 are the index of the assigned punt reason
1090 stats = self.statistics.get_err_counter(
1091 "/err/punt-dispatch/No registrations")
1092 self.assertEqual(stats, 2*NUM_PKTS)
1094 stats = self.statistics.get_counter("/net/punt")
1095 self.assertEqual(stats[0][7]['packets'], NUM_PKTS)
1096 self.assertEqual(stats[0][8]['packets'], NUM_PKTS)
1099 # use the test CLI to test a client that punts exception
1100 # packets out of pg0
1102 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip4)
1103 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip6)
1105 rx4s = self.send_and_expect(self.pg2, p4*NUM_PKTS, self.pg0)
1106 rx6s = self.send_and_expect(self.pg2, p6*NUM_PKTS, self.pg0)
1109 # check the packets come out IP unmodified but destined to pg0 host
1112 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1113 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1114 self.assertEqual(p4[IP].dst, rx[IP].dst)
1115 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1117 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1118 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1119 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1120 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1122 stats = self.statistics.get_counter("/net/punt")
1123 self.assertEqual(stats[0][7]['packets'], 2*NUM_PKTS)
1124 self.assertEqual(stats[0][8]['packets'], 2*NUM_PKTS)
1127 # add another registration for the same reason to send packets
1130 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip4)
1131 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip6)
1133 self.vapi.cli("clear trace")
1134 self.pg2.add_stream(p4 * NUM_PKTS)
1135 self.pg_enable_capture(self.pg_interfaces)
1138 rxd = self.pg0.get_capture(NUM_PKTS)
1140 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1141 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1142 self.assertEqual(p4[IP].dst, rx[IP].dst)
1143 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1144 rxd = self.pg1.get_capture(NUM_PKTS)
1146 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1147 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1148 self.assertEqual(p4[IP].dst, rx[IP].dst)
1149 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1151 self.vapi.cli("clear trace")
1152 self.pg2.add_stream(p6 * NUM_PKTS)
1153 self.pg_enable_capture(self.pg_interfaces)
1156 rxd = self.pg0.get_capture(NUM_PKTS)
1158 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1159 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1160 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1161 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1162 rxd = self.pg1.get_capture(NUM_PKTS)
1164 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1165 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1166 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1167 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1169 stats = self.statistics.get_counter("/net/punt")
1170 self.assertEqual(stats[0][7]['packets'], 3*NUM_PKTS)
1171 self.assertEqual(stats[0][8]['packets'], 3*NUM_PKTS)
1173 self.logger.info(self.vapi.cli("show vlib graph punt-dispatch"))
1174 self.logger.info(self.vapi.cli("show punt client"))
1175 self.logger.info(self.vapi.cli("show punt reason"))
1176 self.logger.info(self.vapi.cli("show punt stats"))
1177 self.logger.info(self.vapi.cli("show punt db"))
1180 # dump the punt registered reasons
1181 # search for a few we know should be there
1183 rs = self.vapi.punt_reason_dump()
1185 reasons = ["ipsec6-no-such-tunnel",
1186 "ipsec4-no-such-tunnel",
1190 for reason in reasons:
1193 if r.reason.name == reason:
1196 self.assertTrue(found)
1199 if __name__ == '__main__':
1200 unittest.main(testRunner=VppTestRunner)