diff options
Diffstat (limited to 'vnet/vnet/ipsec')
-rw-r--r-- | vnet/vnet/ipsec/esp_decrypt.c | 14 | ||||
-rw-r--r-- | vnet/vnet/ipsec/esp_encrypt.c | 33 | ||||
-rw-r--r-- | vnet/vnet/ipsec/ipsec.c | 19 | ||||
-rw-r--r-- | vnet/vnet/ipsec/ipsec.h | 15 | ||||
-rw-r--r-- | vnet/vnet/ipsec/ipsec_cli.c | 2 | ||||
-rw-r--r-- | vnet/vnet/ipsec/ipsec_if.c | 62 | ||||
-rw-r--r-- | vnet/vnet/ipsec/ipsec_if_in.c | 2 | ||||
-rw-r--r-- | vnet/vnet/ipsec/ipsec_input.c | 10 |
8 files changed, 136 insertions, 21 deletions
diff --git a/vnet/vnet/ipsec/esp_decrypt.c b/vnet/vnet/ipsec/esp_decrypt.c index c350508917b..6c7f27f078c 100644 --- a/vnet/vnet/ipsec/esp_decrypt.c +++ b/vnet/vnet/ipsec/esp_decrypt.c @@ -27,7 +27,8 @@ #define foreach_esp_decrypt_next \ _(DROP, "error-drop") \ _(IP4_INPUT, "ip4-input") \ -_(IP6_INPUT, "ip6-input") +_(IP6_INPUT, "ip6-input") \ +_(IPSEC_GRE_INPUT, "ipsec-gre-input") #define _(v, s) ESP_DECRYPT_NEXT_##v, typedef enum @@ -421,7 +422,10 @@ esp_decrypt_node_fn (vlib_main_t * vm, if (PREDICT_TRUE (tunnel_mode)) { if (PREDICT_TRUE (f0->next_header == IP_PROTOCOL_IP_IN_IP)) - next0 = ESP_DECRYPT_NEXT_IP4_INPUT; + { + next0 = ESP_DECRYPT_NEXT_IP4_INPUT; + oh4 = vlib_buffer_get_current (o_b0); + } else if (f0->next_header == IP_PROTOCOL_IPV6) next0 = ESP_DECRYPT_NEXT_IP6_INPUT; else @@ -471,6 +475,12 @@ esp_decrypt_node_fn (vlib_main_t * vm, } } + /* for IPSec-GRE tunnel next node is ipsec-gre-input */ + if (PREDICT_FALSE + ((vnet_buffer (i_b0)->output_features.ipsec_flags) & + IPSEC_FLAG_IPSEC_GRE_TUNNEL)) + next0 = ESP_DECRYPT_NEXT_IPSEC_GRE_INPUT; + to_next[0] = o_bi0; to_next += 1; diff --git a/vnet/vnet/ipsec/esp_encrypt.c b/vnet/vnet/ipsec/esp_encrypt.c index 45b4b3bb72b..0516d43f09b 100644 --- a/vnet/vnet/ipsec/esp_encrypt.c +++ b/vnet/vnet/ipsec/esp_encrypt.c @@ -248,6 +248,8 @@ esp_encrypt_node_fn (vlib_main_t * vm, oh6_0->esp.spi = clib_net_to_host_u32 (sa0->spi); oh6_0->esp.seq = clib_net_to_host_u32 (sa0->seq); ip_proto = ih6_0->ip6.protocol; + + next0 = ESP_ENCRYPT_NEXT_IP6_INPUT; } else { @@ -268,6 +270,8 @@ esp_encrypt_node_fn (vlib_main_t * vm, oh0->esp.spi = clib_net_to_host_u32 (sa0->spi); oh0->esp.seq = clib_net_to_host_u32 (sa0->seq); ip_proto = ih0->ip4.protocol; + + next0 = ESP_ENCRYPT_NEXT_IP4_INPUT; } if (PREDICT_TRUE @@ -276,8 +280,6 @@ esp_encrypt_node_fn (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; - /* in tunnel mode send it back to FIB */ - next0 = ESP_ENCRYPT_NEXT_IP4_INPUT; vnet_buffer (o_b0)->sw_if_index[VLIB_TX] = (u32) ~ 0; } else if (is_ipv6 && sa0->is_tunnel && sa0->is_tunnel_ip6) @@ -291,25 +293,26 @@ esp_encrypt_node_fn (vlib_main_t * vm, oh6_0->ip6.dst_address.as_u64[1] = sa0->tunnel_dst_addr.ip6.as_u64[1]; - /* in tunnel mode send it back to FIB */ - next0 = ESP_ENCRYPT_NEXT_IP6_INPUT; vnet_buffer (o_b0)->sw_if_index[VLIB_TX] = (u32) ~ 0; } else { - transport_mode = 1; - ethernet_header_t *ieh0, *oeh0; - ieh0 = (ethernet_header_t *) i_b0->data; - oeh0 = (ethernet_header_t *) o_b0->data; - clib_memcpy (oeh0, ieh0, sizeof (ethernet_header_t)); vlib_buffer_advance (i_b0, ip_hdr_size); next_hdr_type = ip_proto; - next0 = ESP_ENCRYPT_NEXT_INTERFACE_OUTPUT; - o_b0->flags |= BUFFER_OUTPUT_FEAT_DONE; - vnet_buffer (o_b0)->sw_if_index[VLIB_TX] = - vnet_buffer (i_b0)->sw_if_index[VLIB_TX]; - vnet_buffer (o_b0)->output_features.bitmap = - vnet_buffer (i_b0)->output_features.bitmap; + if (vnet_buffer (i_b0)->sw_if_index[VLIB_TX] != ~0) + { + transport_mode = 1; + ethernet_header_t *ieh0, *oeh0; + ieh0 = (ethernet_header_t *) i_b0->data; + oeh0 = (ethernet_header_t *) o_b0->data; + clib_memcpy (oeh0, ieh0, sizeof (ethernet_header_t)); + next0 = ESP_ENCRYPT_NEXT_INTERFACE_OUTPUT; + o_b0->flags |= BUFFER_OUTPUT_FEAT_DONE; + vnet_buffer (o_b0)->sw_if_index[VLIB_TX] = + vnet_buffer (i_b0)->sw_if_index[VLIB_TX]; + vnet_buffer (o_b0)->output_features.bitmap = + vnet_buffer (i_b0)->output_features.bitmap; + } } ASSERT (sa0->crypto_alg < IPSEC_CRYPTO_N_ALG); diff --git a/vnet/vnet/ipsec/ipsec.c b/vnet/vnet/ipsec/ipsec.c index bf9dd973f86..1b3b9ffcc38 100644 --- a/vnet/vnet/ipsec/ipsec.c +++ b/vnet/vnet/ipsec/ipsec.c @@ -24,6 +24,17 @@ #include <vnet/ipsec/esp.h> #include <vnet/ipsec/ikev2.h> +u32 +ipsec_get_sa_index_by_sa_id (u32 sa_id) +{ + ipsec_main_t *im = &ipsec_main; + uword *p = hash_get (im->sa_index_by_sa_id, sa_id); + if (!p) + return ~0; + + return p[0]; +} + int ipsec_set_interface_spd (vlib_main_t * vm, u32 sw_if_index, u32 spd_id, int is_add) @@ -391,6 +402,7 @@ ipsec_is_sa_used (u32 sa_index) ipsec_main_t *im = &ipsec_main; ipsec_spd_t *spd; ipsec_policy_t *p; + ipsec_tunnel_if_t *t; /* *INDENT-OFF* */ pool_foreach(spd, im->spds, ({ @@ -402,6 +414,13 @@ ipsec_is_sa_used (u32 sa_index) } })); })); + + pool_foreach(t, im->tunnel_interfaces, ({ + if (t->input_sa_index == sa_index) + return 1; + if (t->output_sa_index == sa_index) + return 1; + })); /* *INDENT-ON* */ return 0; diff --git a/vnet/vnet/ipsec/ipsec.h b/vnet/vnet/ipsec/ipsec.h index 5b88c8278fb..fd3e8a361d1 100644 --- a/vnet/vnet/ipsec/ipsec.h +++ b/vnet/vnet/ipsec/ipsec.h @@ -16,6 +16,8 @@ #include <vnet/devices/dpdk/dpdk.h> #endif +#define IPSEC_FLAG_IPSEC_GRE_TUNNEL (1 << 0) + #define foreach_ipsec_policy_action \ _(0, BYPASS, "bypass") \ _(1, DISCARD, "discard") \ @@ -127,6 +129,15 @@ typedef struct u8 remote_integ_key[128]; } ipsec_add_del_tunnel_args_t; +typedef struct +{ + u8 is_add; + u32 local_sa_id; + u32 remote_sa_id; + ip4_address_t local_ip; + ip4_address_t remote_ip; +} ipsec_add_del_ipsec_gre_tunnel_args_t; + typedef enum { IPSEC_IF_SET_KEY_TYPE_NONE, @@ -243,6 +254,7 @@ int ipsec_add_del_policy (vlib_main_t * vm, ipsec_policy_t * policy, int ipsec_add_del_sa (vlib_main_t * vm, ipsec_sa_t * new_sa, int is_add); int ipsec_set_sa_key (vlib_main_t * vm, ipsec_sa_t * sa_update); +u32 ipsec_get_sa_index_by_sa_id (u32 sa_id); u8 *format_ipsec_if_output_trace (u8 * s, va_list * args); u8 *format_ipsec_policy_action (u8 * s, va_list * args); u8 *format_ipsec_crypto_alg (u8 * s, va_list * args); @@ -254,6 +266,9 @@ uword unformat_ipsec_integ_alg (unformat_input_t * input, va_list * args); /*u32 ipsec_add_del_tunnel_if (vnet_main_t * vnm, ipsec_add_del_tunnel_args_t * args); */ int ipsec_add_del_tunnel_if (ipsec_add_del_tunnel_args_t * args); +int ipsec_add_del_ipsec_gre_tunnel (vnet_main_t * vnm, + ipsec_add_del_ipsec_gre_tunnel_args_t * + args); int ipsec_set_interface_key (vnet_main_t * vnm, u32 hw_if_index, ipsec_if_set_key_type_t type, u8 alg, u8 * key); diff --git a/vnet/vnet/ipsec/ipsec_cli.c b/vnet/vnet/ipsec/ipsec_cli.c index 8b15110af0d..785e040b006 100644 --- a/vnet/vnet/ipsec/ipsec_cli.c +++ b/vnet/vnet/ipsec/ipsec_cli.c @@ -561,6 +561,8 @@ show_ipsec_command_fn (vlib_main_t * vm, vlib_cli_output (vm, "tunnel interfaces"); /* *INDENT-OFF* */ pool_foreach (t, im->tunnel_interfaces, ({ + if (t->hw_if_index == ~0) + continue; 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); diff --git a/vnet/vnet/ipsec/ipsec_if.c b/vnet/vnet/ipsec/ipsec_if.c index 475b7bda2bc..f4fad8d95b3 100644 --- a/vnet/vnet/ipsec/ipsec_if.c +++ b/vnet/vnet/ipsec/ipsec_if.c @@ -195,6 +195,68 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm, } int +ipsec_add_del_ipsec_gre_tunnel (vnet_main_t * vnm, + ipsec_add_del_ipsec_gre_tunnel_args_t * args) +{ + ipsec_tunnel_if_t *t = 0; + ipsec_main_t *im = &ipsec_main; + uword *p; + ipsec_sa_t *sa; + u64 key; + u32 isa, osa; + + p = hash_get (im->sa_index_by_sa_id, args->local_sa_id); + if (!p) + return VNET_API_ERROR_INVALID_VALUE; + isa = p[0]; + + p = hash_get (im->sa_index_by_sa_id, args->remote_sa_id); + if (!p) + return VNET_API_ERROR_INVALID_VALUE; + osa = p[0]; + sa = pool_elt_at_index (im->sad, p[0]); + + if (sa->is_tunnel) + key = (u64) sa->tunnel_dst_addr.ip4.as_u32 << 32 | (u64) sa->spi; + else + key = (u64) args->remote_ip.as_u32 << 32 | (u64) sa->spi; + + p = hash_get (im->ipsec_if_pool_index_by_key, key); + + if (args->is_add) + { + /* check if same src/dst pair exists */ + if (p) + return VNET_API_ERROR_INVALID_VALUE; + + pool_get_aligned (im->tunnel_interfaces, t, CLIB_CACHE_LINE_BYTES); + memset (t, 0, sizeof (*t)); + + t->input_sa_index = isa; + t->output_sa_index = osa; + t->hw_if_index = ~0; + hash_set (im->ipsec_if_pool_index_by_key, key, + t - im->tunnel_interfaces); + + /*1st interface, register protocol */ + if (pool_elts (im->tunnel_interfaces) == 1) + ip4_register_protocol (IP_PROTOCOL_IPSEC_ESP, + ipsec_if_input_node.index); + } + else + { + /* check if exists */ + if (!p) + return VNET_API_ERROR_INVALID_VALUE; + + t = pool_elt_at_index (im->tunnel_interfaces, p[0]); + hash_unset (im->ipsec_if_pool_index_by_key, key); + pool_put (im->tunnel_interfaces, t); + } + return 0; +} + +int ipsec_set_interface_key (vnet_main_t * vnm, u32 hw_if_index, ipsec_if_set_key_type_t type, u8 alg, u8 * key) { diff --git a/vnet/vnet/ipsec/ipsec_if_in.c b/vnet/vnet/ipsec/ipsec_if_in.c index e5574421cfa..07d4bf30352 100644 --- a/vnet/vnet/ipsec/ipsec_if_in.c +++ b/vnet/vnet/ipsec/ipsec_if_in.c @@ -113,6 +113,8 @@ ipsec_if_input_node_fn (vlib_main_t * vm, vlib_node_runtime_t * node, t = pool_elt_at_index (im->tunnel_interfaces, p[0]); vnet_buffer (b0)->output_features.ipsec_sad_index = t->input_sa_index; + vnet_buffer (b0)->output_features.ipsec_flags = + t->hw_if_index == ~0 ? IPSEC_FLAG_IPSEC_GRE_TUNNEL : 0; vlib_buffer_advance (b0, ip4_header_bytes (ip0)); next0 = IPSEC_IF_INPUT_NEXT_ESP_DECRYPT; } diff --git a/vnet/vnet/ipsec/ipsec_input.c b/vnet/vnet/ipsec/ipsec_input.c index 2bc4e2b4999..8364e226ae1 100644 --- a/vnet/vnet/ipsec/ipsec_input.c +++ b/vnet/vnet/ipsec/ipsec_input.c @@ -239,11 +239,11 @@ ipsec_input_ip4_node_fn (vlib_main_t * vm, ipsec_policy_t *p0; p0 = ipsec_input_protect_policy_match (spd0, clib_net_to_host_u32 - (ip0->src_address. - as_u32), + (ip0-> + src_address.as_u32), clib_net_to_host_u32 - (ip0->dst_address. - as_u32), + (ip0-> + dst_address.as_u32), clib_net_to_host_u32 (esp0->spi)); @@ -253,6 +253,7 @@ ipsec_input_ip4_node_fn (vlib_main_t * vm, p0->counter.bytes += clib_net_to_host_u16 (ip0->length); vnet_buffer (b0)->output_features.ipsec_sad_index = p0->sa_index; + vnet_buffer (b0)->output_features.ipsec_flags = 0; next0 = IPSEC_INPUT_NEXT_ESP_DECRYPT; vlib_buffer_advance (b0, ip4_header_bytes (ip0)); goto trace0; @@ -382,6 +383,7 @@ VLIB_NODE_FUNCTION_MULTIARCH (ipsec_input_ip4_node, ipsec_input_ip4_node_fn) p0->counter.bytes += header_size; vnet_buffer (b0)->output_features.ipsec_sad_index = p0->sa_index; + vnet_buffer (b0)->output_features.ipsec_flags = 0; next0 = IPSEC_INPUT_NEXT_ESP_DECRYPT; vlib_buffer_advance (b0, header_size); goto trace0; |