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]
80 # FIXME: nr_packets > 3 results in failure
81 # nr_packets = 3 makes the test unstable
86 super(TestPuntSocket, cls).setUpClass()
89 def tearDownClass(cls):
90 super(TestPuntSocket, cls).tearDownClass()
93 def setUpConstants(cls):
94 cls.extra_vpp_punt_config = [
95 "punt", "{", "socket", cls.tempdir+"/socket_punt", "}"]
96 super(TestPuntSocket, cls).setUpConstants()
99 super(TestPuntSocket, self).setUp()
102 self.create_pg_interfaces(range(2))
103 for i in self.pg_interfaces:
107 del self.sock_servers[:]
108 super(TestPuntSocket, self).tearDown()
110 def socket_client_create(self, sock_name, id=None):
111 thread = serverSocketThread(id, sock_name)
112 self.sock_servers.append(thread)
116 def socket_client_close(self):
118 for thread in self.sock_servers:
119 rx_pkts += thread.close()
122 def verify_port(self, pr, vpr):
123 self.assertEqual(vpr.punt.type, pr['type'])
124 self.assertEqual(vpr.punt.punt.l4.port,
125 pr['punt']['l4']['port'])
126 self.assertEqual(vpr.punt.punt.l4.protocol,
127 pr['punt']['l4']['protocol'])
128 self.assertEqual(vpr.punt.punt.l4.af,
129 pr['punt']['l4']['af'])
131 def verify_exception(self, pr, vpr):
132 self.assertEqual(vpr.punt.type, pr['type'])
133 self.assertEqual(vpr.punt.punt.exception.id,
134 pr['punt']['exception']['id'])
136 def verify_ip_proto(self, pr, vpr):
137 self.assertEqual(vpr.punt.type, pr['type'])
138 self.assertEqual(vpr.punt.punt.ip_proto.af,
139 pr['punt']['ip_proto']['af'])
140 self.assertEqual(vpr.punt.punt.ip_proto.protocol,
141 pr['punt']['ip_proto']['protocol'])
143 def verify_udp_pkts(self, rxs, n_rx, port):
146 self.assertTrue(rx.haslayer(UDP))
147 if rx[UDP].dport == port:
149 self.assertEqual(n_match, n_rx)
152 def set_port(pr, port):
153 pr['punt']['l4']['port'] = port
157 def set_reason(pr, reason):
158 pr['punt']['exception']['id'] = reason
163 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
164 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
165 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
171 'protocol': udp_proto
179 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
180 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
181 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
187 'protocol': udp_proto
194 class TestIP4PuntSocket(TestPuntSocket):
195 """ Punt Socket for IPv4 UDP """
199 super(TestIP4PuntSocket, cls).setUpClass()
202 def tearDownClass(cls):
203 super(TestIP4PuntSocket, cls).tearDownClass()
206 super(TestIP4PuntSocket, self).setUp()
208 for i in self.pg_interfaces:
213 super(TestIP4PuntSocket, self).tearDown()
214 for i in self.pg_interfaces:
218 def test_punt_socket_dump(self):
219 """ Punt socket registration/deregistration"""
221 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
222 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
223 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
225 punts = self.vapi.punt_socket_dump(type=pt_l4)
226 self.assertEqual(len(punts), 0)
229 # configure a punt socket
231 punt_l4 = mk_vpp_cfg4()
233 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
234 b"%s/socket_punt_1111" %
235 six.ensure_binary(self.tempdir))
236 self.vapi.punt_socket_register(set_port(punt_l4, 2222),
237 b"%s/socket_punt_2222" %
238 six.ensure_binary(self.tempdir))
239 punts = self.vapi.punt_socket_dump(type=pt_l4)
240 self.assertEqual(len(punts), 2)
241 self.verify_port(set_port(punt_l4, 1111), punts[0])
242 self.verify_port(set_port(punt_l4, 2222), punts[1])
245 # deregister a punt socket
247 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
248 punts = self.vapi.punt_socket_dump(type=pt_l4)
249 self.assertEqual(len(punts), 1)
252 # configure a punt socket again
254 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
255 b"%s/socket_punt_1111" %
256 six.ensure_binary(self.tempdir))
257 self.vapi.punt_socket_register(set_port(punt_l4, 3333),
258 b"%s/socket_punt_3333" %
259 six.ensure_binary(self.tempdir))
260 punts = self.vapi.punt_socket_dump(type=pt_l4)
261 self.assertEqual(len(punts), 3)
263 self.logger.info(self.vapi.cli("sh punt sock reg"))
266 # deregister all punt socket
268 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
269 self.vapi.punt_socket_deregister(set_port(punt_l4, 2222))
270 self.vapi.punt_socket_deregister(set_port(punt_l4, 3333))
271 punts = self.vapi.punt_socket_dump(type=pt_l4)
272 self.assertEqual(len(punts), 0)
274 def test_punt_socket_traffic_single_port_single_socket(self):
275 """ Punt socket traffic single port single socket"""
278 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
279 punt_l4 = set_port(mk_vpp_cfg4(), port)
281 p = (Ether(src=self.pg0.remote_mac,
282 dst=self.pg0.local_mac) /
283 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
284 UDP(sport=9876, dport=port) /
287 pkts = p * self.nr_packets
289 punts = self.vapi.punt_socket_dump(type=pt_l4)
290 self.assertEqual(len(punts), 0)
293 # expect ICMP - port unreachable for all packets
295 rx = self.send_and_expect(self.pg0, pkts, self.pg0)
298 self.assertEqual(int(p[IP].proto), 1) # ICMP
299 self.assertEqual(int(p[ICMP].code), 3) # unreachable
302 # configure a punt socket
304 self.socket_client_create(b"%s/socket_%d" % (
305 six.ensure_binary(self.tempdir), port))
306 self.vapi.punt_socket_register(punt_l4, b"%s/socket_%d" % (
307 six.ensure_binary(self.tempdir), port))
308 punts = self.vapi.punt_socket_dump(type=pt_l4)
309 self.assertEqual(len(punts), 1)
312 # expect punt socket and no packets on pg0
314 self.send_and_assert_no_replies(self.pg0, pkts)
315 rx = self.socket_client_close()
316 self.verify_udp_pkts(rx, len(pkts), port)
319 # remove punt socket. expect ICMP - port unreachable for all packets
321 self.vapi.punt_socket_deregister(punt_l4)
322 punts = self.vapi.punt_socket_dump(type=pt_l4)
323 self.assertEqual(len(punts), 0)
325 rx = self.send_and_expect(self.pg0, pkts, self.pg0)
327 self.assertEqual(int(p[IP].proto), 1) # ICMP
328 self.assertEqual(int(p[ICMP].code), 3) # unreachable
330 def test_punt_socket_traffic_multi_ports_multi_sockets(self):
331 """ Punt socket traffic multi ports and multi sockets"""
333 punt_l4 = mk_vpp_cfg4()
335 # configuration for each UDP port
339 # create stream of packets for each port
341 for port in self.ports:
342 # choose port from port list
345 pkt = (Ether(src=self.pg0.remote_mac,
346 dst=self.pg0.local_mac) /
347 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
348 UDP(sport=9876, dport=port) /
350 cfgs[port]['pkts'] = pkt * self.nr_packets
351 cfgs[port]['port'] = port
352 cfgs[port]['vpp'] = copy.deepcopy(set_port(punt_l4, port))
354 # configure punt sockets
355 cfgs[port]['sock'] = self.socket_client_create(
356 b"%s/socket_%d" % (six.ensure_binary(self.tempdir), port))
357 self.vapi.punt_socket_register(
359 b"%s/socket_%d" % (six.ensure_binary(self.tempdir),
363 # send the packets that get punted
365 for cfg in cfgs.values():
366 self.send_and_assert_no_replies(self.pg0, cfg['pkts'])
369 # test that we got the excepted packets on the expected socket
371 for cfg in cfgs.values():
372 rx = cfg['sock'].close()
373 self.verify_udp_pkts(rx, len(cfg['pkts']), cfg['port'])
374 self.vapi.punt_socket_deregister(cfg['vpp'])
376 def test_punt_socket_traffic_multi_ports_single_socket(self):
377 """ Punt socket traffic multi ports and single socket"""
379 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
380 punt_l4 = mk_vpp_cfg4()
383 # create stream of packets with each port
386 for port in self.ports:
387 # choose port from port list
388 pkt = (Ether(src=self.pg0.remote_mac,
389 dst=self.pg0.local_mac) /
390 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
391 UDP(sport=9876, dport=port) /
393 pkts += pkt * self.nr_packets
396 # configure a punt socket
398 self.socket_client_create(b"%s/socket_multi" %
399 six.ensure_binary(self.tempdir))
401 self.vapi.punt_socket_register(set_port(punt_l4, p),
403 six.ensure_binary(self.tempdir))
404 punts = self.vapi.punt_socket_dump(type=pt_l4)
405 self.assertEqual(len(punts), len(self.ports))
408 # expect punt socket and no packets on pg0
410 self.send_and_assert_no_replies(self.pg0, pkts)
411 self.logger.info(self.vapi.cli("show trace"))
412 rx = self.socket_client_close()
415 self.verify_udp_pkts(rx, self.nr_packets, p)
416 self.vapi.punt_socket_deregister(set_port(punt_l4, p))
417 punts = self.vapi.punt_socket_dump(type=pt_l4)
418 self.assertEqual(len(punts), 0)
421 class TestIP6PuntSocket(TestPuntSocket):
422 """ Punt Socket for IPv6 UDP """
426 super(TestIP6PuntSocket, cls).setUpClass()
429 def tearDownClass(cls):
430 super(TestIP6PuntSocket, cls).tearDownClass()
433 super(TestIP6PuntSocket, self).setUp()
435 for i in self.pg_interfaces:
440 super(TestIP6PuntSocket, self).tearDown()
441 for i in self.pg_interfaces:
445 def test_punt_socket_dump(self):
446 """ Punt socket registration """
448 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
449 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
450 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
452 # configure a punt socket
459 'protocol': udp_proto
464 punts = self.vapi.punt_socket_dump(type=pt_l4)
465 self.assertEqual(len(punts), 0)
468 # configure a punt socket
470 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
472 six.ensure_binary(self.tempdir))
473 self.vapi.punt_socket_register(set_port(punt_l4, 2222),
475 six.ensure_binary(self.tempdir))
476 punts = self.vapi.punt_socket_dump(type=pt_l4)
477 self.assertEqual(len(punts), 2)
478 self.verify_port(set_port(punt_l4, 1111), punts[0])
479 self.verify_port(set_port(punt_l4, 2222), punts[1])
482 # deregister a punt socket
484 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
485 punts = self.vapi.punt_socket_dump(type=pt_l4)
486 self.assertEqual(len(punts), 1)
489 # configure a punt socket again
491 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
493 six.ensure_binary(self.tempdir))
494 punts = self.vapi.punt_socket_dump(type=pt_l4)
495 self.assertEqual(len(punts), 2)
498 # deregister all punt socket
500 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
501 self.vapi.punt_socket_deregister(set_port(punt_l4, 2222))
502 self.vapi.punt_socket_deregister(set_port(punt_l4, 3333))
503 punts = self.vapi.punt_socket_dump(type=pt_l4)
504 self.assertEqual(len(punts), 0)
506 def test_punt_socket_traffic_single_port_single_socket(self):
507 """ Punt socket traffic single port single socket"""
510 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
511 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
512 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
518 'protocol': udp_proto,
524 p = (Ether(src=self.pg0.remote_mac,
525 dst=self.pg0.local_mac) /
526 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
527 inet6.UDP(sport=9876, dport=port) /
530 pkts = p * self.nr_packets
532 punts = self.vapi.punt_socket_dump(type=pt_l4)
533 self.assertEqual(len(punts), 0)
536 # expect ICMPv6 - destination unreachable for all packets
538 self.vapi.cli("clear trace")
539 self.pg0.add_stream(pkts)
540 self.pg_enable_capture(self.pg_interfaces)
542 # FIXME - when punt socket deregister is implemented
543 # rx = self.pg0.get_capture(self.nr_packets)
545 # self.assertEqual(int(p[IPv6].nh), 58) # ICMPv6
546 # self.assertEqual(int(p[ICMPv6DestUnreach].code),4) # unreachable
549 # configure a punt socket
551 self.socket_client_create(b"%s/socket_%d" % (
552 six.ensure_binary(self.tempdir), port))
553 self.vapi.punt_socket_register(punt_l4, b"%s/socket_%d" % (
554 six.ensure_binary(self.tempdir), port))
555 punts = self.vapi.punt_socket_dump(type=pt_l4)
556 self.assertEqual(len(punts), 1)
559 # expect punt socket and no packets on pg0
561 self.vapi.cli("clear errors")
562 self.vapi.cli("clear trace")
563 self.pg0.add_stream(pkts)
564 self.pg_enable_capture(self.pg_interfaces)
566 self.pg0.get_capture(0)
567 self.logger.info(self.vapi.cli("show trace"))
568 rx = self.socket_client_close()
569 self.verify_udp_pkts(rx, len(pkts), port)
572 # remove punt socket. expect ICMP - dest. unreachable for all packets
574 self.vapi.punt_socket_deregister(punt_l4)
575 punts = self.vapi.punt_socket_dump(type=pt_l4)
576 self.assertEqual(len(punts), 0)
577 self.pg0.add_stream(pkts)
578 self.pg_enable_capture(self.pg_interfaces)
580 # FIXME - when punt socket deregister is implemented
581 # self.pg0.get_capture(nr_packets)
583 def test_punt_socket_traffic_multi_ports_multi_sockets(self):
584 """ Punt socket traffic multi ports and multi sockets"""
586 punt_l4 = mk_vpp_cfg6()
588 # configuration for each UDP port
592 # create stream of packets for each port
594 for port in self.ports:
595 # choose port from port list
598 pkt = (Ether(src=self.pg0.remote_mac,
599 dst=self.pg0.local_mac) /
600 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
601 UDP(sport=9876, dport=port) /
603 cfgs[port]['pkts'] = pkt * self.nr_packets
604 cfgs[port]['port'] = port
605 cfgs[port]['vpp'] = copy.deepcopy(set_port(punt_l4, port))
607 # configure punt sockets
608 cfgs[port]['sock'] = self.socket_client_create(
609 b"%s/socket_%d" % (six.ensure_binary(self.tempdir), port))
610 self.vapi.punt_socket_register(
612 b"%s/socket_%d" % (six.ensure_binary(self.tempdir),
616 # send the packets that get punted
618 for cfg in cfgs.values():
619 self.send_and_assert_no_replies(self.pg0, cfg['pkts'])
622 # test that we got the excepted packets on the expected socket
624 for cfg in cfgs.values():
625 rx = cfg['sock'].close()
626 self.verify_udp_pkts(rx, len(cfg['pkts']), cfg['port'])
627 self.vapi.punt_socket_deregister(cfg['vpp'])
629 def test_punt_socket_traffic_multi_ports_single_socket(self):
630 """ Punt socket traffic multi ports and single socket"""
632 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
633 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
634 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
640 'protocol': udp_proto,
646 # create stream of packets with each port
649 for port in self.ports:
650 # choose port from port list
651 pkt = (Ether(src=self.pg0.remote_mac,
652 dst=self.pg0.local_mac) /
653 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
654 UDP(sport=9876, dport=port) /
656 pkts += pkt * self.nr_packets
661 punts = self.vapi.punt_socket_dump(type=pt_l4)
662 self.assertEqual(len(punts), 0)
665 # configure a punt socket
667 self.socket_client_create(b"%s/socket_multi" %
668 six.ensure_binary(self.tempdir))
670 self.vapi.punt_socket_register(set_port(punt_l4, p),
672 six.ensure_binary(self.tempdir))
673 punts = self.vapi.punt_socket_dump(type=pt_l4)
674 self.assertEqual(len(punts), len(self.ports))
677 # expect punt socket and no packets on pg0
679 self.vapi.cli("clear errors")
680 self.vapi.cli("clear trace")
681 self.pg0.add_stream(pkts)
682 self.pg_enable_capture(self.pg_interfaces)
684 # give a chance to punt socket to collect all packets
686 self.pg0.get_capture(0)
687 rx = self.socket_client_close()
690 self.verify_udp_pkts(rx, self.nr_packets, p)
691 self.vapi.punt_socket_deregister(set_port(punt_l4, p))
692 punts = self.vapi.punt_socket_dump(type=pt_l4)
693 self.assertEqual(len(punts), 0)
696 class TestExceptionPuntSocket(TestPuntSocket):
697 """ Punt Socket for Exceptions """
701 super(TestExceptionPuntSocket, cls).setUpClass()
704 def tearDownClass(cls):
705 super(TestExceptionPuntSocket, cls).tearDownClass()
708 super(TestExceptionPuntSocket, self).setUp()
710 for i in self.pg_interfaces:
715 super(TestExceptionPuntSocket, self).tearDown()
716 for i in self.pg_interfaces:
720 def test_registration(self):
721 """ Punt socket registration/deregistration"""
723 pt_ex = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_EXCEPTION
725 punts = self.vapi.punt_socket_dump(type=pt_ex)
726 self.assertEqual(len(punts), 0)
729 # configure a punt socket
738 self.vapi.punt_socket_register(set_reason(punt_ex, 1),
739 b"%s/socket_punt_1" %
740 six.ensure_binary(self.tempdir))
741 self.vapi.punt_socket_register(set_reason(punt_ex, 2),
742 b"%s/socket_punt_2" %
743 six.ensure_binary(self.tempdir))
744 punts = self.vapi.punt_socket_dump(type=pt_ex)
745 self.assertEqual(len(punts), 2)
746 self.verify_exception(set_reason(punt_ex, 1), punts[0])
747 self.verify_exception(set_reason(punt_ex, 2), punts[1])
750 # deregister a punt socket
752 self.vapi.punt_socket_deregister(set_reason(punt_ex, 1))
753 punts = self.vapi.punt_socket_dump(type=pt_ex)
754 self.assertEqual(len(punts), 1)
757 # configure a punt socket again
759 self.vapi.punt_socket_register(set_reason(punt_ex, 1),
760 b"%s/socket_punt_1" %
761 six.ensure_binary(self.tempdir))
762 self.vapi.punt_socket_register(set_reason(punt_ex, 3),
763 b"%s/socket_punt_3" %
764 six.ensure_binary(self.tempdir))
765 punts = self.vapi.punt_socket_dump(type=pt_ex)
766 self.assertEqual(len(punts), 3)
768 self.logger.info(self.vapi.cli("sh punt sock reg exception"))
771 # deregister all punt socket
773 self.vapi.punt_socket_deregister(set_reason(punt_ex, 1))
774 self.vapi.punt_socket_deregister(set_reason(punt_ex, 2))
775 self.vapi.punt_socket_deregister(set_reason(punt_ex, 3))
776 punts = self.vapi.punt_socket_dump(type=pt_ex)
777 self.assertEqual(len(punts), 0)
779 def verify_esp_pkts(self, rxs, n_sent, spi, has_udp):
780 self.assertEqual(len(rxs), n_sent)
782 self.assertTrue(rx.haslayer(IP))
783 self.assertTrue(rx.haslayer(ESP))
784 self.assertEqual(rx[ESP].spi, spi)
786 self.assertTrue(rx.haslayer(UDP))
788 def test_traffic(self):
789 """ Punt socket traffic """
792 pt_ex = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_EXCEPTION
801 # we need an IPSec tunnels for this to work otherwise ESP gets dropped
802 # due to unknown IP proto
804 VppIpsecTunInterface(self, self.pg0, 1000, 1000,
805 (VppEnum.vl_api_ipsec_crypto_alg_t.
806 IPSEC_API_CRYPTO_ALG_AES_CBC_128),
809 (VppEnum.vl_api_ipsec_integ_alg_t.
810 IPSEC_API_INTEG_ALG_SHA1_96),
812 "0123456701234567").add_vpp_config()
813 VppIpsecTunInterface(self, self.pg0, 1001, 1001,
814 (VppEnum.vl_api_ipsec_crypto_alg_t.
815 IPSEC_API_CRYPTO_ALG_AES_CBC_128),
818 (VppEnum.vl_api_ipsec_integ_alg_t.
819 IPSEC_API_INTEG_ALG_SHA1_96),
822 udp_encap=True).add_vpp_config()
825 # we're dealing with IPSec tunnels punting for no-such-tunnel
829 cfgs['ipsec4-no-such-tunnel'] = {'spi': 99, 'udp': False}
830 cfgs['ipsec4-spi-o-udp-0'] = {'spi': 0, 'udp': True}
833 # find the VPP ID for these punt exception reasin
835 rs = self.vapi.punt_reason_dump()
838 if r.reason.name == key:
839 cfgs[key]['id'] = r.reason.id
840 cfgs[key]['vpp'] = copy.deepcopy(
846 # configure punt sockets
848 for cfg in cfgs.values():
849 cfg['sock'] = self.socket_client_create(b"%s/socket_%d" % (
850 six.ensure_binary(self.tempdir), cfg['id']))
851 self.vapi.punt_socket_register(
853 b"%s/socket_%d" % (six.ensure_binary(self.tempdir),
857 # create packet streams for 'no-such-tunnel' exception
859 for cfg in cfgs.values():
860 pkt = (Ether(src=self.pg0.remote_mac,
861 dst=self.pg0.local_mac) /
862 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4))
864 pkt = pkt / UDP(sport=666, dport=4500)
865 pkt = (pkt / ESP(spi=cfg['spi'], seq=3) /
870 # send packets for each SPI we expect to be punted
872 for cfg in cfgs.values():
873 self.send_and_assert_no_replies(self.pg0, cfg['pkts'])
876 # verify the punted packets arrived on the associated socket
878 for cfg in cfgs.values():
879 rx = cfg['sock'].close()
880 self.verify_esp_pkts(rx, len(cfg['pkts']),
881 cfg['spi'], cfg['udp'])
886 for cfg in cfgs.values():
887 self.vapi.punt_socket_deregister(cfg['vpp'])
890 class TestIpProtoPuntSocket(TestPuntSocket):
891 """ Punt Socket for IP packets """
895 super(TestIpProtoPuntSocket, cls).setUpClass()
898 def tearDownClass(cls):
899 super(TestIpProtoPuntSocket, cls).tearDownClass()
902 super(TestIpProtoPuntSocket, self).setUp()
904 for i in self.pg_interfaces:
909 super(TestIpProtoPuntSocket, self).tearDown()
910 for i in self.pg_interfaces:
914 def test_registration(self):
915 """ Punt socket registration/deregistration"""
917 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
918 pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
919 proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
920 proto_eigrp = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_EIGRP
922 punts = self.vapi.punt_socket_dump(type=pt_ip)
923 self.assertEqual(len(punts), 0)
926 # configure a punt socket
933 'protocol': proto_ospf
942 'protocol': proto_eigrp
947 self.vapi.punt_socket_register(punt_ospf,
948 b"%s/socket_punt_1" %
949 six.ensure_binary(self.tempdir))
950 self.vapi.punt_socket_register(punt_eigrp,
951 b"%s/socket_punt_2" %
952 six.ensure_binary(self.tempdir))
953 self.logger.info(self.vapi.cli("sh punt sock reg ip"))
954 punts = self.vapi.punt_socket_dump(type=pt_ip)
955 self.assertEqual(len(punts), 2)
956 self.verify_ip_proto(punt_ospf, punts[0])
957 self.verify_ip_proto(punt_eigrp, punts[1])
960 # deregister a punt socket
962 self.vapi.punt_socket_deregister(punt_ospf)
963 punts = self.vapi.punt_socket_dump(type=pt_ip)
964 self.assertEqual(len(punts), 1)
967 # configure a punt socket again
969 self.vapi.punt_socket_register(punt_ospf,
970 b"%s/socket_punt_3" %
971 six.ensure_binary(self.tempdir))
972 punts = self.vapi.punt_socket_dump(type=pt_ip)
973 self.assertEqual(len(punts), 2)
975 self.logger.info(self.vapi.cli("sh punt sock reg exception"))
978 # deregister all punt socket
980 self.vapi.punt_socket_deregister(punt_eigrp)
981 self.vapi.punt_socket_deregister(punt_ospf)
982 punts = self.vapi.punt_socket_dump(type=pt_ip)
983 self.assertEqual(len(punts), 0)
985 def verify_ospf_pkts(self, rxs, n_sent):
986 self.assertEqual(len(rxs), n_sent)
988 self.assertTrue(rx.haslayer(OSPF_Hdr))
990 def test_traffic(self):
991 """ Punt socket traffic """
993 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
994 pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
995 proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
998 # configure a punt socket to capture OSPF packets
1005 'protocol': proto_ospf
1011 # create packet streams and configure a punt sockets
1013 pkt = (Ether(src=self.pg0.remote_mac,
1014 dst=self.pg0.local_mac) /
1015 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
1020 sock = self.socket_client_create(b"%s/socket_1" % (
1021 six.ensure_binary(self.tempdir)))
1022 self.vapi.punt_socket_register(
1024 b"%s/socket_1" % (six.ensure_binary(self.tempdir)))
1027 # send packets for each SPI we expect to be punted
1029 self.send_and_assert_no_replies(self.pg0, pkts)
1032 # verify the punted packets arrived on the associated socket
1035 self.verify_ospf_pkts(rx, len(pkts))
1036 self.vapi.punt_socket_deregister(punt_ospf)
1039 class TestPunt(VppTestCase):
1040 """ Exception Punt Test Case """
1043 def setUpClass(cls):
1044 super(TestPunt, cls).setUpClass()
1047 def tearDownClass(cls):
1048 super(TestPunt, cls).tearDownClass()
1051 super(TestPunt, self).setUp()
1053 self.create_pg_interfaces(range(4))
1055 for i in self.pg_interfaces:
1063 for i in self.pg_interfaces:
1068 super(TestPunt, self).tearDown()
1070 def test_punt(self):
1071 """ Exception Path testing """
1074 # dump the punt registered reasons
1075 # search for a few we know should be there
1077 rs = self.vapi.punt_reason_dump()
1079 reasons = ["ipsec6-no-such-tunnel",
1080 "ipsec4-no-such-tunnel",
1081 "ipsec4-spi-o-udp-0"]
1083 for reason in reasons:
1086 if r.reason.name == reason:
1089 self.assertTrue(found)
1092 # Using the test CLI we will hook in a exception path to
1093 # send ACL deny packets out of pg0 and pg1.
1094 # the ACL is src,dst = 1.1.1.1,1.1.1.2
1096 ip_1_1_1_2 = VppIpRoute(self, "1.1.1.2", 32,
1097 [VppRoutePath(self.pg3.remote_ip4,
1098 self.pg3.sw_if_index)])
1099 ip_1_1_1_2.add_vpp_config()
1100 ip_1_2 = VppIpRoute(self, "1::2", 128,
1101 [VppRoutePath(self.pg3.remote_ip6,
1102 self.pg3.sw_if_index,
1103 proto=DpoProto.DPO_PROTO_IP6)])
1104 ip_1_2.add_vpp_config()
1106 p4 = (Ether(src=self.pg2.remote_mac,
1107 dst=self.pg2.local_mac) /
1108 IP(src="1.1.1.1", dst="1.1.1.2") /
1109 UDP(sport=1234, dport=1234) /
1111 p6 = (Ether(src=self.pg2.remote_mac,
1112 dst=self.pg2.local_mac) /
1113 IPv6(src="1::1", dst="1::2") /
1114 UDP(sport=1234, dport=1234) /
1116 self.send_and_expect(self.pg2, p4*1, self.pg3)
1117 self.send_and_expect(self.pg2, p6*1, self.pg3)
1120 # apply the punting features
1122 self.vapi.cli("test punt pg2")
1125 # dump the punt reasons to learn the IDs assigned
1127 rs = self.vapi.punt_reason_dump(reason={'name': "reason-v4"})
1128 r4 = rs[0].reason.id
1129 rs = self.vapi.punt_reason_dump(reason={'name': "reason-v6"})
1130 r6 = rs[0].reason.id
1135 self.send_and_assert_no_replies(self.pg2, p4*NUM_PKTS)
1136 self.send_and_assert_no_replies(self.pg2, p6*NUM_PKTS)
1140 # 1 - node error counters
1141 # 2 - per-reason counters
1142 # 2, 3 are the index of the assigned punt reason
1144 stats = self.statistics.get_err_counter(
1145 "/err/punt-dispatch/No registrations")
1146 self.assertEqual(stats, 2*NUM_PKTS)
1148 stats = self.statistics.get_counter("/net/punt")
1149 self.assertEqual(stats[0][r4]['packets'], NUM_PKTS)
1150 self.assertEqual(stats[0][r6]['packets'], NUM_PKTS)
1153 # use the test CLI to test a client that punts exception
1154 # packets out of pg0
1156 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip4)
1157 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip6)
1159 rx4s = self.send_and_expect(self.pg2, p4*NUM_PKTS, self.pg0)
1160 rx6s = self.send_and_expect(self.pg2, p6*NUM_PKTS, self.pg0)
1163 # check the packets come out IP unmodified but destined to pg0 host
1166 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1167 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1168 self.assertEqual(p4[IP].dst, rx[IP].dst)
1169 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1171 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1172 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1173 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1174 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1176 stats = self.statistics.get_counter("/net/punt")
1177 self.assertEqual(stats[0][r4]['packets'], 2*NUM_PKTS)
1178 self.assertEqual(stats[0][r6]['packets'], 2*NUM_PKTS)
1181 # add another registration for the same reason to send packets
1184 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip4)
1185 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip6)
1187 self.vapi.cli("clear trace")
1188 self.pg2.add_stream(p4 * NUM_PKTS)
1189 self.pg_enable_capture(self.pg_interfaces)
1192 rxd = self.pg0.get_capture(NUM_PKTS)
1194 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1195 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1196 self.assertEqual(p4[IP].dst, rx[IP].dst)
1197 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1198 rxd = self.pg1.get_capture(NUM_PKTS)
1200 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1201 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1202 self.assertEqual(p4[IP].dst, rx[IP].dst)
1203 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1205 self.vapi.cli("clear trace")
1206 self.pg2.add_stream(p6 * NUM_PKTS)
1207 self.pg_enable_capture(self.pg_interfaces)
1210 rxd = self.pg0.get_capture(NUM_PKTS)
1212 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1213 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1214 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1215 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1216 rxd = self.pg1.get_capture(NUM_PKTS)
1218 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1219 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1220 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1221 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1223 stats = self.statistics.get_counter("/net/punt")
1224 self.assertEqual(stats[0][r4]['packets'], 3*NUM_PKTS)
1225 self.assertEqual(stats[0][r6]['packets'], 3*NUM_PKTS)
1227 self.logger.info(self.vapi.cli("show vlib graph punt-dispatch"))
1228 self.logger.info(self.vapi.cli("show punt client"))
1229 self.logger.info(self.vapi.cli("show punt reason"))
1230 self.logger.info(self.vapi.cli("show punt stats"))
1231 self.logger.info(self.vapi.cli("show punt db"))
1234 if __name__ == '__main__':
1235 unittest.main(testRunner=VppTestRunner)