wireguard: add async mode for decryption packets
Originally wireguard doesn't support async mode for decryption packets. This patch add async mode for decryption in wireguard. In addition, it contains some performance improvement such as prefetching packet header and reducing the number of current time function calls. Type: improvement Signed-off-by: Gabriel Oginski <gabrielx.oginski@intel.com> Change-Id: Ieba6ae0078f3ff140c05b517891afb57232b3b7d
This commit is contained in:

committed by
Matthew Smith

parent
492d7790ff
commit
77e69ae2d1
@ -25,6 +25,7 @@
|
||||
|
||||
wg_main_t wg_main;
|
||||
wg_async_post_next_t wg_encrypt_async_next;
|
||||
wg_async_post_next_t wg_decrypt_async_next;
|
||||
|
||||
void
|
||||
wg_set_async_mode (u32 is_enabled)
|
||||
@ -39,15 +40,23 @@ wg_set_async_mode (u32 is_enabled)
|
||||
|
||||
static void
|
||||
wireguard_register_post_node (vlib_main_t *vm)
|
||||
|
||||
{
|
||||
wg_async_post_next_t *eit;
|
||||
wg_async_post_next_t *dit;
|
||||
|
||||
eit = &wg_encrypt_async_next;
|
||||
dit = &wg_decrypt_async_next;
|
||||
|
||||
eit->wg4_post_next =
|
||||
vnet_crypto_register_post_node (vm, "wg4-output-tun-post-node");
|
||||
eit->wg6_post_next =
|
||||
vnet_crypto_register_post_node (vm, "wg6-output-tun-post-node");
|
||||
|
||||
dit->wg4_post_next =
|
||||
vnet_crypto_register_post_node (vm, "wg4-input-post-node");
|
||||
dit->wg6_post_next =
|
||||
vnet_crypto_register_post_node (vm, "wg6-input-post-node");
|
||||
}
|
||||
|
||||
static clib_error_t *
|
||||
|
@ -64,6 +64,7 @@ typedef struct
|
||||
} wg_async_post_next_t;
|
||||
|
||||
extern wg_async_post_next_t wg_encrypt_async_next;
|
||||
extern wg_async_post_next_t wg_decrypt_async_next;
|
||||
extern wg_main_t wg_main;
|
||||
|
||||
/**
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -544,41 +544,6 @@ chacha20poly1305_calc (vlib_main_t * vm,
|
||||
return (op->status == VNET_CRYPTO_OP_STATUS_COMPLETED);
|
||||
}
|
||||
|
||||
always_inline void
|
||||
wg_prepare_sync_op (vlib_main_t *vm, vnet_crypto_op_t **crypto_ops, u8 *src,
|
||||
u32 src_len, u8 *dst, u8 *aad, u32 aad_len, u64 nonce,
|
||||
vnet_crypto_op_id_t op_id,
|
||||
vnet_crypto_key_index_t key_index, u32 bi, u8 *iv)
|
||||
{
|
||||
vnet_crypto_op_t _op, *op = &_op;
|
||||
u8 src_[] = {};
|
||||
|
||||
clib_memset (iv, 0, 4);
|
||||
clib_memcpy (iv + 4, &nonce, sizeof (nonce));
|
||||
|
||||
vec_add2_aligned (crypto_ops[0], op, 1, CLIB_CACHE_LINE_BYTES);
|
||||
vnet_crypto_op_init (op, op_id);
|
||||
|
||||
op->tag_len = NOISE_AUTHTAG_LEN;
|
||||
if (op_id == VNET_CRYPTO_OP_CHACHA20_POLY1305_DEC)
|
||||
{
|
||||
op->tag = src + src_len;
|
||||
op->flags |= VNET_CRYPTO_OP_FLAG_HMAC_CHECK;
|
||||
}
|
||||
else
|
||||
op->tag = dst + src_len;
|
||||
|
||||
op->src = !src ? src_ : src;
|
||||
op->len = src_len;
|
||||
|
||||
op->dst = dst;
|
||||
op->key_index = key_index;
|
||||
op->aad = aad;
|
||||
op->aad_len = aad_len;
|
||||
op->iv = iv;
|
||||
op->user_data = bi;
|
||||
}
|
||||
|
||||
enum noise_state_crypt
|
||||
noise_remote_encrypt (vlib_main_t * vm, noise_remote_t * r, uint32_t * r_idx,
|
||||
uint64_t * nonce, uint8_t * src, size_t srclen,
|
||||
@ -629,73 +594,6 @@ error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
enum noise_state_crypt
|
||||
noise_sync_remote_decrypt (vlib_main_t *vm, vnet_crypto_op_t **crypto_ops,
|
||||
noise_remote_t *r, uint32_t r_idx, uint64_t nonce,
|
||||
uint8_t *src, size_t srclen, uint8_t *dst, u32 bi,
|
||||
u8 *iv, f64 time)
|
||||
{
|
||||
noise_keypair_t *kp;
|
||||
enum noise_state_crypt ret = SC_FAILED;
|
||||
|
||||
if ((kp = wg_get_active_keypair (r, r_idx)) == NULL)
|
||||
{
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* We confirm that our values are within our tolerances. These values
|
||||
* are the same as the encrypt routine.
|
||||
*
|
||||
* kp_ctr isn't locked here, we're happy to accept a racy read. */
|
||||
if (wg_birthdate_has_expired_opt (kp->kp_birthdate, REJECT_AFTER_TIME,
|
||||
time) ||
|
||||
kp->kp_ctr.c_recv >= REJECT_AFTER_MESSAGES)
|
||||
goto error;
|
||||
|
||||
/* Decrypt, then validate the counter. We don't want to validate the
|
||||
* counter before decrypting as we do not know the message is authentic
|
||||
* prior to decryption. */
|
||||
wg_prepare_sync_op (vm, crypto_ops, src, srclen, dst, NULL, 0, nonce,
|
||||
VNET_CRYPTO_OP_CHACHA20_POLY1305_DEC, kp->kp_recv_index,
|
||||
bi, iv);
|
||||
|
||||
/* If we've received the handshake confirming data packet then move the
|
||||
* next keypair into current. If we do slide the next keypair in, then
|
||||
* we skip the REKEY_AFTER_TIME_RECV check. This is safe to do as a
|
||||
* data packet can't confirm a session that we are an INITIATOR of. */
|
||||
if (kp == r->r_next)
|
||||
{
|
||||
clib_rwlock_writer_lock (&r->r_keypair_lock);
|
||||
if (kp == r->r_next && kp->kp_local_index == r_idx)
|
||||
{
|
||||
noise_remote_keypair_free (vm, r, &r->r_previous);
|
||||
r->r_previous = r->r_current;
|
||||
r->r_current = r->r_next;
|
||||
r->r_next = NULL;
|
||||
|
||||
ret = SC_CONN_RESET;
|
||||
clib_rwlock_writer_unlock (&r->r_keypair_lock);
|
||||
goto error;
|
||||
}
|
||||
clib_rwlock_writer_unlock (&r->r_keypair_lock);
|
||||
}
|
||||
|
||||
/* Similar to when we encrypt, we want to notify the caller when we
|
||||
* are approaching our tolerances. We notify if:
|
||||
* - we're the initiator and the current keypair is older than
|
||||
* REKEY_AFTER_TIME_RECV seconds. */
|
||||
ret = SC_KEEP_KEY_FRESH;
|
||||
kp = r->r_current;
|
||||
if (kp != NULL && kp->kp_valid && kp->kp_is_initiator &&
|
||||
wg_birthdate_has_expired_opt (kp->kp_birthdate, REKEY_AFTER_TIME_RECV,
|
||||
time))
|
||||
goto error;
|
||||
|
||||
ret = SC_OK;
|
||||
error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Private functions - these should not be called outside this file under any
|
||||
* circumstances. */
|
||||
static noise_keypair_t *
|
||||
@ -706,21 +604,6 @@ noise_remote_keypair_allocate (noise_remote_t * r)
|
||||
return kp;
|
||||
}
|
||||
|
||||
static void
|
||||
noise_remote_keypair_free (vlib_main_t * vm, noise_remote_t * r,
|
||||
noise_keypair_t ** kp)
|
||||
{
|
||||
noise_local_t *local = noise_local_get (r->r_local_idx);
|
||||
struct noise_upcall *u = &local->l_upcall;
|
||||
if (*kp)
|
||||
{
|
||||
u->u_index_drop ((*kp)->kp_local_index);
|
||||
vnet_crypto_key_del (vm, (*kp)->kp_send_index);
|
||||
vnet_crypto_key_del (vm, (*kp)->kp_recv_index);
|
||||
clib_mem_free (*kp);
|
||||
}
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
noise_remote_handshake_index_get (noise_remote_t * r)
|
||||
{
|
||||
|
@ -196,12 +196,6 @@ noise_remote_encrypt (vlib_main_t * vm, noise_remote_t *,
|
||||
uint64_t * nonce,
|
||||
uint8_t * src, size_t srclen, uint8_t * dst);
|
||||
|
||||
enum noise_state_crypt
|
||||
noise_sync_remote_decrypt (vlib_main_t *vm, vnet_crypto_op_t **crypto_ops,
|
||||
noise_remote_t *, uint32_t r_idx, uint64_t nonce,
|
||||
uint8_t *src, size_t srclen, uint8_t *dst, u32 bi,
|
||||
u8 *iv, f64 time);
|
||||
|
||||
static_always_inline noise_keypair_t *
|
||||
wg_get_active_keypair (noise_remote_t *r, uint32_t r_idx)
|
||||
{
|
||||
@ -264,6 +258,21 @@ error:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static_always_inline void
|
||||
noise_remote_keypair_free (vlib_main_t *vm, noise_remote_t *r,
|
||||
noise_keypair_t **kp)
|
||||
{
|
||||
noise_local_t *local = noise_local_get (r->r_local_idx);
|
||||
struct noise_upcall *u = &local->l_upcall;
|
||||
if (*kp)
|
||||
{
|
||||
u->u_index_drop ((*kp)->kp_local_index);
|
||||
vnet_crypto_key_del (vm, (*kp)->kp_send_index);
|
||||
vnet_crypto_key_del (vm, (*kp)->kp_recv_index);
|
||||
clib_mem_free (*kp);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* __included_wg_noise_h__ */
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user