import threading
import struct
import copy
+import fcntl
+import time
+
from struct import unpack, unpack_from
try:
import scapy.layers.inet6 as inet6
from scapy.layers.inet6 import IPv6, ICMPv6DestUnreach
from scapy.contrib.ospf import OSPF_Hdr, OSPFv3_Hello
+from framework import tag_fixme_vpp_workers
from framework import VppTestCase, VppTestRunner
from vpp_ip import DpoProto
from vpp_ip_route import VppIpRoute, VppRoutePath
+from vpp_ipsec import VppIpsecSA, VppIpsecTunProtect, VppIpsecInterface
from vpp_papi import VppEnum
-from vpp_ipsec_tun_interface import VppIpsecTunInterface
NUM_PKTS = 67
self.sockName = sockName
self.sock = None
self.rx_pkts = []
+ self.stop_running = False
def rx_packets(self):
# Wait for some packets on socket
while True:
- data = self.sock.recv(65536)
-
- # punt socket metadata
- # packet_desc = data[0:8]
-
- # Ethernet
- self.rx_pkts.append(Ether(data[8:]))
+ try:
+ data = self.sock.recv(65536)
+
+ # punt socket metadata
+ # packet_desc = data[0:8]
+
+ # Ethernet
+ self.rx_pkts.append(Ether(data[8:]))
+ except IOError as e:
+ if e.errno == 11:
+ # nothing to receive, stop running or sleep a little
+ if self.stop_running:
+ break
+ time.sleep(0.1)
+ pass
+ else:
+ raise
def run(self):
self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_DGRAM)
pass
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 65536)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 65536)
+ fcntl.fcntl(self.sock, fcntl.F_SETFL, os.O_NONBLOCK)
self.sock.bind(self.sockName)
self.rx_packets()
def close(self):
+ self.stop_running = True
+ threading.Thread.join(self)
self.sock.close()
return self.rx_pkts
#
# expect ICMP - port unreachable for all packets
#
- rx = self.send_and_expect(self.pg0, pkts, self.pg0)
+ rx = self.send_and_expect_some(self.pg0, pkts, self.pg0)
for p in rx:
self.assertEqual(int(p[IP].proto), 1) # ICMP
punts = self.vapi.punt_socket_dump(type=pt_l4)
self.assertEqual(len(punts), 0)
- rx = self.send_and_expect(self.pg0, pkts, self.pg0)
+ rx = self.send_and_expect_some(self.pg0, pkts, self.pg0)
for p in rx:
self.assertEqual(int(p[IP].proto), 1) # ICMP
self.assertEqual(int(p[ICMP].code), 3) # unreachable
def setUp(self):
super(TestExceptionPuntSocket, self).setUp()
+ self.create_pg_interfaces(range(2))
for i in self.pg_interfaces:
i.config_ip4()
i.resolve_arp()
}
}
- #
- # we need an IPSec tunnels for this to work otherwise ESP gets dropped
- # due to unknown IP proto
- #
- VppIpsecTunInterface(self, self.pg0, 1000, 1000,
- (VppEnum.vl_api_ipsec_crypto_alg_t.
- IPSEC_API_CRYPTO_ALG_AES_CBC_128),
- b"0123456701234567",
- b"0123456701234567",
- (VppEnum.vl_api_ipsec_integ_alg_t.
- IPSEC_API_INTEG_ALG_SHA1_96),
- b"0123456701234567",
- b"0123456701234567").add_vpp_config()
- VppIpsecTunInterface(self, self.pg0, 1001, 1001,
- (VppEnum.vl_api_ipsec_crypto_alg_t.
- IPSEC_API_CRYPTO_ALG_AES_CBC_128),
- b"0123456701234567",
- b"0123456701234567",
- (VppEnum.vl_api_ipsec_integ_alg_t.
- IPSEC_API_INTEG_ALG_SHA1_96),
- b"0123456701234567",
- b"0123456701234567",
- udp_encap=True).add_vpp_config()
-
#
# we're dealing with IPSec tunnels punting for no-such-tunnel
- # adn SPI=0
+ # (SPI=0 goes to ikev2)
#
cfgs = dict()
- cfgs['ipsec4-no-such-tunnel'] = {'spi': 99, 'udp': False}
- cfgs['ipsec4-spi-o-udp-0'] = {'spi': 0, 'udp': True}
+ cfgs['ipsec4-no-such-tunnel'] = {'spi': 99,
+ 'udp': False,
+ 'itf': self.pg0}
#
# find the VPP ID for these punt exception reasin
rs = self.vapi.punt_reason_dump()
for key in cfgs:
for r in rs:
+ print(r.reason.name)
+ print(key)
if r.reason.name == key:
cfgs[key]['id'] = r.reason.id
cfgs[key]['vpp'] = copy.deepcopy(
# create packet streams for 'no-such-tunnel' exception
#
for cfg in cfgs.values():
- pkt = (Ether(src=self.pg0.remote_mac,
- dst=self.pg0.local_mac) /
- IP(src=self.pg0.remote_ip4, dst=self.pg0.local_ip4))
+ pkt = (Ether(src=cfg['itf'].remote_mac,
+ dst=cfg['itf'].local_mac) /
+ IP(src=cfg['itf'].remote_ip4,
+ dst=cfg['itf'].local_ip4))
if (cfg['udp']):
pkt = pkt / UDP(sport=666, dport=4500)
pkt = (pkt / ESP(spi=cfg['spi'], seq=3) /
# send packets for each SPI we expect to be punted
#
for cfg in cfgs.values():
- self.send_and_assert_no_replies(self.pg0, cfg['pkts'])
+ self.send_and_assert_no_replies(cfg['itf'], cfg['pkts'])
#
# verify the punted packets arrived on the associated socket
cfg['spi'], cfg['udp'])
#
+ # add some tunnels, make sure it still punts
+ #
+ tun = VppIpsecInterface(self).add_vpp_config()
+ sa_in = VppIpsecSA(self, 11, 11,
+ (VppEnum.vl_api_ipsec_integ_alg_t.
+ IPSEC_API_INTEG_ALG_SHA1_96),
+ b"0123456701234567",
+ (VppEnum.vl_api_ipsec_crypto_alg_t.
+ IPSEC_API_CRYPTO_ALG_AES_CBC_128),
+ b"0123456701234567",
+ 50,
+ self.pg0.local_ip4,
+ self.pg0.remote_ip4).add_vpp_config()
+ sa_out = VppIpsecSA(self, 22, 22,
+ (VppEnum.vl_api_ipsec_integ_alg_t.
+ IPSEC_API_INTEG_ALG_SHA1_96),
+ b"0123456701234567",
+ (VppEnum.vl_api_ipsec_crypto_alg_t.
+ IPSEC_API_CRYPTO_ALG_AES_CBC_128),
+ b"0123456701234567",
+ 50,
+ self.pg0.local_ip4,
+ self.pg0.remote_ip4).add_vpp_config()
+ protect = VppIpsecTunProtect(self, tun,
+ sa_out,
+ [sa_in]).add_vpp_config()
+
+ #
+ # send packets for each SPI we expect to be punted
+ #
+ for cfg in cfgs.values():
+ self.send_and_assert_no_replies(cfg['itf'], cfg['pkts'])
+
+ #
+ # verify the punted packets arrived on the associated socket
+ #
+ for cfg in cfgs.values():
+ rx = cfg['sock'].close()
+ self.verify_esp_pkts(rx, len(cfg['pkts']),
+ cfg['spi'], cfg['udp'])
+ #
# socket deregister
#
for cfg in cfgs.values():
self.vapi.punt_socket_deregister(punt_ospf)
+@tag_fixme_vpp_workers
class TestPunt(VppTestCase):
""" Exception Punt Test Case """
for i in self.pg_interfaces:
i.unconfig_ip4()
i.unconfig_ip6()
- i.ip6_disable()
i.admin_down()
super(TestPunt, self).tearDown()