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 tag_fixme_vpp_workers
30 from framework import VppTestCase, VppTestRunner
32 from vpp_ip import DpoProto
33 from vpp_ip_route import VppIpRoute, VppRoutePath
34 from vpp_ipsec import VppIpsecSA, VppIpsecTunProtect, VppIpsecInterface
35 from vpp_papi import VppEnum
40 class serverSocketThread(threading.Thread):
41 """ Socket server thread"""
43 def __init__(self, threadID, sockName):
44 threading.Thread.__init__(self)
45 self.threadID = threadID
46 self.sockName = sockName
49 self.stop_running = False
52 # Wait for some packets on socket
55 data = self.sock.recv(65536)
57 # punt socket metadata
58 # packet_desc = data[0:8]
61 self.rx_pkts.append(Ether(data[8:]))
64 # nothing to receive, stop running or sleep a little
73 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
75 os.unlink(self.sockName)
78 self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 65536)
79 self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 65536)
80 fcntl.fcntl(self.sock, fcntl.F_SETFL, os.O_NONBLOCK)
81 self.sock.bind(self.sockName)
86 self.stop_running = True
87 threading.Thread.join(self)
92 class TestPuntSocket(VppTestCase):
95 ports = [1111, 2222, 3333, 4444]
97 # FIXME: nr_packets > 3 results in failure
98 # nr_packets = 3 makes the test unstable
103 super(TestPuntSocket, cls).setUpClass()
106 def tearDownClass(cls):
107 super(TestPuntSocket, cls).tearDownClass()
110 def setUpConstants(cls):
111 cls.extra_vpp_punt_config = [
112 "punt", "{", "socket", cls.tempdir+"/socket_punt", "}"]
113 super(TestPuntSocket, cls).setUpConstants()
116 super(TestPuntSocket, self).setUp()
119 self.create_pg_interfaces(range(2))
120 for i in self.pg_interfaces:
124 del self.sock_servers[:]
125 super(TestPuntSocket, self).tearDown()
127 def socket_client_create(self, sock_name, id=None):
128 thread = serverSocketThread(id, sock_name)
129 self.sock_servers.append(thread)
133 def socket_client_close(self):
135 for thread in self.sock_servers:
136 rx_pkts += thread.close()
139 def verify_port(self, pr, vpr):
140 self.assertEqual(vpr.punt.type, pr['type'])
141 self.assertEqual(vpr.punt.punt.l4.port,
142 pr['punt']['l4']['port'])
143 self.assertEqual(vpr.punt.punt.l4.protocol,
144 pr['punt']['l4']['protocol'])
145 self.assertEqual(vpr.punt.punt.l4.af,
146 pr['punt']['l4']['af'])
148 def verify_exception(self, pr, vpr):
149 self.assertEqual(vpr.punt.type, pr['type'])
150 self.assertEqual(vpr.punt.punt.exception.id,
151 pr['punt']['exception']['id'])
153 def verify_ip_proto(self, pr, vpr):
154 self.assertEqual(vpr.punt.type, pr['type'])
155 self.assertEqual(vpr.punt.punt.ip_proto.af,
156 pr['punt']['ip_proto']['af'])
157 self.assertEqual(vpr.punt.punt.ip_proto.protocol,
158 pr['punt']['ip_proto']['protocol'])
160 def verify_udp_pkts(self, rxs, n_rx, port):
163 self.assertTrue(rx.haslayer(UDP))
164 if rx[UDP].dport == port:
166 self.assertEqual(n_match, n_rx)
169 def set_port(pr, port):
170 pr['punt']['l4']['port'] = port
174 def set_reason(pr, reason):
175 pr['punt']['exception']['id'] = reason
180 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
181 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
182 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
188 'protocol': udp_proto
196 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
197 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
198 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
204 'protocol': udp_proto
211 class TestIP4PuntSocket(TestPuntSocket):
212 """ Punt Socket for IPv4 UDP """
216 super(TestIP4PuntSocket, cls).setUpClass()
219 def tearDownClass(cls):
220 super(TestIP4PuntSocket, cls).tearDownClass()
223 super(TestIP4PuntSocket, self).setUp()
225 for i in self.pg_interfaces:
230 super(TestIP4PuntSocket, self).tearDown()
231 for i in self.pg_interfaces:
235 def test_punt_socket_dump(self):
236 """ Punt socket registration/deregistration"""
238 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
239 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
240 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
242 punts = self.vapi.punt_socket_dump(type=pt_l4)
243 self.assertEqual(len(punts), 0)
246 # configure a punt socket
248 punt_l4 = mk_vpp_cfg4()
250 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
251 "%s/socket_punt_1111" % self.tempdir)
252 self.vapi.punt_socket_register(set_port(punt_l4, 2222),
253 "%s/socket_punt_2222" % self.tempdir)
254 punts = self.vapi.punt_socket_dump(type=pt_l4)
255 self.assertEqual(len(punts), 2)
256 self.verify_port(set_port(punt_l4, 1111), punts[0])
257 self.verify_port(set_port(punt_l4, 2222), punts[1])
260 # deregister a punt socket
262 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
263 punts = self.vapi.punt_socket_dump(type=pt_l4)
264 self.assertEqual(len(punts), 1)
267 # configure a punt socket again
269 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
270 "%s/socket_punt_1111" % self.tempdir)
271 self.vapi.punt_socket_register(set_port(punt_l4, 3333),
272 "%s/socket_punt_3333" % self.tempdir)
273 punts = self.vapi.punt_socket_dump(type=pt_l4)
274 self.assertEqual(len(punts), 3)
276 self.logger.info(self.vapi.cli("sh punt sock reg"))
279 # deregister all punt socket
281 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
282 self.vapi.punt_socket_deregister(set_port(punt_l4, 2222))
283 self.vapi.punt_socket_deregister(set_port(punt_l4, 3333))
284 punts = self.vapi.punt_socket_dump(type=pt_l4)
285 self.assertEqual(len(punts), 0)
287 def test_punt_socket_traffic_single_port_single_socket(self):
288 """ Punt socket traffic single port single socket"""
291 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
292 punt_l4 = set_port(mk_vpp_cfg4(), port)
294 p = (Ether(src=self.pg0.remote_mac,
295 dst=self.pg0.local_mac) /
296 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
297 UDP(sport=9876, dport=port) /
300 pkts = p * self.nr_packets
302 punts = self.vapi.punt_socket_dump(type=pt_l4)
303 self.assertEqual(len(punts), 0)
306 # expect ICMP - port unreachable for all packets
308 rx = self.send_and_expect_some(self.pg0, pkts, self.pg0)
311 self.assertEqual(int(p[IP].proto), 1) # ICMP
312 self.assertEqual(int(p[ICMP].code), 3) # unreachable
315 # configure a punt socket
317 self.socket_client_create("%s/socket_%d" % (self.tempdir, port))
318 self.vapi.punt_socket_register(punt_l4, "%s/socket_%d" %
319 (self.tempdir, port))
320 punts = self.vapi.punt_socket_dump(type=pt_l4)
321 self.assertEqual(len(punts), 1)
324 # expect punt socket and no packets on pg0
326 self.send_and_assert_no_replies(self.pg0, pkts)
327 rx = self.socket_client_close()
328 self.verify_udp_pkts(rx, len(pkts), port)
331 # remove punt socket. expect ICMP - port unreachable for all packets
333 self.vapi.punt_socket_deregister(punt_l4)
334 punts = self.vapi.punt_socket_dump(type=pt_l4)
335 self.assertEqual(len(punts), 0)
337 rx = self.send_and_expect_some(self.pg0, pkts, self.pg0)
339 self.assertEqual(int(p[IP].proto), 1) # ICMP
340 self.assertEqual(int(p[ICMP].code), 3) # unreachable
342 def test_punt_socket_traffic_multi_ports_multi_sockets(self):
343 """ Punt socket traffic multi ports and multi sockets"""
345 punt_l4 = mk_vpp_cfg4()
347 # configuration for each UDP port
351 # create stream of packets for each port
353 for port in self.ports:
354 # choose port from port list
357 pkt = (Ether(src=self.pg0.remote_mac,
358 dst=self.pg0.local_mac) /
359 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
360 UDP(sport=9876, dport=port) /
362 cfgs[port]['pkts'] = pkt * self.nr_packets
363 cfgs[port]['port'] = port
364 cfgs[port]['vpp'] = copy.deepcopy(set_port(punt_l4, port))
366 # configure punt sockets
367 cfgs[port]['sock'] = self.socket_client_create(
368 "%s/socket_%d" % (self.tempdir, port))
369 self.vapi.punt_socket_register(
371 "%s/socket_%d" % (self.tempdir, port))
374 # send the packets that get punted
376 for cfg in cfgs.values():
377 self.send_and_assert_no_replies(self.pg0, cfg['pkts'])
380 # test that we got the excepted packets on the expected socket
382 for cfg in cfgs.values():
383 rx = cfg['sock'].close()
384 self.verify_udp_pkts(rx, len(cfg['pkts']), cfg['port'])
385 self.vapi.punt_socket_deregister(cfg['vpp'])
387 def test_punt_socket_traffic_multi_ports_single_socket(self):
388 """ Punt socket traffic multi ports and single socket"""
390 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
391 punt_l4 = mk_vpp_cfg4()
394 # create stream of packets with each port
397 for port in self.ports:
398 # choose port from port list
399 pkt = (Ether(src=self.pg0.remote_mac,
400 dst=self.pg0.local_mac) /
401 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
402 UDP(sport=9876, dport=port) /
404 pkts += pkt * self.nr_packets
407 # configure a punt socket
409 self.socket_client_create("%s/socket_multi" % self.tempdir)
411 self.vapi.punt_socket_register(set_port(punt_l4, p),
412 "%s/socket_multi" % self.tempdir)
413 punts = self.vapi.punt_socket_dump(type=pt_l4)
414 self.assertEqual(len(punts), len(self.ports))
417 # expect punt socket and no packets on pg0
419 self.send_and_assert_no_replies(self.pg0, pkts)
420 self.logger.info(self.vapi.cli("show trace"))
421 rx = self.socket_client_close()
424 self.verify_udp_pkts(rx, self.nr_packets, p)
425 self.vapi.punt_socket_deregister(set_port(punt_l4, p))
426 punts = self.vapi.punt_socket_dump(type=pt_l4)
427 self.assertEqual(len(punts), 0)
430 class TestIP6PuntSocket(TestPuntSocket):
431 """ Punt Socket for IPv6 UDP """
435 super(TestIP6PuntSocket, cls).setUpClass()
438 def tearDownClass(cls):
439 super(TestIP6PuntSocket, cls).tearDownClass()
442 super(TestIP6PuntSocket, self).setUp()
444 for i in self.pg_interfaces:
449 super(TestIP6PuntSocket, self).tearDown()
450 for i in self.pg_interfaces:
454 def test_punt_socket_dump(self):
455 """ Punt socket registration """
457 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
458 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
459 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
461 # configure a punt socket
468 'protocol': udp_proto
473 punts = self.vapi.punt_socket_dump(type=pt_l4)
474 self.assertEqual(len(punts), 0)
477 # configure a punt socket
479 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
480 "%s/socket_1111" % self.tempdir)
481 self.vapi.punt_socket_register(set_port(punt_l4, 2222),
482 "%s/socket_2222" % self.tempdir)
483 punts = self.vapi.punt_socket_dump(type=pt_l4)
484 self.assertEqual(len(punts), 2)
485 self.verify_port(set_port(punt_l4, 1111), punts[0])
486 self.verify_port(set_port(punt_l4, 2222), punts[1])
489 # deregister a punt socket
491 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
492 punts = self.vapi.punt_socket_dump(type=pt_l4)
493 self.assertEqual(len(punts), 1)
496 # configure a punt socket again
498 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
499 "%s/socket_1111" % self.tempdir)
500 punts = self.vapi.punt_socket_dump(type=pt_l4)
501 self.assertEqual(len(punts), 2)
504 # deregister all punt socket
506 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
507 self.vapi.punt_socket_deregister(set_port(punt_l4, 2222))
508 self.vapi.punt_socket_deregister(set_port(punt_l4, 3333))
509 punts = self.vapi.punt_socket_dump(type=pt_l4)
510 self.assertEqual(len(punts), 0)
512 def test_punt_socket_traffic_single_port_single_socket(self):
513 """ Punt socket traffic single port single socket"""
516 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
517 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
518 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
524 'protocol': udp_proto,
530 p = (Ether(src=self.pg0.remote_mac,
531 dst=self.pg0.local_mac) /
532 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
533 inet6.UDP(sport=9876, dport=port) /
536 pkts = p * self.nr_packets
538 punts = self.vapi.punt_socket_dump(type=pt_l4)
539 self.assertEqual(len(punts), 0)
542 # expect ICMPv6 - destination unreachable for all packets
544 self.vapi.cli("clear trace")
545 self.pg0.add_stream(pkts)
546 self.pg_enable_capture(self.pg_interfaces)
548 # FIXME - when punt socket deregister is implemented
549 # rx = self.pg0.get_capture(self.nr_packets)
551 # self.assertEqual(int(p[IPv6].nh), 58) # ICMPv6
552 # self.assertEqual(int(p[ICMPv6DestUnreach].code),4) # unreachable
555 # configure a punt socket
557 self.socket_client_create("%s/socket_%d" % (self.tempdir, port))
558 self.vapi.punt_socket_register(punt_l4, "%s/socket_%d" %
559 (self.tempdir, port))
560 punts = self.vapi.punt_socket_dump(type=pt_l4)
561 self.assertEqual(len(punts), 1)
564 # expect punt socket and no packets on pg0
566 self.vapi.cli("clear errors")
567 self.vapi.cli("clear trace")
568 self.pg0.add_stream(pkts)
569 self.pg_enable_capture(self.pg_interfaces)
571 self.pg0.get_capture(0)
572 self.logger.info(self.vapi.cli("show trace"))
573 rx = self.socket_client_close()
574 self.verify_udp_pkts(rx, len(pkts), port)
577 # remove punt socket. expect ICMP - dest. unreachable for all packets
579 self.vapi.punt_socket_deregister(punt_l4)
580 punts = self.vapi.punt_socket_dump(type=pt_l4)
581 self.assertEqual(len(punts), 0)
582 self.pg0.add_stream(pkts)
583 self.pg_enable_capture(self.pg_interfaces)
585 # FIXME - when punt socket deregister is implemented
586 # self.pg0.get_capture(nr_packets)
588 def test_punt_socket_traffic_multi_ports_multi_sockets(self):
589 """ Punt socket traffic multi ports and multi sockets"""
591 punt_l4 = mk_vpp_cfg6()
593 # configuration for each UDP port
597 # create stream of packets for each port
599 for port in self.ports:
600 # choose port from port list
603 pkt = (Ether(src=self.pg0.remote_mac,
604 dst=self.pg0.local_mac) /
605 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
606 UDP(sport=9876, dport=port) /
608 cfgs[port]['pkts'] = pkt * self.nr_packets
609 cfgs[port]['port'] = port
610 cfgs[port]['vpp'] = copy.deepcopy(set_port(punt_l4, port))
612 # configure punt sockets
613 cfgs[port]['sock'] = self.socket_client_create(
614 "%s/socket_%d" % (self.tempdir, port))
615 self.vapi.punt_socket_register(
617 "%s/socket_%d" % (self.tempdir, port))
620 # send the packets that get punted
622 for cfg in cfgs.values():
623 self.send_and_assert_no_replies(self.pg0, cfg['pkts'])
626 # test that we got the excepted packets on the expected socket
628 for cfg in cfgs.values():
629 rx = cfg['sock'].close()
630 self.verify_udp_pkts(rx, len(cfg['pkts']), cfg['port'])
631 self.vapi.punt_socket_deregister(cfg['vpp'])
633 def test_punt_socket_traffic_multi_ports_single_socket(self):
634 """ Punt socket traffic multi ports and single socket"""
636 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
637 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
638 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
644 'protocol': udp_proto,
650 # create stream of packets with each port
653 for port in self.ports:
654 # choose port from port list
655 pkt = (Ether(src=self.pg0.remote_mac,
656 dst=self.pg0.local_mac) /
657 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
658 UDP(sport=9876, dport=port) /
660 pkts += pkt * self.nr_packets
665 punts = self.vapi.punt_socket_dump(type=pt_l4)
666 self.assertEqual(len(punts), 0)
669 # configure a punt socket
671 self.socket_client_create("%s/socket_multi" % self.tempdir)
673 self.vapi.punt_socket_register(set_port(punt_l4, p),
674 "%s/socket_multi" % self.tempdir)
675 punts = self.vapi.punt_socket_dump(type=pt_l4)
676 self.assertEqual(len(punts), len(self.ports))
679 # expect punt socket and no packets on pg0
681 self.vapi.cli("clear errors")
682 self.vapi.cli("clear trace")
683 self.pg0.add_stream(pkts)
684 self.pg_enable_capture(self.pg_interfaces)
686 # give a chance to punt socket to collect all packets
688 self.pg0.get_capture(0)
689 rx = self.socket_client_close()
692 self.verify_udp_pkts(rx, self.nr_packets, p)
693 self.vapi.punt_socket_deregister(set_port(punt_l4, p))
694 punts = self.vapi.punt_socket_dump(type=pt_l4)
695 self.assertEqual(len(punts), 0)
698 class TestExceptionPuntSocket(TestPuntSocket):
699 """ Punt Socket for Exceptions """
703 super(TestExceptionPuntSocket, cls).setUpClass()
706 def tearDownClass(cls):
707 super(TestExceptionPuntSocket, cls).tearDownClass()
710 super(TestExceptionPuntSocket, self).setUp()
712 self.create_pg_interfaces(range(2))
713 for i in self.pg_interfaces:
718 super(TestExceptionPuntSocket, self).tearDown()
719 for i in self.pg_interfaces:
723 def test_registration(self):
724 """ Punt socket registration/deregistration"""
726 pt_ex = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_EXCEPTION
728 punts = self.vapi.punt_socket_dump(type=pt_ex)
729 self.assertEqual(len(punts), 0)
732 # configure a punt socket
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, 2),
744 "%s/socket_punt_2" % self.tempdir)
745 punts = self.vapi.punt_socket_dump(type=pt_ex)
746 self.assertEqual(len(punts), 2)
747 self.verify_exception(set_reason(punt_ex, 1), punts[0])
748 self.verify_exception(set_reason(punt_ex, 2), punts[1])
751 # deregister a punt socket
753 self.vapi.punt_socket_deregister(set_reason(punt_ex, 1))
754 punts = self.vapi.punt_socket_dump(type=pt_ex)
755 self.assertEqual(len(punts), 1)
758 # configure a punt socket again
760 self.vapi.punt_socket_register(set_reason(punt_ex, 1),
761 "%s/socket_punt_1" % self.tempdir)
762 self.vapi.punt_socket_register(set_reason(punt_ex, 3),
763 "%s/socket_punt_3" % self.tempdir)
764 punts = self.vapi.punt_socket_dump(type=pt_ex)
765 self.assertEqual(len(punts), 3)
767 self.logger.info(self.vapi.cli("sh punt sock reg exception"))
770 # deregister all punt socket
772 self.vapi.punt_socket_deregister(set_reason(punt_ex, 1))
773 self.vapi.punt_socket_deregister(set_reason(punt_ex, 2))
774 self.vapi.punt_socket_deregister(set_reason(punt_ex, 3))
775 punts = self.vapi.punt_socket_dump(type=pt_ex)
776 self.assertEqual(len(punts), 0)
778 def verify_esp_pkts(self, rxs, n_sent, spi, has_udp):
779 self.assertEqual(len(rxs), n_sent)
781 self.assertTrue(rx.haslayer(IP))
782 self.assertTrue(rx.haslayer(ESP))
783 self.assertEqual(rx[ESP].spi, spi)
785 self.assertTrue(rx.haslayer(UDP))
787 def test_traffic(self):
788 """ Punt socket traffic """
791 pt_ex = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_EXCEPTION
800 # we're dealing with IPSec tunnels punting for no-such-tunnel
801 # (SPI=0 goes to ikev2)
804 cfgs['ipsec4-no-such-tunnel'] = {'spi': 99,
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 tun = VppIpsecInterface(self).add_vpp_config()
864 sa_in = VppIpsecSA(self, 11, 11,
865 (VppEnum.vl_api_ipsec_integ_alg_t.
866 IPSEC_API_INTEG_ALG_SHA1_96),
868 (VppEnum.vl_api_ipsec_crypto_alg_t.
869 IPSEC_API_CRYPTO_ALG_AES_CBC_128),
873 self.pg0.remote_ip4).add_vpp_config()
874 sa_out = VppIpsecSA(self, 22, 22,
875 (VppEnum.vl_api_ipsec_integ_alg_t.
876 IPSEC_API_INTEG_ALG_SHA1_96),
878 (VppEnum.vl_api_ipsec_crypto_alg_t.
879 IPSEC_API_CRYPTO_ALG_AES_CBC_128),
883 self.pg0.remote_ip4).add_vpp_config()
884 protect = VppIpsecTunProtect(self, tun,
886 [sa_in]).add_vpp_config()
889 # send packets for each SPI we expect to be punted
891 for cfg in cfgs.values():
892 self.send_and_assert_no_replies(cfg['itf'], cfg['pkts'])
895 # verify the punted packets arrived on the associated socket
897 for cfg in cfgs.values():
898 rx = cfg['sock'].close()
899 self.verify_esp_pkts(rx, len(cfg['pkts']),
900 cfg['spi'], cfg['udp'])
904 for cfg in cfgs.values():
905 self.vapi.punt_socket_deregister(cfg['vpp'])
908 class TestIpProtoPuntSocket(TestPuntSocket):
909 """ Punt Socket for IP packets """
913 super(TestIpProtoPuntSocket, cls).setUpClass()
916 def tearDownClass(cls):
917 super(TestIpProtoPuntSocket, cls).tearDownClass()
920 super(TestIpProtoPuntSocket, self).setUp()
922 for i in self.pg_interfaces:
927 super(TestIpProtoPuntSocket, self).tearDown()
928 for i in self.pg_interfaces:
932 def test_registration(self):
933 """ Punt socket registration/deregistration"""
935 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
936 pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
937 proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
938 proto_eigrp = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_EIGRP
940 punts = self.vapi.punt_socket_dump(type=pt_ip)
941 self.assertEqual(len(punts), 0)
944 # configure a punt socket
951 'protocol': proto_ospf
960 'protocol': proto_eigrp
965 self.vapi.punt_socket_register(punt_ospf,
966 "%s/socket_punt_1" % self.tempdir)
967 self.vapi.punt_socket_register(punt_eigrp,
968 "%s/socket_punt_2" % self.tempdir)
969 self.logger.info(self.vapi.cli("sh punt sock reg ip"))
970 punts = self.vapi.punt_socket_dump(type=pt_ip)
971 self.assertEqual(len(punts), 2)
972 self.verify_ip_proto(punt_ospf, punts[0])
973 self.verify_ip_proto(punt_eigrp, punts[1])
976 # deregister a punt socket
978 self.vapi.punt_socket_deregister(punt_ospf)
979 punts = self.vapi.punt_socket_dump(type=pt_ip)
980 self.assertEqual(len(punts), 1)
983 # configure a punt socket again
985 self.vapi.punt_socket_register(punt_ospf,
986 "%s/socket_punt_3" % self.tempdir)
987 punts = self.vapi.punt_socket_dump(type=pt_ip)
988 self.assertEqual(len(punts), 2)
990 self.logger.info(self.vapi.cli("sh punt sock reg exception"))
993 # deregister all punt socket
995 self.vapi.punt_socket_deregister(punt_eigrp)
996 self.vapi.punt_socket_deregister(punt_ospf)
997 punts = self.vapi.punt_socket_dump(type=pt_ip)
998 self.assertEqual(len(punts), 0)
1000 def verify_ospf_pkts(self, rxs, n_sent):
1001 self.assertEqual(len(rxs), n_sent)
1003 self.assertTrue(rx.haslayer(OSPF_Hdr))
1005 def test_traffic(self):
1006 """ Punt socket traffic """
1008 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
1009 pt_ip = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_IP_PROTO
1010 proto_ospf = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_OSPF
1013 # configure a punt socket to capture OSPF packets
1020 'protocol': proto_ospf
1026 # create packet streams and configure a punt sockets
1028 pkt = (Ether(src=self.pg0.remote_mac,
1029 dst=self.pg0.local_mac) /
1030 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
1035 sock = self.socket_client_create("%s/socket_1" % self.tempdir)
1036 self.vapi.punt_socket_register(
1037 punt_ospf, "%s/socket_1" % self.tempdir)
1040 # send packets for each SPI we expect to be punted
1042 self.send_and_assert_no_replies(self.pg0, pkts)
1045 # verify the punted packets arrived on the associated socket
1048 self.verify_ospf_pkts(rx, len(pkts))
1049 self.vapi.punt_socket_deregister(punt_ospf)
1052 @tag_fixme_vpp_workers
1053 class TestPunt(VppTestCase):
1054 """ Exception Punt Test Case """
1057 def setUpClass(cls):
1058 super(TestPunt, cls).setUpClass()
1061 def tearDownClass(cls):
1062 super(TestPunt, cls).tearDownClass()
1065 super(TestPunt, self).setUp()
1067 self.create_pg_interfaces(range(4))
1069 for i in self.pg_interfaces:
1077 for i in self.pg_interfaces:
1081 super(TestPunt, self).tearDown()
1083 def test_punt(self):
1084 """ Exception Path testing """
1087 # dump the punt registered reasons
1088 # search for a few we know should be there
1090 rs = self.vapi.punt_reason_dump()
1092 reasons = ["ipsec6-no-such-tunnel",
1093 "ipsec4-no-such-tunnel",
1094 "ipsec4-spi-o-udp-0"]
1096 for reason in reasons:
1099 if r.reason.name == reason:
1102 self.assertTrue(found)
1105 # Using the test CLI we will hook in a exception path to
1106 # send ACL deny packets out of pg0 and pg1.
1107 # the ACL is src,dst = 1.1.1.1,1.1.1.2
1109 ip_1_1_1_2 = VppIpRoute(self, "1.1.1.2", 32,
1110 [VppRoutePath(self.pg3.remote_ip4,
1111 self.pg3.sw_if_index)])
1112 ip_1_1_1_2.add_vpp_config()
1113 ip_1_2 = VppIpRoute(self, "1::2", 128,
1114 [VppRoutePath(self.pg3.remote_ip6,
1115 self.pg3.sw_if_index,
1116 proto=DpoProto.DPO_PROTO_IP6)])
1117 ip_1_2.add_vpp_config()
1119 p4 = (Ether(src=self.pg2.remote_mac,
1120 dst=self.pg2.local_mac) /
1121 IP(src="1.1.1.1", dst="1.1.1.2") /
1122 UDP(sport=1234, dport=1234) /
1124 p6 = (Ether(src=self.pg2.remote_mac,
1125 dst=self.pg2.local_mac) /
1126 IPv6(src="1::1", dst="1::2") /
1127 UDP(sport=1234, dport=1234) /
1129 self.send_and_expect(self.pg2, p4*1, self.pg3)
1130 self.send_and_expect(self.pg2, p6*1, self.pg3)
1133 # apply the punting features
1135 self.vapi.cli("test punt pg2")
1138 # dump the punt reasons to learn the IDs assigned
1140 rs = self.vapi.punt_reason_dump(reason={'name': "reason-v4"})
1141 r4 = rs[0].reason.id
1142 rs = self.vapi.punt_reason_dump(reason={'name': "reason-v6"})
1143 r6 = rs[0].reason.id
1148 self.send_and_assert_no_replies(self.pg2, p4*NUM_PKTS)
1149 self.send_and_assert_no_replies(self.pg2, p6*NUM_PKTS)
1153 # 1 - node error counters
1154 # 2 - per-reason counters
1155 # 2, 3 are the index of the assigned punt reason
1157 stats = self.statistics.get_err_counter(
1158 "/err/punt-dispatch/No registrations")
1159 self.assertEqual(stats, 2*NUM_PKTS)
1161 stats = self.statistics.get_counter("/net/punt")
1162 self.assertEqual(stats[0][r4]['packets'], NUM_PKTS)
1163 self.assertEqual(stats[0][r6]['packets'], NUM_PKTS)
1166 # use the test CLI to test a client that punts exception
1167 # packets out of pg0
1169 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip4)
1170 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip6)
1172 rx4s = self.send_and_expect(self.pg2, p4*NUM_PKTS, self.pg0)
1173 rx6s = self.send_and_expect(self.pg2, p6*NUM_PKTS, self.pg0)
1176 # check the packets come out IP unmodified but destined to pg0 host
1179 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1180 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1181 self.assertEqual(p4[IP].dst, rx[IP].dst)
1182 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1184 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1185 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1186 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1187 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1189 stats = self.statistics.get_counter("/net/punt")
1190 self.assertEqual(stats[0][r4]['packets'], 2*NUM_PKTS)
1191 self.assertEqual(stats[0][r6]['packets'], 2*NUM_PKTS)
1194 # add another registration for the same reason to send packets
1197 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip4)
1198 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip6)
1200 self.vapi.cli("clear trace")
1201 self.pg2.add_stream(p4 * NUM_PKTS)
1202 self.pg_enable_capture(self.pg_interfaces)
1205 rxd = self.pg0.get_capture(NUM_PKTS)
1207 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1208 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1209 self.assertEqual(p4[IP].dst, rx[IP].dst)
1210 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1211 rxd = self.pg1.get_capture(NUM_PKTS)
1213 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1214 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1215 self.assertEqual(p4[IP].dst, rx[IP].dst)
1216 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1218 self.vapi.cli("clear trace")
1219 self.pg2.add_stream(p6 * NUM_PKTS)
1220 self.pg_enable_capture(self.pg_interfaces)
1223 rxd = self.pg0.get_capture(NUM_PKTS)
1225 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1226 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1227 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1228 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1229 rxd = self.pg1.get_capture(NUM_PKTS)
1231 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1232 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1233 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1234 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1236 stats = self.statistics.get_counter("/net/punt")
1237 self.assertEqual(stats[0][r4]['packets'], 3*NUM_PKTS)
1238 self.assertEqual(stats[0][r6]['packets'], 3*NUM_PKTS)
1240 self.logger.info(self.vapi.cli("show vlib graph punt-dispatch"))
1241 self.logger.info(self.vapi.cli("show punt client"))
1242 self.logger.info(self.vapi.cli("show punt reason"))
1243 self.logger.info(self.vapi.cli("show punt stats"))
1244 self.logger.info(self.vapi.cli("show punt db"))
1247 if __name__ == '__main__':
1248 unittest.main(testRunner=VppTestRunner)