From 1271e3a2a1b028e5b9cd7ca35a6bd06ddbe2c63b Mon Sep 17 00:00:00 2001 From: Maxime Peim Date: Mon, 20 Mar 2023 14:13:56 +0000 Subject: ipsec: manually binding an SA to a worker An SA is normally bound to the first thread using it. However, one could want to manually bind an SA to a specific worker. Type: improvement Signed-off-by: Maxime Peim Change-Id: I05cbbf753e44a01d9964ee47812c964db9bbb488 --- src/vnet/ipsec/ipsec.api | 41 ++++++++++++++++ src/vnet/ipsec/ipsec_api.c | 111 ++++++++++++++++++++++++++++++++++++++++++++ src/vnet/ipsec/ipsec_cli.c | 65 ++++++++++++++++++++++++++ src/vnet/ipsec/ipsec_sa.c | 37 ++++++++++++--- src/vnet/ipsec/ipsec_sa.h | 1 + src/vnet/ipsec/ipsec_test.c | 23 +++++++++ 6 files changed, 272 insertions(+), 6 deletions(-) (limited to 'src/vnet/ipsec') 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 @@ -592,6 +592,36 @@ out: REPLY_MACRO (VL_API_IPSEC_SAD_ENTRY_UPDATE_REPLY); } +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 @@ -211,6 +211,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] ", + .function = ipsec_sa_bind_cli, +}; + static clib_error_t * ipsec_spd_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, 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) @@ -433,6 +445,17 @@ api_ipsec_sa_dump (vat_main_t *vam) return ret; } +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) { -- cgit 1.2.3-korg