#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
-#include <arpa/inet.h>
#include <dlfcn.h>
+#include <rte_swx_port_ethdev.h>
+#include <rte_swx_port_fd.h>
+#include <rte_swx_port_ring.h>
+#include "rte_swx_port_source_sink.h"
+
+#include <rte_swx_table_em.h>
+#include <rte_swx_table_wm.h>
+
#include "rte_swx_pipeline_internal.h"
#define CHECK(condition, err_code) \
switch (type) {
case INSTR_TX:
case INSTR_TX_I:
+ case INSTR_DROP:
return 1;
default:
switch (instr->type) {
case INSTR_TX:
case INSTR_TX_I:
+ case INSTR_DROP:
case INSTR_HDR_EMIT_TX:
case INSTR_HDR_EMIT2_TX:
case INSTR_HDR_EMIT3_TX:
}
static int
-instr_drop_translate(struct rte_swx_pipeline *p,
+instr_drop_translate(struct rte_swx_pipeline *p __rte_unused,
struct action *action __rte_unused,
char **tokens __rte_unused,
int n_tokens,
{
CHECK(n_tokens == 1, EINVAL);
- /* TX_I. */
- instr->type = INSTR_TX_I;
- instr->io.io.val = p->n_ports_out - 1;
+ /* DROP. */
+ instr->type = INSTR_DROP;
return 0;
}
instr_rx_exec(p);
}
+static inline void
+instr_drop_exec(struct rte_swx_pipeline *p)
+{
+ struct thread *t = &p->threads[p->thread_id];
+ struct instruction *ip = t->ip;
+
+ __instr_drop_exec(p, t, ip);
+
+ /* Thread. */
+ thread_ip_reset(p, t);
+ instr_rx_exec(p);
+}
+
/*
* extract.
*/
static int
action_has_nbo_args(struct action *a);
+static int
+learner_action_args_check(struct rte_swx_pipeline *p, struct action *a, const char *mf_name);
+
static int
instr_learn_translate(struct rte_swx_pipeline *p,
struct action *action,
struct instruction_data *data __rte_unused)
{
struct action *a;
+ const char *mf_name;
+ uint32_t mf_offset = 0;
CHECK(action, EINVAL);
- CHECK(n_tokens == 2, EINVAL);
+ CHECK((n_tokens == 2) || (n_tokens == 3), EINVAL);
a = action_find(p, tokens[1]);
CHECK(a, EINVAL);
CHECK(!action_has_nbo_args(a), EINVAL);
+ mf_name = (n_tokens > 2) ? tokens[2] : NULL;
+ CHECK(!learner_action_args_check(p, a, mf_name), EINVAL);
+
+ if (mf_name) {
+ struct field *mf;
+
+ mf = metadata_field_parse(p, mf_name);
+ CHECK(mf, EINVAL);
+
+ mf_offset = mf->offset / 8;
+ }
+
instr->type = INSTR_LEARNER_LEARN;
instr->learn.action_id = a->id;
+ instr->learn.mf_offset = mf_offset;
return 0;
}
CHECK(n_tokens == 3, EINVAL);
fdst = header_field_parse(p, dst, &hdst);
- CHECK(fdst && (fdst->n_bits == 16), EINVAL);
- CHECK(!fdst->var_size, EINVAL);
+ CHECK(fdst, EINVAL);
+ CHECK(!fdst->var_size && (fdst->n_bits == 16), EINVAL);
/* CKADD_FIELD. */
fsrc = header_field_parse(p, src, &hsrc);
/* CKADD_STRUCT, CKADD_STRUCT20. */
hsrc = header_parse(p, src);
CHECK(hsrc, EINVAL);
- CHECK(!hsrc->st->var_size, EINVAL);
instr->type = INSTR_ALU_CKADD_STRUCT;
- if ((hsrc->st->n_bits / 8) == 20)
+ if (!hsrc->st->var_size && ((hsrc->st->n_bits / 8) == 20))
instr->type = INSTR_ALU_CKADD_STRUCT20;
instr->alu.dst.struct_id = (uint8_t)hdst->struct_id;
instr->alu.dst.n_bits = fdst->n_bits;
instr->alu.dst.offset = fdst->offset / 8;
instr->alu.src.struct_id = (uint8_t)hsrc->struct_id;
- instr->alu.src.n_bits = hsrc->st->n_bits;
+ instr->alu.src.n_bits = (uint8_t)hsrc->id; /* The src header ID is stored here. */
instr->alu.src.offset = 0; /* Unused. */
return 0;
}
CHECK(n_tokens == 3, EINVAL);
fdst = header_field_parse(p, dst, &hdst);
- CHECK(fdst && (fdst->n_bits == 16), EINVAL);
- CHECK(!fdst->var_size, EINVAL);
+ CHECK(fdst, EINVAL);
+ CHECK(!fdst->var_size && (fdst->n_bits == 16), EINVAL);
fsrc = header_field_parse(p, src, &hsrc);
CHECK(fsrc, EINVAL);
instr->meter.color_out.struct_id = (uint8_t)color_out_struct_id;
instr->meter.color_out.n_bits = fcout->n_bits;
instr->meter.color_out.offset = fcout->offset / 8;
-
- return 0;
}
/* index = HMEFT, length = HMEFT, color_in = I, color_out = MEF. */
instr->meter.color_out.struct_id = (uint8_t)color_out_struct_id;
instr->meter.color_out.n_bits = fcout->n_bits;
instr->meter.color_out.offset = fcout->offset / 8;
-
- return 0;
}
/* index = I, length = HMEFT, color_in = MEFT, color_out = MEF. */
instr->meter.color_out.struct_id = (uint8_t)color_out_struct_id;
instr->meter.color_out.n_bits = fcout->n_bits;
instr->meter.color_out.offset = fcout->offset / 8;
-
- return 0;
}
/* index = I, length = HMEFT, color_in = I, color_out = MEF. */
instr->meter.color_out.struct_id = (uint8_t)color_out_struct_id;
instr->meter.color_out.n_bits = fcout->n_bits;
instr->meter.color_out.offset = fcout->offset / 8;
-
- return 0;
}
- CHECK(0, EINVAL);
+ return 0;
}
static inline void
instr,
data);
- CHECK(0, EINVAL);
+ return -EINVAL;
}
static struct instruction_data *
continue;
for (j = i + 1; j < n_instructions; j++)
- CHECK(strcmp(label, data[j].label), EINVAL);
+ CHECK(strcmp(label, instruction_data[j].label), EINVAL);
+ }
+
+ /* Check that no jump instruction (either conditional or not) can jump to itself (loop). */
+ for (i = 0; i < n_instructions; i++) {
+ struct instruction_data *data = &instruction_data[i];
+ char *label = data->label;
+ char *jmp_label = data->jmp_label;
+
+ /* Continue if this instruction does not have a label or it is not a jump. */
+ if (!label[0] || !jmp_label[0])
+ continue;
+
+ CHECK(strcmp(label, jmp_label), EINVAL);
}
/* Get users for each instruction label. */
if (!i)
return 0;
- if (!instruction_is_tx(instr[i].type))
+ if (instr[i].type != INSTR_TX)
return 0;
if (data[i].n_users)
[INSTR_RX] = instr_rx_exec,
[INSTR_TX] = instr_tx_exec,
[INSTR_TX_I] = instr_tx_i_exec,
+ [INSTR_DROP] = instr_drop_exec,
[INSTR_HDR_EXTRACT] = instr_hdr_extract_exec,
[INSTR_HDR_EXTRACT2] = instr_hdr_extract2_exec,
uint32_t size)
{
struct table_type *type;
- struct table *t;
+ struct table *t = NULL;
struct action *default_action;
struct header *header = NULL;
uint32_t action_data_size_max = 0, i;
const char *action_name = params->action_names[i];
struct action *a;
uint32_t action_data_size;
+ int action_is_for_table_entries = 1, action_is_for_default_entry = 1;
CHECK_NAME(action_name, EINVAL);
action_data_size = a->st ? a->st->n_bits / 8 : 0;
if (action_data_size > action_data_size_max)
action_data_size_max = action_data_size;
+
+ if (params->action_is_for_table_entries)
+ action_is_for_table_entries = params->action_is_for_table_entries[i];
+ if (params->action_is_for_default_entry)
+ action_is_for_default_entry = params->action_is_for_default_entry[i];
+ CHECK(action_is_for_table_entries || action_is_for_default_entry, EINVAL);
}
CHECK_NAME(params->default_action_name, EINVAL);
params->default_action_name))
break;
CHECK(i < params->n_actions, EINVAL);
+ CHECK(!params->action_is_for_default_entry || params->action_is_for_default_entry[i],
+ EINVAL);
+
default_action = action_find(p, params->default_action_name);
CHECK((default_action->st && params->default_action_data) ||
!params->default_action_data, EINVAL);
/* Memory allocation. */
t = calloc(1, sizeof(struct table));
- CHECK(t, ENOMEM);
+ if (!t)
+ goto nomem;
t->fields = calloc(params->n_fields, sizeof(struct match_field));
- if (!t->fields) {
- free(t);
- CHECK(0, ENOMEM);
- }
+ if (!t->fields)
+ goto nomem;
t->actions = calloc(params->n_actions, sizeof(struct action *));
- if (!t->actions) {
- free(t->fields);
- free(t);
- CHECK(0, ENOMEM);
- }
+ if (!t->actions)
+ goto nomem;
if (action_data_size_max) {
t->default_action_data = calloc(1, action_data_size_max);
- if (!t->default_action_data) {
- free(t->actions);
- free(t->fields);
- free(t);
- CHECK(0, ENOMEM);
- }
+ if (!t->default_action_data)
+ goto nomem;
}
+ t->action_is_for_table_entries = calloc(params->n_actions, sizeof(int));
+ if (!t->action_is_for_table_entries)
+ goto nomem;
+
+ t->action_is_for_default_entry = calloc(params->n_actions, sizeof(int));
+ if (!t->action_is_for_default_entry)
+ goto nomem;
+
/* Node initialization. */
strcpy(t->name, name);
if (args && args[0])
t->n_fields = params->n_fields;
t->header = header;
- for (i = 0; i < params->n_actions; i++)
+ for (i = 0; i < params->n_actions; i++) {
+ int action_is_for_table_entries = 1, action_is_for_default_entry = 1;
+
+ if (params->action_is_for_table_entries)
+ action_is_for_table_entries = params->action_is_for_table_entries[i];
+ if (params->action_is_for_default_entry)
+ action_is_for_default_entry = params->action_is_for_default_entry[i];
+
t->actions[i] = action_find(p, params->action_names[i]);
+ t->action_is_for_table_entries[i] = action_is_for_table_entries;
+ 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,
p->n_tables++;
return 0;
+
+nomem:
+ if (!t)
+ return -ENOMEM;
+
+ free(t->action_is_for_default_entry);
+ free(t->action_is_for_table_entries);
+ free(t->default_action_data);
+ free(t->actions);
+ free(t->fields);
+ free(t);
+
+ return -ENOMEM;
}
static struct rte_swx_table_params *
/* Action checks. */
CHECK(params->n_actions, EINVAL);
-
CHECK(params->action_names, EINVAL);
for (i = 0; i < params->n_actions; i++) {
const char *action_name = params->action_names[i];
- const char *action_field_name = params->action_field_names[i];
struct action *a;
uint32_t action_data_size;
+ int action_is_for_table_entries = 1, action_is_for_default_entry = 1;
CHECK_NAME(action_name, EINVAL);
a = action_find(p, action_name);
CHECK(a, EINVAL);
- status = learner_action_args_check(p, a, action_field_name);
- if (status)
- return status;
-
status = learner_action_learning_check(p,
a,
params->action_names,
action_data_size = a->st ? a->st->n_bits / 8 : 0;
if (action_data_size > action_data_size_max)
action_data_size_max = action_data_size;
+
+ if (params->action_is_for_table_entries)
+ action_is_for_table_entries = params->action_is_for_table_entries[i];
+ if (params->action_is_for_default_entry)
+ action_is_for_default_entry = params->action_is_for_default_entry[i];
+ CHECK(action_is_for_table_entries || action_is_for_default_entry, EINVAL);
}
CHECK_NAME(params->default_action_name, EINVAL);
params->default_action_name))
break;
CHECK(i < params->n_actions, EINVAL);
+ CHECK(!params->action_is_for_default_entry || params->action_is_for_default_entry[i],
+ EINVAL);
default_action = action_find(p, params->default_action_name);
CHECK((default_action->st && params->default_action_data) ||
if (!l->actions)
goto nomem;
- l->action_arg = calloc(params->n_actions, sizeof(struct field *));
- if (!l->action_arg)
- goto nomem;
-
if (action_data_size_max) {
l->default_action_data = calloc(1, action_data_size_max);
if (!l->default_action_data)
goto nomem;
}
+ l->action_is_for_table_entries = calloc(params->n_actions, sizeof(int));
+ if (!l->action_is_for_table_entries)
+ goto nomem;
+
+ l->action_is_for_default_entry = calloc(params->n_actions, sizeof(int));
+ if (!l->action_is_for_default_entry)
+ goto nomem;
+
/* Node initialization. */
strcpy(l->name, name);
l->header = header;
for (i = 0; i < params->n_actions; i++) {
- const char *mf_name = params->action_field_names[i];
+ int action_is_for_table_entries = 1, action_is_for_default_entry = 1;
- l->actions[i] = action_find(p, params->action_names[i]);
+ if (params->action_is_for_table_entries)
+ action_is_for_table_entries = params->action_is_for_table_entries[i];
+ if (params->action_is_for_default_entry)
+ action_is_for_default_entry = params->action_is_for_default_entry[i];
- l->action_arg[i] = mf_name ? metadata_field_parse(p, mf_name) : NULL;
+ l->actions[i] = action_find(p, params->action_names[i]);
+ l->action_is_for_table_entries[i] = action_is_for_table_entries;
+ l->action_is_for_default_entry[i] = action_is_for_default_entry;
}
l->default_action = default_action;
if (!l)
return -ENOMEM;
- free(l->action_arg);
+ free(l->action_is_for_default_entry);
+ free(l->action_is_for_table_entries);
+ free(l->default_action_data);
free(l->actions);
free(l->fields);
free(l);
struct learner_runtime *r = &t->learners[j];
free(r->mailbox);
- free(r->action_data);
}
free(t->learners);
TAILQ_FOREACH(l, &p->learners, node) {
struct learner_runtime *r = &t->learners[l->id];
uint64_t size;
- uint32_t j;
/* r->mailbox. */
size = rte_swx_table_learner_mailbox_size_get();
r->key = l->header ?
&t->structs[l->header->struct_id] :
&t->structs[p->metadata_struct_id];
-
- /* r->action_data. */
- r->action_data = calloc(p->n_actions, sizeof(uint8_t *));
- if (!r->action_data) {
- status = -ENOMEM;
- goto error;
- }
-
- for (j = 0; j < l->n_actions; j++) {
- struct action *a = l->actions[j];
- struct field *mf = l->action_arg[j];
- uint8_t *m = t->structs[p->metadata_struct_id];
-
- r->action_data[a->id] = mf ? &m[mf->offset / 8] : NULL;
- }
}
}
TAILQ_REMOVE(&p->learners, l, node);
free(l->fields);
free(l->actions);
- free(l->action_arg);
free(l->default_action_data);
free(l);
}
struct selector *s;
struct learner *l;
- p->table_state = calloc(p->n_tables + p->n_selectors,
+ p->table_state = calloc(p->n_tables + p->n_selectors + p->n_learners,
sizeof(struct rte_swx_table_state));
CHECK(p->table_state, ENOMEM);
/*
* Pipeline.
*/
+void
+rte_swx_pipeline_free(struct rte_swx_pipeline *p)
+{
+ void *lib;
+
+ if (!p)
+ return;
+
+ lib = p->lib;
+
+ free(p->instruction_data);
+ free(p->instructions);
+
+ metarray_free(p);
+ regarray_free(p);
+ table_state_free(p);
+ learner_free(p);
+ selector_free(p);
+ table_free(p);
+ action_free(p);
+ instruction_table_free(p);
+ metadata_free(p);
+ header_free(p);
+ extern_func_free(p);
+ extern_obj_free(p);
+ port_out_free(p);
+ port_in_free(p);
+ struct_free(p);
+
+ free(p);
+
+ if (lib)
+ dlclose(lib);
+}
+
+static int
+port_in_types_register(struct rte_swx_pipeline *p)
+{
+ int status;
+
+ status = rte_swx_pipeline_port_in_type_register(p,
+ "ethdev",
+ &rte_swx_port_ethdev_reader_ops);
+ if (status)
+ return status;
+
+ status = rte_swx_pipeline_port_in_type_register(p,
+ "ring",
+ &rte_swx_port_ring_reader_ops);
+ if (status)
+ return status;
+
+#ifdef RTE_PORT_PCAP
+ status = rte_swx_pipeline_port_in_type_register(p,
+ "source",
+ &rte_swx_port_source_ops);
+ if (status)
+ return status;
+#endif
+
+ status = rte_swx_pipeline_port_in_type_register(p,
+ "fd",
+ &rte_swx_port_fd_reader_ops);
+ if (status)
+ return status;
+
+ return 0;
+}
+
+static int
+port_out_types_register(struct rte_swx_pipeline *p)
+{
+ int status;
+
+ status = rte_swx_pipeline_port_out_type_register(p,
+ "ethdev",
+ &rte_swx_port_ethdev_writer_ops);
+ if (status)
+ return status;
+
+ status = rte_swx_pipeline_port_out_type_register(p,
+ "ring",
+ &rte_swx_port_ring_writer_ops);
+ if (status)
+ return status;
+
+ status = rte_swx_pipeline_port_out_type_register(p,
+ "sink",
+ &rte_swx_port_sink_ops);
+ if (status)
+ return status;
+
+ status = rte_swx_pipeline_port_out_type_register(p,
+ "fd",
+ &rte_swx_port_fd_writer_ops);
+ if (status)
+ return status;
+
+ return 0;
+}
+
+static int
+table_types_register(struct rte_swx_pipeline *p)
+{
+ int status;
+
+ status = rte_swx_pipeline_table_type_register(p,
+ "exact",
+ RTE_SWX_TABLE_MATCH_EXACT,
+ &rte_swx_table_exact_match_ops);
+ if (status)
+ return status;
+
+ status = rte_swx_pipeline_table_type_register(p,
+ "wildcard",
+ RTE_SWX_TABLE_MATCH_WILDCARD,
+ &rte_swx_table_wildcard_match_ops);
+ if (status)
+ return status;
+
+ return 0;
+}
+
int
rte_swx_pipeline_config(struct rte_swx_pipeline **p, int numa_node)
{
- struct rte_swx_pipeline *pipeline;
+ struct rte_swx_pipeline *pipeline = NULL;
+ int status = 0;
/* Check input parameters. */
CHECK(p, EINVAL);
/* Memory allocation. */
pipeline = calloc(1, sizeof(struct rte_swx_pipeline));
- CHECK(pipeline, ENOMEM);
+ if (!pipeline) {
+ status = -ENOMEM;
+ goto error;
+ }
/* Initialization. */
TAILQ_INIT(&pipeline->struct_types);
pipeline->n_structs = 1; /* Struct 0 is reserved for action_data. */
pipeline->numa_node = numa_node;
- *p = pipeline;
- return 0;
-}
-
-void
-rte_swx_pipeline_free(struct rte_swx_pipeline *p)
-{
- void *lib;
-
- if (!p)
- return;
-
- lib = p->lib;
+ status = port_in_types_register(pipeline);
+ if (status)
+ goto error;
- free(p->instruction_data);
- free(p->instructions);
+ status = port_out_types_register(pipeline);
+ if (status)
+ goto error;
- metarray_free(p);
- regarray_free(p);
- table_state_free(p);
- learner_free(p);
- selector_free(p);
- table_free(p);
- action_free(p);
- instruction_table_free(p);
- metadata_free(p);
- header_free(p);
- extern_func_free(p);
- extern_obj_free(p);
- port_out_free(p);
- port_in_free(p);
- struct_free(p);
+ status = table_types_register(pipeline);
+ if (status)
+ goto error;
- free(p);
+ *p = pipeline;
+ return 0;
- if (lib)
- dlclose(lib);
+error:
+ rte_swx_pipeline_free(pipeline);
+ return status;
}
int
int
rte_swx_pipeline_build(struct rte_swx_pipeline *p)
{
+ struct rte_swx_port_sink_params drop_port_params = {
+ .file_name = NULL,
+ };
int status;
CHECK(p, EINVAL);
if (status)
goto error;
+ /* Drop port. */
+ status = rte_swx_pipeline_port_out_config(p,
+ p->n_ports_out,
+ "sink",
+ &drop_port_params);
+ if (status)
+ goto error;
+
status = port_out_build(p);
if (status)
goto error;
table_action->action_id = t->actions[table_action_id]->id;
+ table_action->action_is_for_table_entries = t->action_is_for_table_entries[table_action_id];
+ table_action->action_is_for_default_entry = t->action_is_for_default_entry[table_action_id];
+
return 0;
}
learner_action->action_id = l->actions[learner_action_id]->id;
+ learner_action->action_is_for_table_entries =
+ l->action_is_for_table_entries[learner_action_id];
+
+ learner_action->action_is_for_default_entry =
+ l->action_is_for_default_entry[learner_action_id];
+
return 0;
}
case INSTR_TX: return "INSTR_TX";
case INSTR_TX_I: return "INSTR_TX_I";
+ case INSTR_DROP: return "INSTR_DROP";
case INSTR_HDR_EXTRACT: return "INSTR_HDR_EXTRACT";
case INSTR_HDR_EXTRACT2: return "INSTR_HDR_EXTRACT2";
instr_type_to_name(instr));
/* instr.io. */
- fprintf(f,
- "\t\t.io = {\n");
+ if (n_io || n_io_imm || n_hdrs)
+ fprintf(f,
+ "\t\t.io = {\n");
/* instr.io.io. */
if (n_io)
}
/* instr.io - closing curly brace. */
- fprintf(f,
- "\t\t},\n");
+ if (n_io || n_io_imm || n_hdrs)
+ fprintf(f,
+ "\t\t},\n");
/* instr - closing curly brace. */
fprintf(f,
[INSTR_TX] = instr_io_export,
[INSTR_TX_I] = instr_io_export,
+ [INSTR_DROP] = instr_io_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_HDR_EXTRACT: return "__instr_hdr_extract_exec";
case INSTR_HDR_EXTRACT2: return "__instr_hdr_extract2_exec";