diff options
Diffstat (limited to 'src/vnet/ipsec')
-rw-r--r-- | src/vnet/ipsec/esp_encrypt.c | 162 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec.c | 4 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec.h | 8 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_itf.c | 8 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_itf.h | 1 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_sa.h | 3 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_tun.c | 128 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_tun.h | 1 |
8 files changed, 123 insertions, 192 deletions
diff --git a/src/vnet/ipsec/esp_encrypt.c b/src/vnet/ipsec/esp_encrypt.c index 33484e9cf43..0d29604e61f 100644 --- a/src/vnet/ipsec/esp_encrypt.c +++ b/src/vnet/ipsec/esp_encrypt.c @@ -50,7 +50,9 @@ typedef enum _ (SEQ_CYCLED, "sequence number cycled (packet dropped)") \ _ (CRYPTO_ENGINE_ERROR, "crypto engine error (packet dropped)") \ _ (CRYPTO_QUEUE_FULL, "crypto queue full (packet dropped)") \ - _ (NO_BUFFERS, "no buffers (packet dropped)") + _ (NO_BUFFERS, "no buffers (packet dropped)") \ + _ (NO_PROTECTION, "no protecting SA (packet dropped)") \ + _ (NO_ENCRYPTION, "no Encrypting SA (packet dropped)") typedef enum { @@ -640,6 +642,14 @@ esp_encrypt_inline (vlib_main_t *vm, vlib_node_runtime_t *node, vnet_buffer (b[0])->ipsec.sad_index = sa_index0 = ipsec_tun_protect_get_sa_out (vnet_buffer (b[0])->ip.adj_index[VLIB_TX]); + + if (PREDICT_FALSE (INDEX_INVALID == sa_index0)) + { + err = ESP_ENCRYPT_ERROR_NO_PROTECTION; + esp_set_next_index (b[0], node, err, n_noop, noop_nexts, + drop_next); + goto trace; + } } else sa_index0 = vnet_buffer (b[0])->ipsec.sad_index; @@ -655,6 +665,15 @@ esp_encrypt_inline (vlib_main_t *vm, vlib_node_runtime_t *node, sa0 = ipsec_sa_get (sa_index0); + if (PREDICT_FALSE ((sa0->crypto_alg == IPSEC_CRYPTO_ALG_NONE && + sa0->integ_alg == IPSEC_INTEG_ALG_NONE) && + !ipsec_sa_is_set_NO_ALGO_NO_DROP (sa0))) + { + err = ESP_ENCRYPT_ERROR_NO_ENCRYPTION; + esp_set_next_index (b[0], node, err, n_noop, noop_nexts, + drop_next); + goto trace; + } /* fetch the second cacheline ASAP */ clib_prefetch_load (sa0->cacheline1); @@ -970,13 +989,19 @@ esp_encrypt_inline (vlib_main_t *vm, vlib_node_runtime_t *node, { esp_encrypt_trace_t *tr = vlib_add_trace (vm, node, b[0], sizeof (*tr)); - tr->sa_index = sa_index0; - tr->spi = sa0->spi; - tr->seq = sa0->seq; - tr->sa_seq_hi = sa0->seq_hi; - tr->udp_encap = ipsec_sa_is_set_UDP_ENCAP (sa0); - tr->crypto_alg = sa0->crypto_alg; - tr->integ_alg = sa0->integ_alg; + if (INDEX_INVALID == sa_index0) + clib_memset_u8 (tr, 0xff, sizeof (*tr)); + else + { + tr->sa_index = sa_index0; + tr->spi = sa0->spi; + tr->spi = sa0->spi; + tr->seq = sa0->seq; + tr->sa_seq_hi = sa0->seq_hi; + tr->udp_encap = ipsec_sa_is_set_UDP_ENCAP (sa0); + tr->crypto_alg = sa0->crypto_alg; + tr->integ_alg = sa0->integ_alg; + } } /* next */ @@ -1002,9 +1027,10 @@ esp_encrypt_inline (vlib_main_t *vm, vlib_node_runtime_t *node, b += 1; } - vlib_increment_combined_counter (&ipsec_sa_counters, thread_index, - current_sa_index, current_sa_packets, - current_sa_bytes); + if (INDEX_INVALID != current_sa_index) + vlib_increment_combined_counter (&ipsec_sa_counters, thread_index, + current_sa_index, current_sa_packets, + current_sa_bytes); if (n_sync) { esp_process_ops (vm, node, ptd->crypto_ops, sync_bufs, sync_nexts, @@ -1368,120 +1394,6 @@ VLIB_REGISTER_NODE (esp_mpls_encrypt_tun_post_node) = { .error_strings = esp_encrypt_error_strings, }; -typedef struct -{ - u32 sa_index; -} esp_no_crypto_trace_t; - -static u8 * -format_esp_no_crypto_trace (u8 * s, va_list * args) -{ - CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *); - CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *); - esp_no_crypto_trace_t *t = va_arg (*args, esp_no_crypto_trace_t *); - - s = format (s, "esp-no-crypto: sa-index %u", t->sa_index); - - return s; -} - -enum -{ - ESP_NO_CRYPTO_NEXT_DROP, - ESP_NO_CRYPTO_N_NEXT, -}; - -enum -{ - ESP_NO_CRYPTO_ERROR_RX_PKTS, -}; - -static char *esp_no_crypto_error_strings[] = { - "Outbound ESP packets received", -}; - -always_inline uword -esp_no_crypto_inline (vlib_main_t * vm, vlib_node_runtime_t * node, - vlib_frame_t * frame) -{ - vlib_buffer_t *bufs[VLIB_FRAME_SIZE], **b = bufs; - u32 *from = vlib_frame_vector_args (frame); - u32 n_left = frame->n_vectors; - - vlib_get_buffers (vm, from, b, n_left); - - while (n_left > 0) - { - u32 sa_index0; - - /* packets are always going to be dropped, but get the sa_index */ - sa_index0 = ipsec_tun_protect_get_sa_out - (vnet_buffer (b[0])->ip.adj_index[VLIB_TX]); - - if (PREDICT_FALSE (b[0]->flags & VLIB_BUFFER_IS_TRACED)) - { - esp_no_crypto_trace_t *tr = vlib_add_trace (vm, node, b[0], - sizeof (*tr)); - tr->sa_index = sa_index0; - } - - n_left -= 1; - b += 1; - } - - vlib_node_increment_counter (vm, node->node_index, - ESP_NO_CRYPTO_ERROR_RX_PKTS, frame->n_vectors); - - vlib_buffer_enqueue_to_single_next (vm, node, from, - ESP_NO_CRYPTO_NEXT_DROP, - frame->n_vectors); - - return frame->n_vectors; -} - -VLIB_NODE_FN (esp4_no_crypto_tun_node) (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * from_frame) -{ - return esp_no_crypto_inline (vm, node, from_frame); -} - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (esp4_no_crypto_tun_node) = -{ - .name = "esp4-no-crypto", - .vector_size = sizeof (u32), - .format_trace = format_esp_no_crypto_trace, - .n_errors = ARRAY_LEN(esp_no_crypto_error_strings), - .error_strings = esp_no_crypto_error_strings, - .n_next_nodes = ESP_NO_CRYPTO_N_NEXT, - .next_nodes = { - [ESP_NO_CRYPTO_NEXT_DROP] = "ip4-drop", - }, -}; - -VLIB_NODE_FN (esp6_no_crypto_tun_node) (vlib_main_t * vm, - vlib_node_runtime_t * node, - vlib_frame_t * from_frame) -{ - return esp_no_crypto_inline (vm, node, from_frame); -} - -/* *INDENT-OFF* */ -VLIB_REGISTER_NODE (esp6_no_crypto_tun_node) = -{ - .name = "esp6-no-crypto", - .vector_size = sizeof (u32), - .format_trace = format_esp_no_crypto_trace, - .n_errors = ARRAY_LEN(esp_no_crypto_error_strings), - .error_strings = esp_no_crypto_error_strings, - .n_next_nodes = ESP_NO_CRYPTO_N_NEXT, - .next_nodes = { - [ESP_NO_CRYPTO_NEXT_DROP] = "ip6-drop", - }, -}; -/* *INDENT-ON* */ - #ifndef CLIB_MARCH_VARIANT static clib_error_t * diff --git a/src/vnet/ipsec/ipsec.c b/src/vnet/ipsec/ipsec.c index 30774ec10ff..5cc8044e3d4 100644 --- a/src/vnet/ipsec/ipsec.c +++ b/src/vnet/ipsec/ipsec.c @@ -25,6 +25,7 @@ #include <vnet/ipsec/esp.h> #include <vnet/ipsec/ah.h> #include <vnet/ipsec/ipsec_tun.h> +#include <vnet/ipsec/ipsec_itf.h> /* Flow cache is sized for 1 million flows with a load factor of .25. */ @@ -254,6 +255,9 @@ ipsec_rsc_in_use (ipsec_main_t * im) if (pool_elts (ipsec_sa_pool) > 0) return clib_error_return (0, "%d SA entries configured", pool_elts (ipsec_sa_pool)); + if (ipsec_itf_count () > 0) + return clib_error_return (0, "%d IPSec interface configured", + ipsec_itf_count ()); return (NULL); } diff --git a/src/vnet/ipsec/ipsec.h b/src/vnet/ipsec/ipsec.h index 968d377cea0..38feaed6f77 100644 --- a/src/vnet/ipsec/ipsec.h +++ b/src/vnet/ipsec/ipsec.h @@ -181,14 +181,6 @@ typedef struct u32 ah6_encrypt_next_index; u32 ah6_decrypt_next_index; - /* tun nodes to drop packets when no crypto alg set on outbound SA */ - u32 esp4_no_crypto_tun_node_index; - u32 esp6_no_crypto_tun_node_index; - - /* tun nodes for encrypt on L2 interfaces */ - u32 esp4_encrypt_l2_tun_node_index; - u32 esp6_encrypt_l2_tun_node_index; - /* pool of ah backends */ ipsec_ah_backend_t *ah_backends; /* pool of esp backends */ diff --git a/src/vnet/ipsec/ipsec_itf.c b/src/vnet/ipsec/ipsec_itf.c index 532d5be4c07..fc0bf85a517 100644 --- a/src/vnet/ipsec/ipsec_itf.c +++ b/src/vnet/ipsec/ipsec_itf.c @@ -36,6 +36,12 @@ ipsec_itf_get (index_t ii) return (pool_elt_at_index (ipsec_itf_pool, ii)); } +u32 +ipsec_itf_count (void) +{ + return (pool_elts (ipsec_itf_pool)); +} + static ipsec_itf_t * ipsec_itf_find_by_sw_if_index (u32 sw_if_index) { @@ -336,6 +342,8 @@ ipsec_itf_delete (u32 sw_if_index) if (ipsec_itf_instance_free (hw->dev_instance) < 0) return VNET_API_ERROR_INVALID_SW_IF_INDEX; + vnet_reset_interface_l3_output_node (vnm->vlib_main, sw_if_index); + vnet_delete_hw_interface (vnm, hw->hw_if_index); pool_put (ipsec_itf_pool, ipsec_itf); diff --git a/src/vnet/ipsec/ipsec_itf.h b/src/vnet/ipsec/ipsec_itf.h index 4958d102b65..7de02745b81 100644 --- a/src/vnet/ipsec/ipsec_itf.h +++ b/src/vnet/ipsec/ipsec_itf.h @@ -109,6 +109,7 @@ extern void ipsec_itf_adj_unstack (adj_index_t ai); extern u8 *format_ipsec_itf (u8 * s, va_list * a); extern ipsec_itf_t *ipsec_itf_get (index_t ii); +extern u32 ipsec_itf_count (void); typedef walk_rc_t (*ipsec_itf_walk_cb_t) (ipsec_itf_t *itf, void *ctx); extern void ipsec_itf_walk (ipsec_itf_walk_cb_t cd, void *ctx); diff --git a/src/vnet/ipsec/ipsec_sa.h b/src/vnet/ipsec/ipsec_sa.h index 2cc64e19546..ec5ca11b179 100644 --- a/src/vnet/ipsec/ipsec_sa.h +++ b/src/vnet/ipsec/ipsec_sa.h @@ -102,7 +102,8 @@ typedef struct ipsec_key_t_ _ (64, IS_INBOUND, "inbound") \ _ (128, IS_AEAD, "aead") \ _ (256, IS_CTR, "ctr") \ - _ (512, IS_ASYNC, "async") + _ (512, IS_ASYNC, "async") \ + _ (1024, NO_ALGO_NO_DROP, "no-algo-no-drop") typedef enum ipsec_sad_flags_t_ { diff --git a/src/vnet/ipsec/ipsec_tun.c b/src/vnet/ipsec/ipsec_tun.c index 1a9a25783ae..ef84d13a373 100644 --- a/src/vnet/ipsec/ipsec_tun.c +++ b/src/vnet/ipsec/ipsec_tun.c @@ -22,6 +22,7 @@ #include <vnet/adj/adj_delegate.h> #include <vnet/adj/adj_midchain.h> #include <vnet/teib/teib.h> +#include <vnet/mpls/mpls.h> /* instantiate the bihash functions */ #include <vppinfra/bihash_8_16.h> @@ -137,12 +138,14 @@ ipsec_tun_protect_from_const_base (const adj_delegate_t * ad) static u32 ipsec_tun_protect_get_adj_next (vnet_link_t linkt, - const ipsec_tun_protect_t * itp) + const ipsec_tun_protect_t *itp) { ipsec_main_t *im; - ipsec_sa_t *sa; u32 next; + im = &ipsec_main; + next = 0; + if (!(itp->itp_flags & IPSEC_PROTECT_ITF)) { if (ip46_address_is_ip4 (&itp->itp_tun.src)) @@ -151,42 +154,48 @@ ipsec_tun_protect_get_adj_next (vnet_link_t linkt, linkt = VNET_LINK_IP6; } - sa = ipsec_sa_get (itp->itp_out_sa); - im = &ipsec_main; - next = 0; - - if ((sa->crypto_alg == IPSEC_CRYPTO_ALG_NONE && - sa->integ_alg == IPSEC_INTEG_ALG_NONE) && - !(itp->itp_flags & IPSEC_PROTECT_ITF)) - next = (VNET_LINK_IP4 == linkt ? im->esp4_no_crypto_tun_node_index : - im->esp6_no_crypto_tun_node_index); - else if (itp->itp_flags & IPSEC_PROTECT_L2) - next = (VNET_LINK_IP4 == linkt ? im->esp4_encrypt_l2_tun_node_index : - im->esp6_encrypt_l2_tun_node_index); - else + switch (linkt) { - switch (linkt) - { - case VNET_LINK_IP4: - next = im->esp4_encrypt_tun_node_index; - break; - case VNET_LINK_IP6: - next = im->esp6_encrypt_tun_node_index; - break; - case VNET_LINK_MPLS: - next = im->esp_mpls_encrypt_tun_node_index; - break; - case VNET_LINK_ARP: - case VNET_LINK_NSH: - case VNET_LINK_ETHERNET: - ASSERT (0); - break; - } + case VNET_LINK_IP4: + next = im->esp4_encrypt_tun_node_index; + break; + case VNET_LINK_IP6: + next = im->esp6_encrypt_tun_node_index; + break; + case VNET_LINK_MPLS: + next = im->esp_mpls_encrypt_tun_node_index; + break; + case VNET_LINK_ARP: + case VNET_LINK_NSH: + case VNET_LINK_ETHERNET: + ASSERT (0); + break; } + return (next); } static void +ipsec_tun_reset_tx_nodes (u32 sw_if_index) +{ + vnet_reset_interface_l3_output_node (vlib_get_main (), sw_if_index); +} + +static void +ipsec_tun_setup_tx_nodes (u32 sw_if_index, const ipsec_tun_protect_t *itp) +{ + vnet_feature_modify_end_node ( + ip4_main.lookup_main.output_feature_arc_index, sw_if_index, + ipsec_tun_protect_get_adj_next (VNET_LINK_IP4, itp)); + vnet_feature_modify_end_node ( + ip6_main.lookup_main.output_feature_arc_index, sw_if_index, + ipsec_tun_protect_get_adj_next (VNET_LINK_IP6, itp)); + vnet_feature_modify_end_node ( + mpls_main.output_feature_arc_index, sw_if_index, + ipsec_tun_protect_get_adj_next (VNET_LINK_MPLS, itp)); +} + +static void ipsec_tun_protect_add_adj (adj_index_t ai, const ipsec_tun_protect_t * itp) { vec_validate_init_empty (ipsec_tun_protect_sa_by_adj_index, ai, @@ -200,8 +209,8 @@ ipsec_tun_protect_add_adj (adj_index_t ai, const ipsec_tun_protect_t * itp) else { ipsec_tun_protect_sa_by_adj_index[ai] = itp->itp_out_sa; - adj_nbr_midchain_update_next_node - (ai, ipsec_tun_protect_get_adj_next (adj_get_link_type (ai), itp)); + adj_nbr_midchain_update_next_node ( + ai, ipsec_tun_protect_get_adj_next (adj_get_link_type (ai), itp)); } } @@ -329,7 +338,7 @@ ipsec_tun_protect_tx_db_add (ipsec_tun_protect_t * itp) { if (INDEX_INVALID == idi->id_itp) { - // ipsec_tun_protect_feature_set (itp, 1); + ipsec_tun_setup_tx_nodes (itp->itp_sw_if_index, itp); } idi->id_itp = itp - ipsec_tun_protect_pool; @@ -347,7 +356,7 @@ ipsec_tun_protect_tx_db_add (ipsec_tun_protect_t * itp) * enable the encrypt feature for egress if this is the first addition * on this interface */ - // ipsec_tun_protect_feature_set (itp, 1); + ipsec_tun_setup_tx_nodes (itp->itp_sw_if_index, itp); } hash_set_mem (idi->id_hash, itp->itp_key, itp - ipsec_tun_protect_pool); @@ -435,7 +444,7 @@ ipsec_tun_protect_tx_db_remove (ipsec_tun_protect_t * itp) if (vnet_sw_interface_is_p2p (vnet_get_main (), itp->itp_sw_if_index)) { - // ipsec_tun_protect_feature_set (itp, 0); + ipsec_tun_reset_tx_nodes (itp->itp_sw_if_index); idi->id_itp = INDEX_INVALID; FOR_EACH_FIB_IP_PROTOCOL (nh_proto) @@ -451,7 +460,7 @@ ipsec_tun_protect_tx_db_remove (ipsec_tun_protect_t * itp) if (0 == hash_elts (idi->id_hash)) { - // ipsec_tun_protect_feature_set (itp, 0); + ipsec_tun_reset_tx_nodes (itp->itp_sw_if_index); hash_free (idi->id_hash); idi->id_hash = NULL; } @@ -502,6 +511,9 @@ ipsec_tun_protect_config (ipsec_main_t * im, ipsec_sa_lock (itp->itp_out_sa); + if (itp->itp_flags & IPSEC_PROTECT_ITF) + ipsec_sa_set_NO_ALGO_NO_DROP (ipsec_sa_get (itp->itp_out_sa)); + /* *INDENT-OFF* */ FOR_EACH_IPSEC_PROTECT_INPUT_SAI(itp, sai, ({ @@ -534,6 +546,7 @@ ipsec_tun_protect_unconfig (ipsec_main_t * im, ipsec_tun_protect_t * itp) ipsec_tun_protect_rx_db_remove (im, itp); ipsec_tun_protect_tx_db_remove (itp); + ipsec_sa_unset_NO_ALGO_NO_DROP (ipsec_sa_get (itp->itp_out_sa)); ipsec_sa_unlock(itp->itp_out_sa); FOR_EACH_IPSEC_PROTECT_INPUT_SAI(itp, sai, @@ -802,19 +815,27 @@ ipsec_tun_feature_update (u32 sw_if_index, u8 arc_index, u8 is_enable, ipsec_main.esp4_decrypt_tun_node_index : ipsec_main.esp6_decrypt_tun_node_index; - vnet_feature_modify_end_node ( - feature_main.device_input_feature_arc_index, sw_if_index, decrypt_tun); - itp->itp_flags |= IPSEC_PROTECT_FEAT; + if (!(itp->itp_flags & IPSEC_PROTECT_FEAT)) + { + itp->itp_flags |= IPSEC_PROTECT_FEAT; + vnet_feature_modify_end_node ( + feature_main.device_input_feature_arc_index, sw_if_index, + decrypt_tun); + } } else { - u32 eth_in = - vlib_get_node_by_name (vlib_get_main (), (u8 *) "ethernet-input") - ->index; + if (itp->itp_flags & IPSEC_PROTECT_FEAT) + { + itp->itp_flags &= ~IPSEC_PROTECT_FEAT; + + u32 eth_in = + vlib_get_node_by_name (vlib_get_main (), (u8 *) "ethernet-input") + ->index; - vnet_feature_modify_end_node ( - feature_main.device_input_feature_arc_index, sw_if_index, eth_in); - itp->itp_flags &= ~IPSEC_PROTECT_FEAT; + vnet_feature_modify_end_node ( + feature_main.device_input_feature_arc_index, sw_if_index, eth_in); + } } /* Propagate flag change into lookup entries */ @@ -848,6 +869,9 @@ ipsec_tun_protect_adj_delegate_adj_created (adj_index_t ai) if (!adj_is_midchain (ai)) return; + vec_validate_init_empty (ipsec_tun_protect_sa_by_adj_index, ai, + INDEX_INVALID); + adj = adj_get (ai); ip_address_from_46 (&adj->sub_type.midchain.next_hop, @@ -956,16 +980,6 @@ ipsec_tunnel_protect_init (vlib_main_t *vm) IPSEC_TUN_DEFAULT_HASH_NUM_BUCKETS, IPSEC_TUN_DEFAULT_HASH_MEMORY_SIZE); - /* set up feature nodes to drop outbound packets with no crypto alg set */ - im->esp4_no_crypto_tun_node_index = - vlib_get_node_by_name (vm, (u8 *) "esp4-no-crypto")->index; - im->esp6_no_crypto_tun_node_index = - vlib_get_node_by_name (vm, (u8 *) "esp6-no-crypto")->index; - im->esp6_encrypt_l2_tun_node_index = - vlib_get_node_by_name (vm, (u8 *) "esp6-encrypt-tun")->index; - im->esp4_encrypt_l2_tun_node_index = - vlib_get_node_by_name (vm, (u8 *) "esp4-encrypt-tun")->index; - ipsec_tun_adj_delegate_type = adj_delegate_register_new_type (&ipsec_tun_adj_delegate_vft); diff --git a/src/vnet/ipsec/ipsec_tun.h b/src/vnet/ipsec/ipsec_tun.h index f452fa4354c..9d8a124443d 100644 --- a/src/vnet/ipsec/ipsec_tun.h +++ b/src/vnet/ipsec/ipsec_tun.h @@ -182,7 +182,6 @@ always_inline index_t ipsec_tun_protect_get_sa_out (adj_index_t ai) { ASSERT (vec_len (ipsec_tun_protect_sa_by_adj_index) > ai); - ASSERT (INDEX_INVALID != ipsec_tun_protect_sa_by_adj_index[ai]); return (ipsec_tun_protect_sa_by_adj_index[ai]); } |