blob: a450bc16e8e879f6ebafa5da190344fbbf625f09 [file] [log] [blame]
/*
* Copyright (c) 2020 Intel 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.
*/
#include <vlib/vlib.h>
#include <vnet/plugin/plugin.h>
#include <vpp/app/version.h>
#include "crypto_sw_scheduler.h"
int
crypto_sw_scheduler_set_worker_crypto (u32 worker_idx, u8 enabled)
{
crypto_sw_scheduler_main_t *cm = &crypto_sw_scheduler_main;
vlib_thread_main_t *tm = vlib_get_thread_main ();
crypto_sw_scheduler_per_thread_data_t *ptd = 0;
u32 count = 0, i = vlib_num_workers () > 0;
if (worker_idx >= vlib_num_workers ())
{
return VNET_API_ERROR_INVALID_VALUE;
}
for (; i < tm->n_vlib_mains; i++)
{
ptd = cm->per_thread_data + i;
count += ptd->self_crypto_enabled;
}
if (enabled || count > 1)
{
cm->per_thread_data[vlib_get_worker_thread_index
(worker_idx)].self_crypto_enabled = enabled;
}
else /* cannot disable all crypto workers */
{
return VNET_API_ERROR_INVALID_VALUE_2;
}
return 0;
}
static void
crypto_sw_scheduler_key_handler (vlib_main_t * vm, vnet_crypto_key_op_t kop,
vnet_crypto_key_index_t idx)
{
crypto_sw_scheduler_main_t *cm = &crypto_sw_scheduler_main;
vnet_crypto_key_t *key = vnet_crypto_get_key (idx);
vec_validate (cm->keys, idx);
if (key->type == VNET_CRYPTO_KEY_TYPE_LINK)
{
if (kop == VNET_CRYPTO_KEY_OP_DEL)
{
cm->keys[idx].index_crypto = UINT32_MAX;
cm->keys[idx].index_integ = UINT32_MAX;
}
else
{
cm->keys[idx] = *key;
}
}
}
static int
crypto_sw_scheduler_frame_enqueue (vlib_main_t * vm,
vnet_crypto_async_frame_t * frame)
{
crypto_sw_scheduler_main_t *cm = &crypto_sw_scheduler_main;
crypto_sw_scheduler_per_thread_data_t *ptd
= vec_elt_at_index (cm->per_thread_data, vm->thread_index);
crypto_sw_scheduler_queue_t *q = ptd->queues[frame->op];
u64 head = q->head;
if (q->jobs[head & CRYPTO_SW_SCHEDULER_QUEUE_MASK])
{
u32 n_elts = frame->n_elts, i;
for (i = 0; i < n_elts; i++)
frame->elts[i].status = VNET_CRYPTO_OP_STATUS_FAIL_ENGINE_ERR;
frame->state = VNET_CRYPTO_FRAME_STATE_ELT_ERROR;
return -1;
}
frame->state = VNET_CRYPTO_FRAME_STATE_NOT_PROCESSED;
q->jobs[head & CRYPTO_SW_SCHEDULER_QUEUE_MASK] = frame;
head += 1;
CLIB_MEMORY_STORE_BARRIER ();
q->head = head;
return 0;
}
static_always_inline vnet_crypto_async_frame_t *
crypto_sw_scheduler_get_pending_frame (crypto_sw_scheduler_queue_t * q)
{
vnet_crypto_async_frame_t *f;
u32 i;
u32 tail = q->tail;
u32 head = q->head;
for (i = tail; i < head; i++)
{
f = q->jobs[i & CRYPTO_SW_SCHEDULER_QUEUE_MASK];
if (!f)
continue;
if (clib_atomic_bool_cmp_and_swap
(&f->state, VNET_CRYPTO_FRAME_STATE_PENDING,
VNET_CRYPTO_FRAME_STATE_WORK_IN_PROGRESS))
{
return f;
}
}
return NULL;
}
static_always_inline vnet_crypto_async_frame_t *
crypto_sw_scheduler_get_completed_frame (crypto_sw_scheduler_queue_t * q)
{
vnet_crypto_async_frame_t *f = 0;
if (q->jobs[q->tail & CRYPTO_SW_SCHEDULER_QUEUE_MASK]
&& q->jobs[q->tail & CRYPTO_SW_SCHEDULER_QUEUE_MASK]->state
>= VNET_CRYPTO_FRAME_STATE_SUCCESS)
{
u32 tail = q->tail;
CLIB_MEMORY_STORE_BARRIER ();
q->tail++;
f = q->jobs[tail & CRYPTO_SW_SCHEDULER_QUEUE_MASK];
q->jobs[tail & CRYPTO_SW_SCHEDULER_QUEUE_MASK] = 0;
}
return f;
}
static_always_inline void
cryptodev_sw_scheduler_sgl (vlib_main_t * vm,
crypto_sw_scheduler_per_thread_data_t * ptd,
vlib_buffer_t * b, vnet_crypto_op_t * op,
i32 offset, i32 len)
{
vnet_crypto_op_chunk_t *ch;
vlib_buffer_t *nb = b;
u32 n_chunks = 0;
u32 chunk_index = vec_len (ptd->chunks);
op->flags |= VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS;
while (len)
{
if (nb->current_data + nb->current_length > offset)
{
vec_add2 (ptd->chunks, ch, 1);
ch->src = ch->dst = nb->data + offset;
ch->len
= clib_min (nb->current_data + nb->current_length - offset, len);
len -= ch->len;
offset = 0;
n_chunks++;
if (!len)
break;
}
if (offset)
offset -= nb->current_data + nb->current_length;
if (nb->flags & VLIB_BUFFER_NEXT_PRESENT)
nb = vlib_get_buffer (vm, nb->next_buffer);
else
break;
}
ASSERT (offset == 0 && len == 0);
op->chunk_index = chunk_index;
op->n_chunks = n_chunks;
}
static_always_inline void
crypto_sw_scheduler_convert_aead (vlib_main_t * vm,
crypto_sw_scheduler_per_thread_data_t * ptd,
vnet_crypto_async_frame_elt_t * fe,
u32 index, u32 bi,
vnet_crypto_op_id_t op_id, u16 aad_len,
u8 tag_len)
{
vlib_buffer_t *b = vlib_get_buffer (vm, bi);
vnet_crypto_op_t *op = 0;
if (fe->flags & VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS)
{
vec_add2 (ptd->chained_crypto_ops, op, 1);
cryptodev_sw_scheduler_sgl (vm, ptd, b, op, fe->crypto_start_offset,
fe->crypto_total_length);
}
else
{
vec_add2 (ptd->crypto_ops, op, 1);
op->src = op->dst = b->data + fe->crypto_start_offset;
op->len = fe->crypto_total_length;
}
op->op = op_id;
op->tag = fe->tag;
op->flags = fe->flags;
op->key_index = fe->key_index;
op->iv = fe->iv;
op->aad = fe->aad;
op->aad_len = aad_len;
op->tag_len = tag_len;
op->user_data = index;
}
static_always_inline void
crypto_sw_scheduler_convert_link_crypto (vlib_main_t * vm,
crypto_sw_scheduler_per_thread_data_t
* ptd, vnet_crypto_key_t * key,
vnet_crypto_async_frame_elt_t * fe,
u32 index, u32 bi,
vnet_crypto_op_id_t crypto_op_id,
vnet_crypto_op_id_t integ_op_id,
u32 digest_len, u8 is_enc)
{
vlib_buffer_t *b = vlib_get_buffer (vm, bi);
vnet_crypto_op_t *crypto_op = 0, *integ_op = 0;
if (fe->flags & VNET_CRYPTO_OP_FLAG_CHAINED_BUFFERS)
{
vec_add2 (ptd->chained_crypto_ops, crypto_op, 1);
vec_add2 (ptd->chained_integ_ops, integ_op, 1);
cryptodev_sw_scheduler_sgl (vm, ptd, b, crypto_op,
fe->crypto_start_offset,
fe->crypto_total_length);
cryptodev_sw_scheduler_sgl (vm, ptd, b, integ_op,
fe->integ_start_offset,
fe->crypto_total_length +
fe->integ_length_adj);
}
else
{
vec_add2 (ptd->crypto_ops, crypto_op, 1);
vec_add2 (ptd->integ_ops, integ_op, 1);
crypto_op->src = crypto_op->dst = b->data + fe->crypto_start_offset;
crypto_op->len = fe->crypto_total_length;
integ_op->src = integ_op->dst = b->data + fe->integ_start_offset;
integ_op->len = fe->crypto_total_length + fe->integ_length_adj;
}
crypto_op->op = crypto_op_id;
crypto_op->iv = fe->iv;
crypto_op->key_index = key->index_crypto;
crypto_op->user_data = 0;
integ_op->op = integ_op_id;
integ_op->digest = fe->digest;
integ_op->digest_len = digest_len;
integ_op->key_index = key->index_integ;
if (is_enc)
crypto_op->flags |= VNET_CRYPTO_OP_FLAG_INIT_IV;
else
integ_op->flags |= VNET_CRYPTO_OP_FLAG_HMAC_CHECK;
crypto_op->user_data = integ_op->user_data = index;
}
static_always_inline void
process_ops (vlib_main_t * vm, vnet_crypto_async_frame_t * f,
vnet_crypto_op_t * ops, u8 * state)
{
u32 n_fail, n_ops = vec_len (ops);
vnet_crypto_op_t *op = ops;
if (n_ops == 0)
return;
n_fail = n_ops - vnet_crypto_process_ops (vm, op, n_ops);
while (n_fail)
{
ASSERT (op - ops < n_ops);
if (op->status != VNET_CRYPTO_OP_STATUS_COMPLETED)
{
f->elts[op->user_data].status = op->status;
*state = VNET_CRYPTO_FRAME_STATE_ELT_ERROR;
n_fail--;
}
op++;
}
}
static_always_inline void
process_chained_ops (vlib_main_t * vm, vnet_crypto_async_frame_t * f,
vnet_crypto_op_t * ops, vnet_crypto_op_chunk_t * chunks,
u8 * state)
{
u32 n_fail, n_ops = vec_len (ops);
vnet_crypto_op_t *op = ops;
if (n_ops == 0)
return;
n_fail = n_ops - vnet_crypto_process_chained_ops (vm, op, chunks, n_ops);
while (n_fail)
{
ASSERT (op - ops < n_ops);
if (op->status != VNET_CRYPTO_OP_STATUS_COMPLETED)
{
f->elts[op->user_data].status = op->status;
*state = VNET_CRYPTO_FRAME_STATE_ELT_ERROR;
n_fail--;
}
op++;
}
}
static_always_inline vnet_crypto_async_frame_t *
crypto_sw_scheduler_dequeue_aead (vlib_main_t * vm,
vnet_crypto_async_op_id_t async_op_id,
vnet_crypto_op_id_t sync_op_id, u8 tag_len,
u8 aad_len, u32 * nb_elts_processed,
u32 * enqueue_thread_idx)
{
crypto_sw_scheduler_main_t *cm = &crypto_sw_scheduler_main;
crypto_sw_scheduler_per_thread_data_t *ptd = 0;
crypto_sw_scheduler_queue_t *q = 0;
vnet_crypto_async_frame_t *f = 0;
vnet_crypto_async_frame_elt_t *fe;
u32 *bi;
u32 n_elts;
int i = 0;
u8 state = VNET_CRYPTO_FRAME_STATE_SUCCESS;
if (cm->per_thread_data[vm->thread_index].self_crypto_enabled)
{
/* *INDENT-OFF* */
vec_foreach_index (i, cm->per_thread_data)
{
ptd = cm->per_thread_data + i;
q = ptd->queues[async_op_id];
f = crypto_sw_scheduler_get_pending_frame (q);
if (f)
break;
}
/* *INDENT-ON* */
}
ptd = cm->per_thread_data + vm->thread_index;
if (f)
{
*nb_elts_processed = n_elts = f->n_elts;
fe = f->elts;
bi = f->buffer_indices;
vec_reset_length (ptd->crypto_ops);
vec_reset_length (ptd->chained_crypto_ops);
vec_reset_length (ptd->chunks);
while (n_elts--)
{
if (n_elts > 1)
CLIB_PREFETCH (fe + 1, CLIB_CACHE_LINE_BYTES, LOAD);
crypto_sw_scheduler_convert_aead (vm, ptd, fe, fe - f->elts, bi[0],
sync_op_id, aad_len, tag_len);
bi++;
fe++;
}
process_ops (vm, f, ptd->crypto_ops, &state);
process_chained_ops (vm, f, ptd->chained_crypto_ops, ptd->chunks,
&state);
f->state = state;
*enqueue_thread_idx = f->enqueue_thread_index;
}
return crypto_sw_scheduler_get_completed_frame (ptd->queues[async_op_id]);
}
static_always_inline vnet_crypto_async_frame_t *
crypto_sw_scheduler_dequeue_link (vlib_main_t * vm,
vnet_crypto_async_op_id_t async_op_id,
vnet_crypto_op_id_t sync_crypto_op_id,
vnet_crypto_op_id_t sync_integ_op_id,
u16 digest_len, u8 is_enc,
u32 * nb_elts_processed,
u32 * enqueue_thread_idx)
{
crypto_sw_scheduler_main_t *cm = &crypto_sw_scheduler_main;
crypto_sw_scheduler_per_thread_data_t *ptd = 0;
crypto_sw_scheduler_queue_t *q = 0;
vnet_crypto_async_frame_t *f = 0;
vnet_crypto_async_frame_elt_t *fe;
u32 *bi;
u32 n_elts;
int i = 0;
u8 state = VNET_CRYPTO_FRAME_STATE_SUCCESS;
if (cm->per_thread_data[vm->thread_index].self_crypto_enabled)
{
/* *INDENT-OFF* */
vec_foreach_index (i, cm->per_thread_data)
{
ptd = cm->per_thread_data + i;
q = ptd->queues[async_op_id];
f = crypto_sw_scheduler_get_pending_frame (q);
if (f)
break;
}
/* *INDENT-ON* */
}
ptd = cm->per_thread_data + vm->thread_index;
if (f)
{
vec_reset_length (ptd->crypto_ops);
vec_reset_length (ptd->integ_ops);
vec_reset_length (ptd->chained_crypto_ops);
vec_reset_length (ptd->chained_integ_ops);
vec_reset_length (ptd->chunks);
*nb_elts_processed = n_elts = f->n_elts;
fe = f->elts;
bi = f->buffer_indices;
while (n_elts--)
{
if (n_elts > 1)
CLIB_PREFETCH (fe + 1, CLIB_CACHE_LINE_BYTES, LOAD);
crypto_sw_scheduler_convert_link_crypto (vm, ptd,
cm->keys + fe->key_index,
fe, fe - f->elts, bi[0],
sync_crypto_op_id,
sync_integ_op_id,
digest_len, is_enc);
bi++;
fe++;
}
if (is_enc)
{
process_ops (vm, f, ptd->crypto_ops, &state);
process_chained_ops (vm, f, ptd->chained_crypto_ops, ptd->chunks,
&state);
process_ops (vm, f, ptd->integ_ops, &state);
process_chained_ops (vm, f, ptd->chained_integ_ops, ptd->chunks,
&state);
}
else
{
process_ops (vm, f, ptd->integ_ops, &state);
process_chained_ops (vm, f, ptd->chained_integ_ops, ptd->chunks,
&state);
process_ops (vm, f, ptd->crypto_ops, &state);
process_chained_ops (vm, f, ptd->chained_crypto_ops, ptd->chunks,
&state);
}
f->state = state;
*enqueue_thread_idx = f->enqueue_thread_index;
}
return crypto_sw_scheduler_get_completed_frame (ptd->queues[async_op_id]);
}
static clib_error_t *
sw_scheduler_set_worker_crypto (vlib_main_t * vm, unformat_input_t * input,
vlib_cli_command_t * cmd)
{
unformat_input_t _line_input, *line_input = &_line_input;
u32 worker_index;
u8 crypto_enable;
int rv;
/* Get a line of input. */
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, "worker %u", &worker_index))
{
if (unformat (line_input, "crypto"))
{
if (unformat (line_input, "on"))
crypto_enable = 1;
else if (unformat (line_input, "off"))
crypto_enable = 0;
else
return (clib_error_return (0, "unknown input '%U'",
format_unformat_error,
line_input));
}
else
return (clib_error_return (0, "unknown input '%U'",
format_unformat_error, line_input));
}
else
return (clib_error_return (0, "unknown input '%U'",
format_unformat_error, line_input));
}
rv = crypto_sw_scheduler_set_worker_crypto (worker_index, crypto_enable);
if (rv == VNET_API_ERROR_INVALID_VALUE)
{
return (clib_error_return (0, "invalid worker idx: %d", worker_index));
}
else if (rv == VNET_API_ERROR_INVALID_VALUE_2)
{
return (clib_error_return (0, "cannot disable all crypto workers"));
}
return 0;
}
/*?
* This command sets if worker will do crypto processing.
*
* @cliexpar
* Example of how to set worker crypto processing off:
* @cliexstart{set sw_scheduler worker 0 crypto off}
* @cliexend
?*/
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (cmd_set_sw_scheduler_worker_crypto, static) = {
.path = "set sw_scheduler",
.short_help = "set sw_scheduler worker <idx> crypto <on|off>",
.function = sw_scheduler_set_worker_crypto,
.is_mp_safe = 1,
};
/* *INDENT-ON* */
static clib_error_t *
sw_scheduler_show_workers (vlib_main_t * vm, unformat_input_t * input,
vlib_cli_command_t * cmd)
{
crypto_sw_scheduler_main_t *cm = &crypto_sw_scheduler_main;
u32 i;
vlib_cli_output (vm, "%-7s%-20s%-8s", "ID", "Name", "Crypto");
for (i = vlib_num_workers () >= 0; i < vlib_thread_main.n_vlib_mains; i++)
{
vlib_cli_output (vm, "%-7d%-20s%-8s", vlib_get_worker_index (i),
(vlib_worker_threads + i)->name,
cm->
per_thread_data[i].self_crypto_enabled ? "on" : "off");
}
return 0;
}
/*?
* This command displays sw_scheduler workers.
*
* @cliexpar
* Example of how to show workers:
* @cliexstart{show sw_scheduler workers}
* @cliexend
?*/
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (cmd_show_sw_scheduler_workers, static) = {
.path = "show sw_scheduler workers",
.short_help = "show sw_scheduler workers",
.function = sw_scheduler_show_workers,
.is_mp_safe = 1,
};
/* *INDENT-ON* */
clib_error_t *
sw_scheduler_cli_init (vlib_main_t * vm)
{
return 0;
}
VLIB_INIT_FUNCTION (sw_scheduler_cli_init);
/* *INDENT-OFF* */
#define _(n, s, k, t, a) \
static vnet_crypto_async_frame_t \
*crypto_sw_scheduler_frame_dequeue_##n##_TAG_##t##_AAD_##a##_enc ( \
vlib_main_t *vm, u32 *nb_elts_processed, u32 * thread_idx) \
{ \
return crypto_sw_scheduler_dequeue_aead ( \
vm, VNET_CRYPTO_OP_##n##_TAG##t##_AAD##a##_ENC, \
VNET_CRYPTO_OP_##n##_ENC, t, a, nb_elts_processed, thread_idx); \
} \
static vnet_crypto_async_frame_t \
*crypto_sw_scheduler_frame_dequeue_##n##_TAG_##t##_AAD_##a##_dec ( \
vlib_main_t *vm, u32 *nb_elts_processed, u32 * thread_idx) \
{ \
return crypto_sw_scheduler_dequeue_aead ( \
vm, VNET_CRYPTO_OP_##n##_TAG##t##_AAD##a##_DEC, \
VNET_CRYPTO_OP_##n##_DEC, t, a, nb_elts_processed, thread_idx); \
}
foreach_crypto_aead_async_alg
#undef _
#define _(c, h, s, k, d) \
static vnet_crypto_async_frame_t \
*crypto_sw_scheduler_frame_dequeue_##c##_##h##_TAG##d##_enc ( \
vlib_main_t *vm, u32 *nb_elts_processed, u32 * thread_idx) \
{ \
return crypto_sw_scheduler_dequeue_link ( \
vm, VNET_CRYPTO_OP_##c##_##h##_TAG##d##_ENC, \
VNET_CRYPTO_OP_##c##_ENC, VNET_CRYPTO_OP_##h##_HMAC, d, 1, \
nb_elts_processed, thread_idx); \
} \
static vnet_crypto_async_frame_t \
*crypto_sw_scheduler_frame_dequeue_##c##_##h##_TAG##d##_dec ( \
vlib_main_t *vm, u32 *nb_elts_processed, u32 * thread_idx) \
{ \
return crypto_sw_scheduler_dequeue_link ( \
vm, VNET_CRYPTO_OP_##c##_##h##_TAG##d##_DEC, \
VNET_CRYPTO_OP_##c##_DEC, VNET_CRYPTO_OP_##h##_HMAC, d, 0, \
nb_elts_processed, thread_idx); \
}
foreach_crypto_link_async_alg
#undef _
/* *INDENT-ON* */
crypto_sw_scheduler_main_t crypto_sw_scheduler_main;
clib_error_t *
crypto_sw_scheduler_init (vlib_main_t * vm)
{
crypto_sw_scheduler_main_t *cm = &crypto_sw_scheduler_main;
vlib_thread_main_t *tm = vlib_get_thread_main ();
clib_error_t *error = 0;
crypto_sw_scheduler_per_thread_data_t *ptd;
u32 queue_size = CRYPTO_SW_SCHEDULER_QUEUE_SIZE * sizeof (void *)
+ sizeof (crypto_sw_scheduler_queue_t);
vec_validate_aligned (cm->per_thread_data, tm->n_vlib_mains - 1,
CLIB_CACHE_LINE_BYTES);
vec_foreach (ptd, cm->per_thread_data)
{
ptd->self_crypto_enabled = 1;
u32 i;
for (i = 0; i < VNET_CRYPTO_ASYNC_OP_N_IDS; i++)
{
crypto_sw_scheduler_queue_t *q
= clib_mem_alloc_aligned (queue_size, CLIB_CACHE_LINE_BYTES);
ASSERT (q != 0);
ptd->queues[i] = q;
clib_memset_u8 (q, 0, queue_size);
}
}
cm->crypto_engine_index =
vnet_crypto_register_engine (vm, "sw_scheduler", 100,
"SW Scheduler Async Engine");
vnet_crypto_register_key_handler (vm, cm->crypto_engine_index,
crypto_sw_scheduler_key_handler);
crypto_sw_scheduler_api_init (vm);
/* *INDENT-OFF* */
#define _(n, s, k, t, a) \
vnet_crypto_register_async_handler ( \
vm, cm->crypto_engine_index, \
VNET_CRYPTO_OP_##n##_TAG##t##_AAD##a##_ENC, \
crypto_sw_scheduler_frame_enqueue, \
crypto_sw_scheduler_frame_dequeue_##n##_TAG_##t##_AAD_##a##_enc); \
vnet_crypto_register_async_handler ( \
vm, cm->crypto_engine_index, \
VNET_CRYPTO_OP_##n##_TAG##t##_AAD##a##_DEC, \
crypto_sw_scheduler_frame_enqueue, \
crypto_sw_scheduler_frame_dequeue_##n##_TAG_##t##_AAD_##a##_dec);
foreach_crypto_aead_async_alg
#undef _
#define _(c, h, s, k, d) \
vnet_crypto_register_async_handler ( \
vm, cm->crypto_engine_index, VNET_CRYPTO_OP_##c##_##h##_TAG##d##_ENC, \
crypto_sw_scheduler_frame_enqueue, \
crypto_sw_scheduler_frame_dequeue_##c##_##h##_TAG##d##_enc); \
vnet_crypto_register_async_handler ( \
vm, cm->crypto_engine_index, VNET_CRYPTO_OP_##c##_##h##_TAG##d##_DEC, \
crypto_sw_scheduler_frame_enqueue, \
crypto_sw_scheduler_frame_dequeue_##c##_##h##_TAG##d##_dec);
foreach_crypto_link_async_alg
#undef _
/* *INDENT-ON* */
if (error)
vec_free (cm->per_thread_data);
return error;
}
/* *INDENT-OFF* */
VLIB_INIT_FUNCTION (crypto_sw_scheduler_init) = {
.runs_after = VLIB_INITS ("vnet_crypto_init"),
};
VLIB_PLUGIN_REGISTER () = {
.version = VPP_BUILD_VER,
.description = "SW Scheduler Crypto Async Engine plugin",
};
/* *INDENT-ON* */
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/