12 from struct import unpack, unpack_from
15 import unittest2 as unittest
19 from util import ppp, ppc
20 from re import compile
22 from scapy.packet import Raw
23 from scapy.layers.l2 import Ether
24 from scapy.layers.inet import IP, UDP, ICMP
25 from scapy.layers.ipsec import ESP
26 import scapy.layers.inet6 as inet6
27 from scapy.layers.inet6 import IPv6, ICMPv6DestUnreach
28 from scapy.contrib.ospf import OSPF_Hdr, OSPFv3_Hello
29 from framework import VppTestCase, VppTestRunner
31 from vpp_ip import DpoProto
32 from vpp_ip_route import VppIpRoute, VppRoutePath
33 from vpp_papi import VppEnum
34 from vpp_ipsec_tun_interface import VppIpsecTunInterface
39 class serverSocketThread(threading.Thread):
40 """ Socket server thread"""
42 def __init__(self, threadID, sockName):
43 threading.Thread.__init__(self)
44 self.threadID = threadID
45 self.sockName = sockName
48 self.keep_running = True
51 # Wait for some packets on socket
52 while self.keep_running:
54 data = self.sock.recv(65536)
56 # punt socket metadata
57 # packet_desc = data[0:8]
60 self.rx_pkts.append(Ether(data[8:]))
63 # nothing to receive, sleep a little
70 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
72 os.unlink(self.sockName)
75 self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 65536)
76 self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 65536)
77 fcntl.fcntl(self.sock, fcntl.F_SETFL, os.O_NONBLOCK)
78 self.sock.bind(self.sockName)
84 self.keep_running = False
88 class TestPuntSocket(VppTestCase):
91 ports = [1111, 2222, 3333, 4444]
93 # FIXME: nr_packets > 3 results in failure
94 # nr_packets = 3 makes the test unstable
99 super(TestPuntSocket, cls).setUpClass()
102 def tearDownClass(cls):
103 super(TestPuntSocket, cls).tearDownClass()
106 def setUpConstants(cls):
107 cls.extra_vpp_punt_config = [
108 "punt", "{", "socket", cls.tempdir+"/socket_punt", "}"]
109 super(TestPuntSocket, cls).setUpConstants()
112 super(TestPuntSocket, self).setUp()
115 self.create_pg_interfaces(range(2))
116 for i in self.pg_interfaces:
120 del self.sock_servers[:]
121 super(TestPuntSocket, self).tearDown()
123 def socket_client_create(self, sock_name, id=None):
124 thread = serverSocketThread(id, sock_name)
125 self.sock_servers.append(thread)
129 def socket_client_close(self):
131 for thread in self.sock_servers:
132 rx_pkts += thread.close()
136 def verify_port(self, pr, vpr):
137 self.assertEqual(vpr.punt.type, pr['type'])
138 self.assertEqual(vpr.punt.punt.l4.port,
139 pr['punt']['l4']['port'])
140 self.assertEqual(vpr.punt.punt.l4.protocol,
141 pr['punt']['l4']['protocol'])
142 self.assertEqual(vpr.punt.punt.l4.af,
143 pr['punt']['l4']['af'])
145 def verify_exception(self, pr, vpr):
146 self.assertEqual(vpr.punt.type, pr['type'])
147 self.assertEqual(vpr.punt.punt.exception.id,
148 pr['punt']['exception']['id'])
150 def verify_ip_proto(self, pr, vpr):
151 self.assertEqual(vpr.punt.type, pr['type'])
152 self.assertEqual(vpr.punt.punt.ip_proto.af,
153 pr['punt']['ip_proto']['af'])
154 self.assertEqual(vpr.punt.punt.ip_proto.protocol,
155 pr['punt']['ip_proto']['protocol'])
157 def verify_udp_pkts(self, rxs, n_rx, port):
160 self.assertTrue(rx.haslayer(UDP))
161 if rx[UDP].dport == port:
163 self.assertEqual(n_match, n_rx)
166 def set_port(pr, port):
167 pr['punt']['l4']['port'] = port
171 def set_reason(pr, reason):
172 pr['punt']['exception']['id'] = reason
177 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
178 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
179 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
185 'protocol': udp_proto
193 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
194 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
195 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
201 'protocol': udp_proto
208 class TestIP4PuntSocket(TestPuntSocket):
209 """ Punt Socket for IPv4 UDP """
213 super(TestIP4PuntSocket, cls).setUpClass()
216 def tearDownClass(cls):
217 super(TestIP4PuntSocket, cls).tearDownClass()
220 super(TestIP4PuntSocket, self).setUp()
222 for i in self.pg_interfaces:
227 super(TestIP4PuntSocket, self).tearDown()
228 for i in self.pg_interfaces:
232 def test_punt_socket_dump(self):
233 """ Punt socket registration/deregistration"""
235 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
236 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
237 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
239 punts = self.vapi.punt_socket_dump(type=pt_l4)
240 self.assertEqual(len(punts), 0)
243 # configure a punt socket
245 punt_l4 = mk_vpp_cfg4()
247 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
248 "%s/socket_punt_1111" % self.tempdir)
249 self.vapi.punt_socket_register(set_port(punt_l4, 2222),
250 "%s/socket_punt_2222" % self.tempdir)
251 punts = self.vapi.punt_socket_dump(type=pt_l4)
252 self.assertEqual(len(punts), 2)
253 self.verify_port(set_port(punt_l4, 1111), punts[0])
254 self.verify_port(set_port(punt_l4, 2222), punts[1])
257 # deregister a punt socket
259 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
260 punts = self.vapi.punt_socket_dump(type=pt_l4)
261 self.assertEqual(len(punts), 1)
264 # configure a punt socket again
266 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
267 "%s/socket_punt_1111" % self.tempdir)
268 self.vapi.punt_socket_register(set_port(punt_l4, 3333),
269 "%s/socket_punt_3333" % self.tempdir)
270 punts = self.vapi.punt_socket_dump(type=pt_l4)
271 self.assertEqual(len(punts), 3)
273 self.logger.info(self.vapi.cli("sh punt sock reg"))
276 # deregister all punt socket
278 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
279 self.vapi.punt_socket_deregister(set_port(punt_l4, 2222))
280 self.vapi.punt_socket_deregister(set_port(punt_l4, 3333))
281 punts = self.vapi.punt_socket_dump(type=pt_l4)
282 self.assertEqual(len(punts), 0)
284 def test_punt_socket_traffic_single_port_single_socket(self):
285 """ Punt socket traffic single port single socket"""
288 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
289 punt_l4 = set_port(mk_vpp_cfg4(), port)
291 p = (Ether(src=self.pg0.remote_mac,
292 dst=self.pg0.local_mac) /
293 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
294 UDP(sport=9876, dport=port) /
297 pkts = p * self.nr_packets
299 punts = self.vapi.punt_socket_dump(type=pt_l4)
300 self.assertEqual(len(punts), 0)
303 # expect ICMP - port unreachable for all packets
305 rx = self.send_and_expect(self.pg0, pkts, self.pg0)
308 self.assertEqual(int(p[IP].proto), 1) # ICMP
309 self.assertEqual(int(p[ICMP].code), 3) # unreachable
312 # configure a punt socket
314 self.socket_client_create("%s/socket_%d" % (self.tempdir, port))
315 self.vapi.punt_socket_register(punt_l4, "%s/socket_%d" %
316 (self.tempdir, port))
317 punts = self.vapi.punt_socket_dump(type=pt_l4)
318 self.assertEqual(len(punts), 1)
321 # expect punt socket and no packets on pg0
323 self.send_and_assert_no_replies(self.pg0, pkts)
324 rx = self.socket_client_close()
325 self.verify_udp_pkts(rx, len(pkts), port)
328 # remove punt socket. expect ICMP - port unreachable for all packets
330 self.vapi.punt_socket_deregister(punt_l4)
331 punts = self.vapi.punt_socket_dump(type=pt_l4)
332 self.assertEqual(len(punts), 0)
334 rx = self.send_and_expect(self.pg0, pkts, self.pg0)
336 self.assertEqual(int(p[IP].proto), 1) # ICMP
337 self.assertEqual(int(p[ICMP].code), 3) # unreachable
339 def test_punt_socket_traffic_multi_ports_multi_sockets(self):
340 """ Punt socket traffic multi ports and multi sockets"""
342 punt_l4 = mk_vpp_cfg4()
344 # configuration for each UDP port
348 # create stream of packets for each port
350 for port in self.ports:
351 # choose port from port list
354 pkt = (Ether(src=self.pg0.remote_mac,
355 dst=self.pg0.local_mac) /
356 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
357 UDP(sport=9876, dport=port) /
359 cfgs[port]['pkts'] = pkt * self.nr_packets
360 cfgs[port]['port'] = port
361 cfgs[port]['vpp'] = copy.deepcopy(set_port(punt_l4, port))
363 # configure punt sockets
364 cfgs[port]['sock'] = self.socket_client_create(
365 "%s/socket_%d" % (self.tempdir, port))
366 self.vapi.punt_socket_register(
368 "%s/socket_%d" % (self.tempdir, port))
371 # send the packets that get punted
373 for cfg in cfgs.values():
374 self.send_and_assert_no_replies(self.pg0, cfg['pkts'])
377 # test that we got the excepted packets on the expected socket
379 for cfg in cfgs.values():
380 rx = cfg['sock'].close()
381 self.verify_udp_pkts(rx, len(cfg['pkts']), cfg['port'])
382 self.vapi.punt_socket_deregister(cfg['vpp'])
384 def test_punt_socket_traffic_multi_ports_single_socket(self):
385 """ Punt socket traffic multi ports and single socket"""
387 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
388 punt_l4 = mk_vpp_cfg4()
391 # create stream of packets with each port
394 for port in self.ports:
395 # choose port from port list
396 pkt = (Ether(src=self.pg0.remote_mac,
397 dst=self.pg0.local_mac) /
398 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
399 UDP(sport=9876, dport=port) /
401 pkts += pkt * self.nr_packets
404 # configure a punt socket
406 self.socket_client_create("%s/socket_multi" % self.tempdir)
408 self.vapi.punt_socket_register(set_port(punt_l4, p),
409 "%s/socket_multi" % self.tempdir)
410 punts = self.vapi.punt_socket_dump(type=pt_l4)
411 self.assertEqual(len(punts), len(self.ports))
414 # expect punt socket and no packets on pg0
416 self.send_and_assert_no_replies(self.pg0, pkts)
417 self.logger.info(self.vapi.cli("show trace"))
418 rx = self.socket_client_close()
421 self.verify_udp_pkts(rx, self.nr_packets, p)
422 self.vapi.punt_socket_deregister(set_port(punt_l4, p))
423 punts = self.vapi.punt_socket_dump(type=pt_l4)
424 self.assertEqual(len(punts), 0)
427 class TestIP6PuntSocket(TestPuntSocket):
428 """ Punt Socket for IPv6 UDP """
432 super(TestIP6PuntSocket, cls).setUpClass()
435 def tearDownClass(cls):
436 super(TestIP6PuntSocket, cls).tearDownClass()
439 super(TestIP6PuntSocket, self).setUp()
441 for i in self.pg_interfaces:
446 super(TestIP6PuntSocket, self).tearDown()
447 for i in self.pg_interfaces:
451 def test_punt_socket_dump(self):
452 """ Punt socket registration """
454 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
455 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
456 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
458 # configure a punt socket
465 'protocol': udp_proto
470 punts = self.vapi.punt_socket_dump(type=pt_l4)
471 self.assertEqual(len(punts), 0)
474 # configure a punt socket
476 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
477 "%s/socket_1111" % self.tempdir)
478 self.vapi.punt_socket_register(set_port(punt_l4, 2222),
479 "%s/socket_2222" % self.tempdir)
480 punts = self.vapi.punt_socket_dump(type=pt_l4)
481 self.assertEqual(len(punts), 2)
482 self.verify_port(set_port(punt_l4, 1111), punts[0])
483 self.verify_port(set_port(punt_l4, 2222), punts[1])
486 # deregister a punt socket
488 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
489 punts = self.vapi.punt_socket_dump(type=pt_l4)
490 self.assertEqual(len(punts), 1)
493 # configure a punt socket again
495 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
496 "%s/socket_1111" % self.tempdir)
497 punts = self.vapi.punt_socket_dump(type=pt_l4)
498 self.assertEqual(len(punts), 2)
501 # deregister all punt socket
503 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
504 self.vapi.punt_socket_deregister(set_port(punt_l4, 2222))
505 self.vapi.punt_socket_deregister(set_port(punt_l4, 3333))
506 punts = self.vapi.punt_socket_dump(type=pt_l4)
507 self.assertEqual(len(punts), 0)
509 def test_punt_socket_traffic_single_port_single_socket(self):
510 """ Punt socket traffic single port single socket"""
513 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
514 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
515 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
521 'protocol': udp_proto,
527 p = (Ether(src=self.pg0.remote_mac,
528 dst=self.pg0.local_mac) /
529 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
530 inet6.UDP(sport=9876, dport=port) /
533 pkts = p * self.nr_packets
535 punts = self.vapi.punt_socket_dump(type=pt_l4)
536 self.assertEqual(len(punts), 0)
539 # expect ICMPv6 - destination unreachable for all packets
541 self.vapi.cli("clear trace")
542 self.pg0.add_stream(pkts)
543 self.pg_enable_capture(self.pg_interfaces)
545 # FIXME - when punt socket deregister is implemented
546 # rx = self.pg0.get_capture(self.nr_packets)
548 # self.assertEqual(int(p[IPv6].nh), 58) # ICMPv6
549 # self.assertEqual(int(p[ICMPv6DestUnreach].code),4) # unreachable
552 # configure a punt socket
554 self.socket_client_create("%s/socket_%d" % (self.tempdir, port))
555 self.vapi.punt_socket_register(punt_l4, "%s/socket_%d" %
556 (self.tempdir, port))
557 punts = self.vapi.punt_socket_dump(type=pt_l4)
558 self.assertEqual(len(punts), 1)
561 # expect punt socket and no packets on pg0
563 self.vapi.cli("clear errors")
564 self.vapi.cli("clear trace")
565 self.pg0.add_stream(pkts)
566 self.pg_enable_capture(self.pg_interfaces)
568 self.pg0.get_capture(0)
569 self.logger.info(self.vapi.cli("show trace"))
570 rx = self.socket_client_close()
571 self.verify_udp_pkts(rx, len(pkts), port)
574 # remove punt socket. expect ICMP - dest. unreachable for all packets
576 self.vapi.punt_socket_deregister(punt_l4)
577 punts = self.vapi.punt_socket_dump(type=pt_l4)
578 self.assertEqual(len(punts), 0)
579 self.pg0.add_stream(pkts)
580 self.pg_enable_capture(self.pg_interfaces)
582 # FIXME - when punt socket deregister is implemented
583 # self.pg0.get_capture(nr_packets)
585 def test_punt_socket_traffic_multi_ports_multi_sockets(self):
586 """ Punt socket traffic multi ports and multi sockets"""
588 punt_l4 = mk_vpp_cfg6()
590 # configuration for each UDP port
594 # create stream of packets for each port
596 for port in self.ports:
597 # choose port from port list
600 pkt = (Ether(src=self.pg0.remote_mac,
601 dst=self.pg0.local_mac) /
602 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
603 UDP(sport=9876, dport=port) /
605 cfgs[port]['pkts'] = pkt * self.nr_packets
606 cfgs[port]['port'] = port
607 cfgs[port]['vpp'] = copy.deepcopy(set_port(punt_l4, port))
609 # configure punt sockets
610 cfgs[port]['sock'] = self.socket_client_create(
611 "%s/socket_%d" % (self.tempdir, port))
612 self.vapi.punt_socket_register(
614 "%s/socket_%d" % (self.tempdir, port))
617 # send the packets that get punted
619 for cfg in cfgs.values():
620 self.send_and_assert_no_replies(self.pg0, cfg['pkts'])
623 # test that we got the excepted packets on the expected socket
625 for cfg in cfgs.values():
626 rx = cfg['sock'].close()
627 self.verify_udp_pkts(rx, len(cfg['pkts']), cfg['port'])
628 self.vapi.punt_socket_deregister(cfg['vpp'])
630 def test_punt_socket_traffic_multi_ports_single_socket(self):
631 """ Punt socket traffic multi ports and single socket"""
633 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
634 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
635 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
641 'protocol': udp_proto,
647 # create stream of packets with each port
650 for port in self.ports:
651 # choose port from port list
652 pkt = (Ether(src=self.pg0.remote_mac,
653 dst=self.pg0.local_mac) /
654 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
655 UDP(sport=9876, dport=port) /
657 pkts += pkt * self.nr_packets
662 punts = self.vapi.punt_socket_dump(type=pt_l4)
663 self.assertEqual(len(punts), 0)
666 # configure a punt socket
668 self.socket_client_create("%s/socket_multi" % self.tempdir)
670 self.vapi.punt_socket_register(set_port(punt_l4, p),
671 "%s/socket_multi" % 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 # give a chance to punt socket to collect all packets
685 self.pg0.get_capture(0)
686 rx = self.socket_client_close()
689 self.verify_udp_pkts(rx, self.nr_packets, p)
690 self.vapi.punt_socket_deregister(set_port(punt_l4, p))
691 punts = self.vapi.punt_socket_dump(type=pt_l4)
692 self.assertEqual(len(punts), 0)
695 class TestExceptionPuntSocket(TestPuntSocket):
696 """ Punt Socket for Exceptions """
700 super(TestExceptionPuntSocket, cls).setUpClass()
703 def tearDownClass(cls):
704 super(TestExceptionPuntSocket, cls).tearDownClass()
707 super(TestExceptionPuntSocket, self).setUp()
709 self.create_pg_interfaces(range(2))
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 "%s/socket_punt_1" % self.tempdir)
740 self.vapi.punt_socket_register(set_reason(punt_ex, 2),
741 "%s/socket_punt_2" % self.tempdir)
742 punts = self.vapi.punt_socket_dump(type=pt_ex)
743 self.assertEqual(len(punts), 2)
744 self.verify_exception(set_reason(punt_ex, 1), punts[0])
745 self.verify_exception(set_reason(punt_ex, 2), punts[1])
748 # deregister a punt socket
750 self.vapi.punt_socket_deregister(set_reason(punt_ex, 1))
751 punts = self.vapi.punt_socket_dump(type=pt_ex)
752 self.assertEqual(len(punts), 1)
755 # configure a punt socket again
757 self.vapi.punt_socket_register(set_reason(punt_ex, 1),
758 "%s/socket_punt_1" % self.tempdir)
759 self.vapi.punt_socket_register(set_reason(punt_ex, 3),
760 "%s/socket_punt_3" % 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're dealing with IPSec tunnels punting for no-such-tunnel
801 cfgs['ipsec4-no-such-tunnel'] = {'spi': 99,
804 cfgs['ipsec4-spi-o-udp-0'] = {'spi': 0,
809 # find the VPP ID for these punt exception reasin
811 rs = self.vapi.punt_reason_dump()
816 if r.reason.name == key:
817 cfgs[key]['id'] = r.reason.id
818 cfgs[key]['vpp'] = copy.deepcopy(
824 # configure punt sockets
826 for cfg in cfgs.values():
827 cfg['sock'] = self.socket_client_create("%s/socket_%d" %
828 (self.tempdir, cfg['id']))
829 self.vapi.punt_socket_register(
830 cfg['vpp'], "%s/socket_%d" % (self.tempdir, cfg['id']))
833 # create packet streams for 'no-such-tunnel' exception
835 for cfg in cfgs.values():
836 pkt = (Ether(src=cfg['itf'].remote_mac,
837 dst=cfg['itf'].local_mac) /
838 IP(src=cfg['itf'].remote_ip4,
839 dst=cfg['itf'].local_ip4))
841 pkt = pkt / UDP(sport=666, dport=4500)
842 pkt = (pkt / ESP(spi=cfg['spi'], seq=3) /
847 # send packets for each SPI we expect to be punted
849 for cfg in cfgs.values():
850 self.send_and_assert_no_replies(cfg['itf'], cfg['pkts'])
853 # verify the punted packets arrived on the associated socket
855 for cfg in cfgs.values():
856 rx = cfg['sock'].close()
857 self.verify_esp_pkts(rx, len(cfg['pkts']),
858 cfg['spi'], cfg['udp'])
861 # add some tunnels, make sure it still punts
863 VppIpsecTunInterface(self, self.pg0, 1000, 1000,
864 (VppEnum.vl_api_ipsec_crypto_alg_t.
865 IPSEC_API_CRYPTO_ALG_AES_CBC_128),
868 (VppEnum.vl_api_ipsec_integ_alg_t.
869 IPSEC_API_INTEG_ALG_SHA1_96),
871 b"0123456701234567").add_vpp_config()
872 VppIpsecTunInterface(self, self.pg1, 1000, 1000,
873 (VppEnum.vl_api_ipsec_crypto_alg_t.
874 IPSEC_API_CRYPTO_ALG_AES_CBC_128),
877 (VppEnum.vl_api_ipsec_integ_alg_t.
878 IPSEC_API_INTEG_ALG_SHA1_96),
881 udp_encap=True).add_vpp_config()
884 # send packets for each SPI we expect to be punted
886 for cfg in cfgs.values():
887 self.send_and_assert_no_replies(cfg['itf'], cfg['pkts'])
890 # verify the punted packets arrived on the associated socket
892 for cfg in cfgs.values():
893 rx = cfg['sock'].close()
894 self.verify_esp_pkts(rx, len(cfg['pkts']),
895 cfg['spi'], cfg['udp'])
899 for cfg in cfgs.values():
900 self.vapi.punt_socket_deregister(cfg['vpp'])
903 class TestIpProtoPuntSocket(TestPuntSocket):
904 """ Punt Socket for IP packets """
908 super(TestIpProtoPuntSocket, cls).setUpClass()
911 def tearDownClass(cls):
912 super(TestIpProtoPuntSocket, cls).tearDownClass()
915 super(TestIpProtoPuntSocket, self).setUp()
917 for i in self.pg_interfaces:
922 super(TestIpProtoPuntSocket, self).tearDown()
923 for i in self.pg_interfaces:
927 def test_registration(self):
928 """ Punt socket registration/deregistration"""
930 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
931 pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
932 proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
933 proto_eigrp = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_EIGRP
935 punts = self.vapi.punt_socket_dump(type=pt_ip)
936 self.assertEqual(len(punts), 0)
939 # configure a punt socket
946 'protocol': proto_ospf
955 'protocol': proto_eigrp
960 self.vapi.punt_socket_register(punt_ospf,
961 "%s/socket_punt_1" % self.tempdir)
962 self.vapi.punt_socket_register(punt_eigrp,
963 "%s/socket_punt_2" % self.tempdir)
964 self.logger.info(self.vapi.cli("sh punt sock reg ip"))
965 punts = self.vapi.punt_socket_dump(type=pt_ip)
966 self.assertEqual(len(punts), 2)
967 self.verify_ip_proto(punt_ospf, punts[0])
968 self.verify_ip_proto(punt_eigrp, punts[1])
971 # deregister a punt socket
973 self.vapi.punt_socket_deregister(punt_ospf)
974 punts = self.vapi.punt_socket_dump(type=pt_ip)
975 self.assertEqual(len(punts), 1)
978 # configure a punt socket again
980 self.vapi.punt_socket_register(punt_ospf,
981 "%s/socket_punt_3" % self.tempdir)
982 punts = self.vapi.punt_socket_dump(type=pt_ip)
983 self.assertEqual(len(punts), 2)
985 self.logger.info(self.vapi.cli("sh punt sock reg exception"))
988 # deregister all punt socket
990 self.vapi.punt_socket_deregister(punt_eigrp)
991 self.vapi.punt_socket_deregister(punt_ospf)
992 punts = self.vapi.punt_socket_dump(type=pt_ip)
993 self.assertEqual(len(punts), 0)
995 def verify_ospf_pkts(self, rxs, n_sent):
996 self.assertEqual(len(rxs), n_sent)
998 self.assertTrue(rx.haslayer(OSPF_Hdr))
1000 def test_traffic(self):
1001 """ Punt socket traffic """
1003 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
1004 pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
1005 proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
1008 # configure a punt socket to capture OSPF packets
1015 'protocol': proto_ospf
1021 # create packet streams and configure a punt sockets
1023 pkt = (Ether(src=self.pg0.remote_mac,
1024 dst=self.pg0.local_mac) /
1025 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
1030 sock = self.socket_client_create("%s/socket_1" % self.tempdir)
1031 self.vapi.punt_socket_register(
1032 punt_ospf, "%s/socket_1" % self.tempdir)
1035 # send packets for each SPI we expect to be punted
1037 self.send_and_assert_no_replies(self.pg0, pkts)
1040 # verify the punted packets arrived on the associated socket
1043 self.verify_ospf_pkts(rx, len(pkts))
1044 self.vapi.punt_socket_deregister(punt_ospf)
1047 class TestPunt(VppTestCase):
1048 """ Exception Punt Test Case """
1051 def setUpClass(cls):
1052 super(TestPunt, cls).setUpClass()
1055 def tearDownClass(cls):
1056 super(TestPunt, cls).tearDownClass()
1059 super(TestPunt, self).setUp()
1061 self.create_pg_interfaces(range(4))
1063 for i in self.pg_interfaces:
1071 for i in self.pg_interfaces:
1075 super(TestPunt, self).tearDown()
1077 def test_punt(self):
1078 """ Exception Path testing """
1081 # dump the punt registered reasons
1082 # search for a few we know should be there
1084 rs = self.vapi.punt_reason_dump()
1086 reasons = ["ipsec6-no-such-tunnel",
1087 "ipsec4-no-such-tunnel",
1088 "ipsec4-spi-o-udp-0"]
1090 for reason in reasons:
1093 if r.reason.name == reason:
1096 self.assertTrue(found)
1099 # Using the test CLI we will hook in a exception path to
1100 # send ACL deny packets out of pg0 and pg1.
1101 # the ACL is src,dst = 1.1.1.1,1.1.1.2
1103 ip_1_1_1_2 = VppIpRoute(self, "1.1.1.2", 32,
1104 [VppRoutePath(self.pg3.remote_ip4,
1105 self.pg3.sw_if_index)])
1106 ip_1_1_1_2.add_vpp_config()
1107 ip_1_2 = VppIpRoute(self, "1::2", 128,
1108 [VppRoutePath(self.pg3.remote_ip6,
1109 self.pg3.sw_if_index,
1110 proto=DpoProto.DPO_PROTO_IP6)])
1111 ip_1_2.add_vpp_config()
1113 p4 = (Ether(src=self.pg2.remote_mac,
1114 dst=self.pg2.local_mac) /
1115 IP(src="1.1.1.1", dst="1.1.1.2") /
1116 UDP(sport=1234, dport=1234) /
1118 p6 = (Ether(src=self.pg2.remote_mac,
1119 dst=self.pg2.local_mac) /
1120 IPv6(src="1::1", dst="1::2") /
1121 UDP(sport=1234, dport=1234) /
1123 self.send_and_expect(self.pg2, p4*1, self.pg3)
1124 self.send_and_expect(self.pg2, p6*1, self.pg3)
1127 # apply the punting features
1129 self.vapi.cli("test punt pg2")
1132 # dump the punt reasons to learn the IDs assigned
1134 rs = self.vapi.punt_reason_dump(reason={'name': "reason-v4"})
1135 r4 = rs[0].reason.id
1136 rs = self.vapi.punt_reason_dump(reason={'name': "reason-v6"})
1137 r6 = rs[0].reason.id
1142 self.send_and_assert_no_replies(self.pg2, p4*NUM_PKTS)
1143 self.send_and_assert_no_replies(self.pg2, p6*NUM_PKTS)
1147 # 1 - node error counters
1148 # 2 - per-reason counters
1149 # 2, 3 are the index of the assigned punt reason
1151 stats = self.statistics.get_err_counter(
1152 "/err/punt-dispatch/No registrations")
1153 self.assertEqual(stats, 2*NUM_PKTS)
1155 stats = self.statistics.get_counter("/net/punt")
1156 self.assertEqual(stats[0][r4]['packets'], NUM_PKTS)
1157 self.assertEqual(stats[0][r6]['packets'], NUM_PKTS)
1160 # use the test CLI to test a client that punts exception
1161 # packets out of pg0
1163 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip4)
1164 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip6)
1166 rx4s = self.send_and_expect(self.pg2, p4*NUM_PKTS, self.pg0)
1167 rx6s = self.send_and_expect(self.pg2, p6*NUM_PKTS, self.pg0)
1170 # check the packets come out IP unmodified but destined to pg0 host
1173 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1174 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1175 self.assertEqual(p4[IP].dst, rx[IP].dst)
1176 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1178 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1179 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1180 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1181 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1183 stats = self.statistics.get_counter("/net/punt")
1184 self.assertEqual(stats[0][r4]['packets'], 2*NUM_PKTS)
1185 self.assertEqual(stats[0][r6]['packets'], 2*NUM_PKTS)
1188 # add another registration for the same reason to send packets
1191 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip4)
1192 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip6)
1194 self.vapi.cli("clear trace")
1195 self.pg2.add_stream(p4 * NUM_PKTS)
1196 self.pg_enable_capture(self.pg_interfaces)
1199 rxd = self.pg0.get_capture(NUM_PKTS)
1201 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1202 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1203 self.assertEqual(p4[IP].dst, rx[IP].dst)
1204 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1205 rxd = self.pg1.get_capture(NUM_PKTS)
1207 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1208 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1209 self.assertEqual(p4[IP].dst, rx[IP].dst)
1210 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1212 self.vapi.cli("clear trace")
1213 self.pg2.add_stream(p6 * NUM_PKTS)
1214 self.pg_enable_capture(self.pg_interfaces)
1217 rxd = self.pg0.get_capture(NUM_PKTS)
1219 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1220 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1221 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1222 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1223 rxd = self.pg1.get_capture(NUM_PKTS)
1225 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1226 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1227 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1228 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1230 stats = self.statistics.get_counter("/net/punt")
1231 self.assertEqual(stats[0][r4]['packets'], 3*NUM_PKTS)
1232 self.assertEqual(stats[0][r6]['packets'], 3*NUM_PKTS)
1234 self.logger.info(self.vapi.cli("show vlib graph punt-dispatch"))
1235 self.logger.info(self.vapi.cli("show punt client"))
1236 self.logger.info(self.vapi.cli("show punt reason"))
1237 self.logger.info(self.vapi.cli("show punt stats"))
1238 self.logger.info(self.vapi.cli("show punt db"))
1241 if __name__ == '__main__':
1242 unittest.main(testRunner=VppTestRunner)