CHECK(ops->create, EINVAL);
CHECK(ops->free, EINVAL);
CHECK(ops->pkt_tx, EINVAL);
+ CHECK(ops->pkt_fast_clone_tx, EINVAL);
+ CHECK(ops->pkt_clone_tx, EINVAL);
CHECK(ops->stats_read, EINVAL);
CHECK(!port_out_type_find(p, name), EEXIST);
struct port_out_runtime *out = &p->out[port->id];
out->pkt_tx = port->type->ops.pkt_tx;
+ out->pkt_fast_clone_tx = port->type->ops.pkt_fast_clone_tx;
+ out->pkt_clone_tx = port->type->ops.pkt_clone_tx;
out->flush = port->type->ops.flush;
out->obj = port->obj;
}
}
}
+/*
+ * Packet mirroring.
+ */
+int
+rte_swx_pipeline_mirroring_config(struct rte_swx_pipeline *p,
+ struct rte_swx_pipeline_mirroring_params *params)
+{
+ CHECK(p, EINVAL);
+ CHECK(params, EINVAL);
+ CHECK(params->n_slots, EINVAL);
+ CHECK(params->n_sessions, EINVAL);
+ CHECK(!p->build_done, EEXIST);
+
+ p->n_mirroring_slots = rte_align32pow2(params->n_slots);
+ if (p->n_mirroring_slots > 64)
+ p->n_mirroring_slots = 64;
+
+ p->n_mirroring_sessions = rte_align32pow2(params->n_sessions);
+
+ return 0;
+}
+
+static void
+mirroring_build_free(struct rte_swx_pipeline *p)
+{
+ uint32_t i;
+
+ for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
+ struct thread *t = &p->threads[i];
+
+ /* mirroring_slots. */
+ free(t->mirroring_slots);
+ t->mirroring_slots = NULL;
+ }
+
+ /* mirroring_sessions. */
+ free(p->mirroring_sessions);
+ p->mirroring_sessions = NULL;
+}
+
+static void
+mirroring_free(struct rte_swx_pipeline *p)
+{
+ mirroring_build_free(p);
+}
+
+static int
+mirroring_build(struct rte_swx_pipeline *p)
+{
+ uint32_t i;
+
+ if (!p->n_mirroring_slots || !p->n_mirroring_sessions)
+ return 0;
+
+ for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
+ struct thread *t = &p->threads[i];
+
+ /* mirroring_slots. */
+ t->mirroring_slots = calloc(p->n_mirroring_slots, sizeof(uint32_t));
+ if (!t->mirroring_slots)
+ goto error;
+ }
+
+ /* mirroring_sessions. */
+ p->mirroring_sessions = calloc(p->n_mirroring_sessions, sizeof(struct mirroring_session));
+ if (!p->mirroring_sessions)
+ goto error;
+
+ return 0;
+
+error:
+ mirroring_build_free(p);
+ return -ENOMEM;
+}
+
/*
* Extern object.
*/
instr_rx_exec(p);
}
+/*
+ * mirror.
+ */
+static int
+instr_mirror_translate(struct rte_swx_pipeline *p,
+ struct action *action,
+ char **tokens,
+ int n_tokens,
+ struct instruction *instr,
+ struct instruction_data *data __rte_unused)
+{
+ char *dst = tokens[1], *src = tokens[2];
+ struct field *fdst, *fsrc;
+ uint32_t dst_struct_id = 0, src_struct_id = 0;
+
+ CHECK(n_tokens == 3, EINVAL);
+
+ fdst = struct_field_parse(p, action, dst, &dst_struct_id);
+ CHECK(fdst, EINVAL);
+ CHECK(dst[0] != 'h', EINVAL);
+ CHECK(!fdst->var_size, EINVAL);
+
+ fsrc = struct_field_parse(p, action, src, &src_struct_id);
+ CHECK(fsrc, EINVAL);
+ CHECK(src[0] != 'h', EINVAL);
+ CHECK(!fsrc->var_size, EINVAL);
+
+ instr->type = INSTR_MIRROR;
+ instr->mirror.dst.struct_id = (uint8_t)dst_struct_id;
+ instr->mirror.dst.n_bits = fdst->n_bits;
+ instr->mirror.dst.offset = fdst->offset / 8;
+ instr->mirror.src.struct_id = (uint8_t)src_struct_id;
+ instr->mirror.src.n_bits = fsrc->n_bits;
+ instr->mirror.src.offset = fsrc->offset / 8;
+
+ return 0;
+}
+
+static inline void
+instr_mirror_exec(struct rte_swx_pipeline *p)
+{
+ struct thread *t = &p->threads[p->thread_id];
+ struct instruction *ip = t->ip;
+
+ __instr_mirror_exec(p, t, ip);
+
+ /* Thread. */
+ thread_ip_inc(p);
+}
+
/*
* extract.
*/
instr,
data);
+ if (!strcmp(tokens[tpos], "mirror"))
+ return instr_mirror_translate(p,
+ action,
+ &tokens[tpos],
+ n_tokens - tpos,
+ instr,
+ data);
+
if (!strcmp(tokens[tpos], "extract"))
return instr_hdr_extract_translate(p,
action,
[INSTR_TX] = instr_tx_exec,
[INSTR_TX_I] = instr_tx_i_exec,
[INSTR_DROP] = instr_drop_exec,
+ [INSTR_MIRROR] = instr_mirror_exec,
[INSTR_HDR_EXTRACT] = instr_hdr_extract_exec,
[INSTR_HDR_EXTRACT2] = instr_hdr_extract2_exec,
uint32_t n_instructions)
{
struct struct_type *args_struct_type = NULL;
- struct action *a;
- int err;
+ struct action *a = NULL;
+ int status = 0;
CHECK(p, EINVAL);
/* Node allocation. */
a = calloc(1, sizeof(struct action));
- CHECK(a, ENOMEM);
+ if (!a) {
+ status = -ENOMEM;
+ goto error;
+ }
+
if (args_struct_type) {
a->args_endianness = calloc(args_struct_type->n_fields, sizeof(int));
if (!a->args_endianness) {
- free(a);
- CHECK(0, ENOMEM);
+ status = -ENOMEM;
+ goto error;
}
}
a->id = p->n_actions;
/* Instruction translation. */
- err = instruction_config(p, a, instructions, n_instructions);
- if (err) {
- free(a->args_endianness);
- free(a);
- return err;
- }
+ status = instruction_config(p, a, instructions, n_instructions);
+ if (status)
+ goto error;
/* Node add to tailq. */
TAILQ_INSERT_TAIL(&p->actions, a, node);
p->n_actions++;
return 0;
+
+error:
+ if (!a)
+ return status;
+
+ free(a->args_endianness);
+ free(a->instructions);
+ free(a->instruction_data);
+ free(a);
+
+ return status;
}
static int
break;
TAILQ_REMOVE(&p->actions, action, node);
- free(action->instruction_data);
+ free(action->args_endianness);
free(action->instructions);
+ free(action->instruction_data);
free(action);
}
}
return n_users;
}
+#if RTE_BYTE_ORDER == RTE_LITTLE_ENDIAN
+#define field_ntoh(val, n_bits) (ntoh64((val) << (64 - n_bits)))
+#define field_hton(val, n_bits) (hton64((val) << (64 - n_bits)))
+#else
+#define field_ntoh(val, n_bits) (val)
+#define field_hton(val, n_bits) (val)
+#endif
+
+#define ACTION_ARGS_TOKENS_MAX 256
+
+static int
+action_args_parse(struct action *a, const char *args, uint8_t *data)
+{
+ char *tokens[ACTION_ARGS_TOKENS_MAX], *s0 = NULL, *s;
+ uint32_t n_tokens = 0, offset = 0, i;
+ int status = 0;
+
+ /* Checks. */
+ if (!a->st || !args || !args[0]) {
+ status = -EINVAL;
+ goto error;
+ }
+
+ /* Memory allocation. */
+ s0 = strdup(args);
+ if (!s0) {
+ status = -ENOMEM;
+ goto error;
+ }
+
+ /* Parse the string into tokens. */
+ for (s = s0; ; ) {
+ char *token;
+
+ token = strtok_r(s, " \f\n\r\t\v", &s);
+ if (!token)
+ break;
+
+ if (n_tokens >= RTE_DIM(tokens)) {
+ status = -EINVAL;
+ goto error;
+ }
+
+ tokens[n_tokens] = token;
+ n_tokens++;
+ }
+
+ /* More checks. */
+ if (n_tokens != a->st->n_fields * 2) {
+ status = -EINVAL;
+ goto error;
+ }
+
+ /* Process the action arguments. */
+ for (i = 0; i < a->st->n_fields; i++) {
+ struct field *f = &a->st->fields[i];
+ char *arg_name = tokens[i * 2];
+ char *arg_val = tokens[i * 2 + 1];
+ uint64_t val;
+
+ if (strcmp(arg_name, f->name)) {
+ status = -EINVAL;
+ goto error;
+ }
+
+ val = strtoull(arg_val, &arg_val, 0);
+ if (arg_val[0]) {
+ status = -EINVAL;
+ goto error;
+ }
+
+ /* Endianness conversion. */
+ if (a->args_endianness[i])
+ val = field_hton(val, f->n_bits);
+
+ /* Copy to entry. */
+ memcpy(&data[offset], (uint8_t *)&val, f->n_bits / 8);
+ offset += f->n_bits / 8;
+ }
+
+error:
+ free(s0);
+ return status;
+}
+
/*
* Table.
*/
EINVAL);
default_action = action_find(p, params->default_action_name);
- CHECK((default_action->st && params->default_action_data) ||
- !params->default_action_data, EINVAL);
+ CHECK((default_action->st && params->default_action_args) || !params->default_action_args,
+ EINVAL);
/* Table type checks. */
if (recommended_table_type_name)
/* Memory allocation. */
t = calloc(1, sizeof(struct table));
- if (!t)
- goto nomem;
+ if (!t) {
+ status = -ENOMEM;
+ goto error;
+ }
t->fields = calloc(params->n_fields, sizeof(struct match_field));
- if (!t->fields)
- goto nomem;
+ if (!t->fields) {
+ status = -ENOMEM;
+ goto error;
+ }
t->actions = calloc(params->n_actions, sizeof(struct action *));
- if (!t->actions)
- goto nomem;
+ if (!t->actions) {
+ status = -ENOMEM;
+ goto error;
+ }
if (action_data_size_max) {
t->default_action_data = calloc(1, action_data_size_max);
- if (!t->default_action_data)
- goto nomem;
+ if (!t->default_action_data) {
+ status = -ENOMEM;
+ goto error;
+ }
}
t->action_is_for_table_entries = calloc(params->n_actions, sizeof(int));
- if (!t->action_is_for_table_entries)
- goto nomem;
+ if (!t->action_is_for_table_entries) {
+ status = -ENOMEM;
+ goto error;
+ }
t->action_is_for_default_entry = calloc(params->n_actions, sizeof(int));
- if (!t->action_is_for_default_entry)
- goto nomem;
+ if (!t->action_is_for_default_entry) {
+ status = -ENOMEM;
+ goto error;
+ }
/* Node initialization. */
strcpy(t->name, name);
t->action_is_for_default_entry[i] = action_is_for_default_entry;
}
t->default_action = default_action;
- if (default_action->st)
- memcpy(t->default_action_data,
- params->default_action_data,
- default_action->st->n_bits / 8);
+ if (default_action->st) {
+ status = action_args_parse(default_action,
+ params->default_action_args,
+ t->default_action_data);
+ if (status)
+ goto error;
+ }
+
t->n_actions = params->n_actions;
t->default_action_is_const = params->default_action_is_const;
t->action_data_size_max = action_data_size_max;
return 0;
-nomem:
+error:
if (!t)
- return -ENOMEM;
+ return status;
free(t->action_is_for_default_entry);
free(t->action_is_for_table_entries);
free(t->fields);
free(t);
- return -ENOMEM;
+ return status;
}
static struct rte_swx_table_params *
EINVAL);
default_action = action_find(p, params->default_action_name);
- CHECK((default_action->st && params->default_action_data) ||
- !params->default_action_data, EINVAL);
+ CHECK((default_action->st && params->default_action_args) || !params->default_action_args,
+ EINVAL);
/* Any other checks. */
CHECK(size, EINVAL);
/* Memory allocation. */
l = calloc(1, sizeof(struct learner));
- if (!l)
- goto nomem;
+ if (!l) {
+ status = -ENOMEM;
+ goto error;
+ }
l->fields = calloc(params->n_fields, sizeof(struct field *));
- if (!l->fields)
- goto nomem;
+ if (!l->fields) {
+ status = -ENOMEM;
+ goto error;
+ }
l->actions = calloc(params->n_actions, sizeof(struct action *));
- if (!l->actions)
- goto nomem;
+ if (!l->actions) {
+ status = -ENOMEM;
+ goto error;
+ }
if (action_data_size_max) {
l->default_action_data = calloc(1, action_data_size_max);
- if (!l->default_action_data)
- goto nomem;
+ if (!l->default_action_data) {
+ status = -ENOMEM;
+ goto error;
+ }
}
l->action_is_for_table_entries = calloc(params->n_actions, sizeof(int));
- if (!l->action_is_for_table_entries)
- goto nomem;
+ if (!l->action_is_for_table_entries) {
+ status = -ENOMEM;
+ goto error;
+ }
l->action_is_for_default_entry = calloc(params->n_actions, sizeof(int));
- if (!l->action_is_for_default_entry)
- goto nomem;
+ if (!l->action_is_for_default_entry) {
+ status = -ENOMEM;
+ goto error;
+ }
/* Node initialization. */
strcpy(l->name, name);
l->default_action = default_action;
- if (default_action->st)
- memcpy(l->default_action_data,
- params->default_action_data,
- default_action->st->n_bits / 8);
+ if (default_action->st) {
+ status = action_args_parse(default_action,
+ params->default_action_args,
+ l->default_action_data);
+ if (status)
+ goto error;
+ }
l->n_actions = params->n_actions;
return 0;
-nomem:
+error:
if (!l)
- return -ENOMEM;
+ return status;
free(l->action_is_for_default_entry);
free(l->action_is_for_table_entries);
free(l->fields);
free(l);
- return -ENOMEM;
+ return status;
}
static void
header_free(p);
extern_func_free(p);
extern_obj_free(p);
+ mirroring_free(p);
port_out_free(p);
port_in_free(p);
struct_free(p);
if (status)
goto error;
+ status = mirroring_build(p);
+ if (status)
+ goto error;
+
status = struct_build(p);
if (status)
goto error;
header_build_free(p);
extern_func_build_free(p);
extern_obj_build_free(p);
+ mirroring_build_free(p);
port_out_build_free(p);
port_in_build_free(p);
struct_build_free(p);
pipeline->n_ports_in = p->n_ports_in;
pipeline->n_ports_out = p->n_ports_out;
+ pipeline->n_mirroring_slots = p->n_mirroring_slots;
+ pipeline->n_mirroring_sessions = p->n_mirroring_sessions;
pipeline->n_actions = n_actions;
pipeline->n_tables = n_tables;
pipeline->n_selectors = p->n_selectors;
return 0;
}
+int
+rte_swx_ctl_pipeline_mirroring_session_set(struct rte_swx_pipeline *p,
+ uint32_t session_id,
+ struct rte_swx_pipeline_mirroring_session_params *params)
+{
+ struct mirroring_session *s;
+
+ CHECK(p, EINVAL);
+ CHECK(p->build_done, EEXIST);
+ CHECK(session_id < p->n_mirroring_sessions, EINVAL);
+ CHECK(params, EINVAL);
+ CHECK(params->port_id < p->n_ports_out, EINVAL);
+
+ s = &p->mirroring_sessions[session_id];
+ s->port_id = params->port_id;
+ s->fast_clone = params->fast_clone;
+ s->truncation_length = params->truncation_length ? params->truncation_length : UINT32_MAX;
+
+ return 0;
+}
+
/*
* Pipeline compilation.
*/
case INSTR_TX: return "INSTR_TX";
case INSTR_TX_I: return "INSTR_TX_I";
case INSTR_DROP: return "INSTR_DROP";
+ case INSTR_MIRROR: return "INSTR_MIRROR";
case INSTR_HDR_EXTRACT: return "INSTR_HDR_EXTRACT";
case INSTR_HDR_EXTRACT2: return "INSTR_HDR_EXTRACT2";
"\t},\n");
}
+static void
+instr_mirror_export(struct instruction *instr, FILE *f)
+{
+ fprintf(f,
+ "\t{\n"
+ "\t\t.type = %s,\n"
+ "\t\t.mirror = {\n"
+ "\t\t\t.dst = {\n"
+ "\t\t\t\t.struct_id = %u,\n"
+ "\t\t\t\t.n_bits = %u,\n"
+ "\t\t\t\t.offset = %u,\n"
+ "\t\t\t}\n,"
+ "\t\t\t.src = {\n"
+ "\t\t\t\t.struct_id = %u,\n"
+ "\t\t\t\t.n_bits = %u,\n"
+ "\t\t\t\t.offset = %u,\n"
+ "\t\t\t}\n,"
+ "\t\t},\n"
+ "\t},\n",
+ instr_type_to_name(instr),
+ instr->mirror.dst.struct_id,
+ instr->mirror.dst.n_bits,
+ instr->mirror.dst.offset,
+ instr->mirror.src.struct_id,
+ instr->mirror.src.n_bits,
+ instr->mirror.src.offset);
+}
+
static void
instr_hdr_validate_export(struct instruction *instr, FILE *f)
{
[INSTR_TX] = instr_io_export,
[INSTR_TX_I] = instr_io_export,
[INSTR_DROP] = instr_io_export,
+ [INSTR_MIRROR] = instr_mirror_export,
[INSTR_HDR_EXTRACT] = instr_io_export,
[INSTR_HDR_EXTRACT2] = instr_io_export,
case INSTR_TX: return "__instr_tx_exec";
case INSTR_TX_I: return "__instr_tx_i_exec";
case INSTR_DROP: return "__instr_drop_exec";
+ case INSTR_MIRROR: return "__instr_mirror_exec";
case INSTR_HDR_EXTRACT: return "__instr_hdr_extract_exec";
case INSTR_HDR_EXTRACT2: return "__instr_hdr_extract2_exec";