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):
145 self.assertTrue(rx.haslayer(UDP))
146 if rx[UDP].dport == port:
148 self.assertEqual(n_match, n_rx)
151 def set_port(pr, port):
152 pr['punt']['l4']['port'] = port
156 def set_reason(pr, reason):
157 pr['punt']['exception']['id'] = reason
162 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
163 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
164 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
170 'protocol': udp_proto
178 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
179 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
180 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
186 'protocol': udp_proto
193 class TestIP4PuntSocket(TestPuntSocket):
194 """ Punt Socket for IPv4 UDP """
198 super(TestIP4PuntSocket, cls).setUpClass()
201 def tearDownClass(cls):
202 super(TestIP4PuntSocket, cls).tearDownClass()
205 super(TestIP4PuntSocket, self).setUp()
207 for i in self.pg_interfaces:
212 super(TestIP4PuntSocket, self).tearDown()
213 for i in self.pg_interfaces:
217 def test_punt_socket_dump(self):
218 """ Punt socket registration/deregistration"""
220 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
221 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
222 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
224 punts = self.vapi.punt_socket_dump(type=pt_l4)
225 self.assertEqual(len(punts), 0)
228 # configure a punt socket
230 punt_l4 = mk_vpp_cfg4()
232 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
233 b"%s/socket_punt_1111" %
234 six.ensure_binary(self.tempdir))
235 self.vapi.punt_socket_register(set_port(punt_l4, 2222),
236 b"%s/socket_punt_2222" %
237 six.ensure_binary(self.tempdir))
238 punts = self.vapi.punt_socket_dump(type=pt_l4)
239 self.assertEqual(len(punts), 2)
240 self.verify_port(set_port(punt_l4, 1111), punts[0])
241 self.verify_port(set_port(punt_l4, 2222), punts[1])
244 # deregister a punt socket
246 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
247 punts = self.vapi.punt_socket_dump(type=pt_l4)
248 self.assertEqual(len(punts), 1)
251 # configure a punt socket again
253 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
254 b"%s/socket_punt_1111" %
255 six.ensure_binary(self.tempdir))
256 self.vapi.punt_socket_register(set_port(punt_l4, 3333),
257 b"%s/socket_punt_3333" %
258 six.ensure_binary(self.tempdir))
259 punts = self.vapi.punt_socket_dump(type=pt_l4)
260 self.assertEqual(len(punts), 3)
262 self.logger.info(self.vapi.cli("sh punt sock reg"))
265 # deregister all punt socket
267 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
268 self.vapi.punt_socket_deregister(set_port(punt_l4, 2222))
269 self.vapi.punt_socket_deregister(set_port(punt_l4, 3333))
270 punts = self.vapi.punt_socket_dump(type=pt_l4)
271 self.assertEqual(len(punts), 0)
273 def test_punt_socket_traffic_single_port_single_socket(self):
274 """ Punt socket traffic single port single socket"""
277 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
278 punt_l4 = set_port(mk_vpp_cfg4(), port)
280 p = (Ether(src=self.pg0.remote_mac,
281 dst=self.pg0.local_mac) /
282 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
283 UDP(sport=9876, dport=port) /
286 pkts = p * self.nr_packets
288 punts = self.vapi.punt_socket_dump(type=pt_l4)
289 self.assertEqual(len(punts), 0)
292 # expect ICMP - port unreachable for all packets
294 rx = self.send_and_expect(self.pg0, pkts, self.pg0)
297 self.assertEqual(int(p[IP].proto), 1) # ICMP
298 self.assertEqual(int(p[ICMP].code), 3) # unreachable
301 # configure a punt socket
303 self.socket_client_create(b"%s/socket_%d" % (
304 six.ensure_binary(self.tempdir), port))
305 self.vapi.punt_socket_register(punt_l4, b"%s/socket_%d" % (
306 six.ensure_binary(self.tempdir), port))
307 punts = self.vapi.punt_socket_dump(type=pt_l4)
308 self.assertEqual(len(punts), 1)
311 # expect punt socket and no packets on pg0
313 self.send_and_assert_no_replies(self.pg0, pkts)
314 rx = self.socket_client_close()
315 self.verify_udp_pkts(rx, len(pkts), port)
318 # remove punt socket. expect ICMP - port unreachable for all packets
320 self.vapi.punt_socket_deregister(punt_l4)
321 punts = self.vapi.punt_socket_dump(type=pt_l4)
322 self.assertEqual(len(punts), 0)
324 rx = self.send_and_expect(self.pg0, pkts, self.pg0)
326 self.assertEqual(int(p[IP].proto), 1) # ICMP
327 self.assertEqual(int(p[ICMP].code), 3) # unreachable
329 def test_punt_socket_traffic_multi_ports_multi_sockets(self):
330 """ Punt socket traffic multi ports and multi sockets"""
332 punt_l4 = mk_vpp_cfg4()
334 # configuration for each UDP port
338 # create stream of packets for each port
340 for port in self.ports:
341 # choose port from port list
344 pkt = (Ether(src=self.pg0.remote_mac,
345 dst=self.pg0.local_mac) /
346 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
347 UDP(sport=9876, dport=port) /
349 cfgs[port]['pkts'] = pkt * self.nr_packets
350 cfgs[port]['port'] = port
351 cfgs[port]['vpp'] = copy.deepcopy(set_port(punt_l4, port))
353 # configure punt sockets
354 cfgs[port]['sock'] = self.socket_client_create(
355 b"%s/socket_%d" % (six.ensure_binary(self.tempdir), port))
356 self.vapi.punt_socket_register(
358 b"%s/socket_%d" % (six.ensure_binary(self.tempdir),
362 # send the packets that get punted
364 for cfg in cfgs.values():
365 self.send_and_assert_no_replies(self.pg0, cfg['pkts'])
368 # test that we got the excepted packets on the expected socket
370 for cfg in cfgs.values():
371 rx = cfg['sock'].close()
372 self.verify_udp_pkts(rx, len(cfg['pkts']), cfg['port'])
373 self.vapi.punt_socket_deregister(cfg['vpp'])
375 def test_punt_socket_traffic_multi_ports_single_socket(self):
376 """ Punt socket traffic multi ports and single socket"""
378 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
379 punt_l4 = mk_vpp_cfg4()
382 # create stream of packets with each port
385 for port in self.ports:
386 # choose port from port list
387 pkt = (Ether(src=self.pg0.remote_mac,
388 dst=self.pg0.local_mac) /
389 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
390 UDP(sport=9876, dport=port) /
392 pkts += pkt * self.nr_packets
395 # configure a punt socket
397 self.socket_client_create(b"%s/socket_multi" %
398 six.ensure_binary(self.tempdir))
400 self.vapi.punt_socket_register(set_port(punt_l4, p),
402 six.ensure_binary(self.tempdir))
403 punts = self.vapi.punt_socket_dump(type=pt_l4)
404 self.assertEqual(len(punts), len(self.ports))
407 # expect punt socket and no packets on pg0
409 self.send_and_assert_no_replies(self.pg0, pkts)
410 self.logger.info(self.vapi.cli("show trace"))
411 rx = self.socket_client_close()
414 self.verify_udp_pkts(rx, self.nr_packets, p)
415 self.vapi.punt_socket_deregister(set_port(punt_l4, p))
416 punts = self.vapi.punt_socket_dump(type=pt_l4)
417 self.assertEqual(len(punts), 0)
420 class TestIP6PuntSocket(TestPuntSocket):
421 """ Punt Socket for IPv6 UDP """
425 super(TestIP6PuntSocket, cls).setUpClass()
428 def tearDownClass(cls):
429 super(TestIP6PuntSocket, cls).tearDownClass()
432 super(TestIP6PuntSocket, self).setUp()
434 for i in self.pg_interfaces:
439 super(TestIP6PuntSocket, self).tearDown()
440 for i in self.pg_interfaces:
444 def test_punt_socket_dump(self):
445 """ Punt socket registration """
447 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
448 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
449 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
451 # configure a punt socket
458 'protocol': udp_proto
463 punts = self.vapi.punt_socket_dump(type=pt_l4)
464 self.assertEqual(len(punts), 0)
467 # configure a punt socket
469 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
471 six.ensure_binary(self.tempdir))
472 self.vapi.punt_socket_register(set_port(punt_l4, 2222),
474 six.ensure_binary(self.tempdir))
475 punts = self.vapi.punt_socket_dump(type=pt_l4)
476 self.assertEqual(len(punts), 2)
477 self.verify_port(set_port(punt_l4, 1111), punts[0])
478 self.verify_port(set_port(punt_l4, 2222), punts[1])
481 # deregister a punt socket
483 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
484 punts = self.vapi.punt_socket_dump(type=pt_l4)
485 self.assertEqual(len(punts), 1)
488 # configure a punt socket again
490 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
492 six.ensure_binary(self.tempdir))
493 punts = self.vapi.punt_socket_dump(type=pt_l4)
494 self.assertEqual(len(punts), 2)
497 # deregister all punt socket
499 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
500 self.vapi.punt_socket_deregister(set_port(punt_l4, 2222))
501 self.vapi.punt_socket_deregister(set_port(punt_l4, 3333))
502 punts = self.vapi.punt_socket_dump(type=pt_l4)
503 self.assertEqual(len(punts), 0)
505 def test_punt_socket_traffic_single_port_single_socket(self):
506 """ Punt socket traffic single port single socket"""
509 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
510 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
511 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
517 'protocol': udp_proto,
523 p = (Ether(src=self.pg0.remote_mac,
524 dst=self.pg0.local_mac) /
525 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
526 inet6.UDP(sport=9876, dport=port) /
529 pkts = p * self.nr_packets
531 punts = self.vapi.punt_socket_dump(type=pt_l4)
532 self.assertEqual(len(punts), 0)
535 # expect ICMPv6 - destination unreachable for all packets
537 self.vapi.cli("clear trace")
538 self.pg0.add_stream(pkts)
539 self.pg_enable_capture(self.pg_interfaces)
541 # FIXME - when punt socket deregister is implemented
542 # rx = self.pg0.get_capture(self.nr_packets)
544 # self.assertEqual(int(p[IPv6].nh), 58) # ICMPv6
545 # self.assertEqual(int(p[ICMPv6DestUnreach].code),4) # unreachable
548 # configure a punt socket
550 self.socket_client_create(b"%s/socket_%d" % (
551 six.ensure_binary(self.tempdir), port))
552 self.vapi.punt_socket_register(punt_l4, b"%s/socket_%d" % (
553 six.ensure_binary(self.tempdir), port))
554 punts = self.vapi.punt_socket_dump(type=pt_l4)
555 self.assertEqual(len(punts), 1)
558 # expect punt socket and no packets on pg0
560 self.vapi.cli("clear errors")
561 self.vapi.cli("clear trace")
562 self.pg0.add_stream(pkts)
563 self.pg_enable_capture(self.pg_interfaces)
565 self.pg0.get_capture(0)
566 self.logger.info(self.vapi.cli("show trace"))
567 rx = self.socket_client_close()
568 self.verify_udp_pkts(rx, len(pkts), port)
571 # remove punt socket. expect ICMP - dest. unreachable for all packets
573 self.vapi.punt_socket_deregister(punt_l4)
574 punts = self.vapi.punt_socket_dump(type=pt_l4)
575 self.assertEqual(len(punts), 0)
576 self.pg0.add_stream(pkts)
577 self.pg_enable_capture(self.pg_interfaces)
579 # FIXME - when punt socket deregister is implemented
580 # self.pg0.get_capture(nr_packets)
582 def test_punt_socket_traffic_multi_ports_multi_sockets(self):
583 """ Punt socket traffic multi ports and multi sockets"""
585 punt_l4 = mk_vpp_cfg6()
587 # configuration for each UDP port
591 # create stream of packets for each port
593 for port in self.ports:
594 # choose port from port list
597 pkt = (Ether(src=self.pg0.remote_mac,
598 dst=self.pg0.local_mac) /
599 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
600 UDP(sport=9876, dport=port) /
602 cfgs[port]['pkts'] = pkt * self.nr_packets
603 cfgs[port]['port'] = port
604 cfgs[port]['vpp'] = copy.deepcopy(set_port(punt_l4, port))
606 # configure punt sockets
607 cfgs[port]['sock'] = self.socket_client_create(
608 b"%s/socket_%d" % (six.ensure_binary(self.tempdir), port))
609 self.vapi.punt_socket_register(
611 b"%s/socket_%d" % (six.ensure_binary(self.tempdir),
615 # send the packets that get punted
617 for cfg in cfgs.values():
618 self.send_and_assert_no_replies(self.pg0, cfg['pkts'])
621 # test that we got the excepted packets on the expected socket
623 for cfg in cfgs.values():
624 rx = cfg['sock'].close()
625 self.verify_udp_pkts(rx, len(cfg['pkts']), cfg['port'])
626 self.vapi.punt_socket_deregister(cfg['vpp'])
628 def test_punt_socket_traffic_multi_ports_single_socket(self):
629 """ Punt socket traffic multi ports and single socket"""
631 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
632 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
633 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
639 'protocol': udp_proto,
645 # create stream of packets with each port
648 for port in self.ports:
649 # choose port from port list
650 pkt = (Ether(src=self.pg0.remote_mac,
651 dst=self.pg0.local_mac) /
652 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
653 UDP(sport=9876, dport=port) /
655 pkts += pkt * self.nr_packets
660 punts = self.vapi.punt_socket_dump(type=pt_l4)
661 self.assertEqual(len(punts), 0)
664 # configure a punt socket
666 self.socket_client_create(b"%s/socket_multi" %
667 six.ensure_binary(self.tempdir))
669 self.vapi.punt_socket_register(set_port(punt_l4, p),
671 six.ensure_binary(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 self.pg0.get_capture(0)
684 rx = self.socket_client_close()
687 self.verify_udp_pkts(rx, self.nr_packets, p)
688 self.vapi.punt_socket_deregister(set_port(punt_l4, p))
689 punts = self.vapi.punt_socket_dump(type=pt_l4)
690 self.assertEqual(len(punts), 0)
693 class TestExceptionPuntSocket(TestPuntSocket):
694 """ Punt Socket for Exceptions """
698 super(TestExceptionPuntSocket, cls).setUpClass()
701 def tearDownClass(cls):
702 super(TestExceptionPuntSocket, cls).tearDownClass()
705 super(TestExceptionPuntSocket, self).setUp()
707 for i in self.pg_interfaces:
712 super(TestExceptionPuntSocket, self).tearDown()
713 for i in self.pg_interfaces:
717 def test_registration(self):
718 """ Punt socket registration/deregistration"""
720 pt_ex = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_EXCEPTION
722 punts = self.vapi.punt_socket_dump(type=pt_ex)
723 self.assertEqual(len(punts), 0)
726 # configure a punt socket
735 self.vapi.punt_socket_register(set_reason(punt_ex, 1),
736 b"%s/socket_punt_1" %
737 six.ensure_binary(self.tempdir))
738 self.vapi.punt_socket_register(set_reason(punt_ex, 2),
739 b"%s/socket_punt_2" %
740 six.ensure_binary(self.tempdir))
741 punts = self.vapi.punt_socket_dump(type=pt_ex)
742 self.assertEqual(len(punts), 2)
743 self.verify_exception(set_reason(punt_ex, 1), punts[0])
744 self.verify_exception(set_reason(punt_ex, 2), punts[1])
747 # deregister a punt socket
749 self.vapi.punt_socket_deregister(set_reason(punt_ex, 1))
750 punts = self.vapi.punt_socket_dump(type=pt_ex)
751 self.assertEqual(len(punts), 1)
754 # configure a punt socket again
756 self.vapi.punt_socket_register(set_reason(punt_ex, 1),
757 b"%s/socket_punt_1" %
758 six.ensure_binary(self.tempdir))
759 self.vapi.punt_socket_register(set_reason(punt_ex, 3),
760 b"%s/socket_punt_3" %
761 six.ensure_binary(self.tempdir))
762 punts = self.vapi.punt_socket_dump(type=pt_ex)
763 self.assertEqual(len(punts), 3)
765 self.logger.info(self.vapi.cli("sh punt sock reg exception"))
768 # deregister all punt socket
770 self.vapi.punt_socket_deregister(set_reason(punt_ex, 1))
771 self.vapi.punt_socket_deregister(set_reason(punt_ex, 2))
772 self.vapi.punt_socket_deregister(set_reason(punt_ex, 3))
773 punts = self.vapi.punt_socket_dump(type=pt_ex)
774 self.assertEqual(len(punts), 0)
776 def verify_esp_pkts(self, rxs, n_sent, spi, has_udp):
777 self.assertEqual(len(rxs), n_sent)
779 self.assertTrue(rx.haslayer(IP))
780 self.assertTrue(rx.haslayer(ESP))
781 self.assertEqual(rx[ESP].spi, spi)
783 self.assertTrue(rx.haslayer(UDP))
785 def test_traffic(self):
786 """ Punt socket traffic """
789 pt_ex = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_EXCEPTION
798 # we need an IPSec tunnels for this to work otherwise ESP gets dropped
799 # due to unknown IP proto
801 VppIpsecTunInterface(self, self.pg0, 1000, 1000,
802 (VppEnum.vl_api_ipsec_crypto_alg_t.
803 IPSEC_API_CRYPTO_ALG_AES_CBC_128),
806 (VppEnum.vl_api_ipsec_integ_alg_t.
807 IPSEC_API_INTEG_ALG_SHA1_96),
809 "0123456701234567").add_vpp_config()
810 VppIpsecTunInterface(self, self.pg0, 1001, 1001,
811 (VppEnum.vl_api_ipsec_crypto_alg_t.
812 IPSEC_API_CRYPTO_ALG_AES_CBC_128),
815 (VppEnum.vl_api_ipsec_integ_alg_t.
816 IPSEC_API_INTEG_ALG_SHA1_96),
819 udp_encap=True).add_vpp_config()
822 # we're dealing with IPSec tunnels punting for no-such-tunnel
826 cfgs['ipsec4-no-such-tunnel'] = {'spi': 99, 'udp': False}
827 cfgs['ipsec4-spi-0'] = {'spi': 0, 'udp': False}
828 cfgs['ipsec4-spi-o-udp-0'] = {'spi': 0, 'udp': True}
831 # find the VPP ID for these punt exception reasin
833 rs = self.vapi.punt_reason_dump()
836 if r.reason.name == key:
837 cfgs[key]['id'] = r.reason.id
838 cfgs[key]['vpp'] = copy.deepcopy(
844 # configure punt sockets
846 for cfg in cfgs.values():
847 cfg['sock'] = self.socket_client_create(b"%s/socket_%d" % (
848 six.ensure_binary(self.tempdir), cfg['id']))
849 self.vapi.punt_socket_register(
851 b"%s/socket_%d" % (six.ensure_binary(self.tempdir),
855 # create packet streams for 'no-such-tunnel' exception
857 for cfg in cfgs.values():
858 pkt = (Ether(src=self.pg0.remote_mac,
859 dst=self.pg0.local_mac) /
860 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4))
862 pkt = pkt / UDP(sport=666, dport=4500)
863 pkt = (pkt / ESP(spi=cfg['spi'], seq=3) /
868 # send packets for each SPI we expect to be punted
870 for cfg in cfgs.values():
871 self.send_and_assert_no_replies(self.pg0, cfg['pkts'])
874 # verify the punted packets arrived on the associated socket
876 for cfg in cfgs.values():
877 rx = cfg['sock'].close()
878 self.verify_esp_pkts(rx, len(cfg['pkts']),
879 cfg['spi'], cfg['udp'])
884 for cfg in cfgs.values():
885 self.vapi.punt_socket_deregister(cfg['vpp'])
888 class TestIpProtoPuntSocket(TestPuntSocket):
889 """ Punt Socket for IP packets """
893 super(TestIpProtoPuntSocket, cls).setUpClass()
896 def tearDownClass(cls):
897 super(TestIpProtoPuntSocket, cls).tearDownClass()
900 super(TestIpProtoPuntSocket, self).setUp()
902 for i in self.pg_interfaces:
907 super(TestIpProtoPuntSocket, self).tearDown()
908 for i in self.pg_interfaces:
912 def test_registration(self):
913 """ Punt socket registration/deregistration"""
915 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
916 pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
917 proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
918 proto_eigrp = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_EIGRP
920 punts = self.vapi.punt_socket_dump(type=pt_ip)
921 self.assertEqual(len(punts), 0)
924 # configure a punt socket
931 'protocol': proto_ospf
940 'protocol': proto_eigrp
945 self.vapi.punt_socket_register(punt_ospf,
946 b"%s/socket_punt_1" %
947 six.ensure_binary(self.tempdir))
948 self.vapi.punt_socket_register(punt_eigrp,
949 b"%s/socket_punt_2" %
950 six.ensure_binary(self.tempdir))
951 self.logger.info(self.vapi.cli("sh punt sock reg ip"))
952 punts = self.vapi.punt_socket_dump(type=pt_ip)
953 self.assertEqual(len(punts), 2)
954 self.verify_ip_proto(punt_ospf, punts[0])
955 self.verify_ip_proto(punt_eigrp, punts[1])
958 # deregister a punt socket
960 self.vapi.punt_socket_deregister(punt_ospf)
961 punts = self.vapi.punt_socket_dump(type=pt_ip)
962 self.assertEqual(len(punts), 1)
965 # configure a punt socket again
967 self.vapi.punt_socket_register(punt_ospf,
968 b"%s/socket_punt_3" %
969 six.ensure_binary(self.tempdir))
970 punts = self.vapi.punt_socket_dump(type=pt_ip)
971 self.assertEqual(len(punts), 2)
973 self.logger.info(self.vapi.cli("sh punt sock reg exception"))
976 # deregister all punt socket
978 self.vapi.punt_socket_deregister(punt_eigrp)
979 self.vapi.punt_socket_deregister(punt_ospf)
980 punts = self.vapi.punt_socket_dump(type=pt_ip)
981 self.assertEqual(len(punts), 0)
983 def verify_ospf_pkts(self, rxs, n_sent):
984 self.assertEqual(len(rxs), n_sent)
986 self.assertTrue(rx.haslayer(OSPF_Hdr))
988 def test_traffic(self):
989 """ Punt socket traffic """
991 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
992 pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
993 proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
996 # configure a punt socket to capture OSPF packets
1003 'protocol': proto_ospf
1009 # create packet streams and configure a punt sockets
1011 pkt = (Ether(src=self.pg0.remote_mac,
1012 dst=self.pg0.local_mac) /
1013 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
1018 sock = self.socket_client_create(b"%s/socket_1" % (
1019 six.ensure_binary(self.tempdir)))
1020 self.vapi.punt_socket_register(
1022 b"%s/socket_1" % (six.ensure_binary(self.tempdir)))
1025 # send packets for each SPI we expect to be punted
1027 self.send_and_assert_no_replies(self.pg0, pkts)
1030 # verify the punted packets arrived on the associated socket
1033 self.verify_ospf_pkts(rx, len(pkts))
1034 self.vapi.punt_socket_deregister(punt_ospf)
1037 class TestPunt(VppTestCase):
1038 """ Exception Punt Test Case """
1041 def setUpClass(cls):
1042 super(TestPunt, cls).setUpClass()
1045 def tearDownClass(cls):
1046 super(TestPunt, cls).tearDownClass()
1049 super(TestPunt, self).setUp()
1051 self.create_pg_interfaces(range(4))
1053 for i in self.pg_interfaces:
1061 for i in self.pg_interfaces:
1066 super(TestPunt, self).tearDown()
1068 def test_punt(self):
1069 """ Exception Path testing """
1072 # Using the test CLI we will hook in a exception path to
1073 # send ACL deny packets out of pg0 and pg1.
1074 # the ACL is src,dst = 1.1.1.1,1.1.1.2
1076 ip_1_1_1_2 = VppIpRoute(self, "1.1.1.2", 32,
1077 [VppRoutePath(self.pg3.remote_ip4,
1078 self.pg3.sw_if_index)])
1079 ip_1_1_1_2.add_vpp_config()
1080 ip_1_2 = VppIpRoute(self, "1::2", 128,
1081 [VppRoutePath(self.pg3.remote_ip6,
1082 self.pg3.sw_if_index,
1083 proto=DpoProto.DPO_PROTO_IP6)],
1085 ip_1_2.add_vpp_config()
1087 p4 = (Ether(src=self.pg2.remote_mac,
1088 dst=self.pg2.local_mac) /
1089 IP(src="1.1.1.1", dst="1.1.1.2") /
1090 UDP(sport=1234, dport=1234) /
1092 p6 = (Ether(src=self.pg2.remote_mac,
1093 dst=self.pg2.local_mac) /
1094 IPv6(src="1::1", dst="1::2") /
1095 UDP(sport=1234, dport=1234) /
1097 self.send_and_expect(self.pg2, p4*1, self.pg3)
1098 self.send_and_expect(self.pg2, p6*1, self.pg3)
1101 # apply the punting features
1103 self.vapi.cli("test punt pg2")
1108 self.send_and_assert_no_replies(self.pg2, p4*NUM_PKTS)
1109 self.send_and_assert_no_replies(self.pg2, p6*NUM_PKTS)
1113 # 1 - node error counters
1114 # 2 - per-reason counters
1115 # 2, 3 are the index of the assigned punt reason
1117 stats = self.statistics.get_err_counter(
1118 "/err/punt-dispatch/No registrations")
1119 self.assertEqual(stats, 2*NUM_PKTS)
1121 stats = self.statistics.get_counter("/net/punt")
1122 self.assertEqual(stats[0][7]['packets'], NUM_PKTS)
1123 self.assertEqual(stats[0][8]['packets'], NUM_PKTS)
1126 # use the test CLI to test a client that punts exception
1127 # packets out of pg0
1129 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip4)
1130 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip6)
1132 rx4s = self.send_and_expect(self.pg2, p4*NUM_PKTS, self.pg0)
1133 rx6s = self.send_and_expect(self.pg2, p6*NUM_PKTS, self.pg0)
1136 # check the packets come out IP unmodified but destined to pg0 host
1139 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1140 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1141 self.assertEqual(p4[IP].dst, rx[IP].dst)
1142 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1144 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1145 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1146 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1147 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1149 stats = self.statistics.get_counter("/net/punt")
1150 self.assertEqual(stats[0][7]['packets'], 2*NUM_PKTS)
1151 self.assertEqual(stats[0][8]['packets'], 2*NUM_PKTS)
1154 # add another registration for the same reason to send packets
1157 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip4)
1158 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip6)
1160 self.vapi.cli("clear trace")
1161 self.pg2.add_stream(p4 * NUM_PKTS)
1162 self.pg_enable_capture(self.pg_interfaces)
1165 rxd = self.pg0.get_capture(NUM_PKTS)
1167 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1168 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1169 self.assertEqual(p4[IP].dst, rx[IP].dst)
1170 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1171 rxd = self.pg1.get_capture(NUM_PKTS)
1173 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1174 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1175 self.assertEqual(p4[IP].dst, rx[IP].dst)
1176 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1178 self.vapi.cli("clear trace")
1179 self.pg2.add_stream(p6 * NUM_PKTS)
1180 self.pg_enable_capture(self.pg_interfaces)
1183 rxd = self.pg0.get_capture(NUM_PKTS)
1185 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1186 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1187 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1188 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1189 rxd = self.pg1.get_capture(NUM_PKTS)
1191 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1192 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1193 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1194 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1196 stats = self.statistics.get_counter("/net/punt")
1197 self.assertEqual(stats[0][7]['packets'], 3*NUM_PKTS)
1198 self.assertEqual(stats[0][8]['packets'], 3*NUM_PKTS)
1200 self.logger.info(self.vapi.cli("show vlib graph punt-dispatch"))
1201 self.logger.info(self.vapi.cli("show punt client"))
1202 self.logger.info(self.vapi.cli("show punt reason"))
1203 self.logger.info(self.vapi.cli("show punt stats"))
1204 self.logger.info(self.vapi.cli("show punt db"))
1207 # dump the punt registered reasons
1208 # search for a few we know should be there
1210 rs = self.vapi.punt_reason_dump()
1212 reasons = ["ipsec6-no-such-tunnel",
1213 "ipsec4-no-such-tunnel",
1217 for reason in reasons:
1220 if r.reason.name == reason:
1223 self.assertTrue(found)
1226 if __name__ == '__main__':
1227 unittest.main(testRunner=VppTestRunner)