diff options
Diffstat (limited to 'src/vnet/ipsec')
-rw-r--r-- | src/vnet/ipsec/ah_decrypt.c | 6 | ||||
-rw-r--r-- | src/vnet/ipsec/ah_encrypt.c | 21 | ||||
-rw-r--r-- | src/vnet/ipsec/esp_decrypt.c | 7 | ||||
-rw-r--r-- | src/vnet/ipsec/esp_encrypt.c | 30 | ||||
-rw-r--r-- | src/vnet/ipsec/ikev2.c | 16 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec.api | 33 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_api.c | 224 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_cli.c | 244 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_format.c | 72 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_if.c | 147 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_if.h | 2 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_if_in.c | 12 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_sa.c | 274 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_sa.h | 68 |
14 files changed, 713 insertions, 443 deletions
diff --git a/src/vnet/ipsec/ah_decrypt.c b/src/vnet/ipsec/ah_decrypt.c index c8c89028f9d..7d2bf814fcc 100644 --- a/src/vnet/ipsec/ah_decrypt.c +++ b/src/vnet/ipsec/ah_decrypt.c @@ -200,9 +200,9 @@ ah_decrypt_inline (vlib_main_t * vm, icv_padding_len = ah_calc_icv_padding_len (icv_size, 0 /* is_ipv6 */ ); } - hmac_calc (sa0->integ_alg, sa0->integ_key, sa0->integ_key_len, - (u8 *) ih4, i_b0->current_length, sig, sa0->use_esn, - sa0->seq_hi); + hmac_calc (sa0->integ_alg, sa0->integ_key.data, + sa0->integ_key.len, (u8 *) ih4, i_b0->current_length, + sig, sa0->use_esn, sa0->seq_hi); if (PREDICT_FALSE (memcmp (digest, sig, icv_size))) { diff --git a/src/vnet/ipsec/ah_encrypt.c b/src/vnet/ipsec/ah_encrypt.c index 8b0c14f0cf3..66286094682 100644 --- a/src/vnet/ipsec/ah_encrypt.c +++ b/src/vnet/ipsec/ah_encrypt.c @@ -59,6 +59,7 @@ static char *ah_encrypt_error_strings[] = { typedef struct { + u32 sa_index; u32 spi; u32 seq; ipsec_integ_alg_t integ_alg; @@ -72,8 +73,9 @@ format_ah_encrypt_trace (u8 * s, va_list * args) CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); ah_encrypt_trace_t *t = va_arg (*args, ah_encrypt_trace_t *); - s = format (s, "ah: spi %u seq %u integrity %U", - t->spi, t->seq, format_ipsec_integ_alg, t->integ_alg); + s = format (s, "ah: sa-index %d spi %u seq %u integrity %U", + t->sa_index, t->spi, t->seq, + format_ipsec_integ_alg, t->integ_alg); return s; } @@ -237,8 +239,9 @@ ah_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; - next0 = AH_ENCRYPT_NEXT_IP4_LOOKUP; - vnet_buffer (i_b0)->sw_if_index[VLIB_TX] = (u32) ~ 0; + next0 = sa0->dpo[IPSEC_PROTOCOL_AH].dpoi_next_node; + vnet_buffer (i_b0)->ip.adj_index[VLIB_TX] = + sa0->dpo[IPSEC_PROTOCOL_AH].dpoi_index; } else if (is_ip6 && sa0->is_tunnel && sa0->is_tunnel_ip6) { @@ -251,8 +254,9 @@ ah_encrypt_inline (vlib_main_t * vm, oh6_0->ip6.dst_address.as_u64[1] = sa0->tunnel_dst_addr.ip6.as_u64[1]; - next0 = AH_ENCRYPT_NEXT_IP6_LOOKUP; - vnet_buffer (i_b0)->sw_if_index[VLIB_TX] = (u32) ~ 0; + next0 = sa0->dpo[IPSEC_PROTOCOL_AH].dpoi_next_node; + vnet_buffer (i_b0)->ip.adj_index[VLIB_TX] = + sa0->dpo[IPSEC_PROTOCOL_AH].dpoi_index; } u8 sig[64]; @@ -262,8 +266,8 @@ ah_encrypt_inline (vlib_main_t * vm, sizeof (ah_header_t); clib_memset (digest, 0, icv_size); - unsigned size = hmac_calc (sa0->integ_alg, sa0->integ_key, - sa0->integ_key_len, + unsigned size = hmac_calc (sa0->integ_alg, sa0->integ_key.data, + sa0->integ_key.len, vlib_buffer_get_current (i_b0), i_b0->current_length, sig, sa0->use_esn, sa0->seq_hi); @@ -297,6 +301,7 @@ ah_encrypt_inline (vlib_main_t * vm, tr->spi = sa0->spi; tr->seq = sa0->seq - 1; tr->integ_alg = sa0->integ_alg; + tr->sa_index = sa_index0; } vlib_validate_buffer_enqueue_x1 (vm, node, next_index, diff --git a/src/vnet/ipsec/esp_decrypt.c b/src/vnet/ipsec/esp_decrypt.c index 3f463505e01..5a3ccdcacd9 100644 --- a/src/vnet/ipsec/esp_decrypt.c +++ b/src/vnet/ipsec/esp_decrypt.c @@ -206,8 +206,9 @@ esp_decrypt_inline (vlib_main_t * vm, icv_size; i_b0->current_length -= icv_size; - hmac_calc (sa0->integ_alg, sa0->integ_key, sa0->integ_key_len, - (u8 *) esp0, i_b0->current_length, sig, sa0->use_esn, + hmac_calc (sa0->integ_alg, sa0->integ_key.data, + sa0->integ_key.len, (u8 *) esp0, + i_b0->current_length, sig, sa0->use_esn, sa0->seq_hi); if (PREDICT_FALSE (memcmp (icv, sig, icv_size))) @@ -299,7 +300,7 @@ esp_decrypt_inline (vlib_main_t * vm, esp0->data + IV_SIZE, (u8 *) vlib_buffer_get_current (o_b0) + ip_hdr_size, BLOCK_SIZE * blocks, - sa0->crypto_key, esp0->data); + sa0->crypto_key.data, esp0->data); o_b0->current_length = (blocks * BLOCK_SIZE) - 2 + ip_hdr_size; o_b0->flags = VLIB_BUFFER_TOTAL_LENGTH_VALID; diff --git a/src/vnet/ipsec/esp_encrypt.c b/src/vnet/ipsec/esp_encrypt.c index 16f985c6cfe..4b325e08b5f 100644 --- a/src/vnet/ipsec/esp_encrypt.c +++ b/src/vnet/ipsec/esp_encrypt.c @@ -62,6 +62,7 @@ static char *esp_encrypt_error_strings[] = { typedef struct { + u32 sa_index; u32 spi; u32 seq; u8 udp_encap; @@ -77,8 +78,8 @@ format_esp_encrypt_trace (u8 * s, va_list * args) CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); esp_encrypt_trace_t *t = va_arg (*args, esp_encrypt_trace_t *); - s = format (s, "esp: spi %u seq %u crypto %U integrity %U%s", - t->spi, t->seq, + s = format (s, "esp: sa-index %d spi %u seq %u crypto %U integrity %U%s", + t->sa_index, t->spi, t->seq, format_ipsec_crypto_alg, t->crypto_alg, format_ipsec_integ_alg, t->integ_alg, t->udp_encap ? " udp-encap-enabled" : ""); @@ -279,7 +280,9 @@ 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] = sa0->tx_fib_index; + next0 = sa0->dpo[IPSEC_PROTOCOL_ESP].dpoi_next_node; + vnet_buffer (o_b0)->ip.adj_index[VLIB_TX] = + sa0->dpo[IPSEC_PROTOCOL_ESP].dpoi_index; } else if (is_ip6 && sa0->is_tunnel && sa0->is_tunnel_ip6) { @@ -292,7 +295,9 @@ 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] = sa0->tx_fib_index; + next0 = sa0->dpo[IPSEC_PROTOCOL_ESP].dpoi_next_node; + vnet_buffer (o_b0)->ip.adj_index[VLIB_TX] = + sa0->dpo[IPSEC_PROTOCOL_ESP].dpoi_index; } else { @@ -367,17 +372,15 @@ esp_encrypt_inline (vlib_main_t * vm, (u8 *) vlib_buffer_get_current (o_b0) + ip_udp_hdr_size + sizeof (esp_header_t) + IV_SIZE, BLOCK_SIZE * blocks, - sa0->crypto_key, iv); + sa0->crypto_key.data, iv); } - o_b0->current_length += hmac_calc (sa0->integ_alg, sa0->integ_key, - sa0->integ_key_len, - (u8 *) o_esp0, - o_b0->current_length - - ip_udp_hdr_size, - vlib_buffer_get_current (o_b0) + - o_b0->current_length, - sa0->use_esn, sa0->seq_hi); + o_b0->current_length += + hmac_calc (sa0->integ_alg, sa0->integ_key.data, + sa0->integ_key.len, (u8 *) o_esp0, + o_b0->current_length - ip_udp_hdr_size, + vlib_buffer_get_current (o_b0) + o_b0->current_length, + sa0->use_esn, sa0->seq_hi); if (is_ip6) @@ -412,6 +415,7 @@ esp_encrypt_inline (vlib_main_t * vm, o_b0->trace_index = i_b0->trace_index; esp_encrypt_trace_t *tr = vlib_add_trace (vm, node, o_b0, sizeof (*tr)); + tr->sa_index = sa_index0; tr->spi = sa0->spi; tr->seq = sa0->seq - 1; tr->udp_encap = sa0->udp_encap; diff --git a/src/vnet/ipsec/ikev2.c b/src/vnet/ipsec/ikev2.c index 80497f20807..3d5c0f766cf 100644 --- a/src/vnet/ipsec/ikev2.c +++ b/src/vnet/ipsec/ikev2.c @@ -1492,16 +1492,16 @@ ikev2_create_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa, a.is_add = 1; if (sa->is_initiator) { - a.local_ip.as_u32 = sa->iaddr.as_u32; - a.remote_ip.as_u32 = sa->raddr.as_u32; + a.local_ip.ip4.as_u32 = sa->iaddr.as_u32; + a.remote_ip.ip4.as_u32 = sa->raddr.as_u32; proposals = child->i_proposals; a.local_spi = child->r_proposals[0].spi; a.remote_spi = child->i_proposals[0].spi; } else { - a.local_ip.as_u32 = sa->raddr.as_u32; - a.remote_ip.as_u32 = sa->iaddr.as_u32; + a.local_ip.ip4.as_u32 = sa->raddr.as_u32; + a.remote_ip.ip4.as_u32 = sa->iaddr.as_u32; proposals = child->r_proposals; a.local_spi = child->i_proposals[0].spi; a.remote_spi = child->r_proposals[0].spi; @@ -1642,8 +1642,8 @@ ikev2_delete_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa, return 0; a.is_add = 0; - a.local_ip.as_u32 = sa->iaddr.as_u32; - a.remote_ip.as_u32 = sa->raddr.as_u32; + a.local_ip.ip4.as_u32 = sa->iaddr.as_u32; + a.remote_ip.ip4.as_u32 = sa->raddr.as_u32; a.local_spi = child->r_proposals[0].spi; a.remote_spi = child->i_proposals[0].spi; } @@ -1653,8 +1653,8 @@ ikev2_delete_tunnel_interface (vnet_main_t * vnm, ikev2_sa_t * sa, return 0; a.is_add = 0; - a.local_ip.as_u32 = sa->raddr.as_u32; - a.remote_ip.as_u32 = sa->iaddr.as_u32; + a.local_ip.ip4.as_u32 = sa->raddr.as_u32; + a.remote_ip.ip4.as_u32 = sa->iaddr.as_u32; a.local_spi = child->i_proposals[0].spi; a.remote_spi = child->r_proposals[0].spi; } diff --git a/src/vnet/ipsec/ipsec.api b/src/vnet/ipsec/ipsec.api index 54cc76bb9d6..ece0b024485 100644 --- a/src/vnet/ipsec/ipsec.api +++ b/src/vnet/ipsec/ipsec.api @@ -232,6 +232,10 @@ enum ipsec_sad_flags IPSEC_API_SAD_FLAG_IS_TUNNEL_V6 = 0x08, /* enable UDP encapsulation for NAT traversal */ IPSEC_API_SAD_FLAG_UDP_ENCAP = 0x10, + + /* come-on Ole please fix this */ + IPSEC_API_SAD_COMBO_12 = 12, + IPSEC_API_SAD_COMBO_20 = 20, }; enum ipsec_proto @@ -261,6 +265,7 @@ typedef key @param integrity_key - integrity keying material @param tunnel_src_address - IPsec tunnel source address IPv6 if is_tunnel_ipv6 is non-zero, else IPv4. Only valid if is_tunnel is non-zero @param tunnel_dst_address - IPsec tunnel destination address IPv6 if is_tunnel_ipv6 is non-zero, else IPv4. Only valid if is_tunnel is non-zero + @param tx_table_id - the FIB id used for encapsulated packets */ typedef ipsec_sad_entry { @@ -280,6 +285,7 @@ typedef ipsec_sad_entry vl_api_address_t tunnel_src; vl_api_address_t tunnel_dst; + u32 tx_table_id; }; /** \brief IPsec: Add/delete Security Association Database entry @@ -687,41 +693,18 @@ 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; - u32 sa_id; - u32 sw_if_index; - - u32 spi; - u8 protocol; - - u8 crypto_alg; - u8 crypto_key_len; - u8 crypto_key[128]; - - u8 integ_alg; - u8 integ_key_len; - u8 integ_key[128]; - - u8 use_esn; - u8 use_anti_replay; - - u8 is_tunnel; - u8 is_tunnel_ip6; - u8 tunnel_src_addr[16]; - u8 tunnel_dst_addr[16]; + vl_api_ipsec_sad_entry_t entry; + u32 sw_if_index; u32 salt; u64 seq_outbound; u64 last_seq_inbound; u64 replay_window; u64 total_data_size; - u8 udp_encap; - - u32 tx_table_id; }; /** \brief Set key on IPsec interface diff --git a/src/vnet/ipsec/ipsec_api.c b/src/vnet/ipsec/ipsec_api.c index 06f954622c7..2d464b31290 100644 --- a/src/vnet/ipsec/ipsec_api.c +++ b/src/vnet/ipsec/ipsec_api.c @@ -217,6 +217,19 @@ ipsec_proto_decode (vl_api_ipsec_proto_t in, ipsec_protocol_t * out) return (VNET_API_ERROR_UNIMPLEMENTED); } +static vl_api_ipsec_proto_t +ipsec_proto_encode (ipsec_protocol_t p) +{ + switch (p) + { + case IPSEC_PROTOCOL_ESP: + return clib_host_to_net_u32 (IPSEC_API_PROTO_ESP); + case IPSEC_PROTOCOL_AH: + return clib_host_to_net_u32 (IPSEC_API_PROTO_AH); + } + return (VNET_API_ERROR_UNIMPLEMENTED); +} + static int ipsec_crypto_algo_decode (vl_api_ipsec_crypto_alg_t in, ipsec_crypto_alg_t * out) @@ -234,6 +247,23 @@ ipsec_crypto_algo_decode (vl_api_ipsec_crypto_alg_t in, return (VNET_API_ERROR_UNIMPLEMENTED); } +static vl_api_ipsec_crypto_alg_t +ipsec_crypto_algo_encode (ipsec_crypto_alg_t c) +{ + switch (c) + { +#define _(v,f,s) case IPSEC_CRYPTO_ALG_##f: \ + return clib_host_to_net_u32(IPSEC_API_CRYPTO_ALG_##f); + foreach_ipsec_crypto_alg +#undef _ + case IPSEC_CRYPTO_N_ALG: + break; + } + ASSERT (0); + return (VNET_API_ERROR_UNIMPLEMENTED); +} + + static int ipsec_integ_algo_decode (vl_api_ipsec_integ_alg_t in, ipsec_integ_alg_t * out) { @@ -250,86 +280,122 @@ ipsec_integ_algo_decode (vl_api_ipsec_integ_alg_t in, ipsec_integ_alg_t * out) return (VNET_API_ERROR_UNIMPLEMENTED); } +static vl_api_ipsec_integ_alg_t +ipsec_integ_algo_encode (ipsec_integ_alg_t i) +{ + switch (i) + { +#define _(v,f,s) case IPSEC_INTEG_ALG_##f: \ + return (clib_host_to_net_u32(IPSEC_API_INTEG_ALG_##f)); + foreach_ipsec_integ_alg +#undef _ + case IPSEC_INTEG_N_ALG: + break; + } + ASSERT (0); + return (VNET_API_ERROR_UNIMPLEMENTED); +} + static void -vl_api_ipsec_key_decode (const vl_api_key_t * key, u8 * len, u8 out[128]) +ipsec_key_decode (const vl_api_key_t * key, ipsec_key_t * out) { - *len = key->length; - clib_memcpy (out, key->data, key->length); + ipsec_mk_key (out, key->data, key->length); } static void -vl_api_ipsec_sad_flags_decode (vl_api_ipsec_sad_flags_t in, ipsec_sa_t * sa) +ipsec_key_encode (const ipsec_key_t * in, vl_api_key_t * out) +{ + out->length = in->len; + clib_memcpy (out->data, in->data, out->length); +} + +static ipsec_sa_flags_t +ipsec_sa_flags_decode (vl_api_ipsec_sad_flags_t in) { + ipsec_sa_flags_t flags = IPSEC_SA_FLAG_NONE; in = clib_net_to_host_u32 (in); - if (in & IPSEC_API_SAD_FLAG_USE_EXTENDED_SEQ_NUM) - sa->use_esn = 1; - if (in & IPSEC_API_SAD_FLAG_USE_ANTI_REPLAY) - sa->use_anti_replay = 1; - if (in & IPSEC_API_SAD_FLAG_IS_TUNNEL) - sa->is_tunnel = 1; - if (in & IPSEC_API_SAD_FLAG_IS_TUNNEL_V6) - sa->is_tunnel_ip6 = 1; - if (in & IPSEC_API_SAD_FLAG_UDP_ENCAP) - sa->udp_encap = 1; +#define _(v,f,s) if (in & IPSEC_API_SAD_FLAG_##f) \ + flags |= IPSEC_SA_FLAG_##f; + foreach_ipsec_sa_flags +#undef _ + return (flags); } +static vl_api_ipsec_sad_flags_t +ipsec_sad_flags_encode (const ipsec_sa_t * sa) +{ + vl_api_ipsec_sad_flags_t flags = IPSEC_API_SAD_FLAG_NONE; + + if (sa->use_esn) + flags |= IPSEC_API_SAD_FLAG_USE_EXTENDED_SEQ_NUM; + if (sa->use_anti_replay) + flags |= IPSEC_API_SAD_FLAG_USE_ANTI_REPLAY; + if (sa->is_tunnel) + flags |= IPSEC_API_SAD_FLAG_IS_TUNNEL; + if (sa->is_tunnel_ip6) + flags |= IPSEC_API_SAD_FLAG_IS_TUNNEL_V6; + if (sa->udp_encap) + flags |= IPSEC_API_SAD_FLAG_UDP_ENCAP; + + return clib_host_to_net_u32 (flags); +} static void vl_api_ipsec_sad_entry_add_del_t_handler (vl_api_ipsec_sad_entry_add_del_t * mp) { vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main (); vl_api_ipsec_sad_entry_add_del_reply_t *rmp; + ip46_address_t tun_src = { }, tun_dst = + { + }; + ipsec_key_t crypto_key, integ_key; + ipsec_crypto_alg_t crypto_alg; + ipsec_integ_alg_t integ_alg; + ipsec_protocol_t proto; + ipsec_sa_flags_t flags; + u32 id, spi; int rv; -#if WITH_LIBSSL > 0 - ipsec_main_t *im = &ipsec_main; - ipsec_sa_t sa; - clib_memset (&sa, 0, sizeof (sa)); +#if WITH_LIBSSL > 0 - sa.id = ntohl (mp->entry.sad_id); - sa.spi = ntohl (mp->entry.spi); + id = ntohl (mp->entry.sad_id); + spi = ntohl (mp->entry.spi); - rv = ipsec_proto_decode (mp->entry.protocol, &sa.protocol); + rv = ipsec_proto_decode (mp->entry.protocol, &proto); if (rv) goto out; - rv = ipsec_crypto_algo_decode (mp->entry.crypto_algorithm, &sa.crypto_alg); + rv = ipsec_crypto_algo_decode (mp->entry.crypto_algorithm, &crypto_alg); if (rv) goto out; - rv = ipsec_integ_algo_decode (mp->entry.integrity_algorithm, &sa.integ_alg); + rv = ipsec_integ_algo_decode (mp->entry.integrity_algorithm, &integ_alg); if (rv) goto out; - vl_api_ipsec_key_decode (&mp->entry.crypto_key, - &sa.crypto_key_len, sa.crypto_key); - vl_api_ipsec_key_decode (&mp->entry.integrity_key, - &sa.integ_key_len, sa.integ_key); + ipsec_key_decode (&mp->entry.crypto_key, &crypto_key); + ipsec_key_decode (&mp->entry.integrity_key, &integ_key); - vl_api_ipsec_sad_flags_decode (mp->entry.flags, &sa); + flags = ipsec_sa_flags_decode (mp->entry.flags); - if (sa.is_tunnel_ip6 || sa.is_tunnel) - { - ip_address_decode (&mp->entry.tunnel_src, &sa.tunnel_src_addr); - ip_address_decode (&mp->entry.tunnel_dst, &sa.tunnel_dst_addr); - } + ip_address_decode (&mp->entry.tunnel_src, &tun_src); + ip_address_decode (&mp->entry.tunnel_dst, &tun_dst); - clib_error_t *err = ipsec_check_support_cb (im, &sa); - if (err) - { - clib_warning ("%s", err->what); - rv = VNET_API_ERROR_UNIMPLEMENTED; - goto out; - } - rv = ipsec_add_del_sa (vm, &sa, mp->is_add); + if (mp->is_add) + rv = ipsec_sa_add (id, spi, proto, + crypto_alg, &crypto_key, + integ_alg, &integ_key, flags, + 0, &tun_src, &tun_dst, NULL); + else + rv = ipsec_sa_del (id); + #else rv = VNET_API_ERROR_UNIMPLEMENTED; - goto out; #endif out: @@ -525,17 +591,17 @@ vl_api_ipsec_sa_set_key_t_handler (vl_api_ipsec_sa_set_key_t * mp) { vlib_main_t *vm __attribute__ ((unused)) = vlib_get_main (); vl_api_ipsec_sa_set_key_reply_t *rmp; + ipsec_key_t ck, ik; + u32 id; int rv; #if WITH_LIBSSL > 0 - ipsec_sa_t sa; - sa.id = ntohl (mp->sa_id); - vl_api_ipsec_key_decode (&mp->crypto_key, - &sa.crypto_key_len, sa.crypto_key); - vl_api_ipsec_key_decode (&mp->integrity_key, - &sa.integ_key_len, sa.integ_key); + id = ntohl (mp->sa_id); - rv = ipsec_set_sa_key (vm, &sa); + ipsec_key_decode (&mp->crypto_key, &ck); + ipsec_key_decode (&mp->integrity_key, &ik); + + rv = ipsec_set_sa_key (id, &ck, &ik); #else rv = VNET_API_ERROR_UNIMPLEMENTED; #endif @@ -571,8 +637,8 @@ vl_api_ipsec_tunnel_if_add_del_t_handler (vl_api_ipsec_tunnel_if_add_del_t * 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_ip.ip4, mp->local_ip, 4); + memcpy (&tun.remote_ip.ip4, mp->remote_ip, 4); memcpy (&tun.local_crypto_key, &mp->local_crypto_key, mp->local_crypto_key_len); memcpy (&tun.remote_crypto_key, &mp->remote_crypto_key, @@ -590,11 +656,12 @@ vl_api_ipsec_tunnel_if_add_del_t_handler (vl_api_ipsec_tunnel_if_add_del_t * rv = VNET_API_ERROR_UNIMPLEMENTED; #endif - REPLY_MACRO2 (VL_API_IPSEC_TUNNEL_IF_ADD_DEL_REPLY, ( - { - rmp->sw_if_index = - htonl (sw_if_index); - })); + /* *INDENT-OFF* */ + REPLY_MACRO2 (VL_API_IPSEC_TUNNEL_IF_ADD_DEL_REPLY, + ({ + rmp->sw_if_index = htonl (sw_if_index); + })); + /* *INDENT-ON* */ } static void @@ -608,40 +675,29 @@ send_ipsec_sa_details (ipsec_sa_t * sa, vl_api_registration_t * reg, mp->_vl_msg_id = ntohs (VL_API_IPSEC_SA_DETAILS); mp->context = context; - mp->sa_id = htonl (sa->id); - mp->sw_if_index = htonl (sw_if_index); - - mp->spi = htonl (sa->spi); - mp->protocol = sa->protocol; - - mp->crypto_alg = sa->crypto_alg; - mp->crypto_key_len = sa->crypto_key_len; - memcpy (mp->crypto_key, sa->crypto_key, sa->crypto_key_len); + mp->entry.sad_id = htonl (sa->id); + mp->entry.spi = htonl (sa->spi); + mp->entry.protocol = ipsec_proto_encode (sa->protocol); + mp->entry.tx_table_id = + htonl (fib_table_get_table_id (sa->tx_fib_index, FIB_PROTOCOL_IP4)); - mp->integ_alg = sa->integ_alg; - mp->integ_key_len = sa->integ_key_len; - memcpy (mp->integ_key, sa->integ_key, sa->integ_key_len); + mp->entry.crypto_algorithm = ipsec_crypto_algo_encode (sa->crypto_alg); + ipsec_key_encode (&sa->crypto_key, &mp->entry.crypto_key); - mp->use_esn = sa->use_esn; - mp->use_anti_replay = sa->use_anti_replay; + mp->entry.integrity_algorithm = ipsec_integ_algo_encode (sa->integ_alg); + ipsec_key_encode (&sa->integ_key, &mp->entry.integrity_key); - mp->is_tunnel = sa->is_tunnel; - mp->is_tunnel_ip6 = sa->is_tunnel_ip6; + mp->entry.flags = ipsec_sad_flags_encode (sa); if (sa->is_tunnel) { - if (sa->is_tunnel_ip6) - { - memcpy (mp->tunnel_src_addr, &sa->tunnel_src_addr.ip6, 16); - memcpy (mp->tunnel_dst_addr, &sa->tunnel_dst_addr.ip6, 16); - } - else - { - memcpy (mp->tunnel_src_addr, &sa->tunnel_src_addr.ip4, 4); - memcpy (mp->tunnel_dst_addr, &sa->tunnel_dst_addr.ip4, 4); - } + ip_address_encode (&sa->tunnel_src_addr, IP46_TYPE_ANY, + &mp->entry.tunnel_src); + ip_address_encode (&sa->tunnel_dst_addr, IP46_TYPE_ANY, + &mp->entry.tunnel_dst); } + mp->sw_if_index = htonl (sw_if_index); mp->salt = clib_host_to_net_u32 (sa->salt); mp->seq_outbound = clib_host_to_net_u64 (((u64) sa->seq)); mp->last_seq_inbound = clib_host_to_net_u64 (((u64) sa->last_seq)); @@ -653,10 +709,6 @@ send_ipsec_sa_details (ipsec_sa_t * sa, vl_api_registration_t * reg, if (sa->use_anti_replay) mp->replay_window = clib_host_to_net_u64 (sa->replay_window); 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 4bc14372042..f66bf6d5aa1 100644 --- a/src/vnet/ipsec/ipsec_cli.c +++ b/src/vnet/ipsec/ipsec_cli.c @@ -73,87 +73,62 @@ ipsec_sa_add_del_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { - ipsec_main_t *im = &ipsec_main; unformat_input_t _line_input, *line_input = &_line_input; - ipsec_sa_t sa; - int is_add = ~0; - u8 *ck = 0, *ik = 0; - clib_error_t *error = NULL; - - clib_memset (&sa, 0, sizeof (sa)); - sa.tx_fib_index = ~((u32) 0); /* Only supported for ipsec interfaces */ + ip46_address_t tun_src = { }, tun_dst = + { + }; + ipsec_crypto_alg_t crypto_alg; + ipsec_integ_alg_t integ_alg; + ipsec_protocol_t proto; + ipsec_sa_flags_t flags; + clib_error_t *error; + ipsec_key_t ck, ik; + int is_add, rv; + u32 id, spi; + + error = NULL; + is_add = 0; + flags = IPSEC_SA_FLAG_NONE; + proto = IPSEC_PROTOCOL_ESP; 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, "add %u", &sa.id)) + if (unformat (line_input, "add %u", &id)) is_add = 1; - else if (unformat (line_input, "del %u", &sa.id)) + else if (unformat (line_input, "del %u", &id)) is_add = 0; - else if (unformat (line_input, "spi %u", &sa.spi)) + else if (unformat (line_input, "spi %u", &spi)) ; else if (unformat (line_input, "esp")) - sa.protocol = IPSEC_PROTOCOL_ESP; + proto = IPSEC_PROTOCOL_ESP; else if (unformat (line_input, "ah")) - { - sa.protocol = IPSEC_PROTOCOL_AH; - } - else - if (unformat (line_input, "crypto-key %U", unformat_hex_string, &ck)) - sa.crypto_key_len = vec_len (ck); - else - if (unformat - (line_input, "crypto-alg %U", unformat_ipsec_crypto_alg, - &sa.crypto_alg)) - { - if (sa.crypto_alg < IPSEC_CRYPTO_ALG_NONE || - sa.crypto_alg >= IPSEC_CRYPTO_N_ALG) - { - error = clib_error_return (0, "unsupported crypto-alg: '%U'", - format_ipsec_crypto_alg, - sa.crypto_alg); - goto done; - } - } - else - if (unformat (line_input, "integ-key %U", unformat_hex_string, &ik)) - sa.integ_key_len = vec_len (ik); - else if (unformat (line_input, "integ-alg %U", unformat_ipsec_integ_alg, - &sa.integ_alg)) - { - if (sa.integ_alg < IPSEC_INTEG_ALG_NONE || - sa.integ_alg >= IPSEC_INTEG_N_ALG) - { - error = clib_error_return (0, "unsupported integ-alg: '%U'", - format_ipsec_integ_alg, - sa.integ_alg); - goto done; - } - } - else if (unformat (line_input, "tunnel-src %U", - unformat_ip4_address, &sa.tunnel_src_addr.ip4)) - sa.is_tunnel = 1; - else if (unformat (line_input, "tunnel-dst %U", - unformat_ip4_address, &sa.tunnel_dst_addr.ip4)) - sa.is_tunnel = 1; + proto = IPSEC_PROTOCOL_AH; + else if (unformat (line_input, "crypto-key %U", + unformat_ipsec_key, &ck)) + ; + else if (unformat (line_input, "crypto-alg %U", + unformat_ipsec_crypto_alg, &crypto_alg)) + ; + else if (unformat (line_input, "integ-key %U", unformat_ipsec_key, &ik)) + ; + else if (unformat (line_input, "integ-alg %U", + unformat_ipsec_integ_alg, &integ_alg)) + ; else if (unformat (line_input, "tunnel-src %U", - unformat_ip6_address, &sa.tunnel_src_addr.ip6)) + unformat_ip46_address, &tun_src)) { - sa.is_tunnel = 1; - sa.is_tunnel_ip6 = 1; + flags |= IPSEC_SA_FLAG_IS_TUNNEL; + if (!ip46_address_is_ip4 (&tun_src)) + flags |= IPSEC_SA_FLAG_IS_TUNNEL_V6; } else if (unformat (line_input, "tunnel-dst %U", - unformat_ip6_address, &sa.tunnel_dst_addr.ip6)) - { - sa.is_tunnel = 1; - sa.is_tunnel_ip6 = 1; - } + unformat_ip46_address, &tun_dst)) + ; else if (unformat (line_input, "udp-encap")) - { - sa.udp_encap = 1; - } + flags |= IPSEC_SA_FLAG_UDP_ENCAP; else { error = clib_error_return (0, "parse error: '%U'", @@ -162,26 +137,15 @@ ipsec_sa_add_del_command_fn (vlib_main_t * vm, } } - if (sa.crypto_key_len > sizeof (sa.crypto_key)) - sa.crypto_key_len = sizeof (sa.crypto_key); - - if (sa.integ_key_len > sizeof (sa.integ_key)) - sa.integ_key_len = sizeof (sa.integ_key); - - if (ck) - memcpy (sa.crypto_key, ck, sa.crypto_key_len); - - if (ik) - memcpy (sa.integ_key, ik, sa.integ_key_len); - if (is_add) - { - error = ipsec_check_support_cb (im, &sa); - if (error) - goto done; - } + rv = ipsec_sa_add (id, spi, proto, crypto_alg, + &ck, integ_alg, &ik, flags, + 0, &tun_src, &tun_dst, NULL); + else + rv = ipsec_sa_del (id); - ipsec_add_del_sa (vm, &sa, is_add); + if (rv) + clib_error_return (0, "failed"); done: unformat_free (line_input); @@ -388,25 +352,22 @@ set_ipsec_sa_key_command_fn (vlib_main_t * vm, vlib_cli_command_t * cmd) { unformat_input_t _line_input, *line_input = &_line_input; - ipsec_sa_t sa; - u8 *ck = 0, *ik = 0; clib_error_t *error = NULL; - - clib_memset (&sa, 0, sizeof (sa)); + ipsec_key_t ck, ik; + u32 id; 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, "%u", &sa.id)) + if (unformat (line_input, "%u", &id)) ; else - if (unformat (line_input, "crypto-key %U", unformat_hex_string, &ck)) - sa.crypto_key_len = vec_len (ck); - else - if (unformat (line_input, "integ-key %U", unformat_hex_string, &ik)) - sa.integ_key_len = vec_len (ik); + if (unformat (line_input, "crypto-key %U", unformat_ipsec_key, &ck)) + ; + else if (unformat (line_input, "integ-key %U", unformat_ipsec_key, &ik)) + ; else { error = clib_error_return (0, "parse error: '%U'", @@ -415,19 +376,7 @@ set_ipsec_sa_key_command_fn (vlib_main_t * vm, } } - if (sa.crypto_key_len > sizeof (sa.crypto_key)) - sa.crypto_key_len = sizeof (sa.crypto_key); - - if (sa.integ_key_len > sizeof (sa.integ_key)) - sa.integ_key_len = sizeof (sa.integ_key); - - if (ck) - strncpy ((char *) sa.crypto_key, (char *) ck, sa.crypto_key_len); - - if (ik) - strncpy ((char *) sa.integ_key, (char *) ik, sa.integ_key_len); - - ipsec_set_sa_key (vm, &sa); + ipsec_set_sa_key (id, &ck, &ik); done: unformat_free (line_input); @@ -448,96 +397,45 @@ static clib_error_t * show_ipsec_command_fn (vlib_main_t * vm, unformat_input_t * input, vlib_cli_command_t * cmd) { - ipsec_sa_t *sa; ipsec_main_t *im = &ipsec_main; - u32 i; - ipsec_tunnel_if_t *t; + u32 spd_id, sw_if_index, sai; vnet_hw_interface_t *hi; + ipsec_tunnel_if_t *t; u8 *protocol = NULL; u8 *policy = NULL; - u32 tx_table_id, spd_id, sw_if_index; + u32 i; /* *INDENT-OFF* */ - pool_foreach (sa, im->sad, ({ - if (sa->id) { - vlib_cli_output(vm, "sa %u spi %u mode %s protocol %s%s%s%s", sa->id, sa->spi, - sa->is_tunnel ? "tunnel" : "transport", - sa->protocol ? "esp" : "ah", - sa->udp_encap ? " udp-encap-enabled" : "", - sa->use_anti_replay ? " anti-replay" : "", - sa->use_esn ? " extended-sequence-number" : ""); - if (sa->protocol == IPSEC_PROTOCOL_ESP) { - vlib_cli_output(vm, " crypto alg %U%s%U integrity alg %U%s%U", - format_ipsec_crypto_alg, sa->crypto_alg, - sa->crypto_alg ? " key " : "", - format_hex_bytes, sa->crypto_key, sa->crypto_key_len, - format_ipsec_integ_alg, sa->integ_alg, - sa->integ_alg ? " key " : "", - format_hex_bytes, sa->integ_key, sa->integ_key_len); - } - if (sa->is_tunnel && sa->is_tunnel_ip6) { - vlib_cli_output(vm, " tunnel src %U dst %U", - format_ip6_address, &sa->tunnel_src_addr.ip6, - format_ip6_address, &sa->tunnel_dst_addr.ip6); - } else if (sa->is_tunnel) { - vlib_cli_output(vm, " tunnel src %U dst %U", - format_ip4_address, &sa->tunnel_src_addr.ip4, - format_ip4_address, &sa->tunnel_dst_addr.ip4); - } - } + pool_foreach_index (sai, im->sad, ({ + vlib_cli_output(vm, "%U", format_ipsec_sa, sai); })); - /* *INDENT-ON* */ - - /* *INDENT-OFF* */ pool_foreach_index (i, im->spds, ({ vlib_cli_output(vm, "%U", format_ipsec_spd, i); })); - /* *INDENT-ON* */ vlib_cli_output (vm, "SPD Bindings:"); - /* *INDENT-OFF* */ + hash_foreach(sw_if_index, spd_id, im->spd_index_by_sw_if_index, ({ - vlib_cli_output (vm, " %d -> %U", spd_id, - format_vnet_sw_if_index_name, im->vnet_main, - sw_if_index); + vlib_cli_output (vm, " %d -> %U", spd_id, + format_vnet_sw_if_index_name, im->vnet_main, + sw_if_index); })); /* *INDENT-ON* */ - 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); - - 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", - format_ipsec_crypto_alg, sa->crypto_alg, - format_hex_bytes, sa->crypto_key, sa->crypto_key_len); - vlib_cli_output(vm, " local-integrity %U %U", - format_ipsec_integ_alg, sa->integ_alg, - format_hex_bytes, sa->integ_key, sa->integ_key_len); - sa = pool_elt_at_index(im->sad, t->input_sa_index); - vlib_cli_output(vm, " last-seq %u last-seq-hi %u esn %u anti-replay %u window %U", - sa->last_seq, sa->last_seq_hi, sa->use_esn, - sa->use_anti_replay, - format_ipsec_replay_window, sa->replay_window); - vlib_cli_output(vm, " remote-spi %u remote-ip %U", sa->spi, - format_ip4_address, &sa->tunnel_src_addr.ip4); - vlib_cli_output(vm, " remote-crypto %U %U", - format_ipsec_crypto_alg, sa->crypto_alg, - format_hex_bytes, sa->crypto_key, sa->crypto_key_len); - vlib_cli_output(vm, " remote-integrity %U %U", - format_ipsec_integ_alg, sa->integ_alg, - format_hex_bytes, sa->integ_key, sa->integ_key_len); + + vlib_cli_output(vm, " %s", hi->name); + + vlib_cli_output(vm, " out-bound sa"); + vlib_cli_output(vm, " %U", format_ipsec_sa, t->output_sa_index); + + vlib_cli_output(vm, " in-bound sa"); + vlib_cli_output(vm, " %U", format_ipsec_sa, t->input_sa_index); })); vec_free(policy); vec_free(protocol); diff --git a/src/vnet/ipsec/ipsec_format.c b/src/vnet/ipsec/ipsec_format.c index cbd67239680..04a2a0b5be1 100644 --- a/src/vnet/ipsec/ipsec_format.c +++ b/src/vnet/ipsec/ipsec_format.c @@ -19,6 +19,7 @@ #include <vnet/api_errno.h> #include <vnet/ip/ip.h> #include <vnet/interface.h> +#include <vnet/fib/fib_table.h> #include <vnet/ipsec/ipsec.h> @@ -208,6 +209,77 @@ format_ipsec_spd (u8 * s, va_list * args) return (s); } +u8 * +format_ipsec_key (u8 * s, va_list * args) +{ + ipsec_key_t *key = va_arg (*args, ipsec_key_t *); + + return (format (s, "%U", format_hex_bytes, key->data, key->len)); +} + +uword +unformat_ipsec_key (unformat_input_t * input, va_list * args) +{ + ipsec_key_t *key = va_arg (*args, ipsec_key_t *); + u8 *data; + + if (unformat (input, "%U", unformat_hex_string, &data)) + { + ipsec_mk_key (key, data, vec_len (data)); + vec_free (data); + } + else + return 0; + return 1; +} + +u8 * +format_ipsec_sa (u8 * s, va_list * args) +{ + u32 sai = va_arg (*args, u32); + ipsec_main_t *im = &ipsec_main; + u32 tx_table_id; + ipsec_sa_t *sa; + + sa = pool_elt_at_index (im->sad, sai); + + s = format (s, "[%d] sa %u spi %u mode %s%s protocol %s%s%s%s", + sai, sa->id, sa->spi, + sa->is_tunnel ? "tunnel" : "transport", + sa->is_tunnel_ip6 ? "-ip6" : "", + sa->protocol ? "esp" : "ah", + sa->udp_encap ? " udp-encap-enabled" : "", + sa->use_anti_replay ? " anti-replay" : "", + sa->use_esn ? " extended-sequence-number" : ""); + s = format (s, "\n last-seq %u last-seq-hi %u window %U", + sa->last_seq, sa->last_seq_hi, + format_ipsec_replay_window, sa->replay_window); + s = format (s, "\n crypto alg %U%s%U", + format_ipsec_crypto_alg, sa->crypto_alg, + sa->crypto_alg ? " key " : "", + format_ipsec_key, &sa->crypto_key); + s = format (s, "\n integrity alg %U%s%U", + format_ipsec_integ_alg, sa->integ_alg, + sa->integ_alg ? " key " : "", format_ipsec_key, &sa->integ_key); + + if (sa->is_tunnel) + { + tx_table_id = fib_table_get_table_id (sa->tx_fib_index, + FIB_PROTOCOL_IP4); + s = format (s, "\n table-ID %d tunnel src %U dst %U", + tx_table_id, + format_ip46_address, &sa->tunnel_src_addr, IP46_TYPE_ANY, + format_ip46_address, &sa->tunnel_dst_addr, IP46_TYPE_ANY); + s = format (s, "\n resovle via fib-entry: %d", sa->fib_entry_index); + s = format (s, "\n stacked on:"); + s = + format (s, "\n %U", format_dpo_id, &sa->dpo[IPSEC_PROTOCOL_ESP], + 6); + } + + return (s); +} + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vnet/ipsec/ipsec_if.c b/src/vnet/ipsec/ipsec_if.c index 0dfb6909e42..357d638d38b 100644 --- a/src/vnet/ipsec/ipsec_if.c +++ b/src/vnet/ipsec/ipsec_if.c @@ -250,6 +250,18 @@ ipsec_add_del_tunnel_if (ipsec_add_del_tunnel_args_t * args) return 0; } +static u32 +ipsec_tun_mk_input_sa_id (u32 ti) +{ + return (0x80000000 | ti); +} + +static u32 +ipsec_tun_mk_output_sa_id (u32 ti) +{ + return (0xc0000000 | ti); +} + int ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm, ipsec_add_del_tunnel_args_t * args, @@ -260,12 +272,13 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm, vnet_hw_interface_t *hi = NULL; u32 hw_if_index = ~0; uword *p; - ipsec_sa_t *sa; u32 dev_instance; u32 slot; - u32 tx_fib_index = ~0; + ipsec_key_t crypto_key, integ_key; + ipsec_sa_flags_t flags; + int rv; - u64 key = (u64) args->remote_ip.as_u32 << 32 | (u64) args->remote_spi; + u64 key = (u64) args->remote_ip.ip4.as_u32 << 32 | (u64) args->remote_spi; p = hash_get (im->ipsec_if_pool_index_by_key, key); if (args->is_add) @@ -274,10 +287,6 @@ 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)); @@ -296,59 +305,53 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm, hash_set (im->ipsec_if_real_dev_by_show_dev, t->show_instance, dev_instance); - pool_get (im->sad, sa); - clib_memset (sa, 0, sizeof (*sa)); - t->input_sa_index = sa - im->sad; - sa->protocol = IPSEC_PROTOCOL_ESP; - sa->spi = args->remote_spi; - sa->tunnel_src_addr.ip4.as_u32 = args->remote_ip.as_u32; - sa->tunnel_dst_addr.ip4.as_u32 = args->local_ip.as_u32; - sa->is_tunnel = 1; - sa->use_esn = args->esn; - 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; - clib_memcpy (sa->integ_key, args->remote_integ_key, - args->remote_integ_key_len); - } - sa->crypto_alg = args->crypto_alg; - if (args->remote_crypto_key_len <= sizeof (args->remote_crypto_key)) - { - sa->crypto_key_len = args->remote_crypto_key_len; - clib_memcpy (sa->crypto_key, args->remote_crypto_key, - args->remote_crypto_key_len); - } - - pool_get (im->sad, sa); - clib_memset (sa, 0, sizeof (*sa)); - t->output_sa_index = sa - im->sad; - sa->protocol = IPSEC_PROTOCOL_ESP; - sa->spi = args->local_spi; - sa->tunnel_src_addr.ip4.as_u32 = args->local_ip.as_u32; - sa->tunnel_dst_addr.ip4.as_u32 = args->remote_ip.as_u32; - sa->is_tunnel = 1; - sa->use_esn = args->esn; - 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; - clib_memcpy (sa->integ_key, args->local_integ_key, - args->local_integ_key_len); - } - sa->crypto_alg = args->crypto_alg; - if (args->local_crypto_key_len <= sizeof (args->local_crypto_key)) - { - sa->crypto_key_len = args->local_crypto_key_len; - clib_memcpy (sa->crypto_key, args->local_crypto_key, - args->local_crypto_key_len); - } + flags = IPSEC_SA_FLAG_IS_TUNNEL; + if (args->udp_encap) + flags |= IPSEC_SA_FLAG_UDP_ENCAP; + if (args->esn) + flags |= IPSEC_SA_FLAG_USE_EXTENDED_SEQ_NUM; + if (args->anti_replay) + flags |= IPSEC_SA_FLAG_USE_ANTI_REPLAY; + + ipsec_mk_key (&crypto_key, + args->remote_crypto_key, args->remote_crypto_key_len); + ipsec_mk_key (&integ_key, + args->remote_integ_key, args->remote_integ_key_len); + + rv = ipsec_sa_add (ipsec_tun_mk_input_sa_id (dev_instance), + args->remote_spi, + IPSEC_PROTOCOL_ESP, + args->crypto_alg, + &crypto_key, + args->integ_alg, + &integ_key, + flags, + args->tx_table_id, + &args->remote_ip, + &args->local_ip, &t->input_sa_index); + + if (rv) + return VNET_API_ERROR_UNIMPLEMENTED; + + ipsec_mk_key (&crypto_key, + args->local_crypto_key, args->local_crypto_key_len); + ipsec_mk_key (&integ_key, + args->local_integ_key, args->local_integ_key_len); + + rv = ipsec_sa_add (ipsec_tun_mk_output_sa_id (dev_instance), + args->local_spi, + IPSEC_PROTOCOL_ESP, + args->crypto_alg, + &crypto_key, + args->integ_alg, + &integ_key, + flags, + args->tx_table_id, + &args->local_ip, + &args->remote_ip, &t->output_sa_index); + + if (rv) + return VNET_API_ERROR_UNIMPLEMENTED; hash_set (im->ipsec_if_pool_index_by_key, key, t - im->tunnel_interfaces); @@ -392,18 +395,14 @@ ipsec_add_del_tunnel_if_internal (vnet_main_t * vnm, vnet_delete_hw_interface (vnm, t->hw_if_index); - /* delete input and output SA */ - - sa = pool_elt_at_index (im->sad, t->input_sa_index); - pool_put (im->sad, sa); - - sa = pool_elt_at_index (im->sad, t->output_sa_index); - pool_put (im->sad, sa); - hash_unset (im->ipsec_if_pool_index_by_key, key); hash_unset (im->ipsec_if_real_dev_by_show_dev, t->show_instance); pool_put (im->tunnel_interfaces, t); + + /* delete input and output SA */ + ipsec_sa_del (ipsec_tun_mk_input_sa_id (p[0])); + ipsec_sa_del (ipsec_tun_mk_output_sa_id (p[0])); } if (sw_if_index) @@ -493,29 +492,25 @@ ipsec_set_interface_key (vnet_main_t * vnm, u32 hw_if_index, { sa = pool_elt_at_index (im->sad, t->output_sa_index); sa->crypto_alg = alg; - sa->crypto_key_len = vec_len (key); - clib_memcpy (sa->crypto_key, key, vec_len (key)); + ipsec_mk_key (&sa->crypto_key, key, vec_len (key)); } else if (type == IPSEC_IF_SET_KEY_TYPE_LOCAL_INTEG) { sa = pool_elt_at_index (im->sad, t->output_sa_index); sa->integ_alg = alg; - sa->integ_key_len = vec_len (key); - clib_memcpy (sa->integ_key, key, vec_len (key)); + ipsec_mk_key (&sa->integ_key, key, vec_len (key)); } else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_CRYPTO) { sa = pool_elt_at_index (im->sad, t->input_sa_index); sa->crypto_alg = alg; - sa->crypto_key_len = vec_len (key); - clib_memcpy (sa->crypto_key, key, vec_len (key)); + ipsec_mk_key (&sa->crypto_key, key, vec_len (key)); } else if (type == IPSEC_IF_SET_KEY_TYPE_REMOTE_INTEG) { sa = pool_elt_at_index (im->sad, t->input_sa_index); sa->integ_alg = alg; - sa->integ_key_len = vec_len (key); - clib_memcpy (sa->integ_key, key, vec_len (key)); + ipsec_mk_key (&sa->integ_key, key, vec_len (key)); } else return VNET_API_ERROR_INVALID_VALUE; diff --git a/src/vnet/ipsec/ipsec_if.h b/src/vnet/ipsec/ipsec_if.h index 96a109ddaf5..67d5554e777 100644 --- a/src/vnet/ipsec/ipsec_if.h +++ b/src/vnet/ipsec/ipsec_if.h @@ -41,7 +41,7 @@ typedef struct u8 is_add; u8 esn; u8 anti_replay; - ip4_address_t local_ip, remote_ip; + ip46_address_t local_ip, remote_ip; u32 local_spi; u32 remote_spi; ipsec_crypto_alg_t crypto_alg; diff --git a/src/vnet/ipsec/ipsec_if_in.c b/src/vnet/ipsec/ipsec_if_in.c index 1dbd12710c9..833f8485340 100644 --- a/src/vnet/ipsec/ipsec_if_in.c +++ b/src/vnet/ipsec/ipsec_if_in.c @@ -25,7 +25,8 @@ /* Statistics (not really errors) */ #define foreach_ipsec_if_input_error \ _(RX, "good packets received") \ -_(DISABLED, "ipsec packets received on disabled interface") +_(DISABLED, "ipsec packets received on disabled interface") \ +_(NO_TUNNEL, "no matching tunnel") static char *ipsec_if_input_error_strings[] = { #define _(sym,string) string, @@ -76,7 +77,7 @@ VLIB_NODE_FN (ipsec_if_input_node) (vlib_main_t * vm, ipsec_sa_t *sa0; vlib_combined_counter_main_t *rx_counter; vlib_combined_counter_main_t *drop_counter; - u32 n_disabled = 0; + u32 n_disabled = 0, n_no_tunnel = 0; rx_counter = vim->combined_sw_if_counters + VNET_INTERFACE_COUNTER_RX; drop_counter = vim->combined_sw_if_counters + VNET_INTERFACE_COUNTER_DROP; @@ -181,6 +182,11 @@ VLIB_NODE_FN (ipsec_if_input_node) (vlib_main_t * vm, vlib_buffer_advance (b0, ip4_header_bytes (ip0)); next0 = im->esp4_decrypt_next_index; } + else + { + b0->error = node->errors[IPSEC_IF_INPUT_ERROR_NO_TUNNEL]; + n_no_tunnel++; + } trace: if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED)) @@ -216,6 +222,8 @@ VLIB_NODE_FN (ipsec_if_input_node) (vlib_main_t * vm, vlib_node_increment_counter (vm, ipsec_if_input_node.index, IPSEC_IF_INPUT_ERROR_DISABLED, n_disabled); + vlib_node_increment_counter (vm, ipsec_if_input_node.index, + IPSEC_IF_INPUT_ERROR_DISABLED, n_no_tunnel); return from_frame->n_vectors; } diff --git a/src/vnet/ipsec/ipsec_sa.c b/src/vnet/ipsec/ipsec_sa.c index d439b4d46d3..f20d941fd68 100644 --- a/src/vnet/ipsec/ipsec_sa.c +++ b/src/vnet/ipsec/ipsec_sa.c @@ -14,6 +14,7 @@ */ #include <vnet/ipsec/ipsec.h> +#include <vnet/fib/fib_table.h> static clib_error_t * ipsec_call_add_del_callbacks (ipsec_main_t * im, ipsec_sa_t * sa, @@ -37,8 +38,146 @@ ipsec_call_add_del_callbacks (ipsec_main_t * im, ipsec_sa_t * sa, return 0; } +void +ipsec_mk_key (ipsec_key_t * key, const u8 * data, u8 len) +{ + memset (key, 0, sizeof (*key)); + + if (len > sizeof (key->data)) + key->len = sizeof (key->data); + else + key->len = len; + + memcpy (key->data, data, key->len); +} + +/** + * 'stack' (resolve the recursion for) the SA tunnel destination + */ +static void +ipsec_sa_stack (ipsec_sa_t * sa) +{ + fib_forward_chain_type_t fct; + dpo_id_t tmp = DPO_INVALID; + vlib_node_t *node; + + fct = fib_forw_chain_type_from_fib_proto ((sa->is_tunnel_ip6 ? + FIB_PROTOCOL_IP6 : + FIB_PROTOCOL_IP4)); + + fib_entry_contribute_forwarding (sa->fib_entry_index, fct, &tmp); + + node = vlib_get_node_by_name (vlib_get_main (), + (sa->is_tunnel_ip6 ? + (u8 *) "ah6-encrypt" : + (u8 *) "ah4-encrypt")); + dpo_stack_from_node (node->index, &sa->dpo[IPSEC_PROTOCOL_AH], &tmp); + + node = vlib_get_node_by_name (vlib_get_main (), + (sa->is_tunnel_ip6 ? + (u8 *) "esp6-encrypt" : + (u8 *) "esp4-encrypt")); + dpo_stack_from_node (node->index, &sa->dpo[IPSEC_PROTOCOL_ESP], &tmp); +} + int -ipsec_add_del_sa (vlib_main_t * vm, ipsec_sa_t * new_sa, int is_add) +ipsec_sa_add (u32 id, + u32 spi, + ipsec_protocol_t proto, + ipsec_crypto_alg_t crypto_alg, + const ipsec_key_t * ck, + ipsec_integ_alg_t integ_alg, + const ipsec_key_t * ik, + ipsec_sa_flags_t flags, + u32 tx_table_id, + const ip46_address_t * tun_src, + const ip46_address_t * tun_dst, u32 * sa_out_index) +{ + ipsec_main_t *im = &ipsec_main; + clib_error_t *err; + ipsec_sa_t *sa; + u32 sa_index; + uword *p; + + p = hash_get (im->sa_index_by_sa_id, id); + if (p) + return VNET_API_ERROR_ENTRY_ALREADY_EXISTS; + + pool_get_zero (im->sad, sa); + + fib_node_init (&sa->node, FIB_NODE_TYPE_IPSEC_SA); + sa_index = sa - im->sad; + + sa->id = id; + sa->spi = spi; + sa->protocol = proto; + sa->crypto_alg = crypto_alg; + clib_memcpy (&sa->crypto_key, ck, sizeof (sa->crypto_key)); + sa->integ_alg = integ_alg; + clib_memcpy (&sa->integ_key, ik, sizeof (sa->integ_key)); + ip46_address_copy (&sa->tunnel_src_addr, tun_src); + ip46_address_copy (&sa->tunnel_dst_addr, tun_dst); + + if (flags & IPSEC_SA_FLAG_USE_EXTENDED_SEQ_NUM) + sa->use_esn = 1; + if (flags & IPSEC_SA_FLAG_USE_ANTI_REPLAY) + sa->use_anti_replay = 1; + if (flags & IPSEC_SA_FLAG_IS_TUNNEL) + sa->is_tunnel = 1; + if (flags & IPSEC_SA_FLAG_IS_TUNNEL_V6) + sa->is_tunnel_ip6 = 1; + if (flags & IPSEC_SA_FLAG_UDP_ENCAP) + sa->udp_encap = 1; + + err = ipsec_check_support_cb (im, sa); + if (err) + { + clib_warning ("%s", err->what); + pool_put (im->sad, sa); + return VNET_API_ERROR_UNIMPLEMENTED; + } + + err = ipsec_call_add_del_callbacks (im, sa, sa_index, 1); + if (err) + { + pool_put (im->sad, sa); + return VNET_API_ERROR_SYSCALL_ERROR_1; + } + + if (sa->is_tunnel) + { + fib_protocol_t fproto = (sa->is_tunnel_ip6 ? + FIB_PROTOCOL_IP6 : FIB_PROTOCOL_IP4); + fib_prefix_t pfx = { + .fp_addr = sa->tunnel_dst_addr, + .fp_len = (sa->is_tunnel_ip6 ? 128 : 32), + .fp_proto = fproto, + }; + sa->tx_fib_index = fib_table_find (fproto, tx_table_id); + if (sa->tx_fib_index == ~((u32) 0)) + { + pool_put (im->sad, sa); + return VNET_API_ERROR_NO_SUCH_FIB; + } + + sa->fib_entry_index = fib_table_entry_special_add (sa->tx_fib_index, + &pfx, + FIB_SOURCE_RR, + FIB_ENTRY_FLAG_NONE); + sa->sibling = fib_entry_child_add (sa->fib_entry_index, + FIB_NODE_TYPE_IPSEC_SA, sa_index); + ipsec_sa_stack (sa); + } + hash_set (im->sa_index_by_sa_id, sa->id, sa_index); + + if (sa_out_index) + *sa_out_index = sa_index; + + return (0); +} + +u32 +ipsec_sa_del (u32 id) { ipsec_main_t *im = &ipsec_main; ipsec_sa_t *sa = 0; @@ -46,39 +185,33 @@ ipsec_add_del_sa (vlib_main_t * vm, ipsec_sa_t * new_sa, int is_add) u32 sa_index; clib_error_t *err; - clib_warning ("id %u spi %u", new_sa->id, new_sa->spi); + p = hash_get (im->sa_index_by_sa_id, id); - p = hash_get (im->sa_index_by_sa_id, new_sa->id); - if (p && is_add) - return VNET_API_ERROR_ENTRY_ALREADY_EXISTS; - if (!p && !is_add) + if (!p) return VNET_API_ERROR_NO_SUCH_ENTRY; - if (!is_add) /* delete */ + sa_index = p[0]; + sa = pool_elt_at_index (im->sad, sa_index); + if (ipsec_is_sa_used (sa_index)) { - sa_index = p[0]; - sa = pool_elt_at_index (im->sad, sa_index); - if (ipsec_is_sa_used (sa_index)) - { - clib_warning ("sa_id %u used in policy", sa->id); - return VNET_API_ERROR_SYSCALL_ERROR_1; /* sa used in policy */ - } - hash_unset (im->sa_index_by_sa_id, sa->id); - err = ipsec_call_add_del_callbacks (im, sa, sa_index, 0); - if (err) - return VNET_API_ERROR_SYSCALL_ERROR_1; - pool_put (im->sad, sa); + clib_warning ("sa_id %u used in policy", sa->id); + /* sa used in policy */ + return VNET_API_ERROR_SYSCALL_ERROR_1; } - else /* create new SA */ + hash_unset (im->sa_index_by_sa_id, sa->id); + err = ipsec_call_add_del_callbacks (im, sa, sa_index, 0); + if (err) + return VNET_API_ERROR_SYSCALL_ERROR_1; + if (sa->is_tunnel) { - pool_get (im->sad, sa); - clib_memcpy (sa, new_sa, sizeof (*sa)); - sa_index = sa - im->sad; - hash_set (im->sa_index_by_sa_id, sa->id, sa_index); - err = ipsec_call_add_del_callbacks (im, sa, sa_index, 1); - if (err) - return VNET_API_ERROR_SYSCALL_ERROR_1; + fib_entry_child_remove (sa->fib_entry_index, sa->sibling); + fib_table_entry_special_remove + (sa->tx_fib_index, + fib_entry_get_prefix (sa->fib_entry_index), FIB_SOURCE_RR); + dpo_reset (&sa->dpo[IPSEC_PROTOCOL_AH]); + dpo_reset (&sa->dpo[IPSEC_PROTOCOL_ESP]); } + pool_put (im->sad, sa); return 0; } @@ -110,7 +243,7 @@ ipsec_is_sa_used (u32 sa_index) } int -ipsec_set_sa_key (vlib_main_t * vm, ipsec_sa_t * sa_update) +ipsec_set_sa_key (u32 id, const ipsec_key_t * ck, const ipsec_key_t * ik) { ipsec_main_t *im = &ipsec_main; uword *p; @@ -118,7 +251,7 @@ ipsec_set_sa_key (vlib_main_t * vm, ipsec_sa_t * sa_update) ipsec_sa_t *sa = 0; clib_error_t *err; - p = hash_get (im->sa_index_by_sa_id, sa_update->id); + p = hash_get (im->sa_index_by_sa_id, id); if (!p) return VNET_API_ERROR_SYSCALL_ERROR_1; /* no such sa-id */ @@ -126,22 +259,18 @@ ipsec_set_sa_key (vlib_main_t * vm, ipsec_sa_t * sa_update) sa = pool_elt_at_index (im->sad, sa_index); /* new crypto key */ - if (0 < sa_update->crypto_key_len) + if (ck) { - clib_memcpy (sa->crypto_key, sa_update->crypto_key, - sa_update->crypto_key_len); - sa->crypto_key_len = sa_update->crypto_key_len; + clib_memcpy (&sa->crypto_key, ck, sizeof (sa->crypto_key)); } /* new integ key */ - if (0 < sa_update->integ_key_len) + if (ik) { - clib_memcpy (sa->integ_key, sa_update->integ_key, - sa_update->integ_key_len); - sa->integ_key_len = sa_update->integ_key_len; + clib_memcpy (&sa->integ_key, 0, sizeof (sa->integ_key)); } - if (0 < sa_update->crypto_key_len || 0 < sa_update->integ_key_len) + if (ck || ik) { err = ipsec_call_add_del_callbacks (im, sa, sa_index, 0); if (err) @@ -162,6 +291,75 @@ ipsec_get_sa_index_by_sa_id (u32 sa_id) return p[0]; } +/** + * Function definition to get a FIB node from its index + */ +static fib_node_t * +ipsec_sa_fib_node_get (fib_node_index_t index) +{ + ipsec_main_t *im; + ipsec_sa_t *sa; + + im = &ipsec_main; + sa = pool_elt_at_index (im->sad, index); + + return (&sa->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) +{ + /* + * The ipsec SA is a root of the graph. As such + * it never has children and thus is never locked. + */ + ASSERT (0); +} + +static ipsec_sa_t * +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))); + +} + +/** + * 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_stack (ipsec_sa_from_fib_node (node)); + + return (FIB_NODE_BACK_WALK_CONTINUE); +} + +/* + * Virtual function table registered by MPLS GRE tunnels + * for participation in the FIB object graph. + */ +const static fib_node_vft_t ipsec_sa_vft = { + .fnv_get = ipsec_sa_fib_node_get, + .fnv_last_lock = ipsec_sa_last_lock_gone, + .fnv_back_walk = ipsec_sa_back_walk, +}; + +/* force inclusion from application's main.c */ +clib_error_t * +ipsec_sa_interface_init (vlib_main_t * vm) +{ + fib_node_register_type (FIB_NODE_TYPE_IPSEC_SA, &ipsec_sa_vft); + + return 0; +} + +VLIB_INIT_FUNCTION (ipsec_sa_interface_init); + /* * fd.io coding-style-patch-verification: ON * diff --git a/src/vnet/ipsec/ipsec_sa.h b/src/vnet/ipsec/ipsec_sa.h index 43d699be928..775343b4b73 100644 --- a/src/vnet/ipsec/ipsec_sa.h +++ b/src/vnet/ipsec/ipsec_sa.h @@ -17,6 +17,7 @@ #include <vlib/vlib.h> #include <vnet/ip/ip.h> +#include <vnet/fib/fib_node.h> #define foreach_ipsec_crypto_alg \ _ (0, NONE, "none") \ @@ -63,19 +64,50 @@ typedef enum IPSEC_PROTOCOL_ESP = 1 } ipsec_protocol_t; +#define IPSEC_N_PROTOCOLS (IPSEC_PROTOCOL_ESP+1) + +#define IPSEC_KEY_MAX_LEN 128 +typedef struct ipsec_key_t_ +{ + u8 len; + u8 data[IPSEC_KEY_MAX_LEN]; +} ipsec_key_t; + +/* + * Enable extended sequence numbers + * Enable Anti-replay + * IPsec tunnel mode if non-zero, else transport mode + * IPsec tunnel mode is IPv6 if non-zero, + * else IPv4 tunnel only valid if is_tunnel is non-zero + * enable UDP encapsulation for NAT traversal + */ +#define foreach_ipsec_sa_flags \ + _ (0, NONE, "none") \ + _ (1, USE_EXTENDED_SEQ_NUM, "esn") \ + _ (2, USE_ANTI_REPLAY, "anti-replay") \ + _ (4, IS_TUNNEL, "tunnel") \ + _ (8, IS_TUNNEL_V6, "tunnel-v6") \ + _ (16, UDP_ENCAP, "udp-encap") \ + +typedef enum ipsec_sad_flags_t_ +{ +#define _(v, f, s) IPSEC_SA_FLAG_##f = v, + foreach_ipsec_sa_flags +#undef _ +} ipsec_sa_flags_t; + typedef struct { + fib_node_t node; u32 id; u32 spi; ipsec_protocol_t protocol; ipsec_crypto_alg_t crypto_alg; - u8 crypto_key_len; - u8 crypto_key[128]; + ipsec_key_t crypto_key; ipsec_integ_alg_t integ_alg; - u8 integ_key_len; - u8 integ_key[128]; + ipsec_key_t integ_key; u8 use_esn; u8 use_anti_replay; @@ -86,6 +118,10 @@ typedef struct ip46_address_t tunnel_src_addr; ip46_address_t tunnel_dst_addr; + fib_node_index_t fib_entry_index; + u32 sibling; + dpo_id_t dpo[IPSEC_N_PROTOCOLS]; + u32 tx_fib_index; u32 salt; @@ -100,18 +136,36 @@ typedef struct u64 total_data_size; } ipsec_sa_t; -extern int ipsec_add_del_sa (vlib_main_t * vm, ipsec_sa_t * new_sa, - int is_add); +extern void ipsec_mk_key (ipsec_key_t * key, const u8 * data, u8 len); + +extern int ipsec_sa_add (u32 id, + u32 spi, + ipsec_protocol_t proto, + ipsec_crypto_alg_t crypto_alg, + const ipsec_key_t * ck, + ipsec_integ_alg_t integ_alg, + const ipsec_key_t * ik, + ipsec_sa_flags_t flags, + u32 tx_table_id, + const ip46_address_t * tunnel_src_addr, + const ip46_address_t * tunnel_dst_addr, + u32 * sa_index); +extern u32 ipsec_sa_del (u32 id); + extern u8 ipsec_is_sa_used (u32 sa_index); -extern int ipsec_set_sa_key (vlib_main_t * vm, ipsec_sa_t * sa_update); +extern int ipsec_set_sa_key (u32 id, + const ipsec_key_t * ck, const ipsec_key_t * ik); extern u32 ipsec_get_sa_index_by_sa_id (u32 sa_id); extern u8 *format_ipsec_crypto_alg (u8 * s, va_list * args); extern u8 *format_ipsec_integ_alg (u8 * s, va_list * args); +extern u8 *format_ipsec_sa (u8 * s, va_list * args); +extern u8 *format_ipsec_key (u8 * s, va_list * args); extern uword unformat_ipsec_crypto_alg (unformat_input_t * input, va_list * args); extern uword unformat_ipsec_integ_alg (unformat_input_t * input, va_list * args); +extern uword unformat_ipsec_key (unformat_input_t * input, va_list * args); #endif /* __IPSEC_SPD_SA_H__ */ |