diff options
-rw-r--r-- | src/vnet/ipsec/ah_decrypt.c | 2 | ||||
-rw-r--r-- | src/vnet/ipsec/ah_encrypt.c | 2 | ||||
-rw-r--r-- | src/vnet/ipsec/esp.h | 3 | ||||
-rw-r--r-- | src/vnet/ipsec/esp_decrypt.c | 7 | ||||
-rw-r--r-- | src/vnet/ipsec/esp_encrypt.c | 20 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec.c | 5 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_sa.c | 129 | ||||
-rw-r--r-- | src/vnet/ipsec/ipsec_sa.h | 91 | ||||
-rw-r--r-- | src/vppinfra/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/vppinfra/pcg.h | 85 |
10 files changed, 208 insertions, 137 deletions
diff --git a/src/vnet/ipsec/ah_decrypt.c b/src/vnet/ipsec/ah_decrypt.c index ce4610dae6e..f20f620eb3c 100644 --- a/src/vnet/ipsec/ah_decrypt.c +++ b/src/vnet/ipsec/ah_decrypt.c @@ -155,7 +155,7 @@ ah_decrypt_inline (vlib_main_t * vm, thread_index, current_sa_index); } - if (PREDICT_FALSE (~0 == sa0->thread_index)) + if (PREDICT_FALSE ((u16) ~0 == sa0->thread_index)) { /* this is the first packet to use this SA, claim the SA * for this thread. this could happen simultaneously on diff --git a/src/vnet/ipsec/ah_encrypt.c b/src/vnet/ipsec/ah_encrypt.c index e2d17d48ccf..03e04880161 100644 --- a/src/vnet/ipsec/ah_encrypt.c +++ b/src/vnet/ipsec/ah_encrypt.c @@ -168,7 +168,7 @@ ah_encrypt_inline (vlib_main_t * vm, pd->sa_index = current_sa_index; next[0] = AH_ENCRYPT_NEXT_DROP; - if (PREDICT_FALSE (~0 == sa0->thread_index)) + if (PREDICT_FALSE ((u16) ~0 == sa0->thread_index)) { /* this is the first packet to use this SA, claim the SA * for this thread. this could happen simultaneously on diff --git a/src/vnet/ipsec/esp.h b/src/vnet/ipsec/esp.h index 05773a2a328..311882af08e 100644 --- a/src/vnet/ipsec/esp.h +++ b/src/vnet/ipsec/esp.h @@ -86,9 +86,6 @@ typedef struct esp_aead_t_ } __clib_packed esp_aead_t; #define ESP_SEQ_MAX (4294967295UL) -#define ESP_MAX_BLOCK_SIZE (16) -#define ESP_MAX_IV_SIZE (16) -#define ESP_MAX_ICV_SIZE (32) u8 *format_esp_header (u8 * s, va_list * args); diff --git a/src/vnet/ipsec/esp_decrypt.c b/src/vnet/ipsec/esp_decrypt.c index 1bcc65ca972..827d168f98a 100644 --- a/src/vnet/ipsec/esp_decrypt.c +++ b/src/vnet/ipsec/esp_decrypt.c @@ -603,7 +603,7 @@ esp_decrypt_prepare_async_frame (vlib_main_t *vm, vlib_node_runtime_t *node, esp_decrypt_packet_data_t *async_pd = &(esp_post_data (b))->decrypt_data; esp_decrypt_packet_data2_t *async_pd2 = esp_post_data2 (b); u8 *tag = payload + len, *iv = payload + esp_sz, *aad = 0; - u32 key_index; + const u32 key_index = sa0->crypto_key_index; u32 crypto_len, integ_len = 0; i16 crypto_start_offset, integ_start_offset = 0; u8 flags = 0; @@ -611,7 +611,6 @@ esp_decrypt_prepare_async_frame (vlib_main_t *vm, vlib_node_runtime_t *node, if (!ipsec_sa_is_set_IS_AEAD (sa0)) { /* linked algs */ - key_index = sa0->linked_key_index; integ_start_offset = payload - b->data; integ_len = len; if (PREDICT_TRUE (sa0->integ_op_id != VNET_CRYPTO_OP_NONE)) @@ -664,8 +663,6 @@ esp_decrypt_prepare_async_frame (vlib_main_t *vm, vlib_node_runtime_t *node, else esp_insert_esn (vm, sa0, pd, pd2, &integ_len, &tag, &len, b, payload); } - else - key_index = sa0->crypto_key_index; out: /* crypto */ @@ -1103,7 +1100,7 @@ esp_decrypt_inline (vlib_main_t *vm, vlib_node_runtime_t *node, is_async = im->async_mode | ipsec_sa_is_set_IS_ASYNC (sa0); } - if (PREDICT_FALSE (~0 == sa0->thread_index)) + if (PREDICT_FALSE ((u16) ~0 == sa0->thread_index)) { /* this is the first packet to use this SA, claim the SA * for this thread. this could happen simultaneously on diff --git a/src/vnet/ipsec/esp_encrypt.c b/src/vnet/ipsec/esp_encrypt.c index 88e93b9b2d4..861b3e98650 100644 --- a/src/vnet/ipsec/esp_encrypt.c +++ b/src/vnet/ipsec/esp_encrypt.c @@ -219,17 +219,18 @@ esp_get_ip6_hdr_len (ip6_header_t * ip6, ip6_ext_header_t ** ext_hdr) * encryption mode: IVs must be unpredictable for AES-CBC whereas it can * be predictable but should never be reused with the same key material * for CTR and GCM. - * We use a packet counter as the IV for CTR and GCM, and to ensure the - * IV is unpredictable for CBC, it is then encrypted using the same key - * as the message. You can refer to NIST SP800-38a and NIST SP800-38d - * for more details. */ + * To avoid reusing the same IVs between multiple VPP instances and between + * restarts, we use a properly chosen PRNG to generate IVs. To ensure the IV is + * unpredictable for CBC, it is then encrypted using the same key as the + * message. You can refer to NIST SP800-38a and NIST SP800-38d for more + * details. */ static_always_inline void * esp_generate_iv (ipsec_sa_t *sa, void *payload, int iv_sz) { ASSERT (iv_sz >= sizeof (u64)); u64 *iv = (u64 *) (payload - iv_sz); clib_memset_u8 (iv, 0, iv_sz); - *iv = sa->iv_counter++; + *iv = clib_pcg64i_random_r (&sa->iv_prng); return iv; } @@ -434,7 +435,7 @@ esp_prepare_sync_op (vlib_main_t *vm, ipsec_per_thread_data_t *ptd, crypto_len += iv_sz; } - if (lb != b[0]) + if (PREDICT_FALSE (lb != b[0])) { /* is chained */ op->flags |= VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS; @@ -497,7 +498,7 @@ esp_prepare_async_frame (vlib_main_t *vm, ipsec_per_thread_data_t *ptd, esp_post_data_t *post = esp_post_data (b); u8 *tag, *iv, *aad = 0; u8 flag = 0; - u32 key_index; + const u32 key_index = sa->crypto_key_index; i16 crypto_start_offset, integ_start_offset; u16 crypto_total_len, integ_total_len; @@ -508,8 +509,6 @@ esp_prepare_async_frame (vlib_main_t *vm, ipsec_per_thread_data_t *ptd, crypto_total_len = integ_total_len = payload_len - icv_sz; tag = payload + crypto_total_len; - key_index = sa->linked_key_index; - /* generate the IV in front of the payload */ void *pkt_iv = esp_generate_iv (sa, payload, iv_sz); @@ -523,7 +522,6 @@ esp_prepare_async_frame (vlib_main_t *vm, ipsec_per_thread_data_t *ptd, /* constuct aad in a scratch space in front of the nonce */ aad = (u8 *) nonce - sizeof (esp_aead_t); esp_aad_fill (aad, esp, sa, sa->seq_hi); - key_index = sa->crypto_key_index; } else { @@ -705,7 +703,7 @@ esp_encrypt_inline (vlib_main_t *vm, vlib_node_runtime_t *node, is_async = im->async_mode | ipsec_sa_is_set_IS_ASYNC (sa0); } - if (PREDICT_FALSE (~0 == sa0->thread_index)) + if (PREDICT_FALSE ((u16) ~0 == sa0->thread_index)) { /* this is the first packet to use this SA, claim the SA * for this thread. this could happen simultaneously on diff --git a/src/vnet/ipsec/ipsec.c b/src/vnet/ipsec/ipsec.c index 3ea2e4d62df..86cb8982d07 100644 --- a/src/vnet/ipsec/ipsec.c +++ b/src/vnet/ipsec/ipsec.c @@ -408,10 +408,7 @@ ipsec_set_async_mode (u32 is_enabled) /* change SA crypto op data */ pool_foreach (sa, ipsec_sa_pool) - { - sa->crypto_op_data = - (is_enabled ? sa->async_op_data.data : sa->sync_op_data.data); - } + ipsec_sa_set_async_mode (sa, is_enabled); } static void diff --git a/src/vnet/ipsec/ipsec_sa.c b/src/vnet/ipsec/ipsec_sa.c index eed71a48500..95db17e7fb1 100644 --- a/src/vnet/ipsec/ipsec_sa.c +++ b/src/vnet/ipsec/ipsec_sa.c @@ -13,6 +13,7 @@ * limitations under the License. */ +#include <sys/random.h> #include <vnet/ipsec/ipsec.h> #include <vnet/ipsec/esp.h> #include <vnet/udp/udp_local.h> @@ -92,14 +93,35 @@ ipsec_sa_stack (ipsec_sa_t * sa) } void +ipsec_sa_set_async_mode (ipsec_sa_t *sa, int is_enabled) +{ + if (is_enabled) + { + sa->crypto_key_index = sa->crypto_async_key_index; + sa->crypto_enc_op_id = sa->crypto_async_enc_op_id; + sa->crypto_dec_op_id = sa->crypto_async_dec_op_id; + sa->integ_key_index = ~0; + sa->integ_op_id = ~0; + } + else + { + sa->crypto_key_index = sa->crypto_sync_key_index; + sa->crypto_enc_op_id = sa->crypto_sync_enc_op_id; + sa->crypto_dec_op_id = sa->crypto_sync_dec_op_id; + sa->integ_key_index = sa->integ_sync_key_index; + sa->integ_op_id = sa->integ_sync_op_id; + } +} + +void ipsec_sa_set_crypto_alg (ipsec_sa_t * sa, ipsec_crypto_alg_t crypto_alg) { ipsec_main_t *im = &ipsec_main; sa->crypto_alg = crypto_alg; sa->crypto_iv_size = im->crypto_algs[crypto_alg].iv_size; sa->esp_block_align = clib_max (4, im->crypto_algs[crypto_alg].block_align); - sa->sync_op_data.crypto_enc_op_id = im->crypto_algs[crypto_alg].enc_op_id; - sa->sync_op_data.crypto_dec_op_id = im->crypto_algs[crypto_alg].dec_op_id; + sa->crypto_sync_enc_op_id = im->crypto_algs[crypto_alg].enc_op_id; + sa->crypto_sync_dec_op_id = im->crypto_algs[crypto_alg].dec_op_id; sa->crypto_calg = im->crypto_algs[crypto_alg].alg; ASSERT (sa->crypto_iv_size <= ESP_MAX_IV_SIZE); ASSERT (sa->esp_block_align <= ESP_MAX_BLOCK_SIZE); @@ -122,7 +144,7 @@ ipsec_sa_set_integ_alg (ipsec_sa_t * sa, ipsec_integ_alg_t integ_alg) ipsec_main_t *im = &ipsec_main; sa->integ_alg = integ_alg; sa->integ_icv_size = im->integ_algs[integ_alg].icv_size; - sa->sync_op_data.integ_op_id = im->integ_algs[integ_alg].op_id; + sa->integ_sync_op_id = im->integ_algs[integ_alg].op_id; sa->integ_calg = im->integ_algs[integ_alg].alg; ASSERT (sa->integ_icv_size <= ESP_MAX_ICV_SIZE); } @@ -133,38 +155,32 @@ ipsec_sa_set_async_op_ids (ipsec_sa_t * sa) /* *INDENT-OFF* */ if (ipsec_sa_is_set_USE_ESN (sa)) { -#define _(n, s, k) \ - if( sa->sync_op_data.crypto_enc_op_id == VNET_CRYPTO_OP_##n##_ENC ) \ - sa->async_op_data.crypto_async_enc_op_id = \ - VNET_CRYPTO_OP_##n##_TAG16_AAD12_ENC; \ - if( sa->sync_op_data.crypto_dec_op_id == VNET_CRYPTO_OP_##n##_DEC ) \ - sa->async_op_data.crypto_async_dec_op_id = \ - VNET_CRYPTO_OP_##n##_TAG16_AAD12_DEC; - foreach_crypto_aead_alg +#define _(n, s, k) \ + if (sa->crypto_sync_enc_op_id == VNET_CRYPTO_OP_##n##_ENC) \ + sa->crypto_async_enc_op_id = VNET_CRYPTO_OP_##n##_TAG16_AAD12_ENC; \ + if (sa->crypto_sync_dec_op_id == VNET_CRYPTO_OP_##n##_DEC) \ + sa->crypto_async_dec_op_id = VNET_CRYPTO_OP_##n##_TAG16_AAD12_DEC; + foreach_crypto_aead_alg #undef _ } else { -#define _(n, s, k) \ - if( sa->sync_op_data.crypto_enc_op_id == VNET_CRYPTO_OP_##n##_ENC ) \ - sa->async_op_data.crypto_async_enc_op_id = \ - VNET_CRYPTO_OP_##n##_TAG16_AAD8_ENC; \ - if( sa->sync_op_data.crypto_dec_op_id == VNET_CRYPTO_OP_##n##_DEC ) \ - sa->async_op_data.crypto_async_dec_op_id = \ - VNET_CRYPTO_OP_##n##_TAG16_AAD8_DEC; - foreach_crypto_aead_alg +#define _(n, s, k) \ + if (sa->crypto_sync_enc_op_id == VNET_CRYPTO_OP_##n##_ENC) \ + sa->crypto_async_enc_op_id = VNET_CRYPTO_OP_##n##_TAG16_AAD8_ENC; \ + if (sa->crypto_sync_dec_op_id == VNET_CRYPTO_OP_##n##_DEC) \ + sa->crypto_async_dec_op_id = VNET_CRYPTO_OP_##n##_TAG16_AAD8_DEC; + foreach_crypto_aead_alg #undef _ } -#define _(c, h, s, k ,d) \ - if( sa->sync_op_data.crypto_enc_op_id == VNET_CRYPTO_OP_##c##_ENC && \ - sa->sync_op_data.integ_op_id == VNET_CRYPTO_OP_##h##_HMAC) \ - sa->async_op_data.crypto_async_enc_op_id = \ - VNET_CRYPTO_OP_##c##_##h##_TAG##d##_ENC; \ - if( sa->sync_op_data.crypto_dec_op_id == VNET_CRYPTO_OP_##c##_DEC && \ - sa->sync_op_data.integ_op_id == VNET_CRYPTO_OP_##h##_HMAC) \ - sa->async_op_data.crypto_async_dec_op_id = \ - VNET_CRYPTO_OP_##c##_##h##_TAG##d##_DEC; +#define _(c, h, s, k, d) \ + if (sa->crypto_sync_enc_op_id == VNET_CRYPTO_OP_##c##_ENC && \ + sa->integ_sync_op_id == VNET_CRYPTO_OP_##h##_HMAC) \ + sa->crypto_async_enc_op_id = VNET_CRYPTO_OP_##c##_##h##_TAG##d##_ENC; \ + if (sa->crypto_sync_dec_op_id == VNET_CRYPTO_OP_##c##_DEC && \ + sa->integ_sync_op_id == VNET_CRYPTO_OP_##h##_HMAC) \ + sa->crypto_async_dec_op_id = VNET_CRYPTO_OP_##c##_##h##_TAG##d##_DEC; foreach_crypto_link_async_alg #undef _ /* *INDENT-ON* */ @@ -313,6 +329,7 @@ ipsec_sa_add_and_lock (u32 id, u32 spi, ipsec_protocol_t proto, clib_error_t *err; ipsec_sa_t *sa; u32 sa_index; + u64 rand[2]; uword *p; int rv; @@ -320,8 +337,13 @@ ipsec_sa_add_and_lock (u32 id, u32 spi, ipsec_protocol_t proto, if (p) return VNET_API_ERROR_ENTRY_ALREADY_EXISTS; + if (getrandom (rand, sizeof (rand), 0) != sizeof (rand)) + return VNET_API_ERROR_INIT_FAILED; + pool_get_aligned_zero (ipsec_sa_pool, sa, CLIB_CACHE_LINE_BYTES); + clib_pcg64i_srandom_r (&sa->iv_prng, rand[0], rand[1]); + fib_node_init (&sa->node, FIB_NODE_TYPE_IPSEC_SA); fib_node_lock (&sa->node); sa_index = sa - ipsec_sa_pool; @@ -352,10 +374,9 @@ ipsec_sa_add_and_lock (u32 id, u32 spi, ipsec_protocol_t proto, clib_memcpy (&sa->crypto_key, ck, sizeof (sa->crypto_key)); - sa->crypto_key_index = vnet_crypto_key_add (vm, - im->crypto_algs[crypto_alg].alg, - (u8 *) ck->data, ck->len); - if (~0 == sa->crypto_key_index) + sa->crypto_sync_key_index = vnet_crypto_key_add ( + vm, im->crypto_algs[crypto_alg].alg, (u8 *) ck->data, ck->len); + if (~0 == sa->crypto_sync_key_index) { pool_put (ipsec_sa_pool, sa); return VNET_API_ERROR_KEY_LENGTH; @@ -363,36 +384,34 @@ ipsec_sa_add_and_lock (u32 id, u32 spi, ipsec_protocol_t proto, if (integ_alg != IPSEC_INTEG_ALG_NONE) { - sa->integ_key_index = vnet_crypto_key_add (vm, - im-> - integ_algs[integ_alg].alg, - (u8 *) ik->data, ik->len); - if (~0 == sa->integ_key_index) + sa->integ_sync_key_index = vnet_crypto_key_add ( + vm, im->integ_algs[integ_alg].alg, (u8 *) ik->data, ik->len); + if (~0 == sa->integ_sync_key_index) { pool_put (ipsec_sa_pool, sa); return VNET_API_ERROR_KEY_LENGTH; } } - if (sa->async_op_data.crypto_async_enc_op_id && - !ipsec_sa_is_set_IS_AEAD (sa)) - { //AES-CBC & HMAC - sa->async_op_data.linked_key_index = - vnet_crypto_key_add_linked (vm, sa->crypto_key_index, - sa->integ_key_index); - } + if (sa->crypto_async_enc_op_id && !ipsec_sa_is_set_IS_AEAD (sa)) + sa->crypto_async_key_index = + vnet_crypto_key_add_linked (vm, sa->crypto_sync_key_index, + sa->integ_sync_key_index); // AES-CBC & HMAC + else + sa->crypto_async_key_index = sa->crypto_sync_key_index; if (im->async_mode) - sa->crypto_op_data = sa->async_op_data.data; + { + ipsec_sa_set_async_mode (sa, 1); + } + else if (ipsec_sa_is_set_IS_ASYNC (sa)) + { + vnet_crypto_request_async_mode (1); + ipsec_sa_set_async_mode (sa, 1 /* is_enabled */); + } else { - if (ipsec_sa_is_set_IS_ASYNC (sa)) - { - vnet_crypto_request_async_mode (1); - sa->crypto_op_data = sa->async_op_data.data; - } - else - sa->crypto_op_data = sa->sync_op_data.data; + ipsec_sa_set_async_mode (sa, 0 /* is_enabled */); } err = ipsec_check_support_cb (im, sa); @@ -489,7 +508,7 @@ ipsec_sa_del (ipsec_sa_t * sa) { vnet_crypto_request_async_mode (0); if (!ipsec_sa_is_set_IS_AEAD (sa)) - vnet_crypto_key_del (vm, sa->async_op_data.linked_key_index); + vnet_crypto_key_del (vm, sa->crypto_async_key_index); } if (ipsec_sa_is_set_UDP_ENCAP (sa) && ipsec_sa_is_set_IS_INBOUND (sa)) @@ -498,9 +517,9 @@ ipsec_sa_del (ipsec_sa_t * sa) if (ipsec_sa_is_set_IS_TUNNEL (sa) && !ipsec_sa_is_set_IS_INBOUND (sa)) dpo_reset (&sa->dpo); - vnet_crypto_key_del (vm, sa->crypto_key_index); + vnet_crypto_key_del (vm, sa->crypto_sync_key_index); if (sa->integ_alg != IPSEC_INTEG_ALG_NONE) - vnet_crypto_key_del (vm, sa->integ_key_index); + vnet_crypto_key_del (vm, sa->integ_sync_key_index); pool_put (ipsec_sa_pool, sa); } diff --git a/src/vnet/ipsec/ipsec_sa.h b/src/vnet/ipsec/ipsec_sa.h index 4ef8f87dbef..ab1e3cdb1f9 100644 --- a/src/vnet/ipsec/ipsec_sa.h +++ b/src/vnet/ipsec/ipsec_sa.h @@ -16,11 +16,16 @@ #define __IPSEC_SPD_SA_H__ #include <vlib/vlib.h> +#include <vppinfra/pcg.h> #include <vnet/crypto/crypto.h> #include <vnet/ip/ip.h> #include <vnet/fib/fib_node.h> #include <vnet/tunnel/tunnel.h> +#define ESP_MAX_ICV_SIZE (32) +#define ESP_MAX_IV_SIZE (16) +#define ESP_MAX_BLOCK_SIZE (16) + #define foreach_ipsec_crypto_alg \ _ (0, NONE, "none") \ _ (1, AES_CBC_128, "aes-cbc-128") \ @@ -151,47 +156,27 @@ typedef struct { CLIB_CACHE_LINE_ALIGN_MARK (cacheline0); - /* flags */ - ipsec_sa_flags_t flags; - - u8 crypto_iv_size; - u8 esp_block_align; - u8 integ_icv_size; - - u8 __pad1[3]; + clib_pcg64i_random_t iv_prng; - u32 thread_index; - - u32 spi; - u32 seq; - u32 seq_hi; u64 replay_window; - u64 iv_counter; dpo_id_t dpo; vnet_crypto_key_index_t crypto_key_index; vnet_crypto_key_index_t integ_key_index; - /* Union data shared by sync and async ops, updated when mode is - * changed. */ - union - { - struct - { - vnet_crypto_op_id_t crypto_enc_op_id:16; - vnet_crypto_op_id_t crypto_dec_op_id:16; - vnet_crypto_op_id_t integ_op_id:16; - }; + u32 spi; + u32 seq; + u32 seq_hi; - struct - { - vnet_crypto_async_op_id_t crypto_async_enc_op_id:16; - vnet_crypto_async_op_id_t crypto_async_dec_op_id:16; - vnet_crypto_key_index_t linked_key_index; - }; + u16 crypto_enc_op_id; + u16 crypto_dec_op_id; + u16 integ_op_id; + ipsec_sa_flags_t flags; + u16 thread_index; - u64 crypto_op_data; - }; + u16 integ_icv_size : 6; + u16 crypto_iv_size : 5; + u16 esp_block_align : 5; CLIB_CACHE_LINE_ALIGN_MARK (cacheline1); @@ -213,30 +198,7 @@ typedef struct CLIB_CACHE_LINE_ALIGN_MARK (cacheline2); /* Elements with u64 size multiples */ - union - { - struct - { - vnet_crypto_op_id_t crypto_enc_op_id:16; - vnet_crypto_op_id_t crypto_dec_op_id:16; - vnet_crypto_op_id_t integ_op_id:16; - }; - u64 data; - } sync_op_data; - - union - { - struct - { - vnet_crypto_async_op_id_t crypto_async_enc_op_id:16; - vnet_crypto_async_op_id_t crypto_async_dec_op_id:16; - vnet_crypto_key_index_t linked_key_index; - }; - u64 data; - } async_op_data; - tunnel_t tunnel; - fib_node_t node; /* elements with u32 size */ @@ -244,6 +206,16 @@ typedef struct u32 stat_index; vnet_crypto_alg_t integ_calg; vnet_crypto_alg_t crypto_calg; + u32 crypto_sync_key_index; + u32 integ_sync_key_index; + u32 crypto_async_key_index; + + /* elements with u16 size */ + u16 crypto_sync_enc_op_id; + u16 crypto_sync_dec_op_id; + u16 integ_sync_op_id; + u16 crypto_async_enc_op_id; + u16 crypto_async_dec_op_id; /* else u8 packed */ ipsec_crypto_alg_t crypto_alg; @@ -253,6 +225,10 @@ typedef struct ipsec_key_t crypto_key; } ipsec_sa_t; +STATIC_ASSERT (VNET_CRYPTO_N_OP_IDS < (1 << 16), "crypto ops overflow"); +STATIC_ASSERT (ESP_MAX_ICV_SIZE < (1 << 6), "integer icv overflow"); +STATIC_ASSERT (ESP_MAX_IV_SIZE < (1 << 5), "esp iv overflow"); +STATIC_ASSERT (ESP_MAX_BLOCK_SIZE < (1 << 5), "esp alignment overflow"); STATIC_ASSERT_OFFSET_OF (ipsec_sa_t, cacheline1, CLIB_CACHE_LINE_BYTES); STATIC_ASSERT_OFFSET_OF (ipsec_sa_t, cacheline2, 2 * CLIB_CACHE_LINE_BYTES); @@ -316,6 +292,7 @@ extern void ipsec_sa_set_crypto_alg (ipsec_sa_t * sa, ipsec_crypto_alg_t crypto_alg); extern void ipsec_sa_set_integ_alg (ipsec_sa_t * sa, ipsec_integ_alg_t integ_alg); +extern void ipsec_sa_set_async_mode (ipsec_sa_t *sa, int is_enabled); typedef walk_rc_t (*ipsec_sa_walk_cb_t) (ipsec_sa_t * sa, void *ctx); extern void ipsec_sa_walk (ipsec_sa_walk_cb_t cd, void *ctx); @@ -668,8 +645,8 @@ ipsec_sa_anti_replay_advance (ipsec_sa_t *sa, u32 thread_index, u32 seq, * Makes choice for thread_id should be assigned. * if input ~0, gets random worker_id based on unix_time_now_nsec */ -always_inline u32 -ipsec_sa_assign_thread (u32 thread_id) +always_inline u16 +ipsec_sa_assign_thread (u16 thread_id) { return ((thread_id) ? thread_id : (unix_time_now_nsec () % vlib_num_workers ()) + 1); diff --git a/src/vppinfra/CMakeLists.txt b/src/vppinfra/CMakeLists.txt index 4a9c008b65e..975bf503827 100644 --- a/src/vppinfra/CMakeLists.txt +++ b/src/vppinfra/CMakeLists.txt @@ -158,6 +158,7 @@ set(VPPINFRA_HEADERS os.h pcap.h pcap_funcs.h + pcg.h perfmon/perfmon.h pmalloc.h pool.h diff --git a/src/vppinfra/pcg.h b/src/vppinfra/pcg.h new file mode 100644 index 00000000000..a7cc9201b8f --- /dev/null +++ b/src/vppinfra/pcg.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2022 Cisco and/or its affiliates. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * PCG Random Number Generation for C. + * + * Copyright 2014-2019 Melissa O'Neill <oneill@pcg-random.org>, + * and the PCG Project contributors. + * + * SPDX-License-Identifier: (Apache-2.0 OR MIT) + * + * Licensed under the Apache License, Version 2.0 (provided in + * LICENSE-APACHE.txt and at http://www.apache.org/licenses/LICENSE-2.0) + * or under the MIT license (provided in LICENSE-MIT.txt and at + * http://opensource.org/licenses/MIT), at your option. This file may not + * be copied, modified, or distributed except according to those terms. + * + * Distributed on an "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, either + * express or implied. See your chosen license for details. + * + * For additional information about the PCG random number generation scheme, + * visit http://www.pcg-random.org/. + */ + +/* This implements the pcg64i_random_t PCG specialized generator: + * https://www.pcg-random.org/using-pcg-c.html#specialized-generators + * This generator produces each 64-bits output exactly once, which is + * perfectly suited to generated non-repeating IVs. However, because of this + * property the entire internal state is revealed with each output. + * It has a 2^64 period and supports 2^63 non-overlaping streams */ + +#define clib_pcg64i_random_r clib_pcg_setseq_64_rxs_m_xs_64_random_r +#define clib_pcg64i_srandom_r clib_pcg_setseq_64_srandom_r + +typedef struct +{ + u64 state; + u64 inc; +} clib_pcg_state_setseq_64_t; + +typedef clib_pcg_state_setseq_64_t clib_pcg64i_random_t; + +static_always_inline void +clib_pcg_setseq_64_step_r (clib_pcg_state_setseq_64_t *rng) +{ + rng->state = rng->state * 6364136223846793005ULL + rng->inc; +} + +static_always_inline u64 +clib_pcg_output_rxs_m_xs_64_64 (u64 state) +{ + u64 word = + ((state >> ((state >> 59u) + 5u)) ^ state) * 12605985483714917081ull; + return (word >> 43u) ^ word; +} + +static_always_inline u64 +clib_pcg_setseq_64_rxs_m_xs_64_random_r (clib_pcg_state_setseq_64_t *rng) +{ + u64 oldstate = rng->state; + clib_pcg_setseq_64_step_r (rng); + return clib_pcg_output_rxs_m_xs_64_64 (oldstate); +} + +static_always_inline void +clib_pcg_setseq_64_srandom_r (clib_pcg_state_setseq_64_t *rng, u64 initstate, + u64 initseq) +{ + rng->state = 0U; + rng->inc = (initseq << 1u) | 1u; + clib_pcg_setseq_64_step_r (rng); + rng->state += initstate; + clib_pcg_setseq_64_step_r (rng); +} |