/* rx m.port_in */
INSTR_RX,
- /* tx m.port_out */
- INSTR_TX,
+ /* tx port_out
+ * port_out = MI
+ */
+ INSTR_TX, /* port_out = M */
+ INSTR_TX_I, /* port_out = I */
/* extract h.header */
INSTR_HDR_EXTRACT,
struct instr_io {
struct {
- uint8_t offset;
- uint8_t n_bits;
- uint8_t pad[2];
+ union {
+ struct {
+ uint8_t offset;
+ uint8_t n_bits;
+ uint8_t pad[2];
+ };
+
+ uint32_t val;
+ };
} io;
struct {
uint8_t **key;
};
+struct table_statistics {
+ uint64_t n_pkts_hit[2]; /* 0 = Miss, 1 = Hit. */
+ uint64_t *n_pkts_action;
+};
+
/*
* Register array.
*/
struct port_out_runtime *out;
struct instruction **action_instructions;
struct rte_swx_table_state *table_state;
+ struct table_statistics *table_stats;
struct regarray_runtime *regarray_runtime;
struct metarray_runtime *metarray_runtime;
struct instruction *instructions;
/*
* Instruction.
*/
+static int
+instruction_is_tx(enum instruction_type type)
+{
+ switch (type) {
+ case INSTR_TX:
+ case INSTR_TX_I:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
static int
instruction_is_jmp(struct instruction *instr)
{
struct instruction *instr,
struct instruction_data *data __rte_unused)
{
+ char *port = tokens[1];
struct field *f;
+ uint32_t port_val;
CHECK(n_tokens == 2, EINVAL);
- f = metadata_field_parse(p, tokens[1]);
- CHECK(f, EINVAL);
+ f = metadata_field_parse(p, port);
+ if (f) {
+ instr->type = INSTR_TX;
+ instr->io.io.offset = f->offset / 8;
+ instr->io.io.n_bits = f->n_bits;
+ return 0;
+ }
- instr->type = INSTR_TX;
- instr->io.io.offset = f->offset / 8;
- instr->io.io.n_bits = f->n_bits;
+ /* TX_I. */
+ port_val = strtoul(port, &port, 0);
+ CHECK(!port[0], EINVAL);
+
+ instr->type = INSTR_TX_I;
+ instr->io.io.val = port_val;
+ return 0;
+}
+
+static int
+instr_drop_translate(struct rte_swx_pipeline *p,
+ struct action *action __rte_unused,
+ char **tokens __rte_unused,
+ int n_tokens,
+ struct instruction *instr,
+ struct instruction_data *data __rte_unused)
+{
+ CHECK(n_tokens == 1, EINVAL);
+
+ /* TX_I. */
+ instr->type = INSTR_TX_I;
+ instr->io.io.val = p->n_ports_out - 1;
return 0;
}
instr_rx_exec(p);
}
+static inline void
+instr_tx_i_exec(struct rte_swx_pipeline *p)
+{
+ struct thread *t = &p->threads[p->thread_id];
+ struct instruction *ip = t->ip;
+ uint64_t port_id = ip->io.io.val;
+ struct port_out_runtime *port = &p->out[port_id];
+ struct rte_swx_pkt *pkt = &t->pkt;
+
+ TRACE("[Thread %2u]: tx (i) 1 pkt to port %u\n",
+ p->thread_id,
+ (uint32_t)port_id);
+
+ /* Headers. */
+ emit_handler(t);
+
+ /* Packet. */
+ port->pkt_tx(port->obj, pkt);
+
+ /* Thread. */
+ thread_ip_reset(p, t);
+ instr_rx_exec(p);
+}
+
/*
* extract.
*/
uint32_t table_id = ip->table.table_id;
struct rte_swx_table_state *ts = &t->table_state[table_id];
struct table_runtime *table = &t->tables[table_id];
- uint64_t action_id;
+ struct table_statistics *stats = &p->table_stats[table_id];
+ uint64_t action_id, n_pkts_hit, n_pkts_action;
uint8_t *action_data;
int done, hit;
action_id = hit ? action_id : ts->default_action_id;
action_data = hit ? action_data : ts->default_action_data;
+ n_pkts_hit = stats->n_pkts_hit[hit];
+ n_pkts_action = stats->n_pkts_action[action_id];
TRACE("[Thread %2u] table %u (%s, action %u)\n",
p->thread_id,
t->action_id = action_id;
t->structs[0] = action_data;
t->hit = hit;
+ stats->n_pkts_hit[hit] = n_pkts_hit + 1;
+ stats->n_pkts_action[action_id] = n_pkts_action + 1;
/* Thread. */
thread_ip_action_call(p, t, action_id);
instr,
data);
+ if (!strcmp(tokens[tpos], "drop"))
+ return instr_drop_translate(p,
+ action,
+ &tokens[tpos],
+ n_tokens - tpos,
+ instr,
+ data);
+
if (!strcmp(tokens[tpos], "extract"))
return instr_hdr_extract_translate(p,
action,
for (i = 0; i < n_instructions; i++) {
type = instr[i].type;
- if (type == INSTR_TX)
+ if (instruction_is_tx(type))
break;
}
CHECK(i < n_instructions, EINVAL);
* jump.
*/
type = instr[n_instructions - 1].type;
- CHECK((type == INSTR_TX) || (type == INSTR_JMP), EINVAL);
+ CHECK(instruction_is_tx(type) || (type == INSTR_JMP), EINVAL);
}
if (a) {
for (i = 0; i < n_instructions; i++) {
type = instr[i].type;
- if ((type == INSTR_RETURN) || (type == INSTR_TX))
+ if ((type == INSTR_RETURN) || instruction_is_tx(type))
break;
}
CHECK(i < n_instructions, EINVAL);
if (!i)
return 0;
- if (instr[i].type != INSTR_TX)
+ if (!instruction_is_tx(instr[i].type))
return 0;
if (data[i].n_users)
static instr_exec_t instruction_table[] = {
[INSTR_RX] = instr_rx_exec,
[INSTR_TX] = instr_tx_exec,
+ [INSTR_TX_I] = instr_tx_i_exec,
[INSTR_HDR_EXTRACT] = instr_hdr_extract_exec,
[INSTR_HDR_EXTRACT2] = instr_hdr_extract2_exec,
{
uint32_t i;
+ /* Per pipeline: table statistics. */
+ p->table_stats = calloc(p->n_tables, sizeof(struct table_statistics));
+ CHECK(p->table_stats, ENOMEM);
+
+ for (i = 0; i < p->n_tables; i++) {
+ p->table_stats[i].n_pkts_action = calloc(p->n_actions, sizeof(uint64_t));
+ CHECK(p->table_stats[i].n_pkts_action, ENOMEM);
+ }
+
+ /* Per thread: table runt-time. */
for (i = 0; i < RTE_SWX_PIPELINE_THREADS_MAX; i++) {
struct thread *t = &p->threads[i];
struct table *table;
free(t->tables);
t->tables = NULL;
}
+
+ if (p->table_stats) {
+ for (i = 0; i < p->n_tables; i++)
+ free(p->table_stats[i].n_pkts_action);
+
+ free(p->table_stats);
+ }
}
static void
return 0;
}
+int
+rte_swx_ctl_pipeline_table_stats_read(struct rte_swx_pipeline *p,
+ const char *table_name,
+ struct rte_swx_table_stats *stats)
+{
+ struct table *table;
+ struct table_statistics *table_stats;
+
+ if (!p || !table_name || !table_name[0] || !stats || !stats->n_pkts_action)
+ return -EINVAL;
+
+ table = table_find(p, table_name);
+ if (!table)
+ return -EINVAL;
+
+ table_stats = &p->table_stats[table->id];
+
+ memcpy(&stats->n_pkts_action,
+ &table_stats->n_pkts_action,
+ p->n_actions * sizeof(uint64_t));
+
+ stats->n_pkts_hit = table_stats->n_pkts_hit[1];
+ stats->n_pkts_miss = table_stats->n_pkts_hit[0];
+
+ return 0;
+}
+
int
rte_swx_ctl_regarray_info_get(struct rte_swx_pipeline *p,
uint32_t regarray_id,