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:
Gabriel Oginski
2021-11-17 10:27:00 +00:00
committed by Matthew Smith
parent 492d7790ff
commit 77e69ae2d1
5 changed files with 452 additions and 224 deletions

View File

@ -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 *

View File

@ -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

View File

@ -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)
{

View File

@ -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__ */
/*