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_ipsec import VppIpsecSA, VppIpsecTunProtect, VppIpsecInterface
34 from vpp_papi import VppEnum
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
798 # (SPI=0 goes to ikev2)
801 cfgs['ipsec4-no-such-tunnel'] = {'spi': 99,
806 # find the VPP ID for these punt exception reasin
808 rs = self.vapi.punt_reason_dump()
813 if r.reason.name == key:
814 cfgs[key]['id'] = r.reason.id
815 cfgs[key]['vpp'] = copy.deepcopy(
821 # configure punt sockets
823 for cfg in cfgs.values():
824 cfg['sock'] = self.socket_client_create("%s/socket_%d" %
825 (self.tempdir, cfg['id']))
826 self.vapi.punt_socket_register(
827 cfg['vpp'], "%s/socket_%d" % (self.tempdir, cfg['id']))
830 # create packet streams for 'no-such-tunnel' exception
832 for cfg in cfgs.values():
833 pkt = (Ether(src=cfg['itf'].remote_mac,
834 dst=cfg['itf'].local_mac) /
835 IP(src=cfg['itf'].remote_ip4,
836 dst=cfg['itf'].local_ip4))
838 pkt = pkt / UDP(sport=666, dport=4500)
839 pkt = (pkt / ESP(spi=cfg['spi'], seq=3) /
844 # send packets for each SPI we expect to be punted
846 for cfg in cfgs.values():
847 self.send_and_assert_no_replies(cfg['itf'], cfg['pkts'])
850 # verify the punted packets arrived on the associated socket
852 for cfg in cfgs.values():
853 rx = cfg['sock'].close()
854 self.verify_esp_pkts(rx, len(cfg['pkts']),
855 cfg['spi'], cfg['udp'])
858 # add some tunnels, make sure it still punts
860 tun = VppIpsecInterface(self).add_vpp_config()
861 sa_in = VppIpsecSA(self, 11, 11,
862 (VppEnum.vl_api_ipsec_integ_alg_t.
863 IPSEC_API_INTEG_ALG_SHA1_96),
865 (VppEnum.vl_api_ipsec_crypto_alg_t.
866 IPSEC_API_CRYPTO_ALG_AES_CBC_128),
870 self.pg0.remote_ip4).add_vpp_config()
871 sa_out = VppIpsecSA(self, 22, 22,
872 (VppEnum.vl_api_ipsec_integ_alg_t.
873 IPSEC_API_INTEG_ALG_SHA1_96),
875 (VppEnum.vl_api_ipsec_crypto_alg_t.
876 IPSEC_API_CRYPTO_ALG_AES_CBC_128),
880 self.pg0.remote_ip4).add_vpp_config()
881 protect = VppIpsecTunProtect(self, tun,
883 [sa_in]).add_vpp_config()
886 # send packets for each SPI we expect to be punted
888 for cfg in cfgs.values():
889 self.send_and_assert_no_replies(cfg['itf'], cfg['pkts'])
892 # verify the punted packets arrived on the associated socket
894 for cfg in cfgs.values():
895 rx = cfg['sock'].close()
896 self.verify_esp_pkts(rx, len(cfg['pkts']),
897 cfg['spi'], cfg['udp'])
901 for cfg in cfgs.values():
902 self.vapi.punt_socket_deregister(cfg['vpp'])
905 class TestIpProtoPuntSocket(TestPuntSocket):
906 """ Punt Socket for IP packets """
910 super(TestIpProtoPuntSocket, cls).setUpClass()
913 def tearDownClass(cls):
914 super(TestIpProtoPuntSocket, cls).tearDownClass()
917 super(TestIpProtoPuntSocket, self).setUp()
919 for i in self.pg_interfaces:
924 super(TestIpProtoPuntSocket, self).tearDown()
925 for i in self.pg_interfaces:
929 def test_registration(self):
930 """ Punt socket registration/deregistration"""
932 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
933 pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
934 proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
935 proto_eigrp = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_EIGRP
937 punts = self.vapi.punt_socket_dump(type=pt_ip)
938 self.assertEqual(len(punts), 0)
941 # configure a punt socket
948 'protocol': proto_ospf
957 'protocol': proto_eigrp
962 self.vapi.punt_socket_register(punt_ospf,
963 "%s/socket_punt_1" % self.tempdir)
964 self.vapi.punt_socket_register(punt_eigrp,
965 "%s/socket_punt_2" % self.tempdir)
966 self.logger.info(self.vapi.cli("sh punt sock reg ip"))
967 punts = self.vapi.punt_socket_dump(type=pt_ip)
968 self.assertEqual(len(punts), 2)
969 self.verify_ip_proto(punt_ospf, punts[0])
970 self.verify_ip_proto(punt_eigrp, punts[1])
973 # deregister a punt socket
975 self.vapi.punt_socket_deregister(punt_ospf)
976 punts = self.vapi.punt_socket_dump(type=pt_ip)
977 self.assertEqual(len(punts), 1)
980 # configure a punt socket again
982 self.vapi.punt_socket_register(punt_ospf,
983 "%s/socket_punt_3" % self.tempdir)
984 punts = self.vapi.punt_socket_dump(type=pt_ip)
985 self.assertEqual(len(punts), 2)
987 self.logger.info(self.vapi.cli("sh punt sock reg exception"))
990 # deregister all punt socket
992 self.vapi.punt_socket_deregister(punt_eigrp)
993 self.vapi.punt_socket_deregister(punt_ospf)
994 punts = self.vapi.punt_socket_dump(type=pt_ip)
995 self.assertEqual(len(punts), 0)
997 def verify_ospf_pkts(self, rxs, n_sent):
998 self.assertEqual(len(rxs), n_sent)
1000 self.assertTrue(rx.haslayer(OSPF_Hdr))
1002 def test_traffic(self):
1003 """ Punt socket traffic """
1005 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
1006 pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
1007 proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
1010 # configure a punt socket to capture OSPF packets
1017 'protocol': proto_ospf
1023 # create packet streams and configure a punt sockets
1025 pkt = (Ether(src=self.pg0.remote_mac,
1026 dst=self.pg0.local_mac) /
1027 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
1032 sock = self.socket_client_create("%s/socket_1" % self.tempdir)
1033 self.vapi.punt_socket_register(
1034 punt_ospf, "%s/socket_1" % self.tempdir)
1037 # send packets for each SPI we expect to be punted
1039 self.send_and_assert_no_replies(self.pg0, pkts)
1042 # verify the punted packets arrived on the associated socket
1045 self.verify_ospf_pkts(rx, len(pkts))
1046 self.vapi.punt_socket_deregister(punt_ospf)
1049 class TestPunt(VppTestCase):
1050 """ Exception Punt Test Case """
1053 def setUpClass(cls):
1054 super(TestPunt, cls).setUpClass()
1057 def tearDownClass(cls):
1058 super(TestPunt, cls).tearDownClass()
1061 super(TestPunt, self).setUp()
1063 self.create_pg_interfaces(range(4))
1065 for i in self.pg_interfaces:
1073 for i in self.pg_interfaces:
1077 super(TestPunt, self).tearDown()
1079 def test_punt(self):
1080 """ Exception Path testing """
1083 # dump the punt registered reasons
1084 # search for a few we know should be there
1086 rs = self.vapi.punt_reason_dump()
1088 reasons = ["ipsec6-no-such-tunnel",
1089 "ipsec4-no-such-tunnel",
1090 "ipsec4-spi-o-udp-0"]
1092 for reason in reasons:
1095 if r.reason.name == reason:
1098 self.assertTrue(found)
1101 # Using the test CLI we will hook in a exception path to
1102 # send ACL deny packets out of pg0 and pg1.
1103 # the ACL is src,dst = 1.1.1.1,1.1.1.2
1105 ip_1_1_1_2 = VppIpRoute(self, "1.1.1.2", 32,
1106 [VppRoutePath(self.pg3.remote_ip4,
1107 self.pg3.sw_if_index)])
1108 ip_1_1_1_2.add_vpp_config()
1109 ip_1_2 = VppIpRoute(self, "1::2", 128,
1110 [VppRoutePath(self.pg3.remote_ip6,
1111 self.pg3.sw_if_index,
1112 proto=DpoProto.DPO_PROTO_IP6)])
1113 ip_1_2.add_vpp_config()
1115 p4 = (Ether(src=self.pg2.remote_mac,
1116 dst=self.pg2.local_mac) /
1117 IP(src="1.1.1.1", dst="1.1.1.2") /
1118 UDP(sport=1234, dport=1234) /
1120 p6 = (Ether(src=self.pg2.remote_mac,
1121 dst=self.pg2.local_mac) /
1122 IPv6(src="1::1", dst="1::2") /
1123 UDP(sport=1234, dport=1234) /
1125 self.send_and_expect(self.pg2, p4*1, self.pg3)
1126 self.send_and_expect(self.pg2, p6*1, self.pg3)
1129 # apply the punting features
1131 self.vapi.cli("test punt pg2")
1134 # dump the punt reasons to learn the IDs assigned
1136 rs = self.vapi.punt_reason_dump(reason={'name': "reason-v4"})
1137 r4 = rs[0].reason.id
1138 rs = self.vapi.punt_reason_dump(reason={'name': "reason-v6"})
1139 r6 = rs[0].reason.id
1144 self.send_and_assert_no_replies(self.pg2, p4*NUM_PKTS)
1145 self.send_and_assert_no_replies(self.pg2, p6*NUM_PKTS)
1149 # 1 - node error counters
1150 # 2 - per-reason counters
1151 # 2, 3 are the index of the assigned punt reason
1153 stats = self.statistics.get_err_counter(
1154 "/err/punt-dispatch/No registrations")
1155 self.assertEqual(stats, 2*NUM_PKTS)
1157 stats = self.statistics.get_counter("/net/punt")
1158 self.assertEqual(stats[0][r4]['packets'], NUM_PKTS)
1159 self.assertEqual(stats[0][r6]['packets'], NUM_PKTS)
1162 # use the test CLI to test a client that punts exception
1163 # packets out of pg0
1165 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip4)
1166 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip6)
1168 rx4s = self.send_and_expect(self.pg2, p4*NUM_PKTS, self.pg0)
1169 rx6s = self.send_and_expect(self.pg2, p6*NUM_PKTS, self.pg0)
1172 # check the packets come out IP unmodified but destined to pg0 host
1175 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1176 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1177 self.assertEqual(p4[IP].dst, rx[IP].dst)
1178 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1180 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1181 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1182 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1183 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1185 stats = self.statistics.get_counter("/net/punt")
1186 self.assertEqual(stats[0][r4]['packets'], 2*NUM_PKTS)
1187 self.assertEqual(stats[0][r6]['packets'], 2*NUM_PKTS)
1190 # add another registration for the same reason to send packets
1193 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip4)
1194 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip6)
1196 self.vapi.cli("clear trace")
1197 self.pg2.add_stream(p4 * NUM_PKTS)
1198 self.pg_enable_capture(self.pg_interfaces)
1201 rxd = self.pg0.get_capture(NUM_PKTS)
1203 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1204 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1205 self.assertEqual(p4[IP].dst, rx[IP].dst)
1206 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1207 rxd = self.pg1.get_capture(NUM_PKTS)
1209 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1210 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1211 self.assertEqual(p4[IP].dst, rx[IP].dst)
1212 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1214 self.vapi.cli("clear trace")
1215 self.pg2.add_stream(p6 * NUM_PKTS)
1216 self.pg_enable_capture(self.pg_interfaces)
1219 rxd = self.pg0.get_capture(NUM_PKTS)
1221 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1222 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1223 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1224 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1225 rxd = self.pg1.get_capture(NUM_PKTS)
1227 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1228 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1229 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1230 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1232 stats = self.statistics.get_counter("/net/punt")
1233 self.assertEqual(stats[0][r4]['packets'], 3*NUM_PKTS)
1234 self.assertEqual(stats[0][r6]['packets'], 3*NUM_PKTS)
1236 self.logger.info(self.vapi.cli("show vlib graph punt-dispatch"))
1237 self.logger.info(self.vapi.cli("show punt client"))
1238 self.logger.info(self.vapi.cli("show punt reason"))
1239 self.logger.info(self.vapi.cli("show punt stats"))
1240 self.logger.info(self.vapi.cli("show punt db"))
1243 if __name__ == '__main__':
1244 unittest.main(testRunner=VppTestRunner)