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
26 from framework import VppTestCase, VppTestRunner
28 from vpp_ip import DpoProto
29 from vpp_ip_route import VppIpRoute, VppRoutePath
30 from vpp_papi import VppEnum
31 from vpp_ipsec_tun_interface import VppIpsecTunInterface
36 class serverSocketThread(threading.Thread):
37 """ Socket server thread"""
39 def __init__(self, threadID, sockName):
40 threading.Thread.__init__(self)
41 self.threadID = threadID
42 self.sockName = sockName
47 # Wait for some packets on socket
49 data = self.sock.recv(65536)
51 # punt socket metadata
52 # packet_desc = data[0:8]
55 self.rx_pkts.append(Ether(data[8:]))
58 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
60 os.unlink(self.sockName)
63 self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 65536)
64 self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 65536)
65 self.sock.bind(self.sockName)
74 class TestPuntSocket(VppTestCase):
77 ports = [1111, 2222, 3333, 4444]
79 # FIXME: nr_packets > 3 results in failure
80 # nr_packets = 3 makes the test unstable
85 super(TestPuntSocket, cls).setUpClass()
88 def tearDownClass(cls):
89 super(TestPuntSocket, cls).tearDownClass()
92 def setUpConstants(cls):
93 cls.extra_vpp_punt_config = [
94 "punt", "{", "socket", cls.tempdir+"/socket_punt", "}"]
95 super(TestPuntSocket, cls).setUpConstants()
98 super(TestPuntSocket, self).setUp()
101 self.create_pg_interfaces(range(2))
102 for i in self.pg_interfaces:
106 del self.sock_servers[:]
107 super(TestPuntSocket, self).tearDown()
109 def socket_client_create(self, sock_name, id=None):
110 thread = serverSocketThread(id, sock_name)
111 self.sock_servers.append(thread)
115 def socket_client_close(self):
117 for thread in self.sock_servers:
118 rx_pkts += thread.close()
121 def verify_port(self, pr, vpr):
122 self.assertEqual(vpr.punt.type, pr['type'])
123 self.assertEqual(vpr.punt.punt.l4.port,
124 pr['punt']['l4']['port'])
125 self.assertEqual(vpr.punt.punt.l4.protocol,
126 pr['punt']['l4']['protocol'])
127 self.assertEqual(vpr.punt.punt.l4.af,
128 pr['punt']['l4']['af'])
130 def verify_exception(self, pr, vpr):
131 self.assertEqual(vpr.punt.type, pr['type'])
132 self.assertEqual(vpr.punt.punt.exception.id,
133 pr['punt']['exception']['id'])
135 def verify_ip_proto(self, pr, vpr):
136 self.assertEqual(vpr.punt.type, pr['type'])
137 self.assertEqual(vpr.punt.punt.ip_proto.af,
138 pr['punt']['ip_proto']['af'])
139 self.assertEqual(vpr.punt.punt.ip_proto.protocol,
140 pr['punt']['ip_proto']['protocol'])
142 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 "%s/socket_punt_1111" % self.tempdir)
234 self.vapi.punt_socket_register(set_port(punt_l4, 2222),
235 "%s/socket_punt_2222" % self.tempdir)
236 punts = self.vapi.punt_socket_dump(type=pt_l4)
237 self.assertEqual(len(punts), 2)
238 self.verify_port(set_port(punt_l4, 1111), punts[0])
239 self.verify_port(set_port(punt_l4, 2222), punts[1])
242 # deregister a punt socket
244 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
245 punts = self.vapi.punt_socket_dump(type=pt_l4)
246 self.assertEqual(len(punts), 1)
249 # configure a punt socket again
251 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
252 "%s/socket_punt_1111" % self.tempdir)
253 self.vapi.punt_socket_register(set_port(punt_l4, 3333),
254 "%s/socket_punt_3333" % self.tempdir)
255 punts = self.vapi.punt_socket_dump(type=pt_l4)
256 self.assertEqual(len(punts), 3)
258 self.logger.info(self.vapi.cli("sh punt sock reg"))
261 # deregister all punt socket
263 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
264 self.vapi.punt_socket_deregister(set_port(punt_l4, 2222))
265 self.vapi.punt_socket_deregister(set_port(punt_l4, 3333))
266 punts = self.vapi.punt_socket_dump(type=pt_l4)
267 self.assertEqual(len(punts), 0)
269 def test_punt_socket_traffic_single_port_single_socket(self):
270 """ Punt socket traffic single port single socket"""
273 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
274 punt_l4 = set_port(mk_vpp_cfg4(), port)
276 p = (Ether(src=self.pg0.remote_mac,
277 dst=self.pg0.local_mac) /
278 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
279 UDP(sport=9876, dport=port) /
282 pkts = p * self.nr_packets
284 punts = self.vapi.punt_socket_dump(type=pt_l4)
285 self.assertEqual(len(punts), 0)
288 # expect ICMP - port unreachable for all packets
290 rx = self.send_and_expect(self.pg0, pkts, self.pg0)
293 self.assertEqual(int(p[IP].proto), 1) # ICMP
294 self.assertEqual(int(p[ICMP].code), 3) # unreachable
297 # configure a punt socket
299 self.socket_client_create("%s/socket_%d" % (self.tempdir, port))
300 self.vapi.punt_socket_register(punt_l4, "%s/socket_%d" %
301 (self.tempdir, port))
302 punts = self.vapi.punt_socket_dump(type=pt_l4)
303 self.assertEqual(len(punts), 1)
306 # expect punt socket and no packets on pg0
308 self.send_and_assert_no_replies(self.pg0, pkts)
309 rx = self.socket_client_close()
310 self.verify_udp_pkts(rx, len(pkts), port)
313 # remove punt socket. expect ICMP - port unreachable for all packets
315 self.vapi.punt_socket_deregister(punt_l4)
316 punts = self.vapi.punt_socket_dump(type=pt_l4)
317 self.assertEqual(len(punts), 0)
319 rx = self.send_and_expect(self.pg0, pkts, self.pg0)
321 self.assertEqual(int(p[IP].proto), 1) # ICMP
322 self.assertEqual(int(p[ICMP].code), 3) # unreachable
324 def test_punt_socket_traffic_multi_ports_multi_sockets(self):
325 """ Punt socket traffic multi ports and multi sockets"""
327 punt_l4 = mk_vpp_cfg4()
329 # configuration for each UDP port
333 # create stream of packets for each port
335 for port in self.ports:
336 # choose port from port list
339 pkt = (Ether(src=self.pg0.remote_mac,
340 dst=self.pg0.local_mac) /
341 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
342 UDP(sport=9876, dport=port) /
344 cfgs[port]['pkts'] = pkt * self.nr_packets
345 cfgs[port]['port'] = port
346 cfgs[port]['vpp'] = copy.deepcopy(set_port(punt_l4, port))
348 # configure punt sockets
349 cfgs[port]['sock'] = self.socket_client_create(
350 "%s/socket_%d" % (self.tempdir, port))
351 self.vapi.punt_socket_register(
353 "%s/socket_%d" % (self.tempdir, port))
356 # send the packets that get punted
358 for cfg in cfgs.values():
359 self.send_and_assert_no_replies(self.pg0, cfg['pkts'])
362 # test that we got the excepted packets on the expected socket
364 for cfg in cfgs.values():
365 rx = cfg['sock'].close()
366 self.verify_udp_pkts(rx, len(cfg['pkts']), cfg['port'])
367 self.vapi.punt_socket_deregister(cfg['vpp'])
369 def test_punt_socket_traffic_multi_ports_single_socket(self):
370 """ Punt socket traffic multi ports and single socket"""
372 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
373 punt_l4 = mk_vpp_cfg4()
376 # create stream of packets with each port
379 for port in self.ports:
380 # choose port from port list
381 pkt = (Ether(src=self.pg0.remote_mac,
382 dst=self.pg0.local_mac) /
383 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
384 UDP(sport=9876, dport=port) /
386 pkts += pkt * self.nr_packets
389 # configure a punt socket
391 self.socket_client_create("%s/socket_multi" % self.tempdir)
393 self.vapi.punt_socket_register(set_port(punt_l4, p),
394 "%s/socket_multi" % self.tempdir)
395 punts = self.vapi.punt_socket_dump(type=pt_l4)
396 self.assertEqual(len(punts), len(self.ports))
399 # expect punt socket and no packets on pg0
401 self.send_and_assert_no_replies(self.pg0, pkts)
402 self.logger.info(self.vapi.cli("show trace"))
403 rx = self.socket_client_close()
406 self.verify_udp_pkts(rx, self.nr_packets, p)
407 self.vapi.punt_socket_deregister(set_port(punt_l4, p))
408 punts = self.vapi.punt_socket_dump(type=pt_l4)
409 self.assertEqual(len(punts), 0)
412 class TestIP6PuntSocket(TestPuntSocket):
413 """ Punt Socket for IPv6 UDP """
417 super(TestIP6PuntSocket, cls).setUpClass()
420 def tearDownClass(cls):
421 super(TestIP6PuntSocket, cls).tearDownClass()
424 super(TestIP6PuntSocket, self).setUp()
426 for i in self.pg_interfaces:
431 super(TestIP6PuntSocket, self).tearDown()
432 for i in self.pg_interfaces:
436 def test_punt_socket_dump(self):
437 """ Punt socket registration """
439 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
440 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
441 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
443 # configure a punt socket
450 'protocol': udp_proto
455 punts = self.vapi.punt_socket_dump(type=pt_l4)
456 self.assertEqual(len(punts), 0)
459 # configure a punt socket
461 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
462 "%s/socket_1111" % self.tempdir)
463 self.vapi.punt_socket_register(set_port(punt_l4, 2222),
464 "%s/socket_2222" % self.tempdir)
465 punts = self.vapi.punt_socket_dump(type=pt_l4)
466 self.assertEqual(len(punts), 2)
467 self.verify_port(set_port(punt_l4, 1111), punts[0])
468 self.verify_port(set_port(punt_l4, 2222), punts[1])
471 # deregister a punt socket
473 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
474 punts = self.vapi.punt_socket_dump(type=pt_l4)
475 self.assertEqual(len(punts), 1)
478 # configure a punt socket again
480 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
481 "%s/socket_1111" % self.tempdir)
482 punts = self.vapi.punt_socket_dump(type=pt_l4)
483 self.assertEqual(len(punts), 2)
486 # deregister all punt socket
488 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
489 self.vapi.punt_socket_deregister(set_port(punt_l4, 2222))
490 self.vapi.punt_socket_deregister(set_port(punt_l4, 3333))
491 punts = self.vapi.punt_socket_dump(type=pt_l4)
492 self.assertEqual(len(punts), 0)
494 def test_punt_socket_traffic_single_port_single_socket(self):
495 """ Punt socket traffic single port single socket"""
498 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
499 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
500 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
506 'protocol': udp_proto,
512 p = (Ether(src=self.pg0.remote_mac,
513 dst=self.pg0.local_mac) /
514 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
515 inet6.UDP(sport=9876, dport=port) /
518 pkts = p * self.nr_packets
520 punts = self.vapi.punt_socket_dump(type=pt_l4)
521 self.assertEqual(len(punts), 0)
524 # expect ICMPv6 - destination unreachable for all packets
526 self.vapi.cli("clear trace")
527 self.pg0.add_stream(pkts)
528 self.pg_enable_capture(self.pg_interfaces)
530 # FIXME - when punt socket deregister is implemented
531 # rx = self.pg0.get_capture(self.nr_packets)
533 # self.assertEqual(int(p[IPv6].nh), 58) # ICMPv6
534 # self.assertEqual(int(p[ICMPv6DestUnreach].code),4) # unreachable
537 # configure a punt socket
539 self.socket_client_create("%s/socket_%d" % (self.tempdir, port))
540 self.vapi.punt_socket_register(punt_l4, "%s/socket_%d" %
541 (self.tempdir, port))
542 punts = self.vapi.punt_socket_dump(type=pt_l4)
543 self.assertEqual(len(punts), 1)
546 # expect punt socket and no packets on pg0
548 self.vapi.cli("clear errors")
549 self.vapi.cli("clear trace")
550 self.pg0.add_stream(pkts)
551 self.pg_enable_capture(self.pg_interfaces)
553 self.pg0.get_capture(0)
554 self.logger.info(self.vapi.cli("show trace"))
555 rx = self.socket_client_close()
556 self.verify_udp_pkts(rx, len(pkts), port)
559 # remove punt socket. expect ICMP - dest. unreachable for all packets
561 self.vapi.punt_socket_deregister(punt_l4)
562 punts = self.vapi.punt_socket_dump(type=pt_l4)
563 self.assertEqual(len(punts), 0)
564 self.pg0.add_stream(pkts)
565 self.pg_enable_capture(self.pg_interfaces)
567 # FIXME - when punt socket deregister is implemented
568 # self.pg0.get_capture(nr_packets)
570 def test_punt_socket_traffic_multi_ports_multi_sockets(self):
571 """ Punt socket traffic multi ports and multi sockets"""
573 punt_l4 = mk_vpp_cfg6()
575 # configuration for each UDP port
579 # create stream of packets for each port
581 for port in self.ports:
582 # choose port from port list
585 pkt = (Ether(src=self.pg0.remote_mac,
586 dst=self.pg0.local_mac) /
587 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
588 UDP(sport=9876, dport=port) /
590 cfgs[port]['pkts'] = pkt * self.nr_packets
591 cfgs[port]['port'] = port
592 cfgs[port]['vpp'] = copy.deepcopy(set_port(punt_l4, port))
594 # configure punt sockets
595 cfgs[port]['sock'] = self.socket_client_create(
596 "%s/socket_%d" % (self.tempdir, port))
597 self.vapi.punt_socket_register(
599 "%s/socket_%d" % (self.tempdir, port))
602 # send the packets that get punted
604 for cfg in cfgs.values():
605 self.send_and_assert_no_replies(self.pg0, cfg['pkts'])
608 # test that we got the excepted packets on the expected socket
610 for cfg in cfgs.values():
611 rx = cfg['sock'].close()
612 self.verify_udp_pkts(rx, len(cfg['pkts']), cfg['port'])
613 self.vapi.punt_socket_deregister(cfg['vpp'])
615 def test_punt_socket_traffic_multi_ports_single_socket(self):
616 """ Punt socket traffic multi ports and single socket"""
618 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
619 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
620 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
626 'protocol': udp_proto,
632 # create stream of packets with each port
635 for port in self.ports:
636 # choose port from port list
637 pkt = (Ether(src=self.pg0.remote_mac,
638 dst=self.pg0.local_mac) /
639 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
640 UDP(sport=9876, dport=port) /
642 pkts += pkt * self.nr_packets
647 punts = self.vapi.punt_socket_dump(type=pt_l4)
648 self.assertEqual(len(punts), 0)
651 # configure a punt socket
653 self.socket_client_create("%s/socket_multi" % self.tempdir)
655 self.vapi.punt_socket_register(set_port(punt_l4, p),
656 "%s/socket_multi" % self.tempdir)
657 punts = self.vapi.punt_socket_dump(type=pt_l4)
658 self.assertEqual(len(punts), len(self.ports))
661 # expect punt socket and no packets on pg0
663 self.vapi.cli("clear errors")
664 self.vapi.cli("clear trace")
665 self.pg0.add_stream(pkts)
666 self.pg_enable_capture(self.pg_interfaces)
668 # give a chance to punt socket to collect all packets
670 self.pg0.get_capture(0)
671 rx = self.socket_client_close()
674 self.verify_udp_pkts(rx, self.nr_packets, p)
675 self.vapi.punt_socket_deregister(set_port(punt_l4, p))
676 punts = self.vapi.punt_socket_dump(type=pt_l4)
677 self.assertEqual(len(punts), 0)
680 class TestExceptionPuntSocket(TestPuntSocket):
681 """ Punt Socket for Exceptions """
685 super(TestExceptionPuntSocket, cls).setUpClass()
688 def tearDownClass(cls):
689 super(TestExceptionPuntSocket, cls).tearDownClass()
692 super(TestExceptionPuntSocket, self).setUp()
694 for i in self.pg_interfaces:
699 super(TestExceptionPuntSocket, self).tearDown()
700 for i in self.pg_interfaces:
704 def test_registration(self):
705 """ Punt socket registration/deregistration"""
707 pt_ex = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_EXCEPTION
709 punts = self.vapi.punt_socket_dump(type=pt_ex)
710 self.assertEqual(len(punts), 0)
713 # configure a punt socket
722 self.vapi.punt_socket_register(set_reason(punt_ex, 1),
723 "%s/socket_punt_1" % self.tempdir)
724 self.vapi.punt_socket_register(set_reason(punt_ex, 2),
725 "%s/socket_punt_2" % self.tempdir)
726 punts = self.vapi.punt_socket_dump(type=pt_ex)
727 self.assertEqual(len(punts), 2)
728 self.verify_exception(set_reason(punt_ex, 1), punts[0])
729 self.verify_exception(set_reason(punt_ex, 2), punts[1])
732 # deregister a punt socket
734 self.vapi.punt_socket_deregister(set_reason(punt_ex, 1))
735 punts = self.vapi.punt_socket_dump(type=pt_ex)
736 self.assertEqual(len(punts), 1)
739 # configure a punt socket again
741 self.vapi.punt_socket_register(set_reason(punt_ex, 1),
742 "%s/socket_punt_1" % self.tempdir)
743 self.vapi.punt_socket_register(set_reason(punt_ex, 3),
744 "%s/socket_punt_3" % self.tempdir)
745 punts = self.vapi.punt_socket_dump(type=pt_ex)
746 self.assertEqual(len(punts), 3)
748 self.logger.info(self.vapi.cli("sh punt sock reg exception"))
751 # deregister all punt socket
753 self.vapi.punt_socket_deregister(set_reason(punt_ex, 1))
754 self.vapi.punt_socket_deregister(set_reason(punt_ex, 2))
755 self.vapi.punt_socket_deregister(set_reason(punt_ex, 3))
756 punts = self.vapi.punt_socket_dump(type=pt_ex)
757 self.assertEqual(len(punts), 0)
759 def verify_esp_pkts(self, rxs, n_sent, spi, has_udp):
760 self.assertEqual(len(rxs), n_sent)
762 self.assertTrue(rx.haslayer(IP))
763 self.assertTrue(rx.haslayer(ESP))
764 self.assertEqual(rx[ESP].spi, spi)
766 self.assertTrue(rx.haslayer(UDP))
768 def test_traffic(self):
769 """ Punt socket traffic """
772 pt_ex = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_EXCEPTION
781 # we need an IPSec tunnels for this to work otherwise ESP gets dropped
782 # due to unknown IP proto
784 VppIpsecTunInterface(self, self.pg0, 1000, 1000,
785 (VppEnum.vl_api_ipsec_crypto_alg_t.
786 IPSEC_API_CRYPTO_ALG_AES_CBC_128),
789 (VppEnum.vl_api_ipsec_integ_alg_t.
790 IPSEC_API_INTEG_ALG_SHA1_96),
792 b"0123456701234567").add_vpp_config()
793 VppIpsecTunInterface(self, self.pg0, 1001, 1001,
794 (VppEnum.vl_api_ipsec_crypto_alg_t.
795 IPSEC_API_CRYPTO_ALG_AES_CBC_128),
798 (VppEnum.vl_api_ipsec_integ_alg_t.
799 IPSEC_API_INTEG_ALG_SHA1_96),
802 udp_encap=True).add_vpp_config()
805 # we're dealing with IPSec tunnels punting for no-such-tunnel
809 cfgs['ipsec4-no-such-tunnel'] = {'spi': 99, 'udp': False}
810 cfgs['ipsec4-spi-o-udp-0'] = {'spi': 0, 'udp': True}
813 # find the VPP ID for these punt exception reasin
815 rs = self.vapi.punt_reason_dump()
818 if r.reason.name == key:
819 cfgs[key]['id'] = r.reason.id
820 cfgs[key]['vpp'] = copy.deepcopy(
826 # configure punt sockets
828 for cfg in cfgs.values():
829 cfg['sock'] = self.socket_client_create("%s/socket_%d" %
830 (self.tempdir, cfg['id']))
831 self.vapi.punt_socket_register(
832 cfg['vpp'], "%s/socket_%d" % (self.tempdir, cfg['id']))
835 # create packet streams for 'no-such-tunnel' exception
837 for cfg in cfgs.values():
838 pkt = (Ether(src=self.pg0.remote_mac,
839 dst=self.pg0.local_mac) /
840 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4))
842 pkt = pkt / UDP(sport=666, dport=4500)
843 pkt = (pkt / ESP(spi=cfg['spi'], seq=3) /
848 # send packets for each SPI we expect to be punted
850 for cfg in cfgs.values():
851 self.send_and_assert_no_replies(self.pg0, cfg['pkts'])
854 # verify the punted packets arrived on the associated socket
856 for cfg in cfgs.values():
857 rx = cfg['sock'].close()
858 self.verify_esp_pkts(rx, len(cfg['pkts']),
859 cfg['spi'], cfg['udp'])
864 for cfg in cfgs.values():
865 self.vapi.punt_socket_deregister(cfg['vpp'])
868 class TestIpProtoPuntSocket(TestPuntSocket):
869 """ Punt Socket for IP packets """
873 super(TestIpProtoPuntSocket, cls).setUpClass()
876 def tearDownClass(cls):
877 super(TestIpProtoPuntSocket, cls).tearDownClass()
880 super(TestIpProtoPuntSocket, self).setUp()
882 for i in self.pg_interfaces:
887 super(TestIpProtoPuntSocket, self).tearDown()
888 for i in self.pg_interfaces:
892 def test_registration(self):
893 """ Punt socket registration/deregistration"""
895 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
896 pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
897 proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
898 proto_eigrp = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_EIGRP
900 punts = self.vapi.punt_socket_dump(type=pt_ip)
901 self.assertEqual(len(punts), 0)
904 # configure a punt socket
911 'protocol': proto_ospf
920 'protocol': proto_eigrp
925 self.vapi.punt_socket_register(punt_ospf,
926 "%s/socket_punt_1" % self.tempdir)
927 self.vapi.punt_socket_register(punt_eigrp,
928 "%s/socket_punt_2" % self.tempdir)
929 self.logger.info(self.vapi.cli("sh punt sock reg ip"))
930 punts = self.vapi.punt_socket_dump(type=pt_ip)
931 self.assertEqual(len(punts), 2)
932 self.verify_ip_proto(punt_ospf, punts[0])
933 self.verify_ip_proto(punt_eigrp, punts[1])
936 # deregister a punt socket
938 self.vapi.punt_socket_deregister(punt_ospf)
939 punts = self.vapi.punt_socket_dump(type=pt_ip)
940 self.assertEqual(len(punts), 1)
943 # configure a punt socket again
945 self.vapi.punt_socket_register(punt_ospf,
946 "%s/socket_punt_3" % self.tempdir)
947 punts = self.vapi.punt_socket_dump(type=pt_ip)
948 self.assertEqual(len(punts), 2)
950 self.logger.info(self.vapi.cli("sh punt sock reg exception"))
953 # deregister all punt socket
955 self.vapi.punt_socket_deregister(punt_eigrp)
956 self.vapi.punt_socket_deregister(punt_ospf)
957 punts = self.vapi.punt_socket_dump(type=pt_ip)
958 self.assertEqual(len(punts), 0)
960 def verify_ospf_pkts(self, rxs, n_sent):
961 self.assertEqual(len(rxs), n_sent)
963 self.assertTrue(rx.haslayer(OSPF_Hdr))
965 def test_traffic(self):
966 """ Punt socket traffic """
968 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
969 pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
970 proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
973 # configure a punt socket to capture OSPF packets
980 'protocol': proto_ospf
986 # create packet streams and configure a punt sockets
988 pkt = (Ether(src=self.pg0.remote_mac,
989 dst=self.pg0.local_mac) /
990 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
995 sock = self.socket_client_create("%s/socket_1" % self.tempdir)
996 self.vapi.punt_socket_register(
997 punt_ospf, "%s/socket_1" % self.tempdir)
1000 # send packets for each SPI we expect to be punted
1002 self.send_and_assert_no_replies(self.pg0, pkts)
1005 # verify the punted packets arrived on the associated socket
1008 self.verify_ospf_pkts(rx, len(pkts))
1009 self.vapi.punt_socket_deregister(punt_ospf)
1012 class TestPunt(VppTestCase):
1013 """ Exception Punt Test Case """
1016 def setUpClass(cls):
1017 super(TestPunt, cls).setUpClass()
1020 def tearDownClass(cls):
1021 super(TestPunt, cls).tearDownClass()
1024 super(TestPunt, self).setUp()
1026 self.create_pg_interfaces(range(4))
1028 for i in self.pg_interfaces:
1036 for i in self.pg_interfaces:
1041 super(TestPunt, self).tearDown()
1043 def test_punt(self):
1044 """ Exception Path testing """
1047 # dump the punt registered reasons
1048 # search for a few we know should be there
1050 rs = self.vapi.punt_reason_dump()
1052 reasons = ["ipsec6-no-such-tunnel",
1053 "ipsec4-no-such-tunnel",
1054 "ipsec4-spi-o-udp-0"]
1056 for reason in reasons:
1059 if r.reason.name == reason:
1062 self.assertTrue(found)
1065 # Using the test CLI we will hook in a exception path to
1066 # send ACL deny packets out of pg0 and pg1.
1067 # the ACL is src,dst = 1.1.1.1,1.1.1.2
1069 ip_1_1_1_2 = VppIpRoute(self, "1.1.1.2", 32,
1070 [VppRoutePath(self.pg3.remote_ip4,
1071 self.pg3.sw_if_index)])
1072 ip_1_1_1_2.add_vpp_config()
1073 ip_1_2 = VppIpRoute(self, "1::2", 128,
1074 [VppRoutePath(self.pg3.remote_ip6,
1075 self.pg3.sw_if_index,
1076 proto=DpoProto.DPO_PROTO_IP6)])
1077 ip_1_2.add_vpp_config()
1079 p4 = (Ether(src=self.pg2.remote_mac,
1080 dst=self.pg2.local_mac) /
1081 IP(src="1.1.1.1", dst="1.1.1.2") /
1082 UDP(sport=1234, dport=1234) /
1084 p6 = (Ether(src=self.pg2.remote_mac,
1085 dst=self.pg2.local_mac) /
1086 IPv6(src="1::1", dst="1::2") /
1087 UDP(sport=1234, dport=1234) /
1089 self.send_and_expect(self.pg2, p4*1, self.pg3)
1090 self.send_and_expect(self.pg2, p6*1, self.pg3)
1093 # apply the punting features
1095 self.vapi.cli("test punt pg2")
1098 # dump the punt reasons to learn the IDs assigned
1100 rs = self.vapi.punt_reason_dump(reason={'name': "reason-v4"})
1101 r4 = rs[0].reason.id
1102 rs = self.vapi.punt_reason_dump(reason={'name': "reason-v6"})
1103 r6 = rs[0].reason.id
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][r4]['packets'], NUM_PKTS)
1123 self.assertEqual(stats[0][r6]['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][r4]['packets'], 2*NUM_PKTS)
1151 self.assertEqual(stats[0][r6]['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][r4]['packets'], 3*NUM_PKTS)
1198 self.assertEqual(stats[0][r6]['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 if __name__ == '__main__':
1208 unittest.main(testRunner=VppTestRunner)