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, 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 need an IPSec tunnels for this to work otherwise ESP gets dropped
798 # due to unknown IP proto
800 VppIpsecTunInterface(self, self.pg0, 1000, 1000,
801 (VppEnum.vl_api_ipsec_crypto_alg_t.
802 IPSEC_API_CRYPTO_ALG_AES_CBC_128),
805 (VppEnum.vl_api_ipsec_integ_alg_t.
806 IPSEC_API_INTEG_ALG_SHA1_96),
808 "0123456701234567").add_vpp_config()
809 VppIpsecTunInterface(self, self.pg0, 1001, 1001,
810 (VppEnum.vl_api_ipsec_crypto_alg_t.
811 IPSEC_API_CRYPTO_ALG_AES_CBC_128),
814 (VppEnum.vl_api_ipsec_integ_alg_t.
815 IPSEC_API_INTEG_ALG_SHA1_96),
818 udp_encap=True).add_vpp_config()
821 # we're dealing with IPSec tunnels punting for no-such-tunnel
825 cfgs['ipsec4-no-such-tunnel'] = {'spi': 99, 'udp': False}
826 cfgs['ipsec4-spi-0'] = {'spi': 0, 'udp': False}
827 cfgs['ipsec4-spi-o-udp-0'] = {'spi': 0, 'udp': True}
830 # find the VPP ID for these punt exception reasin
832 rs = self.vapi.punt_reason_dump()
835 if r.reason.name == key:
836 cfgs[key]['id'] = r.reason.id
837 cfgs[key]['vpp'] = copy.deepcopy(
843 # configure punt sockets
845 for cfg in cfgs.values():
846 cfg['sock'] = self.socket_client_create(b"%s/socket_%d" % (
847 six.ensure_binary(self.tempdir), cfg['id']))
848 self.vapi.punt_socket_register(
850 b"%s/socket_%d" % (six.ensure_binary(self.tempdir),
854 # create packet streams for 'no-such-tunnel' exception
856 for cfg in cfgs.values():
857 pkt = (Ether(src=self.pg0.remote_mac,
858 dst=self.pg0.local_mac) /
859 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4))
861 pkt = pkt / UDP(sport=666, dport=4500)
862 pkt = (pkt / ESP(spi=cfg['spi'], seq=3) /
867 # send packets for each SPI we expect to be punted
869 for cfg in cfgs.values():
870 self.send_and_assert_no_replies(self.pg0, cfg['pkts'])
873 # verify the punted packets arrived on the associated socket
875 for cfg in cfgs.values():
876 rx = cfg['sock'].close()
877 self.verify_esp_pkts(rx, len(cfg['pkts']),
878 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
930 'protocol': proto_ospf
939 'protocol': proto_eigrp
944 self.vapi.punt_socket_register(punt_ospf,
945 b"%s/socket_punt_1" %
946 six.ensure_binary(self.tempdir))
947 self.vapi.punt_socket_register(punt_eigrp,
948 b"%s/socket_punt_2" %
949 six.ensure_binary(self.tempdir))
950 self.logger.info(self.vapi.cli("sh punt sock reg ip"))
951 punts = self.vapi.punt_socket_dump(type=pt_ip)
952 self.assertEqual(len(punts), 2)
953 self.verify_ip_proto(punt_ospf, punts[0])
954 self.verify_ip_proto(punt_eigrp, punts[1])
957 # deregister a punt socket
959 self.vapi.punt_socket_deregister(punt_ospf)
960 punts = self.vapi.punt_socket_dump(type=pt_ip)
961 self.assertEqual(len(punts), 1)
964 # configure a punt socket again
966 self.vapi.punt_socket_register(punt_ospf,
967 b"%s/socket_punt_3" %
968 six.ensure_binary(self.tempdir))
969 punts = self.vapi.punt_socket_dump(type=pt_ip)
970 self.assertEqual(len(punts), 2)
972 self.logger.info(self.vapi.cli("sh punt sock reg exception"))
975 # deregister all punt socket
977 self.vapi.punt_socket_deregister(punt_eigrp)
978 self.vapi.punt_socket_deregister(punt_ospf)
979 punts = self.vapi.punt_socket_dump(type=pt_ip)
980 self.assertEqual(len(punts), 0)
982 def verify_ospf_pkts(self, rxs, n_sent):
983 self.assertEqual(len(rxs), n_sent)
985 self.assertTrue(rx.haslayer(OSPF_Hdr))
987 def test_traffic(self):
988 """ Punt socket traffic """
990 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
991 pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
992 proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
995 # configure a punt socket to capture OSPF packets
1002 'protocol': proto_ospf
1008 # create packet streams and configure a punt sockets
1010 pkt = (Ether(src=self.pg0.remote_mac,
1011 dst=self.pg0.local_mac) /
1012 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
1017 sock = self.socket_client_create(b"%s/socket_1" % (
1018 six.ensure_binary(self.tempdir)))
1019 self.vapi.punt_socket_register(
1021 b"%s/socket_1" % (six.ensure_binary(self.tempdir)))
1024 # send packets for each SPI we expect to be punted
1026 self.send_and_assert_no_replies(self.pg0, pkts)
1029 # verify the punted packets arrived on the associated socket
1032 self.verify_ospf_pkts(rx, len(pkts))
1033 self.vapi.punt_socket_deregister(punt_ospf)
1036 class TestPunt(VppTestCase):
1037 """ Exception Punt Test Case """
1040 def setUpClass(cls):
1041 super(TestPunt, cls).setUpClass()
1044 def tearDownClass(cls):
1045 super(TestPunt, cls).tearDownClass()
1048 super(TestPunt, self).setUp()
1050 self.create_pg_interfaces(range(4))
1052 for i in self.pg_interfaces:
1060 for i in self.pg_interfaces:
1065 super(TestPunt, self).tearDown()
1067 def test_punt(self):
1068 """ Exception Path testing """
1071 # Using the test CLI we will hook in a exception path to
1072 # send ACL deny packets out of pg0 and pg1.
1073 # the ACL is src,dst = 1.1.1.1,1.1.1.2
1075 ip_1_1_1_2 = VppIpRoute(self, "1.1.1.2", 32,
1076 [VppRoutePath(self.pg3.remote_ip4,
1077 self.pg3.sw_if_index)])
1078 ip_1_1_1_2.add_vpp_config()
1079 ip_1_2 = VppIpRoute(self, "1::2", 128,
1080 [VppRoutePath(self.pg3.remote_ip6,
1081 self.pg3.sw_if_index,
1082 proto=DpoProto.DPO_PROTO_IP6)])
1083 ip_1_2.add_vpp_config()
1085 p4 = (Ether(src=self.pg2.remote_mac,
1086 dst=self.pg2.local_mac) /
1087 IP(src="1.1.1.1", dst="1.1.1.2") /
1088 UDP(sport=1234, dport=1234) /
1090 p6 = (Ether(src=self.pg2.remote_mac,
1091 dst=self.pg2.local_mac) /
1092 IPv6(src="1::1", dst="1::2") /
1093 UDP(sport=1234, dport=1234) /
1095 self.send_and_expect(self.pg2, p4*1, self.pg3)
1096 self.send_and_expect(self.pg2, p6*1, self.pg3)
1099 # apply the punting features
1101 self.vapi.cli("test punt pg2")
1106 self.send_and_assert_no_replies(self.pg2, p4*NUM_PKTS)
1107 self.send_and_assert_no_replies(self.pg2, p6*NUM_PKTS)
1111 # 1 - node error counters
1112 # 2 - per-reason counters
1113 # 2, 3 are the index of the assigned punt reason
1115 stats = self.statistics.get_err_counter(
1116 "/err/punt-dispatch/No registrations")
1117 self.assertEqual(stats, 2*NUM_PKTS)
1119 stats = self.statistics.get_counter("/net/punt")
1120 self.assertEqual(stats[0][7]['packets'], NUM_PKTS)
1121 self.assertEqual(stats[0][8]['packets'], NUM_PKTS)
1124 # use the test CLI to test a client that punts exception
1125 # packets out of pg0
1127 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip4)
1128 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip6)
1130 rx4s = self.send_and_expect(self.pg2, p4*NUM_PKTS, self.pg0)
1131 rx6s = self.send_and_expect(self.pg2, p6*NUM_PKTS, self.pg0)
1134 # check the packets come out IP unmodified but destined to pg0 host
1137 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1138 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1139 self.assertEqual(p4[IP].dst, rx[IP].dst)
1140 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1142 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1143 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1144 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1145 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1147 stats = self.statistics.get_counter("/net/punt")
1148 self.assertEqual(stats[0][7]['packets'], 2*NUM_PKTS)
1149 self.assertEqual(stats[0][8]['packets'], 2*NUM_PKTS)
1152 # add another registration for the same reason to send packets
1155 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip4)
1156 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip6)
1158 self.vapi.cli("clear trace")
1159 self.pg2.add_stream(p4 * NUM_PKTS)
1160 self.pg_enable_capture(self.pg_interfaces)
1163 rxd = self.pg0.get_capture(NUM_PKTS)
1165 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1166 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1167 self.assertEqual(p4[IP].dst, rx[IP].dst)
1168 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1169 rxd = self.pg1.get_capture(NUM_PKTS)
1171 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1172 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1173 self.assertEqual(p4[IP].dst, rx[IP].dst)
1174 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1176 self.vapi.cli("clear trace")
1177 self.pg2.add_stream(p6 * NUM_PKTS)
1178 self.pg_enable_capture(self.pg_interfaces)
1181 rxd = self.pg0.get_capture(NUM_PKTS)
1183 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1184 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1185 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1186 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1187 rxd = self.pg1.get_capture(NUM_PKTS)
1189 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1190 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1191 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1192 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1194 stats = self.statistics.get_counter("/net/punt")
1195 self.assertEqual(stats[0][7]['packets'], 3*NUM_PKTS)
1196 self.assertEqual(stats[0][8]['packets'], 3*NUM_PKTS)
1198 self.logger.info(self.vapi.cli("show vlib graph punt-dispatch"))
1199 self.logger.info(self.vapi.cli("show punt client"))
1200 self.logger.info(self.vapi.cli("show punt reason"))
1201 self.logger.info(self.vapi.cli("show punt stats"))
1202 self.logger.info(self.vapi.cli("show punt db"))
1205 # dump the punt registered reasons
1206 # search for a few we know should be there
1208 rs = self.vapi.punt_reason_dump()
1210 reasons = ["ipsec6-no-such-tunnel",
1211 "ipsec4-no-such-tunnel",
1215 for reason in reasons:
1218 if r.reason.name == reason:
1221 self.assertTrue(found)
1224 if __name__ == '__main__':
1225 unittest.main(testRunner=VppTestRunner)