summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeale Ranns <neale@graphiant.com>2021-06-07 09:34:07 +0000
committerOle Tr�an <otroan@employees.org>2021-06-14 13:13:13 +0000
commit89d939e52c999edec66194c60bc5afb2397a2842 (patch)
tree00e8ec98863ead022c30e8619b45a7585fc7a5de
parent6197cb730e1571ca69859489c0ae7ea90a5c5fd4 (diff)
linux-cp: Add tests for tun devices
Type: test Signed-off-by: Neale Ranns <neale@graphiant.com> Change-Id: Iec69d8624b15766ed65e7d09777819d2242dee17
-rw-r--r--src/vnet/ipsec/ipsec_api.c31
-rw-r--r--src/vnet/ipsec/ipsec_itf.c12
-rw-r--r--src/vnet/ipsec/ipsec_itf.h3
-rw-r--r--test/test_linux_cp.py246
-rw-r--r--test/vpp_ipip_tun_interface.py5
-rw-r--r--test/vpp_ipsec.py6
6 files changed, 298 insertions, 5 deletions
diff --git a/src/vnet/ipsec/ipsec_api.c b/src/vnet/ipsec/ipsec_api.c
index b954a6eae9f..0eb51b5727f 100644
--- a/src/vnet/ipsec/ipsec_api.c
+++ b/src/vnet/ipsec/ipsec_api.c
@@ -696,9 +696,40 @@ vl_api_ipsec_itf_delete_t_handler (vl_api_ipsec_itf_delete_t * mp)
REPLY_MACRO (VL_API_IPSEC_ITF_DELETE_REPLY);
}
+static walk_rc_t
+send_ipsec_itf_details (ipsec_itf_t *itf, void *arg)
+{
+ ipsec_dump_walk_ctx_t *ctx = arg;
+ vl_api_ipsec_itf_details_t *mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ clib_memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (VL_API_IPSEC_ITF_DETAILS);
+ mp->context = ctx->context;
+
+ mp->itf.mode = tunnel_mode_encode (itf->ii_mode);
+ mp->itf.user_instance = htonl (itf->ii_user_instance);
+ mp->itf.sw_if_index = htonl (itf->ii_sw_if_index);
+ vl_api_send_msg (ctx->reg, (u8 *) mp);
+
+ return (WALK_CONTINUE);
+}
+
static void
vl_api_ipsec_itf_dump_t_handler (vl_api_ipsec_itf_dump_t * mp)
{
+ vl_api_registration_t *reg;
+
+ reg = vl_api_client_index_to_registration (mp->client_index);
+ if (!reg)
+ return;
+
+ ipsec_dump_walk_ctx_t ctx = {
+ .reg = reg,
+ .context = mp->context,
+ };
+
+ ipsec_itf_walk (send_ipsec_itf_details, &ctx);
}
typedef struct ipsec_sa_dump_match_ctx_t_
diff --git a/src/vnet/ipsec/ipsec_itf.c b/src/vnet/ipsec/ipsec_itf.c
index ae8e3427b12..532d5be4c07 100644
--- a/src/vnet/ipsec/ipsec_itf.c
+++ b/src/vnet/ipsec/ipsec_itf.c
@@ -342,6 +342,18 @@ ipsec_itf_delete (u32 sw_if_index)
return 0;
}
+void
+ipsec_itf_walk (ipsec_itf_walk_cb_t cb, void *ctx)
+{
+ ipsec_itf_t *itf;
+
+ pool_foreach (itf, ipsec_itf_pool)
+ {
+ if (WALK_CONTINUE != cb (itf, ctx))
+ break;
+ }
+}
+
static clib_error_t *
ipsec_itf_create_cli (vlib_main_t * vm,
unformat_input_t * input, vlib_cli_command_t * cmd)
diff --git a/src/vnet/ipsec/ipsec_itf.h b/src/vnet/ipsec/ipsec_itf.h
index ab317e10332..4958d102b65 100644
--- a/src/vnet/ipsec/ipsec_itf.h
+++ b/src/vnet/ipsec/ipsec_itf.h
@@ -110,6 +110,9 @@ extern u8 *format_ipsec_itf (u8 * s, va_list * a);
extern ipsec_itf_t *ipsec_itf_get (index_t ii);
+typedef walk_rc_t (*ipsec_itf_walk_cb_t) (ipsec_itf_t *itf, void *ctx);
+extern void ipsec_itf_walk (ipsec_itf_walk_cb_t cd, void *ctx);
+
/*
* fd.io coding-style-patch-verification: ON
*
diff --git a/test/test_linux_cp.py b/test/test_linux_cp.py
index df38681b16e..4cbcf6c5a07 100644
--- a/test/test_linux_cp.py
+++ b/test/test_linux_cp.py
@@ -6,8 +6,16 @@ from scapy.layers.inet import IP, UDP
from scapy.layers.inet6 import IPv6, Raw
from scapy.layers.l2 import Ether, ARP, Dot1Q
+from util import reassemble4
from vpp_object import VppObject
from framework import VppTestCase, VppTestRunner
+from vpp_ipip_tun_interface import VppIpIpTunInterface
+from template_ipsec import TemplateIpsec, IpsecTun4Tests, \
+ IpsecTun4, mk_scapy_crypt_key, config_tun_params
+from template_ipsec import TemplateIpsec, IpsecTun4Tests, \
+ IpsecTun4, mk_scapy_crypt_key, config_tun_params
+from test_ipsec_tun_if_esp import TemplateIpsecItf4
+from vpp_ipsec import VppIpsecSA, VppIpsecTunProtect, VppIpsecInterface
class VppLcpPair(VppObject):
@@ -62,10 +70,13 @@ class TestLinuxCP(VppTestCase):
def setUp(self):
super(TestLinuxCP, self).setUp()
- # create 4 pg interfaces so there are a few addresses
- # in the FIB
+ # create 4 pg interfaces so we can create two pairs
self.create_pg_interfaces(range(4))
+ # create on ip4 and one ip6 pg tun
+ self.pg_interfaces += self.create_pg_ip4_interfaces(range(4, 5))
+ self.pg_interfaces += self.create_pg_ip6_interfaces(range(5, 6))
+
for i in self.pg_interfaces:
i.admin_up()
@@ -169,6 +180,237 @@ class TestLinuxCP(VppTestCase):
for phy in phys:
phy.unconfig_ip4()
+ def test_linux_cp_tun(self):
+ """ Linux CP TUN """
+
+ #
+ # Setup
+ #
+ N_PKTS = 31
+
+ # create two pairs, wihch a bunch of hots on the phys
+ hosts = [self.pg4, self.pg5]
+ phy = self.pg2
+
+ phy.config_ip4()
+ phy.config_ip6()
+ phy.resolve_arp()
+ phy.resolve_ndp()
+
+ tun4 = VppIpIpTunInterface(
+ self,
+ phy,
+ phy.local_ip4,
+ phy.remote_ip4).add_vpp_config()
+ tun6 = VppIpIpTunInterface(
+ self,
+ phy,
+ phy.local_ip6,
+ phy.remote_ip6).add_vpp_config()
+ tuns = [tun4, tun6]
+
+ tun4.admin_up()
+ tun4.config_ip4()
+ tun6.admin_up()
+ tun6.config_ip6()
+
+ pair1 = VppLcpPair(self, tuns[0], hosts[0]).add_vpp_config()
+ pair2 = VppLcpPair(self, tuns[1], hosts[1]).add_vpp_config()
+
+ self.logger.info(self.vapi.cli("sh lcp adj verbose"))
+ self.logger.info(self.vapi.cli("sh lcp"))
+ self.logger.info(self.vapi.cli("sh ip punt redirect"))
+
+ #
+ # Traffic Tests
+ #
+
+ # host to phy for v4
+ p = (IP(src=tun4.local_ip4, dst="2.2.2.2") /
+ UDP(sport=1234, dport=1234) /
+ Raw())
+
+ rxs = self.send_and_expect(self.pg4, p * N_PKTS, phy)
+
+ # verify inner packet is unchanged and has the tunnel encap
+ for rx in rxs:
+ self.assertEqual(rx[Ether].dst, phy.remote_mac)
+ self.assertEqual(rx[IP].dst, phy.remote_ip4)
+ self.assertEqual(rx[IP].src, phy.local_ip4)
+ inner = IP(rx[IP].payload)
+ self.assertEqual(inner.src, tun4.local_ip4)
+ self.assertEqual(inner.dst, "2.2.2.2")
+
+ # host to phy for v6
+ p = (IPv6(src=tun6.local_ip6, dst="2::2") /
+ UDP(sport=1234, dport=1234) /
+ Raw())
+
+ rxs = self.send_and_expect(self.pg5, p * N_PKTS, phy)
+
+ # verify inner packet is unchanged and has the tunnel encap
+ for rx in rxs:
+ self.assertEqual(rx[IPv6].dst, phy.remote_ip6)
+ self.assertEqual(rx[IPv6].src, phy.local_ip6)
+ inner = IPv6(rx[IPv6].payload)
+ self.assertEqual(inner.src, tun6.local_ip6)
+ self.assertEqual(inner.dst, "2::2")
+
+ # phy to host v4
+ p = (Ether(dst=phy.local_mac, src=phy.remote_mac) /
+ IP(dst=phy.local_ip4, src=phy.remote_ip4) /
+ IP(dst=tun4.local_ip4, src=tun4.remote_ip4) /
+ UDP(sport=1234, dport=1234) /
+ Raw())
+
+ rxs = self.send_and_expect(phy, p * N_PKTS, self.pg4)
+ for rx in rxs:
+ rx = IP(rx)
+ self.assertEqual(rx[IP].dst, tun4.local_ip4)
+ self.assertEqual(rx[IP].src, tun4.remote_ip4)
+
+ # phy to host v6
+ p = (Ether(dst=phy.local_mac, src=phy.remote_mac) /
+ IPv6(dst=phy.local_ip6, src=phy.remote_ip6) /
+ IPv6(dst=tun6.local_ip6, src=tun6.remote_ip6) /
+ UDP(sport=1234, dport=1234) /
+ Raw())
+
+ rxs = self.send_and_expect(phy, p * N_PKTS, self.pg5)
+ for rx in rxs:
+ rx = IPv6(rx)
+ self.assertEqual(rx[IPv6].dst, tun6.local_ip6)
+ self.assertEqual(rx[IPv6].src, tun6.remote_ip6)
+
+ # cleanup
+ phy.unconfig_ip4()
+ phy.unconfig_ip6()
+
+ tun4.unconfig_ip4()
+ tun6.unconfig_ip6()
+
+
+class TestLinuxCPIpsec(TemplateIpsec,
+ TemplateIpsecItf4,
+ IpsecTun4):
+ """ IPsec Interface IPv4 """
+
+ extra_vpp_plugin_config = ["plugin",
+ "linux_cp_plugin.so",
+ "{", "enable", "}",
+ "plugin",
+ "linux_cp_unittest_plugin.so",
+ "{", "enable", "}"]
+
+ def setUp(self):
+ super(TestLinuxCPIpsec, self).setUp()
+
+ self.tun_if = self.pg0
+ self.pg_interfaces += self.create_pg_ip4_interfaces(range(3, 4))
+ self.pg_interfaces += self.create_pg_ip6_interfaces(range(4, 5))
+
+ def tearDown(self):
+ super(TestLinuxCPIpsec, self).tearDown()
+
+ def verify_encrypted(self, p, sa, rxs):
+ decrypt_pkts = []
+ for rx in rxs:
+ if p.nat_header:
+ self.assertEqual(rx[UDP].dport, 4500)
+ self.assert_packet_checksums_valid(rx)
+ self.assertEqual(len(rx) - len(Ether()), rx[IP].len)
+ try:
+ rx_ip = rx[IP]
+ decrypt_pkt = p.vpp_tun_sa.decrypt(rx_ip)
+ if not decrypt_pkt.haslayer(IP):
+ decrypt_pkt = IP(decrypt_pkt[Raw].load)
+ if rx_ip.proto == socket.IPPROTO_ESP:
+ self.verify_esp_padding(sa, rx_ip[ESP].data, decrypt_pkt)
+ decrypt_pkts.append(decrypt_pkt)
+ self.assert_equal(decrypt_pkt.src, p.tun_if.local_ip4)
+ self.assert_equal(decrypt_pkt.dst, p.tun_if.remote_ip4)
+ except:
+ self.logger.debug(ppp("Unexpected packet:", rx))
+ try:
+ self.logger.debug(ppp("Decrypted packet:", decrypt_pkt))
+ except:
+ pass
+ raise
+ pkts = reassemble4(decrypt_pkts)
+ for pkt in pkts:
+ self.assert_packet_checksums_valid(pkt)
+
+ def verify_decrypted(self, p, rxs):
+ for rx in rxs:
+ rx = IP(rx)
+ self.assert_equal(rx[IP].src, p.tun_if.remote_ip4)
+ self.assert_equal(rx[IP].dst, p.tun_if.local_ip4)
+ self.assert_packet_checksums_valid(rx)
+
+ def gen_encrypt_pkts(self, p, sa, sw_intf, src, dst, count=1,
+ payload_size=54):
+ return [Ether(src=sw_intf.remote_mac, dst=sw_intf.local_mac) /
+ sa.encrypt(IP(src=src, dst=dst) /
+ UDP(sport=1111, dport=2222) /
+ Raw(b'X' * payload_size))
+ for i in range(count)]
+
+ def test_linux_cp_ipsec4_tun(self):
+ """ Linux CP Ipsec TUN """
+
+ #
+ # Setup
+ #
+ N_PKTS = 31
+
+ # the pg that paris with the tunnel
+ self.host = self.pg3
+
+ # tunnel and protection setup
+ p = self.ipv4_params
+
+ self.config_network(p)
+ self.config_sa_tun(p,
+ self.pg0.local_ip4,
+ self.pg0.remote_ip4)
+ self.config_protect(p)
+
+ pair = VppLcpPair(self, p.tun_if, self.host).add_vpp_config()
+
+ self.logger.error(self.vapi.cli("sh int addr"))
+ self.logger.info(self.vapi.cli("sh lcp"))
+ self.logger.info(self.vapi.cli("sh ip punt redirect"))
+
+ #
+ # Traffic Tests
+ #
+
+ # host to phy for v4
+ pkt = (IP(src=p.tun_if.local_ip4,
+ dst=p.tun_if.remote_ip4) /
+ UDP(sport=1234, dport=1234) /
+ Raw())
+
+ rxs = self.send_and_expect(self.host, pkt * N_PKTS, self.tun_if)
+ self.verify_encrypted(p, p.vpp_tun_sa, rxs)
+
+ # phy to host for v4
+ pkts = self.gen_encrypt_pkts(p, p.scapy_tun_sa, self.tun_if,
+ src=p.tun_if.remote_ip4,
+ dst=p.tun_if.local_ip4,
+ count=N_PKTS)
+ try:
+ rxs = self.send_and_expect(self.tun_if, pkts, self.host)
+ self.verify_decrypted(p, rxs)
+ finally:
+ self.logger.error(self.vapi.cli("sh trace"))
+
+ # cleanup
+ pair.remove_vpp_config()
+ self.unconfig_protect(p)
+ self.unconfig_sa(p)
+ self.unconfig_network(p)
+
if __name__ == '__main__':
unittest.main(testRunner=VppTestRunner)
diff --git a/test/vpp_ipip_tun_interface.py b/test/vpp_ipip_tun_interface.py
index 67cc1b5f1d8..6517458d3d6 100644
--- a/test/vpp_ipip_tun_interface.py
+++ b/test/vpp_ipip_tun_interface.py
@@ -34,6 +34,9 @@ class VppIpIpTunInterface(VppTunnelInterface):
'mode': self.mode,
})
self.set_sw_if_index(r.sw_if_index)
+ r = self.test.vapi.ipip_tunnel_dump(
+ sw_if_index=self.sw_if_index)
+ self.instance = r[0].tunnel.instance
self.test.registry.register(self, self.test.logger)
return self
@@ -51,7 +54,7 @@ class VppIpIpTunInterface(VppTunnelInterface):
return self.object_id()
def object_id(self):
- return "ipip-%d" % self._sw_if_index
+ return "ipip%d" % self.instance
@property
def remote_ip(self):
diff --git a/test/vpp_ipsec.py b/test/vpp_ipsec.py
index aa2a05d1068..2bf7eda4c23 100644
--- a/test/vpp_ipsec.py
+++ b/test/vpp_ipsec.py
@@ -412,6 +412,8 @@ class VppIpsecInterface(VppInterface):
})
self.set_sw_if_index(r.sw_if_index)
self.test.registry.register(self, self.test.logger)
+ ts = self.test.vapi.ipsec_itf_dump(sw_if_index=self._sw_if_index)
+ self.instance = ts[0].itf.user_instance
return self
def remove_vpp_config(self):
@@ -420,7 +422,7 @@ class VppIpsecInterface(VppInterface):
def query_vpp_config(self):
ts = self.test.vapi.ipsec_itf_dump(sw_if_index=0xffffffff)
for t in ts:
- if t.tunnel.sw_if_index == self._sw_if_index:
+ if t.itf.sw_if_index == self._sw_if_index:
return True
return False
@@ -428,4 +430,4 @@ class VppIpsecInterface(VppInterface):
return self.object_id()
def object_id(self):
- return "ipsec-%d" % self._sw_if_index
+ return "ipsec%d" % self.instance