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
30 from framework import VppTestCase, VppTestRunner
32 from vpp_ip import DpoProto
33 from vpp_ip_route import VppIpRoute, VppRoutePath
34 from vpp_papi import VppEnum
35 from vpp_ipsec_tun_interface import VppIpsecTunInterface
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.keep_running = True
52 # Wait for some packets on socket
53 while self.keep_running:
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, sleep a little
71 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
73 os.unlink(self.sockName)
76 self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 65536)
77 self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 65536)
78 fcntl.fcntl(self.sock, fcntl.F_SETFL, os.O_NONBLOCK)
79 self.sock.bind(self.sockName)
85 self.keep_running = False
89 class TestPuntSocket(VppTestCase):
92 ports = [1111, 2222, 3333, 4444]
94 # FIXME: nr_packets > 3 results in failure
95 # nr_packets = 3 makes the test unstable
100 super(TestPuntSocket, cls).setUpClass()
103 def tearDownClass(cls):
104 super(TestPuntSocket, cls).tearDownClass()
107 def setUpConstants(cls):
108 cls.extra_vpp_punt_config = [
109 "punt", "{", "socket", cls.tempdir+"/socket_punt", "}"]
110 super(TestPuntSocket, cls).setUpConstants()
113 super(TestPuntSocket, self).setUp()
116 self.create_pg_interfaces(range(2))
117 for i in self.pg_interfaces:
121 del self.sock_servers[:]
122 super(TestPuntSocket, self).tearDown()
124 def socket_client_create(self, sock_name, id=None):
125 thread = serverSocketThread(id, sock_name)
126 self.sock_servers.append(thread)
130 def socket_client_close(self):
132 for thread in self.sock_servers:
133 rx_pkts += thread.close()
137 def verify_port(self, pr, vpr):
138 self.assertEqual(vpr.punt.type, pr['type'])
139 self.assertEqual(vpr.punt.punt.l4.port,
140 pr['punt']['l4']['port'])
141 self.assertEqual(vpr.punt.punt.l4.protocol,
142 pr['punt']['l4']['protocol'])
143 self.assertEqual(vpr.punt.punt.l4.af,
144 pr['punt']['l4']['af'])
146 def verify_exception(self, pr, vpr):
147 self.assertEqual(vpr.punt.type, pr['type'])
148 self.assertEqual(vpr.punt.punt.exception.id,
149 pr['punt']['exception']['id'])
151 def verify_ip_proto(self, pr, vpr):
152 self.assertEqual(vpr.punt.type, pr['type'])
153 self.assertEqual(vpr.punt.punt.ip_proto.af,
154 pr['punt']['ip_proto']['af'])
155 self.assertEqual(vpr.punt.punt.ip_proto.protocol,
156 pr['punt']['ip_proto']['protocol'])
158 def verify_udp_pkts(self, rxs, n_rx, port):
161 self.assertTrue(rx.haslayer(UDP))
162 if rx[UDP].dport == port:
164 self.assertEqual(n_match, n_rx)
167 def set_port(pr, port):
168 pr['punt']['l4']['port'] = port
172 def set_reason(pr, reason):
173 pr['punt']['exception']['id'] = reason
178 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
179 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
180 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
186 'protocol': udp_proto
194 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
195 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
196 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
202 'protocol': udp_proto
209 class TestIP4PuntSocket(TestPuntSocket):
210 """ Punt Socket for IPv4 UDP """
214 super(TestIP4PuntSocket, cls).setUpClass()
217 def tearDownClass(cls):
218 super(TestIP4PuntSocket, cls).tearDownClass()
221 super(TestIP4PuntSocket, self).setUp()
223 for i in self.pg_interfaces:
228 super(TestIP4PuntSocket, self).tearDown()
229 for i in self.pg_interfaces:
233 def test_punt_socket_dump(self):
234 """ Punt socket registration/deregistration"""
236 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
237 af_ip4 = VppEnum.vl_api_address_family_t.ADDRESS_IP4
238 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
240 punts = self.vapi.punt_socket_dump(type=pt_l4)
241 self.assertEqual(len(punts), 0)
244 # configure a punt socket
246 punt_l4 = mk_vpp_cfg4()
248 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
249 b"%s/socket_punt_1111" %
250 six.ensure_binary(self.tempdir))
251 self.vapi.punt_socket_register(set_port(punt_l4, 2222),
252 b"%s/socket_punt_2222" %
253 six.ensure_binary(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 b"%s/socket_punt_1111" %
271 six.ensure_binary(self.tempdir))
272 self.vapi.punt_socket_register(set_port(punt_l4, 3333),
273 b"%s/socket_punt_3333" %
274 six.ensure_binary(self.tempdir))
275 punts = self.vapi.punt_socket_dump(type=pt_l4)
276 self.assertEqual(len(punts), 3)
278 self.logger.info(self.vapi.cli("sh punt sock reg"))
281 # deregister all punt socket
283 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
284 self.vapi.punt_socket_deregister(set_port(punt_l4, 2222))
285 self.vapi.punt_socket_deregister(set_port(punt_l4, 3333))
286 punts = self.vapi.punt_socket_dump(type=pt_l4)
287 self.assertEqual(len(punts), 0)
289 def test_punt_socket_traffic_single_port_single_socket(self):
290 """ Punt socket traffic single port single socket"""
293 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
294 punt_l4 = set_port(mk_vpp_cfg4(), port)
296 p = (Ether(src=self.pg0.remote_mac,
297 dst=self.pg0.local_mac) /
298 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
299 UDP(sport=9876, dport=port) /
302 pkts = p * self.nr_packets
304 punts = self.vapi.punt_socket_dump(type=pt_l4)
305 self.assertEqual(len(punts), 0)
308 # expect ICMP - port unreachable for all packets
310 rx = self.send_and_expect(self.pg0, pkts, self.pg0)
313 self.assertEqual(int(p[IP].proto), 1) # ICMP
314 self.assertEqual(int(p[ICMP].code), 3) # unreachable
317 # configure a punt socket
319 self.socket_client_create(b"%s/socket_%d" % (
320 six.ensure_binary(self.tempdir), port))
321 self.vapi.punt_socket_register(punt_l4, b"%s/socket_%d" % (
322 six.ensure_binary(self.tempdir), port))
323 punts = self.vapi.punt_socket_dump(type=pt_l4)
324 self.assertEqual(len(punts), 1)
327 # expect punt socket and no packets on pg0
329 self.send_and_assert_no_replies(self.pg0, pkts)
330 rx = self.socket_client_close()
331 self.verify_udp_pkts(rx, len(pkts), port)
334 # remove punt socket. expect ICMP - port unreachable for all packets
336 self.vapi.punt_socket_deregister(punt_l4)
337 punts = self.vapi.punt_socket_dump(type=pt_l4)
338 self.assertEqual(len(punts), 0)
340 rx = self.send_and_expect(self.pg0, pkts, self.pg0)
342 self.assertEqual(int(p[IP].proto), 1) # ICMP
343 self.assertEqual(int(p[ICMP].code), 3) # unreachable
345 def test_punt_socket_traffic_multi_ports_multi_sockets(self):
346 """ Punt socket traffic multi ports and multi sockets"""
348 punt_l4 = mk_vpp_cfg4()
350 # configuration for each UDP port
354 # create stream of packets for each port
356 for port in self.ports:
357 # choose port from port list
360 pkt = (Ether(src=self.pg0.remote_mac,
361 dst=self.pg0.local_mac) /
362 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
363 UDP(sport=9876, dport=port) /
365 cfgs[port]['pkts'] = pkt * self.nr_packets
366 cfgs[port]['port'] = port
367 cfgs[port]['vpp'] = copy.deepcopy(set_port(punt_l4, port))
369 # configure punt sockets
370 cfgs[port]['sock'] = self.socket_client_create(
371 b"%s/socket_%d" % (six.ensure_binary(self.tempdir), port))
372 self.vapi.punt_socket_register(
374 b"%s/socket_%d" % (six.ensure_binary(self.tempdir),
378 # send the packets that get punted
380 for cfg in cfgs.values():
381 self.send_and_assert_no_replies(self.pg0, cfg['pkts'])
384 # test that we got the excepted packets on the expected socket
386 for cfg in cfgs.values():
387 rx = cfg['sock'].close()
388 self.verify_udp_pkts(rx, len(cfg['pkts']), cfg['port'])
389 self.vapi.punt_socket_deregister(cfg['vpp'])
391 def test_punt_socket_traffic_multi_ports_single_socket(self):
392 """ Punt socket traffic multi ports and single socket"""
394 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
395 punt_l4 = mk_vpp_cfg4()
398 # create stream of packets with each port
401 for port in self.ports:
402 # choose port from port list
403 pkt = (Ether(src=self.pg0.remote_mac,
404 dst=self.pg0.local_mac) /
405 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4) /
406 UDP(sport=9876, dport=port) /
408 pkts += pkt * self.nr_packets
411 # configure a punt socket
413 self.socket_client_create(b"%s/socket_multi" %
414 six.ensure_binary(self.tempdir))
416 self.vapi.punt_socket_register(set_port(punt_l4, p),
418 six.ensure_binary(self.tempdir))
419 punts = self.vapi.punt_socket_dump(type=pt_l4)
420 self.assertEqual(len(punts), len(self.ports))
423 # expect punt socket and no packets on pg0
425 self.send_and_assert_no_replies(self.pg0, pkts)
426 self.logger.info(self.vapi.cli("show trace"))
427 rx = self.socket_client_close()
430 self.verify_udp_pkts(rx, self.nr_packets, p)
431 self.vapi.punt_socket_deregister(set_port(punt_l4, p))
432 punts = self.vapi.punt_socket_dump(type=pt_l4)
433 self.assertEqual(len(punts), 0)
436 class TestIP6PuntSocket(TestPuntSocket):
437 """ Punt Socket for IPv6 UDP """
441 super(TestIP6PuntSocket, cls).setUpClass()
444 def tearDownClass(cls):
445 super(TestIP6PuntSocket, cls).tearDownClass()
448 super(TestIP6PuntSocket, self).setUp()
450 for i in self.pg_interfaces:
455 super(TestIP6PuntSocket, self).tearDown()
456 for i in self.pg_interfaces:
460 def test_punt_socket_dump(self):
461 """ Punt socket registration """
463 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
464 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
465 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
467 # configure a punt socket
474 'protocol': udp_proto
479 punts = self.vapi.punt_socket_dump(type=pt_l4)
480 self.assertEqual(len(punts), 0)
483 # configure a punt socket
485 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
487 six.ensure_binary(self.tempdir))
488 self.vapi.punt_socket_register(set_port(punt_l4, 2222),
490 six.ensure_binary(self.tempdir))
491 punts = self.vapi.punt_socket_dump(type=pt_l4)
492 self.assertEqual(len(punts), 2)
493 self.verify_port(set_port(punt_l4, 1111), punts[0])
494 self.verify_port(set_port(punt_l4, 2222), punts[1])
497 # deregister a punt socket
499 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
500 punts = self.vapi.punt_socket_dump(type=pt_l4)
501 self.assertEqual(len(punts), 1)
504 # configure a punt socket again
506 self.vapi.punt_socket_register(set_port(punt_l4, 1111),
508 six.ensure_binary(self.tempdir))
509 punts = self.vapi.punt_socket_dump(type=pt_l4)
510 self.assertEqual(len(punts), 2)
513 # deregister all punt socket
515 self.vapi.punt_socket_deregister(set_port(punt_l4, 1111))
516 self.vapi.punt_socket_deregister(set_port(punt_l4, 2222))
517 self.vapi.punt_socket_deregister(set_port(punt_l4, 3333))
518 punts = self.vapi.punt_socket_dump(type=pt_l4)
519 self.assertEqual(len(punts), 0)
521 def test_punt_socket_traffic_single_port_single_socket(self):
522 """ Punt socket traffic single port single socket"""
525 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
526 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
527 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
533 'protocol': udp_proto,
539 p = (Ether(src=self.pg0.remote_mac,
540 dst=self.pg0.local_mac) /
541 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
542 inet6.UDP(sport=9876, dport=port) /
545 pkts = p * self.nr_packets
547 punts = self.vapi.punt_socket_dump(type=pt_l4)
548 self.assertEqual(len(punts), 0)
551 # expect ICMPv6 - destination unreachable for all packets
553 self.vapi.cli("clear trace")
554 self.pg0.add_stream(pkts)
555 self.pg_enable_capture(self.pg_interfaces)
557 # FIXME - when punt socket deregister is implemented
558 # rx = self.pg0.get_capture(self.nr_packets)
560 # self.assertEqual(int(p[IPv6].nh), 58) # ICMPv6
561 # self.assertEqual(int(p[ICMPv6DestUnreach].code),4) # unreachable
564 # configure a punt socket
566 self.socket_client_create(b"%s/socket_%d" % (
567 six.ensure_binary(self.tempdir), port))
568 self.vapi.punt_socket_register(punt_l4, b"%s/socket_%d" % (
569 six.ensure_binary(self.tempdir), port))
570 punts = self.vapi.punt_socket_dump(type=pt_l4)
571 self.assertEqual(len(punts), 1)
574 # expect punt socket and no packets on pg0
576 self.vapi.cli("clear errors")
577 self.vapi.cli("clear trace")
578 self.pg0.add_stream(pkts)
579 self.pg_enable_capture(self.pg_interfaces)
581 self.pg0.get_capture(0)
582 self.logger.info(self.vapi.cli("show trace"))
583 rx = self.socket_client_close()
584 self.verify_udp_pkts(rx, len(pkts), port)
587 # remove punt socket. expect ICMP - dest. unreachable for all packets
589 self.vapi.punt_socket_deregister(punt_l4)
590 punts = self.vapi.punt_socket_dump(type=pt_l4)
591 self.assertEqual(len(punts), 0)
592 self.pg0.add_stream(pkts)
593 self.pg_enable_capture(self.pg_interfaces)
595 # FIXME - when punt socket deregister is implemented
596 # self.pg0.get_capture(nr_packets)
598 def test_punt_socket_traffic_multi_ports_multi_sockets(self):
599 """ Punt socket traffic multi ports and multi sockets"""
601 punt_l4 = mk_vpp_cfg6()
603 # configuration for each UDP port
607 # create stream of packets for each port
609 for port in self.ports:
610 # choose port from port list
613 pkt = (Ether(src=self.pg0.remote_mac,
614 dst=self.pg0.local_mac) /
615 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
616 UDP(sport=9876, dport=port) /
618 cfgs[port]['pkts'] = pkt * self.nr_packets
619 cfgs[port]['port'] = port
620 cfgs[port]['vpp'] = copy.deepcopy(set_port(punt_l4, port))
622 # configure punt sockets
623 cfgs[port]['sock'] = self.socket_client_create(
624 b"%s/socket_%d" % (six.ensure_binary(self.tempdir), port))
625 self.vapi.punt_socket_register(
627 b"%s/socket_%d" % (six.ensure_binary(self.tempdir),
631 # send the packets that get punted
633 for cfg in cfgs.values():
634 self.send_and_assert_no_replies(self.pg0, cfg['pkts'])
637 # test that we got the excepted packets on the expected socket
639 for cfg in cfgs.values():
640 rx = cfg['sock'].close()
641 self.verify_udp_pkts(rx, len(cfg['pkts']), cfg['port'])
642 self.vapi.punt_socket_deregister(cfg['vpp'])
644 def test_punt_socket_traffic_multi_ports_single_socket(self):
645 """ Punt socket traffic multi ports and single socket"""
647 pt_l4 = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_L4
648 af_ip6 = VppEnum.vl_api_address_family_t.ADDRESS_IP6
649 udp_proto = VppEnum.vl_api_ip_proto_t.IP_API_PROTO_UDP
655 'protocol': udp_proto,
661 # create stream of packets with each port
664 for port in self.ports:
665 # choose port from port list
666 pkt = (Ether(src=self.pg0.remote_mac,
667 dst=self.pg0.local_mac) /
668 IPv6(src=self.pg0.remote_ip6, dst=self.pg0.local_ip6) /
669 UDP(sport=9876, dport=port) /
671 pkts += pkt * self.nr_packets
676 punts = self.vapi.punt_socket_dump(type=pt_l4)
677 self.assertEqual(len(punts), 0)
680 # configure a punt socket
682 self.socket_client_create(b"%s/socket_multi" %
683 six.ensure_binary(self.tempdir))
685 self.vapi.punt_socket_register(set_port(punt_l4, p),
687 six.ensure_binary(self.tempdir))
688 punts = self.vapi.punt_socket_dump(type=pt_l4)
689 self.assertEqual(len(punts), len(self.ports))
692 # expect punt socket and no packets on pg0
694 self.vapi.cli("clear errors")
695 self.vapi.cli("clear trace")
696 self.pg0.add_stream(pkts)
697 self.pg_enable_capture(self.pg_interfaces)
699 # give a chance to punt socket to collect all packets
701 self.pg0.get_capture(0)
702 rx = self.socket_client_close()
705 self.verify_udp_pkts(rx, self.nr_packets, p)
706 self.vapi.punt_socket_deregister(set_port(punt_l4, p))
707 punts = self.vapi.punt_socket_dump(type=pt_l4)
708 self.assertEqual(len(punts), 0)
711 class TestExceptionPuntSocket(TestPuntSocket):
712 """ Punt Socket for Exceptions """
716 super(TestExceptionPuntSocket, cls).setUpClass()
719 def tearDownClass(cls):
720 super(TestExceptionPuntSocket, cls).tearDownClass()
723 super(TestExceptionPuntSocket, self).setUp()
725 for i in self.pg_interfaces:
730 super(TestExceptionPuntSocket, self).tearDown()
731 for i in self.pg_interfaces:
735 def test_registration(self):
736 """ Punt socket registration/deregistration"""
738 pt_ex = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_EXCEPTION
740 punts = self.vapi.punt_socket_dump(type=pt_ex)
741 self.assertEqual(len(punts), 0)
744 # configure a punt socket
753 self.vapi.punt_socket_register(set_reason(punt_ex, 1),
754 b"%s/socket_punt_1" %
755 six.ensure_binary(self.tempdir))
756 self.vapi.punt_socket_register(set_reason(punt_ex, 2),
757 b"%s/socket_punt_2" %
758 six.ensure_binary(self.tempdir))
759 punts = self.vapi.punt_socket_dump(type=pt_ex)
760 self.assertEqual(len(punts), 2)
761 self.verify_exception(set_reason(punt_ex, 1), punts[0])
762 self.verify_exception(set_reason(punt_ex, 2), punts[1])
765 # deregister a punt socket
767 self.vapi.punt_socket_deregister(set_reason(punt_ex, 1))
768 punts = self.vapi.punt_socket_dump(type=pt_ex)
769 self.assertEqual(len(punts), 1)
772 # configure a punt socket again
774 self.vapi.punt_socket_register(set_reason(punt_ex, 1),
775 b"%s/socket_punt_1" %
776 six.ensure_binary(self.tempdir))
777 self.vapi.punt_socket_register(set_reason(punt_ex, 3),
778 b"%s/socket_punt_3" %
779 six.ensure_binary(self.tempdir))
780 punts = self.vapi.punt_socket_dump(type=pt_ex)
781 self.assertEqual(len(punts), 3)
783 self.logger.info(self.vapi.cli("sh punt sock reg exception"))
786 # deregister all punt socket
788 self.vapi.punt_socket_deregister(set_reason(punt_ex, 1))
789 self.vapi.punt_socket_deregister(set_reason(punt_ex, 2))
790 self.vapi.punt_socket_deregister(set_reason(punt_ex, 3))
791 punts = self.vapi.punt_socket_dump(type=pt_ex)
792 self.assertEqual(len(punts), 0)
794 def verify_esp_pkts(self, rxs, n_sent, spi, has_udp):
795 self.assertEqual(len(rxs), n_sent)
797 self.assertTrue(rx.haslayer(IP))
798 self.assertTrue(rx.haslayer(ESP))
799 self.assertEqual(rx[ESP].spi, spi)
801 self.assertTrue(rx.haslayer(UDP))
803 def test_traffic(self):
804 """ Punt socket traffic """
807 pt_ex = VppEnum.vl_api_punt_type_t.PUNT_API_TYPE_EXCEPTION
816 # we need an IPSec tunnels for this to work otherwise ESP gets dropped
817 # due to unknown IP proto
819 VppIpsecTunInterface(self, self.pg0, 1000, 1000,
820 (VppEnum.vl_api_ipsec_crypto_alg_t.
821 IPSEC_API_CRYPTO_ALG_AES_CBC_128),
824 (VppEnum.vl_api_ipsec_integ_alg_t.
825 IPSEC_API_INTEG_ALG_SHA1_96),
827 "0123456701234567").add_vpp_config()
828 VppIpsecTunInterface(self, self.pg0, 1001, 1001,
829 (VppEnum.vl_api_ipsec_crypto_alg_t.
830 IPSEC_API_CRYPTO_ALG_AES_CBC_128),
833 (VppEnum.vl_api_ipsec_integ_alg_t.
834 IPSEC_API_INTEG_ALG_SHA1_96),
837 udp_encap=True).add_vpp_config()
840 # we're dealing with IPSec tunnels punting for no-such-tunnel
844 cfgs['ipsec4-no-such-tunnel'] = {'spi': 99, 'udp': False}
845 cfgs['ipsec4-spi-o-udp-0'] = {'spi': 0, 'udp': True}
848 # find the VPP ID for these punt exception reasin
850 rs = self.vapi.punt_reason_dump()
853 if r.reason.name == key:
854 cfgs[key]['id'] = r.reason.id
855 cfgs[key]['vpp'] = copy.deepcopy(
861 # configure punt sockets
863 for cfg in cfgs.values():
864 cfg['sock'] = self.socket_client_create(b"%s/socket_%d" % (
865 six.ensure_binary(self.tempdir), cfg['id']))
866 self.vapi.punt_socket_register(
868 b"%s/socket_%d" % (six.ensure_binary(self.tempdir),
872 # create packet streams for 'no-such-tunnel' exception
874 for cfg in cfgs.values():
875 pkt = (Ether(src=self.pg0.remote_mac,
876 dst=self.pg0.local_mac) /
877 IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4))
879 pkt = pkt / UDP(sport=666, dport=4500)
880 pkt = (pkt / ESP(spi=cfg['spi'], seq=3) /
885 # send packets for each SPI we expect to be punted
887 for cfg in cfgs.values():
888 self.send_and_assert_no_replies(self.pg0, cfg['pkts'])
891 # verify the punted packets arrived on the associated socket
893 for cfg in cfgs.values():
894 rx = cfg['sock'].close()
895 self.verify_esp_pkts(rx, len(cfg['pkts']),
896 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 b"%s/socket_punt_1" %
964 six.ensure_binary(self.tempdir))
965 self.vapi.punt_socket_register(punt_eigrp,
966 b"%s/socket_punt_2" %
967 six.ensure_binary(self.tempdir))
968 self.logger.info(self.vapi.cli("sh punt sock reg ip"))
969 punts = self.vapi.punt_socket_dump(type=pt_ip)
970 self.assertEqual(len(punts), 2)
971 self.verify_ip_proto(punt_ospf, punts[0])
972 self.verify_ip_proto(punt_eigrp, punts[1])
975 # deregister a punt socket
977 self.vapi.punt_socket_deregister(punt_ospf)
978 punts = self.vapi.punt_socket_dump(type=pt_ip)
979 self.assertEqual(len(punts), 1)
982 # configure a punt socket again
984 self.vapi.punt_socket_register(punt_ospf,
985 b"%s/socket_punt_3" %
986 six.ensure_binary(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(b"%s/socket_1" % (
1036 six.ensure_binary(self.tempdir)))
1037 self.vapi.punt_socket_register(
1039 b"%s/socket_1" % (six.ensure_binary(self.tempdir)))
1042 # send packets for each SPI we expect to be punted
1044 self.send_and_assert_no_replies(self.pg0, pkts)
1047 # verify the punted packets arrived on the associated socket
1050 self.verify_ospf_pkts(rx, len(pkts))
1051 self.vapi.punt_socket_deregister(punt_ospf)
1054 class TestPunt(VppTestCase):
1055 """ Exception Punt Test Case """
1058 def setUpClass(cls):
1059 super(TestPunt, cls).setUpClass()
1062 def tearDownClass(cls):
1063 super(TestPunt, cls).tearDownClass()
1066 super(TestPunt, self).setUp()
1068 self.create_pg_interfaces(range(4))
1070 for i in self.pg_interfaces:
1078 for i in self.pg_interfaces:
1083 super(TestPunt, self).tearDown()
1085 def test_punt(self):
1086 """ Exception Path testing """
1089 # dump the punt registered reasons
1090 # search for a few we know should be there
1092 rs = self.vapi.punt_reason_dump()
1094 reasons = ["ipsec6-no-such-tunnel",
1095 "ipsec4-no-such-tunnel",
1096 "ipsec4-spi-o-udp-0"]
1098 for reason in reasons:
1101 if r.reason.name == reason:
1104 self.assertTrue(found)
1107 # Using the test CLI we will hook in a exception path to
1108 # send ACL deny packets out of pg0 and pg1.
1109 # the ACL is src,dst = 1.1.1.1,1.1.1.2
1111 ip_1_1_1_2 = VppIpRoute(self, "1.1.1.2", 32,
1112 [VppRoutePath(self.pg3.remote_ip4,
1113 self.pg3.sw_if_index)])
1114 ip_1_1_1_2.add_vpp_config()
1115 ip_1_2 = VppIpRoute(self, "1::2", 128,
1116 [VppRoutePath(self.pg3.remote_ip6,
1117 self.pg3.sw_if_index,
1118 proto=DpoProto.DPO_PROTO_IP6)])
1119 ip_1_2.add_vpp_config()
1121 p4 = (Ether(src=self.pg2.remote_mac,
1122 dst=self.pg2.local_mac) /
1123 IP(src="1.1.1.1", dst="1.1.1.2") /
1124 UDP(sport=1234, dport=1234) /
1126 p6 = (Ether(src=self.pg2.remote_mac,
1127 dst=self.pg2.local_mac) /
1128 IPv6(src="1::1", dst="1::2") /
1129 UDP(sport=1234, dport=1234) /
1131 self.send_and_expect(self.pg2, p4*1, self.pg3)
1132 self.send_and_expect(self.pg2, p6*1, self.pg3)
1135 # apply the punting features
1137 self.vapi.cli("test punt pg2")
1140 # dump the punt reasons to learn the IDs assigned
1142 rs = self.vapi.punt_reason_dump(reason={'name': "reason-v4"})
1143 r4 = rs[0].reason.id
1144 rs = self.vapi.punt_reason_dump(reason={'name': "reason-v6"})
1145 r6 = rs[0].reason.id
1150 self.send_and_assert_no_replies(self.pg2, p4*NUM_PKTS)
1151 self.send_and_assert_no_replies(self.pg2, p6*NUM_PKTS)
1155 # 1 - node error counters
1156 # 2 - per-reason counters
1157 # 2, 3 are the index of the assigned punt reason
1159 stats = self.statistics.get_err_counter(
1160 "/err/punt-dispatch/No registrations")
1161 self.assertEqual(stats, 2*NUM_PKTS)
1163 stats = self.statistics.get_counter("/net/punt")
1164 self.assertEqual(stats[0][r4]['packets'], NUM_PKTS)
1165 self.assertEqual(stats[0][r6]['packets'], NUM_PKTS)
1168 # use the test CLI to test a client that punts exception
1169 # packets out of pg0
1171 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip4)
1172 self.vapi.cli("test punt pg0 %s" % self.pg0.remote_ip6)
1174 rx4s = self.send_and_expect(self.pg2, p4*NUM_PKTS, self.pg0)
1175 rx6s = self.send_and_expect(self.pg2, p6*NUM_PKTS, self.pg0)
1178 # check the packets come out IP unmodified but destined to pg0 host
1181 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1182 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1183 self.assertEqual(p4[IP].dst, rx[IP].dst)
1184 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1186 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1187 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1188 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1189 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1191 stats = self.statistics.get_counter("/net/punt")
1192 self.assertEqual(stats[0][r4]['packets'], 2*NUM_PKTS)
1193 self.assertEqual(stats[0][r6]['packets'], 2*NUM_PKTS)
1196 # add another registration for the same reason to send packets
1199 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip4)
1200 self.vapi.cli("test punt pg1 %s" % self.pg1.remote_ip6)
1202 self.vapi.cli("clear trace")
1203 self.pg2.add_stream(p4 * NUM_PKTS)
1204 self.pg_enable_capture(self.pg_interfaces)
1207 rxd = self.pg0.get_capture(NUM_PKTS)
1209 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1210 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1211 self.assertEqual(p4[IP].dst, rx[IP].dst)
1212 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1213 rxd = self.pg1.get_capture(NUM_PKTS)
1215 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1216 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1217 self.assertEqual(p4[IP].dst, rx[IP].dst)
1218 self.assertEqual(p4[IP].ttl, rx[IP].ttl)
1220 self.vapi.cli("clear trace")
1221 self.pg2.add_stream(p6 * NUM_PKTS)
1222 self.pg_enable_capture(self.pg_interfaces)
1225 rxd = self.pg0.get_capture(NUM_PKTS)
1227 self.assertEqual(rx[Ether].dst, self.pg0.remote_mac)
1228 self.assertEqual(rx[Ether].src, self.pg0.local_mac)
1229 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1230 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1231 rxd = self.pg1.get_capture(NUM_PKTS)
1233 self.assertEqual(rx[Ether].dst, self.pg1.remote_mac)
1234 self.assertEqual(rx[Ether].src, self.pg1.local_mac)
1235 self.assertEqual(p6[IPv6].dst, rx[IPv6].dst)
1236 self.assertEqual(p6[IPv6].hlim, rx[IPv6].hlim)
1238 stats = self.statistics.get_counter("/net/punt")
1239 self.assertEqual(stats[0][r4]['packets'], 3*NUM_PKTS)
1240 self.assertEqual(stats[0][r6]['packets'], 3*NUM_PKTS)
1242 self.logger.info(self.vapi.cli("show vlib graph punt-dispatch"))
1243 self.logger.info(self.vapi.cli("show punt client"))
1244 self.logger.info(self.vapi.cli("show punt reason"))
1245 self.logger.info(self.vapi.cli("show punt stats"))
1246 self.logger.info(self.vapi.cli("show punt db"))
1249 if __name__ == '__main__':
1250 unittest.main(testRunner=VppTestRunner)