aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/vnet/ipsec/ipsec.api41
-rw-r--r--src/vnet/ipsec/ipsec_api.c111
-rw-r--r--src/vnet/ipsec/ipsec_cli.c65
-rw-r--r--src/vnet/ipsec/ipsec_sa.c37
-rw-r--r--src/vnet/ipsec/ipsec_sa.h1
-rw-r--r--src/vnet/ipsec/ipsec_test.c23
-rw-r--r--test/test_ipsec_api.py38
7 files changed, 310 insertions, 6 deletions
diff --git a/src/vnet/ipsec/ipsec.api b/src/vnet/ipsec/ipsec.api
index 2e69e625034..d31caf5b182 100644
--- a/src/vnet/ipsec/ipsec.api
+++ b/src/vnet/ipsec/ipsec.api
@@ -201,6 +201,29 @@ autoreply define ipsec_sad_entry_del
u32 id;
};
+
+/** \brief An API to bind an SAD entry to a specific worker
+
+ @param client_index - opaque cookie to identify the sender
+ @param context - sender context, to match reply w/ request
+ @param sa_id - the id of the SA to bind
+ @param worker - the worker's index to which the SA will be bound to
+ */
+autoreply define ipsec_sad_bind
+{
+ u32 client_index;
+ u32 context;
+ u32 sa_id;
+ u32 worker;
+};
+
+autoreply define ipsec_sad_unbind
+{
+ u32 client_index;
+ u32 context;
+ u32 sa_id;
+};
+
/** \brief An API to update the tunnel parameters and the ports associated with an SA
Used in the NAT-T case when the NAT data changes
@@ -430,6 +453,12 @@ define ipsec_sa_v3_dump
u32 context;
u32 sa_id;
};
+define ipsec_sa_v4_dump
+{
+ u32 client_index;
+ u32 context;
+ u32 sa_id;
+};
/** \brief IPsec security association database response
@param context - sender context which was passed in the request
@@ -479,6 +508,18 @@ define ipsec_sa_v3_details {
u32 stat_index;
};
+define ipsec_sa_v4_details {
+ u32 context;
+ vl_api_ipsec_sad_entry_v3_t entry;
+
+ vl_api_interface_index_t sw_if_index;
+ u64 seq_outbound;
+ u64 last_seq_inbound;
+ u64 replay_window;
+
+ u32 thread_index;
+ u32 stat_index;
+};
/** \brief Dump IPsec backends
@param client_index - opaque cookie to identify the sender
diff --git a/src/vnet/ipsec/ipsec_api.c b/src/vnet/ipsec/ipsec_api.c
index 3994150d895..7fc68f60369 100644
--- a/src/vnet/ipsec/ipsec_api.c
+++ b/src/vnet/ipsec/ipsec_api.c
@@ -593,6 +593,36 @@ out:
}
static void
+vl_api_ipsec_sad_bind_t_handler (vl_api_ipsec_sad_bind_t *mp)
+{
+ vl_api_ipsec_sad_bind_reply_t *rmp;
+ u32 sa_id;
+ u32 worker;
+ int rv;
+
+ sa_id = ntohl (mp->sa_id);
+ worker = ntohl (mp->worker);
+
+ rv = ipsec_sa_bind (sa_id, worker, true /* bind */);
+
+ REPLY_MACRO (VL_API_IPSEC_SAD_BIND_REPLY);
+}
+
+static void
+vl_api_ipsec_sad_unbind_t_handler (vl_api_ipsec_sad_unbind_t *mp)
+{
+ vl_api_ipsec_sad_unbind_reply_t *rmp;
+ u32 sa_id;
+ int rv;
+
+ sa_id = ntohl (mp->sa_id);
+
+ rv = ipsec_sa_bind (sa_id, ~0, false /* bind */);
+
+ REPLY_MACRO (VL_API_IPSEC_SAD_UNBIND_REPLY);
+}
+
+static void
send_ipsec_spds_details (ipsec_spd_t * spd, vl_api_registration_t * reg,
u32 context)
{
@@ -1116,6 +1146,87 @@ vl_api_ipsec_sa_v3_dump_t_handler (vl_api_ipsec_sa_v3_dump_t *mp)
ipsec_sa_walk (send_ipsec_sa_v3_details, &ctx);
}
+static walk_rc_t
+send_ipsec_sa_v4_details (ipsec_sa_t *sa, void *arg)
+{
+ ipsec_dump_walk_ctx_t *ctx = arg;
+ vl_api_ipsec_sa_v4_details_t *mp;
+
+ mp = vl_msg_api_alloc (sizeof (*mp));
+ clib_memset (mp, 0, sizeof (*mp));
+ mp->_vl_msg_id = ntohs (REPLY_MSG_ID_BASE + VL_API_IPSEC_SA_V4_DETAILS);
+ mp->context = ctx->context;
+
+ mp->entry.sad_id = htonl (sa->id);
+ mp->entry.spi = htonl (sa->spi);
+ mp->entry.protocol = ipsec_proto_encode (sa->protocol);
+
+ mp->entry.crypto_algorithm = ipsec_crypto_algo_encode (sa->crypto_alg);
+ ipsec_key_encode (&sa->crypto_key, &mp->entry.crypto_key);
+
+ mp->entry.integrity_algorithm = ipsec_integ_algo_encode (sa->integ_alg);
+ ipsec_key_encode (&sa->integ_key, &mp->entry.integrity_key);
+
+ mp->entry.flags = ipsec_sad_flags_encode (sa);
+ mp->entry.salt = clib_host_to_net_u32 (sa->salt);
+
+ if (ipsec_sa_is_set_IS_PROTECT (sa))
+ {
+ ipsec_sa_dump_match_ctx_t ctx = {
+ .sai = sa - ipsec_sa_pool,
+ .sw_if_index = ~0,
+ };
+ ipsec_tun_protect_walk (ipsec_sa_dump_match_sa, &ctx);
+
+ mp->sw_if_index = htonl (ctx.sw_if_index);
+ }
+ else
+ mp->sw_if_index = ~0;
+
+ if (ipsec_sa_is_set_IS_TUNNEL (sa))
+ tunnel_encode (&sa->tunnel, &mp->entry.tunnel);
+
+ if (ipsec_sa_is_set_UDP_ENCAP (sa))
+ {
+ mp->entry.udp_src_port = sa->udp_hdr.src_port;
+ mp->entry.udp_dst_port = sa->udp_hdr.dst_port;
+ }
+
+ mp->seq_outbound = clib_host_to_net_u64 (((u64) sa->seq));
+ mp->last_seq_inbound = clib_host_to_net_u64 (((u64) sa->seq));
+ if (ipsec_sa_is_set_USE_ESN (sa))
+ {
+ mp->seq_outbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi));
+ mp->last_seq_inbound |= (u64) (clib_host_to_net_u32 (sa->seq_hi));
+ }
+ if (ipsec_sa_is_set_USE_ANTI_REPLAY (sa))
+ mp->replay_window = clib_host_to_net_u64 (sa->replay_window);
+
+ mp->thread_index = clib_host_to_net_u32 (sa->thread_index);
+ mp->stat_index = clib_host_to_net_u32 (sa->stat_index);
+
+ vl_api_send_msg (ctx->reg, (u8 *) mp);
+
+ return (WALK_CONTINUE);
+}
+
+static void
+vl_api_ipsec_sa_v4_dump_t_handler (vl_api_ipsec_sa_v4_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_sa_walk (send_ipsec_sa_v4_details, &ctx);
+}
+
static void
vl_api_ipsec_backend_dump_t_handler (vl_api_ipsec_backend_dump_t * mp)
{
diff --git a/src/vnet/ipsec/ipsec_cli.c b/src/vnet/ipsec/ipsec_cli.c
index 35fee297a4d..d0029ea7fcb 100644
--- a/src/vnet/ipsec/ipsec_cli.c
+++ b/src/vnet/ipsec/ipsec_cli.c
@@ -212,6 +212,71 @@ VLIB_CLI_COMMAND (ipsec_sa_add_del_command, static) = {
/* *INDENT-ON* */
static clib_error_t *
+ipsec_sa_bind_cli (vlib_main_t *vm, unformat_input_t *input,
+ vlib_cli_command_t *cmd)
+{
+ unformat_input_t _line_input, *line_input = &_line_input;
+ u32 id = ~0;
+ u32 worker = ~0;
+ bool bind = 1;
+ int rv;
+ clib_error_t *error = NULL;
+
+ if (!unformat_user (input, unformat_line_input, line_input))
+ return 0;
+
+ while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
+ {
+ if (unformat (line_input, "unbind"))
+ bind = 0;
+ else if (id != ~0 && unformat (line_input, "%u", &id))
+ ;
+ else if (unformat (line_input, "%u", &worker))
+ ;
+ else
+ {
+ error = clib_error_return (0, "parse error: '%U'",
+ format_unformat_error, line_input);
+ goto done;
+ }
+ }
+
+ if (id == ~0)
+ {
+ error = clib_error_return (0, "please specify SA ID");
+ goto done;
+ }
+
+ if (bind && ~0 == worker)
+ {
+ error = clib_error_return (0, "please specify worker to bind to");
+ goto done;
+ }
+
+ rv = ipsec_sa_bind (id, worker, bind);
+ switch (rv)
+ {
+ case VNET_API_ERROR_INVALID_VALUE:
+ error = clib_error_return (0, "please specify a valid SA ID");
+ break;
+ case VNET_API_ERROR_INVALID_WORKER:
+ error = clib_error_return (0, "please specify a valid worker index");
+ break;
+ }
+
+done:
+ unformat_free (line_input);
+
+ return error;
+}
+
+VLIB_CLI_COMMAND (ipsec_sa_bind_cmd, static) = {
+ .path = "ipsec sa bind",
+ .short_help = "ipsec sa [unbind] <sa-id> <worker>",
+ .function = ipsec_sa_bind_cli,
+};
+
+static clib_error_t *
ipsec_spd_add_del_command_fn (vlib_main_t * vm,
unformat_input_t * input,
vlib_cli_command_t * cmd)
diff --git a/src/vnet/ipsec/ipsec_sa.c b/src/vnet/ipsec/ipsec_sa.c
index c842caf8f16..80e61d09247 100644
--- a/src/vnet/ipsec/ipsec_sa.c
+++ b/src/vnet/ipsec/ipsec_sa.c
@@ -521,6 +521,32 @@ ipsec_sa_del (ipsec_sa_t * sa)
pool_put (ipsec_sa_pool, sa);
}
+int
+ipsec_sa_bind (u32 id, u32 worker, bool bind)
+{
+ ipsec_main_t *im = &ipsec_main;
+ uword *p;
+ ipsec_sa_t *sa;
+
+ p = hash_get (im->sa_index_by_sa_id, id);
+ if (!p)
+ return VNET_API_ERROR_INVALID_VALUE;
+
+ sa = ipsec_sa_get (p[0]);
+
+ if (!bind)
+ {
+ sa->thread_index = ~0;
+ return 0;
+ }
+
+ if (worker >= vlib_num_workers ())
+ return VNET_API_ERROR_INVALID_WORKER;
+
+ sa->thread_index = vlib_get_worker_thread_index (worker);
+ return 0;
+}
+
void
ipsec_sa_unlock (index_t sai)
{
@@ -618,19 +644,18 @@ ipsec_sa_fib_node_get (fib_node_index_t index)
}
static ipsec_sa_t *
-ipsec_sa_from_fib_node (fib_node_t * node)
+ipsec_sa_from_fib_node (fib_node_t *node)
{
ASSERT (FIB_NODE_TYPE_IPSEC_SA == node->fn_type);
- return ((ipsec_sa_t *) (((char *) node) -
- STRUCT_OFFSET_OF (ipsec_sa_t, node)));
-
+ return (
+ (ipsec_sa_t *) (((char *) node) - STRUCT_OFFSET_OF (ipsec_sa_t, node)));
}
/**
* Function definition to inform the FIB node that its last lock has gone.
*/
static void
-ipsec_sa_last_lock_gone (fib_node_t * node)
+ipsec_sa_last_lock_gone (fib_node_t *node)
{
/*
* The ipsec SA is a root of the graph. As such
@@ -643,7 +668,7 @@ ipsec_sa_last_lock_gone (fib_node_t * node)
* Function definition to backwalk a FIB node
*/
static fib_node_back_walk_rc_t
-ipsec_sa_back_walk (fib_node_t * node, fib_node_back_walk_ctx_t * ctx)
+ipsec_sa_back_walk (fib_node_t *node, fib_node_back_walk_ctx_t *ctx)
{
ipsec_sa_stack (ipsec_sa_from_fib_node (node));
diff --git a/src/vnet/ipsec/ipsec_sa.h b/src/vnet/ipsec/ipsec_sa.h
index ab1e3cdb1f9..a9abfdb05e2 100644
--- a/src/vnet/ipsec/ipsec_sa.h
+++ b/src/vnet/ipsec/ipsec_sa.h
@@ -283,6 +283,7 @@ ipsec_sa_add_and_lock (u32 id, u32 spi, ipsec_protocol_t proto,
ipsec_integ_alg_t integ_alg, const ipsec_key_t *ik,
ipsec_sa_flags_t flags, u32 salt, u16 src_port,
u16 dst_port, const tunnel_t *tun, u32 *sa_out_index);
+extern int ipsec_sa_bind (u32 id, u32 worker, bool bind);
extern index_t ipsec_sa_find_and_lock (u32 id);
extern int ipsec_sa_unlock_id (u32 id);
extern void ipsec_sa_unlock (index_t sai);
diff --git a/src/vnet/ipsec/ipsec_test.c b/src/vnet/ipsec/ipsec_test.c
index 16d86427ea7..9b42ae71a80 100644
--- a/src/vnet/ipsec/ipsec_test.c
+++ b/src/vnet/ipsec/ipsec_test.c
@@ -288,6 +288,18 @@ api_ipsec_sad_entry_del (vat_main_t *vat)
return -1;
}
+static int
+api_ipsec_sad_bind (vat_main_t *vat)
+{
+ return -1;
+}
+
+static int
+api_ipsec_sad_unbind (vat_main_t *vat)
+{
+ return -1;
+}
+
static void
vl_api_ipsec_sad_entry_add_del_v2_reply_t_handler (
vl_api_ipsec_sad_entry_add_del_v2_reply_t *mp)
@@ -434,6 +446,17 @@ api_ipsec_sa_dump (vat_main_t *vam)
}
static void
+vl_api_ipsec_sa_v4_details_t_handler (vl_api_ipsec_sa_v4_details_t *mp)
+{
+}
+
+static int
+api_ipsec_sa_v4_dump (vat_main_t *mp)
+{
+ return -1;
+}
+
+static void
vl_api_ipsec_sa_details_t_handler (vl_api_ipsec_sa_details_t *mp)
{
vat_main_t *vam = &vat_main;
diff --git a/test/test_ipsec_api.py b/test/test_ipsec_api.py
index 9c62c87e16d..521762b8181 100644
--- a/test/test_ipsec_api.py
+++ b/test/test_ipsec_api.py
@@ -4,10 +4,14 @@ from framework import VppTestCase, VppTestRunner
from template_ipsec import TemplateIpsec, IPsecIPv4Params
from vpp_papi import VppEnum
+from vpp_ipsec import VppIpsecSA
+
class IpsecApiTestCase(VppTestCase):
"""IPSec API tests"""
+ vpp_worker_count = 2
+
@classmethod
def setUpClass(cls):
super(IpsecApiTestCase, cls).setUpClass()
@@ -115,6 +119,40 @@ class IpsecApiTestCase(VppTestCase):
)
self.vapi.ipsec_select_backend(protocol=self.vpp_ah_protocol, index=0)
+ def __check_sa_binding(self, sa_id, thread_index):
+ found_sa = False
+ sa_dumps = self.vapi.ipsec_sa_v4_dump()
+ for dump in sa_dumps:
+ if dump.entry.sad_id == sa_id:
+ self.assertEqual(dump.thread_index, thread_index)
+ found_sa = True
+ break
+
+ if not found_sa:
+ self.fail("SA not found in VPP")
+
+ def test_sa_worker_bind(self):
+ """Bind an SA to a worker"""
+ sa = VppIpsecSA(
+ self,
+ self.ipv4_params.scapy_tun_sa_id,
+ self.ipv4_params.scapy_tun_spi,
+ self.ipv4_params.auth_algo_vpp_id,
+ self.ipv4_params.auth_key,
+ self.ipv4_params.crypt_algo_vpp_id,
+ self.ipv4_params.crypt_key,
+ VppEnum.vl_api_ipsec_proto_t.IPSEC_API_PROTO_ESP,
+ )
+ sa.add_vpp_config()
+
+ self.__check_sa_binding(sa.id, 0xFFFF)
+
+ self.vapi.ipsec_sad_bind(sa_id=sa.id, worker=1)
+
+ self.__check_sa_binding(sa.id, 2)
+
+ sa.remove_vpp_config()
+
if __name__ == "__main__":
unittest.main(testRunner=VppTestRunner)