From 4c422f9a3c9d5a4ecae3f4ef6bee16bb8ce35bb2 Mon Sep 17 00:00:00 2001 From: Pierre Pfister Date: Mon, 10 Dec 2018 11:19:08 +0100 Subject: [PATCH] Add IPSec interface FIB index for TX packet This patch adds a configuration parameter to IPSec tunnels, enabling custom FIB selection for encapsulated packets. Although this option could also be used for policy-based IPSec, this change only enables it for virtual-tunnel-interface mode. Note that this patch does change the API default behavior regarding TX fib selection for encapsulated packets. Previous behavior was to use the same FIB after and before encap. The new default behavior consists in using the FIB 0 as default. Change-Id: I5c212af909940a8cf6c7e3971bdc7623a2296452 Signed-off-by: Pierre Pfister --- src/vnet/ipsec/esp_encrypt.c | 4 ++-- src/vnet/ipsec/ipsec.api | 7 ++++++- src/vnet/ipsec/ipsec.h | 2 ++ src/vnet/ipsec/ipsec_api.c | 5 +++++ src/vnet/ipsec/ipsec_cli.c | 16 +++++++++++++--- src/vnet/ipsec/ipsec_if.c | 8 ++++++++ 6 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/vnet/ipsec/esp_encrypt.c b/src/vnet/ipsec/esp_encrypt.c index ff9c1e63097..16f985c6cfe 100644 --- a/src/vnet/ipsec/esp_encrypt.c +++ b/src/vnet/ipsec/esp_encrypt.c @@ -279,7 +279,7 @@ esp_encrypt_inline (vlib_main_t * vm, oh0->ip4.src_address.as_u32 = sa0->tunnel_src_addr.ip4.as_u32; oh0->ip4.dst_address.as_u32 = sa0->tunnel_dst_addr.ip4.as_u32; - vnet_buffer (o_b0)->sw_if_index[VLIB_TX] = (u32) ~ 0; + vnet_buffer (o_b0)->sw_if_index[VLIB_TX] = sa0->tx_fib_index; } else if (is_ip6 && sa0->is_tunnel && sa0->is_tunnel_ip6) { @@ -292,7 +292,7 @@ esp_encrypt_inline (vlib_main_t * vm, oh6_0->ip6.dst_address.as_u64[1] = sa0->tunnel_dst_addr.ip6.as_u64[1]; - vnet_buffer (o_b0)->sw_if_index[VLIB_TX] = (u32) ~ 0; + vnet_buffer (o_b0)->sw_if_index[VLIB_TX] = sa0->tx_fib_index; } else { diff --git a/src/vnet/ipsec/ipsec.api b/src/vnet/ipsec/ipsec.api index 610f2325ebc..2b015f9c223 100644 --- a/src/vnet/ipsec/ipsec.api +++ b/src/vnet/ipsec/ipsec.api @@ -13,7 +13,7 @@ * limitations under the License. */ -option version = "2.0.0"; +option version = "2.1.0"; /** \brief IPsec: Add/delete Security Policy Database @param client_index - opaque cookie to identify the sender @@ -563,6 +563,7 @@ define ipsec_spd_interface_details { @param renumber - intf display name uses a specified instance if != 0 @param show_instance - instance to display for intf if renumber is set @param udp_encap - enable UDP encapsulation for NAT traversal + @param tx_table_id - the FIB id used after packet encap */ define ipsec_tunnel_if_add_del { u32 client_index; @@ -587,6 +588,7 @@ define ipsec_tunnel_if_add_del { u8 renumber; u32 show_instance; u8 udp_encap; + u32 tx_table_id; }; /** \brief Add/delete IPsec tunnel interface response @@ -637,6 +639,7 @@ define ipsec_sa_dump { @param replay_window - bit map of seq nums received relative to last_seq if using anti-replay @param total_data_size - total bytes sent or received @param udp_encap - 1 if UDP encap enabled, 0 otherwise + @param tx_table_id - the FIB id used for encapsulated packets */ define ipsec_sa_details { u32 context; @@ -669,6 +672,8 @@ define ipsec_sa_details { u64 total_data_size; u8 udp_encap; + + u32 tx_table_id; }; /** \brief Set key on IPsec interface diff --git a/src/vnet/ipsec/ipsec.h b/src/vnet/ipsec/ipsec.h index d40767001b8..691bc071bba 100644 --- a/src/vnet/ipsec/ipsec.h +++ b/src/vnet/ipsec/ipsec.h @@ -139,6 +139,7 @@ typedef struct ip46_address_t tunnel_src_addr; ip46_address_t tunnel_dst_addr; + u32 tx_fib_index; u32 salt; /* runtime */ @@ -183,6 +184,7 @@ typedef struct u8 renumber; u32 show_instance; u8 udp_encap; + u32 tx_table_id; } ipsec_add_del_tunnel_args_t; typedef struct diff --git a/src/vnet/ipsec/ipsec_api.c b/src/vnet/ipsec/ipsec_api.c index 3f30a7dc321..59fb868f878 100644 --- a/src/vnet/ipsec/ipsec_api.c +++ b/src/vnet/ipsec/ipsec_api.c @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -471,6 +472,7 @@ vl_api_ipsec_tunnel_if_add_del_t_handler (vl_api_ipsec_tunnel_if_add_del_t * tun.local_integ_key_len = mp->local_integ_key_len; tun.remote_integ_key_len = mp->remote_integ_key_len; tun.udp_encap = mp->udp_encap; + tun.tx_table_id = ntohl (mp->tx_table_id); memcpy (&tun.local_ip, mp->local_ip, 4); memcpy (&tun.remote_ip, mp->remote_ip, 4); memcpy (&tun.local_crypto_key, &mp->local_crypto_key, @@ -555,6 +557,9 @@ send_ipsec_sa_details (ipsec_sa_t * sa, vl_api_registration_t * reg, mp->total_data_size = clib_host_to_net_u64 (sa->total_data_size); mp->udp_encap = sa->udp_encap; + mp->tx_table_id = + htonl (fib_table_get_table_id (sa->tx_fib_index, FIB_PROTOCOL_IP4)); + vl_api_send_msg (reg, (u8 *) mp); } diff --git a/src/vnet/ipsec/ipsec_cli.c b/src/vnet/ipsec/ipsec_cli.c index f96551429af..f0717e91dd1 100644 --- a/src/vnet/ipsec/ipsec_cli.c +++ b/src/vnet/ipsec/ipsec_cli.c @@ -19,6 +19,7 @@ #include #include #include +#include #include @@ -80,6 +81,7 @@ ipsec_sa_add_del_command_fn (vlib_main_t * vm, clib_error_t *error = NULL; clib_memset (&sa, 0, sizeof (sa)); + sa.tx_fib_index = ~((u32) 0); /* Only supported for ipsec interfaces */ if (!unformat_user (input, unformat_line_input, line_input)) return 0; @@ -458,6 +460,7 @@ show_ipsec_command_fn (vlib_main_t * vm, vnet_hw_interface_t *hi; u8 *protocol = NULL; u8 *policy = NULL; + u32 tx_table_id; /* *INDENT-OFF* */ pool_foreach (sa, im->sad, ({ @@ -670,8 +673,11 @@ show_ipsec_command_fn (vlib_main_t * vm, hi = vnet_get_hw_interface (im->vnet_main, t->hw_if_index); vlib_cli_output(vm, " %s seq", hi->name); sa = pool_elt_at_index(im->sad, t->output_sa_index); - vlib_cli_output(vm, " seq %u seq-hi %u esn %u anti-replay %u udp-encap %u", - sa->seq, sa->seq_hi, sa->use_esn, sa->use_anti_replay, sa->udp_encap); + + tx_table_id = fib_table_get_table_id(sa->tx_fib_index, FIB_PROTOCOL_IP4); + + vlib_cli_output(vm, " seq %u seq-hi %u esn %u anti-replay %u udp-encap %u tx-table %u", + sa->seq, sa->seq_hi, sa->use_esn, sa->use_anti_replay, sa->udp_encap, tx_table_id); vlib_cli_output(vm, " local-spi %u local-ip %U", sa->spi, format_ip4_address, &sa->tunnel_src_addr.ip4); vlib_cli_output(vm, " local-crypto %U %U", @@ -910,6 +916,8 @@ create_ipsec_tunnel_command_fn (vlib_main_t * vm, a.is_add = 0; else if (unformat (line_input, "udp-encap")) a.udp_encap = 1; + else if (unformat (line_input, "tx-table %u", &a.tx_table_id)) + ; else { error = clib_error_return (0, "unknown input `%U'", @@ -952,7 +960,9 @@ done: /* *INDENT-OFF* */ VLIB_CLI_COMMAND (create_ipsec_tunnel_command, static) = { .path = "create ipsec tunnel", - .short_help = "create ipsec tunnel local-ip local-spi remote-ip remote-spi [instance ] [udp-encap]", + .short_help = "create ipsec tunnel local-ip local-spi " + "remote-ip remote-spi [instance ] [udp-encap] " + "[tx-table ]", .function = create_ipsec_tunnel_command_fn, }; /* *INDENT-ON* */ diff --git a/src/vnet/ipsec/ipsec_if.c b/src/vnet/ipsec/ipsec_if.c index 2e0dae0a35d..3054af16765 100644 --- a/src/vnet/ipsec/ipsec_if.c +++ b/src/vnet/ipsec/ipsec_if.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -262,6 +263,7 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm, ipsec_sa_t *sa; u32 dev_instance; u32 slot; + u32 tx_fib_index = ~0; u64 key = (u64) args->remote_ip.as_u32 << 32 | (u64) args->remote_spi; p = hash_get (im->ipsec_if_pool_index_by_key, key); @@ -272,6 +274,10 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm, if (p) return VNET_API_ERROR_INVALID_VALUE; + tx_fib_index = fib_table_find (FIB_PROTOCOL_IP4, args->tx_table_id); + if (tx_fib_index == ~((u32) 0)) + return VNET_API_ERROR_NO_SUCH_FIB; + pool_get_aligned (im->tunnel_interfaces, t, CLIB_CACHE_LINE_BYTES); clib_memset (t, 0, sizeof (*t)); @@ -301,6 +307,7 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm, sa->use_anti_replay = args->anti_replay; sa->integ_alg = args->integ_alg; sa->udp_encap = args->udp_encap; + sa->tx_fib_index = ~((u32) 0); /* Not used, but set for troubleshooting */ if (args->remote_integ_key_len <= sizeof (args->remote_integ_key)) { sa->integ_key_len = args->remote_integ_key_len; @@ -326,6 +333,7 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm, sa->use_anti_replay = args->anti_replay; sa->integ_alg = args->integ_alg; sa->udp_encap = args->udp_encap; + sa->tx_fib_index = tx_fib_index; if (args->local_integ_key_len <= sizeof (args->local_integ_key)) { sa->integ_key_len = args->local_integ_key_len; -- 2.16.6