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-o-udp-0'] = {'spi': 0, 'udp': True}
829 # find the VPP ID for these punt exception reasin
831 rs = self.vapi.punt_reason_dump()
834 if r.reason.name == key:
835 cfgs[key]['id'] = r.reason.id
836 cfgs[key]['vpp'] = copy.deepcopy(
842 # configure punt sockets
844 for cfg in cfgs.values():
845 cfg['sock'] = self.socket_client_create(b"%s/socket_%d" % (
846 six.ensure_binary(self.tempdir), cfg['id']))
847 self.vapi.punt_socket_register(
849 b"%s/socket_%d" % (six.ensure_binary(self.tempdir),
853 # create packet streams for 'no-such-tunnel' exception
855 for cfg in cfgs.values():
856 pkt = (Ether(src=self.pg0.remote_mac,
857 dst=self.pg0.local_mac) /
858 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4))
860 pkt = pkt / UDP(sport=666, dport=4500)
861 pkt = (pkt / ESP(spi=cfg['spi'], seq=3) /
866 # send packets for each SPI we expect to be punted
868 for cfg in cfgs.values():
869 self.send_and_assert_no_replies(self.pg0, cfg['pkts'])
872 # verify the punted packets arrived on the associated socket
874 for cfg in cfgs.values():
875 rx = cfg['sock'].close()
876 self.verify_esp_pkts(rx, len(cfg['pkts']),
877 cfg['spi'], cfg['udp'])
882 for cfg in cfgs.values():
883 self.vapi.punt_socket_deregister(cfg['vpp'])
886 class TestIpProtoPuntSocket(TestPuntSocket):
887 """ Punt Socket for IP packets """
891 super(TestIpProtoPuntSocket, cls).setUpClass()
894 def tearDownClass(cls):
895 super(TestIpProtoPuntSocket, cls).tearDownClass()
898 super(TestIpProtoPuntSocket, self).setUp()
900 for i in self.pg_interfaces:
905 super(TestIpProtoPuntSocket, self).tearDown()
906 for i in self.pg_interfaces:
910 def test_registration(self):
911 """ Punt socket registration/deregistration"""
913 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
914 pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
915 proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
916 proto_eigrp = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_EIGRP
918 punts = self.vapi.punt_socket_dump(type=pt_ip)
919 self.assertEqual(len(punts), 0)
922 # configure a punt socket
929 'protocol': proto_ospf
938 'protocol': proto_eigrp
943 self.vapi.punt_socket_register(punt_ospf,
944 b"%s/socket_punt_1" %
945 six.ensure_binary(self.tempdir))
946 self.vapi.punt_socket_register(punt_eigrp,
947 b"%s/socket_punt_2" %
948 six.ensure_binary(self.tempdir))
949 self.logger.info(self.vapi.cli("sh punt sock reg ip"))
950 punts = self.vapi.punt_socket_dump(type=pt_ip)
951 self.assertEqual(len(punts), 2)
952 self.verify_ip_proto(punt_ospf, punts[0])
953 self.verify_ip_proto(punt_eigrp, punts[1])
956 # deregister a punt socket
958 self.vapi.punt_socket_deregister(punt_ospf)
959 punts = self.vapi.punt_socket_dump(type=pt_ip)
960 self.assertEqual(len(punts), 1)
963 # configure a punt socket again
965 self.vapi.punt_socket_register(punt_ospf,
966 b"%s/socket_punt_3" %
967 six.ensure_binary(self.tempdir))
968 punts = self.vapi.punt_socket_dump(type=pt_ip)
969 self.assertEqual(len(punts), 2)
971 self.logger.info(self.vapi.cli("sh punt sock reg exception"))
974 # deregister all punt socket
976 self.vapi.punt_socket_deregister(punt_eigrp)
977 self.vapi.punt_socket_deregister(punt_ospf)
978 punts = self.vapi.punt_socket_dump(type=pt_ip)
979 self.assertEqual(len(punts), 0)
981 def verify_ospf_pkts(self, rxs, n_sent):
982 self.assertEqual(len(rxs), n_sent)
984 self.assertTrue(rx.haslayer(OSPF_Hdr))
986 def test_traffic(self):
987 """ Punt socket traffic """
989 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
990 pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
991 proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
994 # configure a punt socket to capture OSPF packets
1001 'protocol': proto_ospf
1007 # create packet streams and configure a punt sockets
1009 pkt = (Ether(src=self.pg0.remote_mac,
1010 dst=self.pg0.local_mac) /
1011 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
1016 sock = self.socket_client_create(b"%s/socket_1" % (
1017 six.ensure_binary(self.tempdir)))
1018 self.vapi.punt_socket_register(
1020 b"%s/socket_1" % (six.ensure_binary(self.tempdir)))
1023 # send packets for each SPI we expect to be punted
1025 self.send_and_assert_no_replies(self.pg0, pkts)
1028 # verify the punted packets arrived on the associated socket
1031 self.verify_ospf_pkts(rx, len(pkts))
1032 self.vapi.punt_socket_deregister(punt_ospf)
1035 class TestPunt(VppTestCase):
1036 """ Exception Punt Test Case """
1039 def setUpClass(cls):
1040 super(TestPunt, cls).setUpClass()
1043 def tearDownClass(cls):
1044 super(TestPunt, cls).tearDownClass()
1047 super(TestPunt, self).setUp()
1049 self.create_pg_interfaces(range(4))
1051 for i in self.pg_interfaces:
1059 for i in self.pg_interfaces:
1064 super(TestPunt, self).tearDown()
1066 def test_punt(self):
1067 """ Exception Path testing """
1070 # dump the punt registered reasons
1071 # search for a few we know should be there
1073 rs = self.vapi.punt_reason_dump()
1075 reasons = ["ipsec6-no-such-tunnel",
1076 "ipsec4-no-such-tunnel",
1077 "ipsec4-spi-o-udp-0"]
1079 for reason in reasons:
1082 if r.reason.name == reason:
1085 self.assertTrue(found)
1088 # Using the test CLI we will hook in a exception path to
1089 # send ACL deny packets out of pg0 and pg1.
1090 # the ACL is src,dst = 1.1.1.1,1.1.1.2
1092 ip_1_1_1_2 = VppIpRoute(self, "1.1.1.2", 32,
1093 [VppRoutePath(self.pg3.remote_ip4,
1094 self.pg3.sw_if_index)])
1095 ip_1_1_1_2.add_vpp_config()
1096 ip_1_2 = VppIpRoute(self, "1::2", 128,
1097 [VppRoutePath(self.pg3.remote_ip6,
1098 self.pg3.sw_if_index,
1099 proto=DpoProto.DPO_PROTO_IP6)])
1100 ip_1_2.add_vpp_config()
1102 p4 = (Ether(src=self.pg2.remote_mac,
1103 dst=self.pg2.local_mac) /
1104 IP(src="1.1.1.1", dst="1.1.1.2") /
1105 UDP(sport=1234, dport=1234) /
1107 p6 = (Ether(src=self.pg2.remote_mac,
1108 dst=self.pg2.local_mac) /
1109 IPv6(src="1::1", dst="1::2") /
1110 UDP(sport=1234, dport=1234) /
1112 self.send_and_expect(self.pg2, p4*1, self.pg3)
1113 self.send_and_expect(self.pg2, p6*1, self.pg3)
1116 # apply the punting features
1118 self.vapi.cli("test punt pg2")
1121 # dump the punt reasons to learn the IDs assigned
1123 rs = self.vapi.punt_reason_dump(reason={'name': "reason-v4"})
1124 r4 = rs[0].reason.id
1125 rs = self.vapi.punt_reason_dump(reason={'name': "reason-v6"})
1126 r6 = rs[0].reason.id
1131 self.send_and_assert_no_replies(self.pg2, p4*NUM_PKTS)
1132 self.send_and_assert_no_replies(self.pg2, p6*NUM_PKTS)
1136 # 1 - node error counters
1137 # 2 - per-reason counters
1138 # 2, 3 are the index of the assigned punt reason
1140 stats = self.statistics.get_err_counter(
1141 "/err/punt-dispatch/No registrations")
1142 self.assertEqual(stats, 2*NUM_PKTS)
1144 stats = self.statistics.get_counter("/net/punt")
1145 self.assertEqual(stats[0][r4]['packets'], NUM_PKTS)
1146 self.assertEqual(stats[0][r6]['packets'], NUM_PKTS)
1149 # use the test CLI to test a client that punts exception
1150 # packets out of pg0
1152 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip4)
1153 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip6)
1155 rx4s = self.send_and_expect(self.pg2, p4*NUM_PKTS, self.pg0)
1156 rx6s = self.send_and_expect(self.pg2, p6*NUM_PKTS, self.pg0)
1159 # check the packets come out IP unmodified but destined to pg0 host
1162 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1163 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1164 self.assertEqual(p4[IP].dst, rx[IP].dst)
1165 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1167 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1168 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1169 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1170 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1172 stats = self.statistics.get_counter("/net/punt")
1173 self.assertEqual(stats[0][r4]['packets'], 2*NUM_PKTS)
1174 self.assertEqual(stats[0][r6]['packets'], 2*NUM_PKTS)
1177 # add another registration for the same reason to send packets
1180 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip4)
1181 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip6)
1183 self.vapi.cli("clear trace")
1184 self.pg2.add_stream(p4 * NUM_PKTS)
1185 self.pg_enable_capture(self.pg_interfaces)
1188 rxd = self.pg0.get_capture(NUM_PKTS)
1190 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1191 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1192 self.assertEqual(p4[IP].dst, rx[IP].dst)
1193 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1194 rxd = self.pg1.get_capture(NUM_PKTS)
1196 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1197 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1198 self.assertEqual(p4[IP].dst, rx[IP].dst)
1199 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1201 self.vapi.cli("clear trace")
1202 self.pg2.add_stream(p6 * NUM_PKTS)
1203 self.pg_enable_capture(self.pg_interfaces)
1206 rxd = self.pg0.get_capture(NUM_PKTS)
1208 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1209 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1210 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1211 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1212 rxd = self.pg1.get_capture(NUM_PKTS)
1214 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1215 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1216 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1217 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1219 stats = self.statistics.get_counter("/net/punt")
1220 self.assertEqual(stats[0][r4]['packets'], 3*NUM_PKTS)
1221 self.assertEqual(stats[0][r6]['packets'], 3*NUM_PKTS)
1223 self.logger.info(self.vapi.cli("show vlib graph punt-dispatch"))
1224 self.logger.info(self.vapi.cli("show punt client"))
1225 self.logger.info(self.vapi.cli("show punt reason"))
1226 self.logger.info(self.vapi.cli("show punt stats"))
1227 self.logger.info(self.vapi.cli("show punt db"))
1230 if __name__ == '__main__':
1231 unittest.main(testRunner=VppTestRunner)