X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=drivers%2Fnet%2Fsoftnic%2Frte_eth_softnic_cli.c;h=bc95f164396360dfc0765b6dfad49cd28dca38cd;hb=df6cd7c1f73a62e2bd889cc1aa4832096cb8c245;hp=c13f4d8dc09a4cef255b57b3929061ef91a1b667;hpb=9bc0ce0ad17c168be4dc66a94598dcf5dcf1cccd;p=dpdk.git diff --git a/drivers/net/softnic/rte_eth_softnic_cli.c b/drivers/net/softnic/rte_eth_softnic_cli.c index c13f4d8dc0..bc95f16439 100644 --- a/drivers/net/softnic/rte_eth_softnic_cli.c +++ b/drivers/net/softnic/rte_eth_softnic_cli.c @@ -9,6 +9,8 @@ #include #include +#include +#include #include "rte_eth_softnic_internals.h" #include "parser.h" @@ -185,1343 +187,2088 @@ cmd_swq(struct pmd_internals *softnic, } /** - * tap + * tmgr shaper profile + * id + * rate size + * adj */ static void -cmd_tap(struct pmd_internals *softnic, +cmd_tmgr_shaper_profile(struct pmd_internals *softnic, char **tokens, uint32_t n_tokens, char *out, size_t out_size) { - char *name; - struct softnic_tap *tap; + struct rte_tm_shaper_params sp; + struct rte_tm_error error; + uint32_t shaper_profile_id; + uint16_t port_id; + int status; - if (n_tokens != 2) { + memset(&sp, 0, sizeof(struct rte_tm_shaper_params)); + + if (n_tokens != 11) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } - name = tokens[1]; + if (strcmp(tokens[1], "shaper") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "shaper"); + return; + } - tap = softnic_tap_create(softnic, name); - if (tap == NULL) { + if (strcmp(tokens[2], "profile") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); + return; + } + + if (strcmp(tokens[3], "id") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "id"); + return; + } + + if (softnic_parser_read_uint32(&shaper_profile_id, tokens[4]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "profile_id"); + return; + } + + if (strcmp(tokens[5], "rate") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rate"); + return; + } + + if (softnic_parser_read_uint64(&sp.peak.rate, tokens[6]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate"); + return; + } + + if (strcmp(tokens[7], "size") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); + return; + } + + if (softnic_parser_read_uint64(&sp.peak.size, tokens[8]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "tb_size"); + return; + } + + if (strcmp(tokens[9], "adj") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "adj"); + return; + } + + if (softnic_parser_read_int32(&sp.pkt_length_adjust, tokens[10]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "packet_length_adjust"); + return; + } + + status = rte_eth_dev_get_port_by_name(softnic->params.name, &port_id); + if (status) + return; + + status = rte_tm_shaper_profile_add(port_id, shaper_profile_id, &sp, &error); + if (status != 0) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } /** - * port in action profile - * [filter match | mismatch offset mask key port ] - * [balance offset mask port ... ] + * tmgr shared shaper + * id + * profile */ static void -cmd_port_in_action_profile(struct pmd_internals *softnic, +cmd_tmgr_shared_shaper(struct pmd_internals *softnic, char **tokens, uint32_t n_tokens, char *out, size_t out_size) { - struct softnic_port_in_action_profile_params p; - struct softnic_port_in_action_profile *ap; - char *name; - uint32_t t0; - - memset(&p, 0, sizeof(p)); + struct rte_tm_error error; + uint32_t shared_shaper_id, shaper_profile_id; + uint16_t port_id; + int status; - if (n_tokens < 5) { + if (n_tokens != 7) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } - if (strcmp(tokens[1], "in") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); + if (strcmp(tokens[1], "shared") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "shared"); return; } - if (strcmp(tokens[2], "action") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action"); + if (strcmp(tokens[2], "shaper") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "shaper"); return; } - if (strcmp(tokens[3], "profile") != 0) { + if (strcmp(tokens[3], "id") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "id"); + return; + } + + if (softnic_parser_read_uint32(&shared_shaper_id, tokens[4]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "shared_shaper_id"); + return; + } + + if (strcmp(tokens[5], "profile") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); return; } - name = tokens[4]; + if (softnic_parser_read_uint32(&shaper_profile_id, tokens[6]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "shaper_profile_id"); + return; + } - t0 = 5; + status = rte_eth_dev_get_port_by_name(softnic->params.name, &port_id); + if (status) + return; - if (t0 < n_tokens && - (strcmp(tokens[t0], "filter") == 0)) { - uint32_t size; + status = rte_tm_shared_shaper_add_update(port_id, + shared_shaper_id, + shaper_profile_id, + &error); + if (status != 0) { + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); + return; + } +} - if (n_tokens < t0 + 10) { - snprintf(out, out_size, MSG_ARG_MISMATCH, "port in action profile filter"); - return; - } +/** + * tmgr node + * id + * parent + * priority + * weight + * [shaper profile ] + * [shared shaper ] + * [nonleaf sp ] + */ +static void +cmd_tmgr_node(struct pmd_internals *softnic, + char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size) +{ + struct rte_tm_error error; + struct rte_tm_node_params np; + uint32_t node_id, parent_node_id, priority, weight, shared_shaper_id; + uint16_t port_id; + int status; - if (strcmp(tokens[t0 + 1], "match") == 0) { - p.fltr.filter_on_match = 1; - } else if (strcmp(tokens[t0 + 1], "mismatch") == 0) { - p.fltr.filter_on_match = 0; - } else { - snprintf(out, out_size, MSG_ARG_INVALID, "match or mismatch"); - return; - } + memset(&np, 0, sizeof(struct rte_tm_node_params)); + np.shaper_profile_id = RTE_TM_SHAPER_PROFILE_ID_NONE; + np.nonleaf.n_sp_priorities = 1; - if (strcmp(tokens[t0 + 2], "offset") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); - return; - } + if (n_tokens < 10) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } - if (softnic_parser_read_uint32(&p.fltr.key_offset, - tokens[t0 + 3]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); - return; - } + if (strcmp(tokens[1], "node") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "node"); + return; + } - if (strcmp(tokens[t0 + 4], "mask") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); - return; - } + if (strcmp(tokens[2], "id") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "id"); + return; + } - size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE; - if ((softnic_parse_hex_string(tokens[t0 + 5], - p.fltr.key_mask, &size) != 0) || - size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE) { - snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); - return; - } + if (softnic_parser_read_uint32(&node_id, tokens[3]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "node_id"); + return; + } - if (strcmp(tokens[t0 + 6], "key") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key"); - return; - } + if (strcmp(tokens[4], "parent") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "parent"); + return; + } - size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE; - if ((softnic_parse_hex_string(tokens[t0 + 7], - p.fltr.key, &size) != 0) || - size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE) { - snprintf(out, out_size, MSG_ARG_INVALID, "key_value"); + if (strcmp(tokens[5], "none") == 0) + parent_node_id = RTE_TM_NODE_ID_NULL; + else { + if (softnic_parser_read_uint32(&parent_node_id, tokens[5]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "parent_node_id"); return; } + } - if (strcmp(tokens[t0 + 8], "port") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); - return; - } + if (strcmp(tokens[6], "priority") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "priority"); + return; + } - if (softnic_parser_read_uint32(&p.fltr.port_id, - tokens[t0 + 9]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); - return; - } + if (softnic_parser_read_uint32(&priority, tokens[7]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "priority"); + return; + } - p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_FLTR; - t0 += 10; - } /* filter */ + if (strcmp(tokens[8], "weight") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "weight"); + return; + } - if (t0 < n_tokens && - (strcmp(tokens[t0], "balance") == 0)) { - uint32_t i; + if (softnic_parser_read_uint32(&weight, tokens[9]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "weight"); + return; + } - if (n_tokens < t0 + 22) { - snprintf(out, out_size, MSG_ARG_MISMATCH, - "port in action profile balance"); + tokens += 10; + n_tokens -= 10; + + if (n_tokens >= 2 && + (strcmp(tokens[0], "shaper") == 0) && + (strcmp(tokens[1], "profile") == 0)) { + if (n_tokens < 3) { + snprintf(out, out_size, MSG_ARG_MISMATCH, "tmgr node"); return; } - if (strcmp(tokens[t0 + 1], "offset") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); - return; + if (strcmp(tokens[2], "none") == 0) { + np.shaper_profile_id = RTE_TM_SHAPER_PROFILE_ID_NONE; + } else { + if (softnic_parser_read_uint32(&np.shaper_profile_id, tokens[2]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "shaper_profile_id"); + return; + } } - if (softnic_parser_read_uint32(&p.lb.key_offset, - tokens[t0 + 2]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); + tokens += 3; + n_tokens -= 3; + } /* shaper profile */ + + if (n_tokens >= 2 && + (strcmp(tokens[0], "shared") == 0) && + (strcmp(tokens[1], "shaper") == 0)) { + if (n_tokens < 3) { + snprintf(out, out_size, MSG_ARG_MISMATCH, "tmgr node"); return; } - if (strcmp(tokens[t0 + 3], "mask") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); + if (softnic_parser_read_uint32(&shared_shaper_id, tokens[2]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "shared_shaper_id"); return; } - p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX; - if (softnic_parse_hex_string(tokens[t0 + 4], - p.lb.key_mask, &p.lb.key_size) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); + np.shared_shaper_id = &shared_shaper_id; + np.n_shared_shapers = 1; + + tokens += 3; + n_tokens -= 3; + } /* shared shaper */ + + if (n_tokens >= 2 && + (strcmp(tokens[0], "nonleaf") == 0) && + (strcmp(tokens[1], "sp") == 0)) { + if (n_tokens < 3) { + snprintf(out, out_size, MSG_ARG_MISMATCH, "tmgr node"); return; } - if (strcmp(tokens[t0 + 5], "port") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); + if (softnic_parser_read_uint32(&np.nonleaf.n_sp_priorities, tokens[2]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "n_sp_priorities"); return; } - for (i = 0; i < 16; i++) - if (softnic_parser_read_uint32(&p.lb.port_id[i], - tokens[t0 + 6 + i]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); - return; - } - - p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_LB; - t0 += 22; - } /* balance */ + tokens += 3; + n_tokens -= 3; + } /* nonleaf sp */ - if (t0 < n_tokens) { + if (n_tokens) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } - ap = softnic_port_in_action_profile_create(softnic, name, &p); - if (ap == NULL) { + status = rte_eth_dev_get_port_by_name(softnic->params.name, &port_id); + if (status != 0) + return; + + status = rte_tm_node_add(port_id, + node_id, + parent_node_id, + priority, + weight, + RTE_TM_NODE_LEVEL_ID_ANY, + &np, + &error); + if (status != 0) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } -/** - * table action profile - * ipv4 | ipv6 - * offset - * fwd - * [balance offset mask outoffset ] - * [meter srtcm | trtcm - * tc - * stats none | pkts | bytes | both] - * [tm spp pps ] - * [encap ether | vlan | qinq | mpls | pppoe] - * [nat src | dst - * proto udp | tcp] - * [ttl drop | fwd - * stats none | pkts] - * [stats pkts | bytes | both] - * [time] - */ -static void -cmd_table_action_profile(struct pmd_internals *softnic, - char **tokens, - uint32_t n_tokens, - char *out, - size_t out_size) +static uint32_t +root_node_id(uint32_t n_spp, + uint32_t n_pps) { - struct softnic_table_action_profile_params p; - struct softnic_table_action_profile *ap; - char *name; - uint32_t t0; - - memset(&p, 0, sizeof(p)); + uint32_t n_queues = n_spp * n_pps * RTE_SCHED_QUEUES_PER_PIPE; + uint32_t n_tc = n_spp * n_pps * RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; + uint32_t n_pipes = n_spp * n_pps; - if (n_tokens < 8) { - snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); - return; - } + return n_queues + n_tc + n_pipes + n_spp; +} - if (strcmp(tokens[1], "action") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action"); - return; - } +static uint32_t +subport_node_id(uint32_t n_spp, + uint32_t n_pps, + uint32_t subport_id) +{ + uint32_t n_pipes = n_spp * n_pps; + uint32_t n_tc = n_pipes * RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; + uint32_t n_queues = n_pipes * RTE_SCHED_QUEUES_PER_PIPE; - if (strcmp(tokens[2], "profile") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); - return; - } + return n_queues + n_tc + n_pipes + subport_id; +} - name = tokens[3]; +static uint32_t +pipe_node_id(uint32_t n_spp, + uint32_t n_pps, + uint32_t subport_id, + uint32_t pipe_id) +{ + uint32_t n_pipes = n_spp * n_pps; + uint32_t n_tc = n_pipes * RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; + uint32_t n_queues = n_pipes * RTE_SCHED_QUEUES_PER_PIPE; + + return n_queues + + n_tc + + pipe_id + + subport_id * n_pps; +} - if (strcmp(tokens[4], "ipv4") == 0) { - p.common.ip_version = 1; - } else if (strcmp(tokens[4], "ipv6") == 0) { - p.common.ip_version = 0; - } else { - snprintf(out, out_size, MSG_ARG_INVALID, "ipv4 or ipv6"); +static uint32_t +tc_node_id(uint32_t n_spp, + uint32_t n_pps, + uint32_t subport_id, + uint32_t pipe_id, + uint32_t tc_id) +{ + uint32_t n_pipes = n_spp * n_pps; + uint32_t n_queues = n_pipes * RTE_SCHED_QUEUES_PER_PIPE; + + return n_queues + + tc_id + + (pipe_id + subport_id * n_pps) * RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; +} + +static uint32_t +queue_node_id(uint32_t n_spp __rte_unused, + uint32_t n_pps, + uint32_t subport_id, + uint32_t pipe_id, + uint32_t tc_id, + uint32_t queue_id) +{ + return queue_id + tc_id + + (pipe_id + subport_id * n_pps) * RTE_SCHED_QUEUES_PER_PIPE; +} + +struct tmgr_hierarchy_default_params { + uint32_t n_spp; /**< Number of subports per port. */ + uint32_t n_pps; /**< Number of pipes per subport. */ + + struct { + uint32_t port; + uint32_t subport; + uint32_t pipe; + uint32_t tc[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE]; + } shaper_profile_id; + + struct { + uint32_t tc[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE]; + uint32_t tc_valid[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE]; + } shared_shaper_id; + + struct { + uint32_t queue[RTE_SCHED_QUEUES_PER_PIPE]; + } weight; +}; + +static int +tmgr_hierarchy_default(struct pmd_internals *softnic, + struct tmgr_hierarchy_default_params *params) +{ + struct rte_tm_node_params root_node_params = { + .shaper_profile_id = params->shaper_profile_id.port, + .nonleaf = { + .n_sp_priorities = 1, + }, + }; + + struct rte_tm_node_params subport_node_params = { + .shaper_profile_id = params->shaper_profile_id.subport, + .nonleaf = { + .n_sp_priorities = 1, + }, + }; + + struct rte_tm_node_params pipe_node_params = { + .shaper_profile_id = params->shaper_profile_id.pipe, + .nonleaf = { + .n_sp_priorities = RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE, + }, + }; + + uint32_t *shared_shaper_id = + (uint32_t *)calloc(RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE, + sizeof(uint32_t)); + + if (shared_shaper_id == NULL) + return -1; + + memcpy(shared_shaper_id, params->shared_shaper_id.tc, + sizeof(params->shared_shaper_id.tc)); + + struct rte_tm_node_params tc_node_params[] = { + [0] = { + .shaper_profile_id = params->shaper_profile_id.tc[0], + .shared_shaper_id = &shared_shaper_id[0], + .n_shared_shapers = + (¶ms->shared_shaper_id.tc_valid[0]) ? 1 : 0, + .nonleaf = { + .n_sp_priorities = 1, + }, + }, + + [1] = { + .shaper_profile_id = params->shaper_profile_id.tc[1], + .shared_shaper_id = &shared_shaper_id[1], + .n_shared_shapers = + (¶ms->shared_shaper_id.tc_valid[1]) ? 1 : 0, + .nonleaf = { + .n_sp_priorities = 1, + }, + }, + + [2] = { + .shaper_profile_id = params->shaper_profile_id.tc[2], + .shared_shaper_id = &shared_shaper_id[2], + .n_shared_shapers = + (¶ms->shared_shaper_id.tc_valid[2]) ? 1 : 0, + .nonleaf = { + .n_sp_priorities = 1, + }, + }, + + [3] = { + .shaper_profile_id = params->shaper_profile_id.tc[3], + .shared_shaper_id = &shared_shaper_id[3], + .n_shared_shapers = + (¶ms->shared_shaper_id.tc_valid[3]) ? 1 : 0, + .nonleaf = { + .n_sp_priorities = 1, + }, + }, + + [4] = { + .shaper_profile_id = params->shaper_profile_id.tc[4], + .shared_shaper_id = &shared_shaper_id[4], + .n_shared_shapers = + (¶ms->shared_shaper_id.tc_valid[4]) ? 1 : 0, + .nonleaf = { + .n_sp_priorities = 1, + }, + }, + + [5] = { + .shaper_profile_id = params->shaper_profile_id.tc[5], + .shared_shaper_id = &shared_shaper_id[5], + .n_shared_shapers = + (¶ms->shared_shaper_id.tc_valid[5]) ? 1 : 0, + .nonleaf = { + .n_sp_priorities = 1, + }, + }, + + [6] = { + .shaper_profile_id = params->shaper_profile_id.tc[6], + .shared_shaper_id = &shared_shaper_id[6], + .n_shared_shapers = + (¶ms->shared_shaper_id.tc_valid[6]) ? 1 : 0, + .nonleaf = { + .n_sp_priorities = 1, + }, + }, + + [7] = { + .shaper_profile_id = params->shaper_profile_id.tc[7], + .shared_shaper_id = &shared_shaper_id[7], + .n_shared_shapers = + (¶ms->shared_shaper_id.tc_valid[7]) ? 1 : 0, + .nonleaf = { + .n_sp_priorities = 1, + }, + }, + + [8] = { + .shaper_profile_id = params->shaper_profile_id.tc[8], + .shared_shaper_id = &shared_shaper_id[8], + .n_shared_shapers = + (¶ms->shared_shaper_id.tc_valid[8]) ? 1 : 0, + .nonleaf = { + .n_sp_priorities = 1, + }, + }, + + [9] = { + .shaper_profile_id = params->shaper_profile_id.tc[9], + .shared_shaper_id = &shared_shaper_id[9], + .n_shared_shapers = + (¶ms->shared_shaper_id.tc_valid[9]) ? 1 : 0, + .nonleaf = { + .n_sp_priorities = 1, + }, + }, + + [10] = { + .shaper_profile_id = params->shaper_profile_id.tc[10], + .shared_shaper_id = &shared_shaper_id[10], + .n_shared_shapers = + (¶ms->shared_shaper_id.tc_valid[10]) ? 1 : 0, + .nonleaf = { + .n_sp_priorities = 1, + }, + }, + + [11] = { + .shaper_profile_id = params->shaper_profile_id.tc[11], + .shared_shaper_id = &shared_shaper_id[11], + .n_shared_shapers = + (¶ms->shared_shaper_id.tc_valid[11]) ? 1 : 0, + .nonleaf = { + .n_sp_priorities = 1, + }, + }, + + [12] = { + .shaper_profile_id = params->shaper_profile_id.tc[12], + .shared_shaper_id = &shared_shaper_id[12], + .n_shared_shapers = + (¶ms->shared_shaper_id.tc_valid[12]) ? 1 : 0, + .nonleaf = { + .n_sp_priorities = 1, + }, + }, + }; + + struct rte_tm_node_params queue_node_params = { + .shaper_profile_id = RTE_TM_SHAPER_PROFILE_ID_NONE, + }; + + struct rte_tm_error error; + uint32_t n_spp = params->n_spp, n_pps = params->n_pps, s; + int status; + uint16_t port_id; + + status = rte_eth_dev_get_port_by_name(softnic->params.name, &port_id); + if (status) + return -1; + + /* Hierarchy level 0: Root node */ + status = rte_tm_node_add(port_id, + root_node_id(n_spp, n_pps), + RTE_TM_NODE_ID_NULL, + 0, + 1, + RTE_TM_NODE_LEVEL_ID_ANY, + &root_node_params, + &error); + if (status) + return -1; + + /* Hierarchy level 1: Subport nodes */ + for (s = 0; s < params->n_spp; s++) { + uint32_t p; + + status = rte_tm_node_add(port_id, + subport_node_id(n_spp, n_pps, s), + root_node_id(n_spp, n_pps), + 0, + 1, + RTE_TM_NODE_LEVEL_ID_ANY, + &subport_node_params, + &error); + if (status) + return -1; + + /* Hierarchy level 2: Pipe nodes */ + for (p = 0; p < params->n_pps; p++) { + uint32_t t; + + status = rte_tm_node_add(port_id, + pipe_node_id(n_spp, n_pps, s, p), + subport_node_id(n_spp, n_pps, s), + 0, + 1, + RTE_TM_NODE_LEVEL_ID_ANY, + &pipe_node_params, + &error); + if (status) + return -1; + + /* Hierarchy level 3: Traffic class nodes */ + for (t = 0; t < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; t++) { + uint32_t q; + + status = rte_tm_node_add(port_id, + tc_node_id(n_spp, n_pps, s, p, t), + pipe_node_id(n_spp, n_pps, s, p), + t, + 1, + RTE_TM_NODE_LEVEL_ID_ANY, + &tc_node_params[t], + &error); + if (status) + return -1; + + /* Hierarchy level 4: Queue nodes */ + if (t < RTE_SCHED_TRAFFIC_CLASS_BE) { + /* Strict-priority traffic class queues */ + q = 0; + status = rte_tm_node_add(port_id, + queue_node_id(n_spp, n_pps, s, p, t, q), + tc_node_id(n_spp, n_pps, s, p, t), + 0, + params->weight.queue[q], + RTE_TM_NODE_LEVEL_ID_ANY, + &queue_node_params, + &error); + if (status) + return -1; + + continue; + } + /* Best-effort traffic class queues */ + for (q = 0; q < RTE_SCHED_BE_QUEUES_PER_PIPE; q++) { + status = rte_tm_node_add(port_id, + queue_node_id(n_spp, n_pps, s, p, t, q), + tc_node_id(n_spp, n_pps, s, p, t), + 0, + params->weight.queue[q], + RTE_TM_NODE_LEVEL_ID_ANY, + &queue_node_params, + &error); + if (status) + return -1; + } + } /* TC */ + } /* Pipe */ + } /* Subport */ + + return 0; +} + + +/** + * tmgr hierarchy-default + * spp + * pps + * shaper profile + * port + * subport + * pipe + * tc0 + * tc1 + * tc2 + * tc3 + * tc4 + * tc5 + * tc6 + * tc7 + * tc8 + * tc9 + * tc10 + * tc11 + * tc12 + * shared shaper + * tc0 + * tc1 + * tc2 + * tc3 + * tc4 + * tc5 + * tc6 + * tc7 + * tc8 + * tc9 + * tc10 + * tc11 + * tc12 + * weight + * queue ... + */ +static void +cmd_tmgr_hierarchy_default(struct pmd_internals *softnic, + char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size) +{ + struct tmgr_hierarchy_default_params p; + int i, j, status; + + memset(&p, 0, sizeof(p)); + + if (n_tokens != 74) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } - if (strcmp(tokens[5], "offset") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); + if (strcmp(tokens[1], "hierarchy-default") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "hierarchy-default"); return; } - if (softnic_parser_read_uint32(&p.common.ip_offset, - tokens[6]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "ip_offset"); + if (strcmp(tokens[2], "spp") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp"); return; } - if (strcmp(tokens[7], "fwd") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fwd"); + if (softnic_parser_read_uint32(&p.n_spp, tokens[3]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "n_subports_per_port"); return; } - p.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD; + if (strcmp(tokens[4], "pps") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps"); + return; + } - t0 = 8; - if (t0 < n_tokens && - (strcmp(tokens[t0], "balance") == 0)) { - if (n_tokens < t0 + 7) { - snprintf(out, out_size, MSG_ARG_MISMATCH, "table action profile balance"); - return; - } + if (softnic_parser_read_uint32(&p.n_pps, tokens[5]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport"); + return; + } - if (strcmp(tokens[t0 + 1], "offset") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); + /* Shaper profile */ + + if (strcmp(tokens[6], "shaper") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "shaper"); + return; + } + + if (strcmp(tokens[7], "profile") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); + return; + } + + if (strcmp(tokens[8], "port") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); + return; + } + + if (softnic_parser_read_uint32(&p.shaper_profile_id.port, tokens[9]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "port profile id"); + return; + } + + if (strcmp(tokens[10], "subport") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "subport"); + return; + } + + if (softnic_parser_read_uint32(&p.shaper_profile_id.subport, tokens[11]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "subport profile id"); + return; + } + + if (strcmp(tokens[12], "pipe") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pipe"); + return; + } + + if (softnic_parser_read_uint32(&p.shaper_profile_id.pipe, tokens[13]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "pipe_profile_id"); + return; + } + + if (strcmp(tokens[14], "tc0") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc0"); + return; + } + + if (softnic_parser_read_uint32(&p.shaper_profile_id.tc[0], tokens[15]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "tc0 profile id"); + return; + } + + if (strcmp(tokens[16], "tc1") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc1"); + return; + } + + if (softnic_parser_read_uint32(&p.shaper_profile_id.tc[1], tokens[17]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "tc1 profile id"); + return; + } + + if (strcmp(tokens[18], "tc2") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc2"); + return; + } + + if (softnic_parser_read_uint32(&p.shaper_profile_id.tc[2], tokens[19]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "tc2 profile id"); + return; + } + + if (strcmp(tokens[20], "tc3") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc3"); + return; + } + + if (softnic_parser_read_uint32(&p.shaper_profile_id.tc[3], tokens[21]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "tc3 profile id"); + return; + } + + if (strcmp(tokens[22], "tc4") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc4"); + return; + } + + if (softnic_parser_read_uint32(&p.shaper_profile_id.tc[4], tokens[23]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "tc4 profile id"); + return; + } + + if (strcmp(tokens[24], "tc5") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc5"); + return; + } + + if (softnic_parser_read_uint32(&p.shaper_profile_id.tc[5], tokens[25]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "tc5 profile id"); + return; + } + + if (strcmp(tokens[26], "tc6") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc6"); + return; + } + + if (softnic_parser_read_uint32(&p.shaper_profile_id.tc[6], tokens[27]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "tc6 profile id"); + return; + } + + if (strcmp(tokens[28], "tc7") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc7"); + return; + } + + if (softnic_parser_read_uint32(&p.shaper_profile_id.tc[7], tokens[29]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "tc7 profile id"); + return; + } + + if (strcmp(tokens[30], "tc8") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc8"); + return; + } + + if (softnic_parser_read_uint32(&p.shaper_profile_id.tc[8], tokens[31]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "tc8 profile id"); + return; + } + + if (strcmp(tokens[32], "tc9") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc9"); + return; + } + + if (softnic_parser_read_uint32(&p.shaper_profile_id.tc[9], tokens[33]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "tc9 profile id"); + return; + } + + if (strcmp(tokens[34], "tc10") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc10"); + return; + } + + if (softnic_parser_read_uint32(&p.shaper_profile_id.tc[10], tokens[35]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "tc10 profile id"); + return; + } + + if (strcmp(tokens[36], "tc11") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc11"); + return; + } + + if (softnic_parser_read_uint32(&p.shaper_profile_id.tc[11], tokens[37]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "tc11 profile id"); + return; + } + + if (strcmp(tokens[38], "tc12") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc12"); + return; + } + + if (softnic_parser_read_uint32(&p.shaper_profile_id.tc[12], tokens[39]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "tc12 profile id"); + return; + } + + /* Shared shaper */ + + if (strcmp(tokens[40], "shared") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "shared"); + return; + } + + if (strcmp(tokens[41], "shaper") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "shaper"); + return; + } + + if (strcmp(tokens[42], "tc0") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc0"); + return; + } + + if (strcmp(tokens[43], "none") == 0) + p.shared_shaper_id.tc_valid[0] = 0; + else { + if (softnic_parser_read_uint32(&p.shared_shaper_id.tc[0], + tokens[43]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "shared shaper tc0"); return; } - if (softnic_parser_read_uint32(&p.lb.key_offset, - tokens[t0 + 2]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); + p.shared_shaper_id.tc_valid[0] = 1; + } + + if (strcmp(tokens[44], "tc1") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc1"); + return; + } + + if (strcmp(tokens[45], "none") == 0) + p.shared_shaper_id.tc_valid[1] = 0; + else { + if (softnic_parser_read_uint32(&p.shared_shaper_id.tc[1], + tokens[45]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "shared shaper tc1"); return; } - if (strcmp(tokens[t0 + 3], "mask") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); + p.shared_shaper_id.tc_valid[1] = 1; + } + + if (strcmp(tokens[46], "tc2") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc2"); + return; + } + + if (strcmp(tokens[47], "none") == 0) + p.shared_shaper_id.tc_valid[2] = 0; + else { + if (softnic_parser_read_uint32(&p.shared_shaper_id.tc[2], + tokens[47]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "shared shaper tc2"); return; } - p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX; - if (softnic_parse_hex_string(tokens[t0 + 4], - p.lb.key_mask, &p.lb.key_size) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); + p.shared_shaper_id.tc_valid[2] = 1; + } + + if (strcmp(tokens[48], "tc3") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc3"); + return; + } + + if (strcmp(tokens[49], "none") == 0) + p.shared_shaper_id.tc_valid[3] = 0; + else { + if (softnic_parser_read_uint32(&p.shared_shaper_id.tc[3], + tokens[49]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "shared shaper tc3"); return; } - if (strcmp(tokens[t0 + 5], "outoffset") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "outoffset"); + p.shared_shaper_id.tc_valid[3] = 1; + } + + if (strcmp(tokens[50], "tc4") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc4"); + return; + } + + if (strcmp(tokens[51], "none") == 0) { + p.shared_shaper_id.tc_valid[4] = 0; + } else { + if (softnic_parser_read_uint32(&p.shared_shaper_id.tc[4], + tokens[51]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "shared shaper tc4"); return; } - if (softnic_parser_read_uint32(&p.lb.out_offset, - tokens[t0 + 6]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "out_offset"); + p.shared_shaper_id.tc_valid[4] = 1; + } + + if (strcmp(tokens[52], "tc5") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc5"); + return; + } + + if (strcmp(tokens[53], "none") == 0) { + p.shared_shaper_id.tc_valid[5] = 0; + } else { + if (softnic_parser_read_uint32(&p.shared_shaper_id.tc[5], + tokens[53]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "shared shaper tc5"); return; } - p.action_mask |= 1LLU << RTE_TABLE_ACTION_LB; - t0 += 7; - } /* balance */ + p.shared_shaper_id.tc_valid[5] = 1; + } - if (t0 < n_tokens && - (strcmp(tokens[t0], "meter") == 0)) { - if (n_tokens < t0 + 6) { - snprintf(out, out_size, MSG_ARG_MISMATCH, - "table action profile meter"); + if (strcmp(tokens[54], "tc6") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc6"); + return; + } + + if (strcmp(tokens[55], "none") == 0) { + p.shared_shaper_id.tc_valid[6] = 0; + } else { + if (softnic_parser_read_uint32(&p.shared_shaper_id.tc[6], + tokens[55]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "shared shaper tc6"); return; } - if (strcmp(tokens[t0 + 1], "srtcm") == 0) { - p.mtr.alg = RTE_TABLE_ACTION_METER_SRTCM; - } else if (strcmp(tokens[t0 + 1], "trtcm") == 0) { - p.mtr.alg = RTE_TABLE_ACTION_METER_TRTCM; - } else { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, - "srtcm or trtcm"); + p.shared_shaper_id.tc_valid[6] = 1; + } + + if (strcmp(tokens[56], "tc7") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc7"); + return; + } + + if (strcmp(tokens[57], "none") == 0) { + p.shared_shaper_id.tc_valid[7] = 0; + } else { + if (softnic_parser_read_uint32(&p.shared_shaper_id.tc[7], + tokens[57]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "shared shaper tc7"); return; } - if (strcmp(tokens[t0 + 2], "tc") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc"); + p.shared_shaper_id.tc_valid[7] = 1; + } + + if (strcmp(tokens[58], "tc8") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc8"); + return; + } + + if (strcmp(tokens[59], "none") == 0) { + p.shared_shaper_id.tc_valid[8] = 0; + } else { + if (softnic_parser_read_uint32(&p.shared_shaper_id.tc[8], + tokens[59]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "shared shaper tc8"); return; } - if (softnic_parser_read_uint32(&p.mtr.n_tc, - tokens[t0 + 3]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "n_tc"); - return; - } - - if (strcmp(tokens[t0 + 4], "stats") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); - return; - } - - if (strcmp(tokens[t0 + 5], "none") == 0) { - p.mtr.n_packets_enabled = 0; - p.mtr.n_bytes_enabled = 0; - } else if (strcmp(tokens[t0 + 5], "pkts") == 0) { - p.mtr.n_packets_enabled = 1; - p.mtr.n_bytes_enabled = 0; - } else if (strcmp(tokens[t0 + 5], "bytes") == 0) { - p.mtr.n_packets_enabled = 0; - p.mtr.n_bytes_enabled = 1; - } else if (strcmp(tokens[t0 + 5], "both") == 0) { - p.mtr.n_packets_enabled = 1; - p.mtr.n_bytes_enabled = 1; - } else { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, - "none or pkts or bytes or both"); - return; - } - - p.action_mask |= 1LLU << RTE_TABLE_ACTION_MTR; - t0 += 6; - } /* meter */ - - if (t0 < n_tokens && - (strcmp(tokens[t0], "tm") == 0)) { - if (n_tokens < t0 + 5) { - snprintf(out, out_size, MSG_ARG_MISMATCH, - "table action profile tm"); - return; - } - - if (strcmp(tokens[t0 + 1], "spp") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp"); - return; - } - - if (softnic_parser_read_uint32(&p.tm.n_subports_per_port, - tokens[t0 + 2]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, - "n_subports_per_port"); - return; - } - - if (strcmp(tokens[t0 + 3], "pps") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps"); - return; - } - - if (softnic_parser_read_uint32(&p.tm.n_pipes_per_subport, - tokens[t0 + 4]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, - "n_pipes_per_subport"); - return; - } + p.shared_shaper_id.tc_valid[8] = 1; + } - p.action_mask |= 1LLU << RTE_TABLE_ACTION_TM; - t0 += 5; - } /* tm */ + if (strcmp(tokens[60], "tc9") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc9"); + return; + } - if (t0 < n_tokens && - (strcmp(tokens[t0], "encap") == 0)) { - if (n_tokens < t0 + 2) { - snprintf(out, out_size, MSG_ARG_MISMATCH, - "action profile encap"); + if (strcmp(tokens[61], "none") == 0) { + p.shared_shaper_id.tc_valid[9] = 0; + } else { + if (softnic_parser_read_uint32(&p.shared_shaper_id.tc[9], + tokens[61]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "shared shaper tc9"); return; } - if (strcmp(tokens[t0 + 1], "ether") == 0) { - p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER; - } else if (strcmp(tokens[t0 + 1], "vlan") == 0) { - p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN; - } else if (strcmp(tokens[t0 + 1], "qinq") == 0) { - p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ; - } else if (strcmp(tokens[t0 + 1], "mpls") == 0) { - p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS; - } else if (strcmp(tokens[t0 + 1], "pppoe") == 0) { - p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE; - } else { - snprintf(out, out_size, MSG_ARG_MISMATCH, "encap"); - return; - } + p.shared_shaper_id.tc_valid[9] = 1; + } - p.action_mask |= 1LLU << RTE_TABLE_ACTION_ENCAP; - t0 += 2; - } /* encap */ + if (strcmp(tokens[62], "tc10") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc10"); + return; + } - if (t0 < n_tokens && - (strcmp(tokens[t0], "nat") == 0)) { - if (n_tokens < t0 + 4) { - snprintf(out, out_size, MSG_ARG_MISMATCH, - "table action profile nat"); + if (strcmp(tokens[63], "none") == 0) { + p.shared_shaper_id.tc_valid[10] = 0; + } else { + if (softnic_parser_read_uint32(&p.shared_shaper_id.tc[10], + tokens[63]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "shared shaper tc10"); return; } - if (strcmp(tokens[t0 + 1], "src") == 0) { - p.nat.source_nat = 1; - } else if (strcmp(tokens[t0 + 1], "dst") == 0) { - p.nat.source_nat = 0; - } else { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, - "src or dst"); - return; - } + p.shared_shaper_id.tc_valid[10] = 1; + } - if (strcmp(tokens[t0 + 2], "proto") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "proto"); - return; - } + if (strcmp(tokens[64], "tc11") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc11"); + return; + } - if (strcmp(tokens[t0 + 3], "tcp") == 0) { - p.nat.proto = 0x06; - } else if (strcmp(tokens[t0 + 3], "udp") == 0) { - p.nat.proto = 0x11; - } else { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, - "tcp or udp"); + if (strcmp(tokens[65], "none") == 0) { + p.shared_shaper_id.tc_valid[11] = 0; + } else { + if (softnic_parser_read_uint32(&p.shared_shaper_id.tc[11], + tokens[65]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "shared shaper tc11"); return; } - p.action_mask |= 1LLU << RTE_TABLE_ACTION_NAT; - t0 += 4; - } /* nat */ + p.shared_shaper_id.tc_valid[11] = 1; + } - if (t0 < n_tokens && - (strcmp(tokens[t0], "ttl") == 0)) { - if (n_tokens < t0 + 4) { - snprintf(out, out_size, MSG_ARG_MISMATCH, - "table action profile ttl"); - return; - } + if (strcmp(tokens[66], "tc12") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc12"); + return; + } - if (strcmp(tokens[t0 + 1], "drop") == 0) { - p.ttl.drop = 1; - } else if (strcmp(tokens[t0 + 1], "fwd") == 0) { - p.ttl.drop = 0; - } else { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, - "drop or fwd"); + if (strcmp(tokens[67], "none") == 0) { + p.shared_shaper_id.tc_valid[12] = 0; + } else { + if (softnic_parser_read_uint32(&p.shared_shaper_id.tc[12], + tokens[67]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "shared shaper tc12"); return; } - if (strcmp(tokens[t0 + 2], "stats") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); - return; - } + p.shared_shaper_id.tc_valid[12] = 1; + } - if (strcmp(tokens[t0 + 3], "none") == 0) { - p.ttl.n_packets_enabled = 0; - } else if (strcmp(tokens[t0 + 3], "pkts") == 0) { - p.ttl.n_packets_enabled = 1; - } else { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, - "none or pkts"); - return; - } + /* Weight */ - p.action_mask |= 1LLU << RTE_TABLE_ACTION_TTL; - t0 += 4; - } /* ttl */ + if (strcmp(tokens[68], "weight") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "weight"); + return; + } - if (t0 < n_tokens && - (strcmp(tokens[t0], "stats") == 0)) { - if (n_tokens < t0 + 2) { - snprintf(out, out_size, MSG_ARG_MISMATCH, - "table action profile stats"); - return; - } + if (strcmp(tokens[69], "queue") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "queue"); + return; + } - if (strcmp(tokens[t0 + 1], "pkts") == 0) { - p.stats.n_packets_enabled = 1; - p.stats.n_bytes_enabled = 0; - } else if (strcmp(tokens[t0 + 1], "bytes") == 0) { - p.stats.n_packets_enabled = 0; - p.stats.n_bytes_enabled = 1; - } else if (strcmp(tokens[t0 + 1], "both") == 0) { - p.stats.n_packets_enabled = 1; - p.stats.n_bytes_enabled = 1; + for (i = 0, j = 0; i < 16; i++) { + if (i < RTE_SCHED_TRAFFIC_CLASS_BE) { + p.weight.queue[i] = 1; } else { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, - "pkts or bytes or both"); - return; + if (softnic_parser_read_uint32(&p.weight.queue[i], + tokens[70 + j]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "weight queue"); + return; + } + j++; } - - p.action_mask |= 1LLU << RTE_TABLE_ACTION_STATS; - t0 += 2; - } /* stats */ - - if (t0 < n_tokens && - (strcmp(tokens[t0], "time") == 0)) { - p.action_mask |= 1LLU << RTE_TABLE_ACTION_TIME; - t0 += 1; - } /* time */ - - if (t0 < n_tokens) { - snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); - return; } - ap = softnic_table_action_profile_create(softnic, name, &p); - if (ap == NULL) { + status = tmgr_hierarchy_default(softnic, &p); + if (status != 0) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } /** - * pipeline - * period - * offset_port_id + * tmgr hierarchy commit */ static void -cmd_pipeline(struct pmd_internals *softnic, +cmd_tmgr_hierarchy_commit(struct pmd_internals *softnic, char **tokens, uint32_t n_tokens, char *out, size_t out_size) { - struct pipeline_params p; - char *name; - struct pipeline *pipeline; + struct rte_tm_error error; + uint16_t port_id; + int status; - if (n_tokens != 6) { + if (n_tokens != 3) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } - name = tokens[1]; - - if (strcmp(tokens[2], "period") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period"); - return; - } - - if (softnic_parser_read_uint32(&p.timer_period_ms, - tokens[3]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms"); + if (strcmp(tokens[1], "hierarchy") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "hierarchy"); return; } - if (strcmp(tokens[4], "offset_port_id") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset_port_id"); + if (strcmp(tokens[2], "commit") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "commit"); return; } - if (softnic_parser_read_uint32(&p.offset_port_id, - tokens[5]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "offset_port_id"); + status = rte_eth_dev_get_port_by_name(softnic->params.name, &port_id); + if (status != 0) return; - } - pipeline = softnic_pipeline_create(softnic, name, &p); - if (pipeline == NULL) { + status = rte_tm_hierarchy_commit(port_id, 1, &error); + if (status) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } /** - * pipeline port in - * bsz - * link rxq - * | swq - * | tmgr - * | tap mempool mtu - * | source mempool file bpp - * [action ] - * [disabled] + * tmgr */ static void -cmd_pipeline_port_in(struct pmd_internals *softnic, +cmd_tmgr(struct pmd_internals *softnic, char **tokens, uint32_t n_tokens, char *out, size_t out_size) { - struct softnic_port_in_params p; - char *pipeline_name; - uint32_t t0; - int enabled, status; + char *name; + struct softnic_tmgr_port *tmgr_port; - if (n_tokens < 7) { + if (n_tokens != 2) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } - pipeline_name = tokens[1]; + name = tokens[1]; - if (strcmp(tokens[2], "port") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); + tmgr_port = softnic_tmgr_port_create(softnic, name); + if (tmgr_port == NULL) { + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } +} - if (strcmp(tokens[3], "in") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); - return; - } +/** + * tap + */ +static void +cmd_tap(struct pmd_internals *softnic, + char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size) +{ + char *name; + struct softnic_tap *tap; - if (strcmp(tokens[4], "bsz") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); + if (n_tokens != 2) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } - if (softnic_parser_read_uint32(&p.burst_size, tokens[5]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "burst_size"); + name = tokens[1]; + + tap = softnic_tap_create(softnic, name); + if (tap == NULL) { + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } +} - t0 = 6; - - if (strcmp(tokens[t0], "link") == 0) { - if (n_tokens < t0 + 4) { - snprintf(out, out_size, MSG_ARG_MISMATCH, - "pipeline port in link"); - return; - } - - p.type = PORT_IN_RXQ; - - p.dev_name = tokens[t0 + 1]; - - if (strcmp(tokens[t0 + 2], "rxq") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq"); - return; - } - - if (softnic_parser_read_uint16(&p.rxq.queue_id, - tokens[t0 + 3]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, - "queue_id"); - return; - } - t0 += 4; - } else if (strcmp(tokens[t0], "swq") == 0) { - if (n_tokens < t0 + 2) { - snprintf(out, out_size, MSG_ARG_MISMATCH, - "pipeline port in swq"); - return; - } - - p.type = PORT_IN_SWQ; - - p.dev_name = tokens[t0 + 1]; - - t0 += 2; - } else if (strcmp(tokens[t0], "tmgr") == 0) { - if (n_tokens < t0 + 2) { - snprintf(out, out_size, MSG_ARG_MISMATCH, - "pipeline port in tmgr"); - return; - } - - p.type = PORT_IN_TMGR; - - p.dev_name = tokens[t0 + 1]; - - t0 += 2; - } else if (strcmp(tokens[t0], "tap") == 0) { - if (n_tokens < t0 + 6) { - snprintf(out, out_size, MSG_ARG_MISMATCH, - "pipeline port in tap"); - return; - } - - p.type = PORT_IN_TAP; - - p.dev_name = tokens[t0 + 1]; - - if (strcmp(tokens[t0 + 2], "mempool") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, - "mempool"); - return; - } - - p.tap.mempool_name = tokens[t0 + 3]; - - if (strcmp(tokens[t0 + 4], "mtu") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, - "mtu"); - return; - } - - if (softnic_parser_read_uint32(&p.tap.mtu, - tokens[t0 + 5]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "mtu"); - return; - } - - t0 += 6; - } else if (strcmp(tokens[t0], "source") == 0) { - if (n_tokens < t0 + 6) { - snprintf(out, out_size, MSG_ARG_MISMATCH, - "pipeline port in source"); - return; - } - - p.type = PORT_IN_SOURCE; - - p.dev_name = NULL; - - if (strcmp(tokens[t0 + 1], "mempool") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, - "mempool"); - return; - } - - p.source.mempool_name = tokens[t0 + 2]; +/** + * cryptodev dev | dev_id + * queue max_sessions + **/ - if (strcmp(tokens[t0 + 3], "file") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, - "file"); - return; - } +static void +cmd_cryptodev(struct pmd_internals *softnic, + char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size) +{ + struct softnic_cryptodev_params params; + char *name; - p.source.file_name = tokens[t0 + 4]; + memset(¶ms, 0, sizeof(params)); + if (n_tokens != 9) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } - if (strcmp(tokens[t0 + 5], "bpp") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, - "bpp"); - return; - } + name = tokens[1]; - if (softnic_parser_read_uint32(&p.source.n_bytes_per_pkt, - tokens[t0 + 6]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, - "n_bytes_per_pkt"); + if (strcmp(tokens[2], "dev") == 0) + params.dev_name = tokens[3]; + else if (strcmp(tokens[2], "dev_id") == 0) { + if (softnic_parser_read_uint32(¶ms.dev_id, tokens[3]) < 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "dev_id"); return; } - - t0 += 7; } else { - snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); + snprintf(out, out_size, MSG_ARG_INVALID, + "cryptodev"); return; } - p.action_profile_name = NULL; - if (n_tokens > t0 && - (strcmp(tokens[t0], "action") == 0)) { - if (n_tokens < t0 + 2) { - snprintf(out, out_size, MSG_ARG_MISMATCH, "action"); - return; - } - - p.action_profile_name = tokens[t0 + 1]; + if (strcmp(tokens[4], "queue")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "4"); + return; + } - t0 += 2; + if (softnic_parser_read_uint32(¶ms.n_queues, tokens[5]) < 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "q"); + return; } - enabled = 1; - if (n_tokens > t0 && - (strcmp(tokens[t0], "disabled") == 0)) { - enabled = 0; + if (softnic_parser_read_uint32(¶ms.queue_size, tokens[6]) < 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "queue_size"); + return; + } - t0 += 1; + if (strcmp(tokens[7], "max_sessions")) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "4"); + return; } - if (n_tokens != t0) { - snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + if (softnic_parser_read_uint32(¶ms.session_pool_size, tokens[8]) + < 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "q"); return; } - status = softnic_pipeline_port_in_create(softnic, - pipeline_name, - &p, - enabled); - if (status) { + if (softnic_cryptodev_create(softnic, name, ¶ms) == NULL) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } /** - * pipeline port out - * bsz - * link txq - * | swq - * | tmgr - * | tap - * | sink [file pkts ] + * port in action profile + * [filter match | mismatch offset mask key port ] + * [balance offset mask port ... ] */ static void -cmd_pipeline_port_out(struct pmd_internals *softnic, +cmd_port_in_action_profile(struct pmd_internals *softnic, char **tokens, uint32_t n_tokens, char *out, size_t out_size) { - struct softnic_port_out_params p; - char *pipeline_name; - int status; + struct softnic_port_in_action_profile_params p; + struct softnic_port_in_action_profile *ap; + char *name; + uint32_t t0; memset(&p, 0, sizeof(p)); - if (n_tokens < 7) { + if (n_tokens < 5) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } - pipeline_name = tokens[1]; - - if (strcmp(tokens[2], "port") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); + if (strcmp(tokens[1], "in") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); return; } - if (strcmp(tokens[3], "out") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out"); + if (strcmp(tokens[2], "action") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action"); return; } - if (strcmp(tokens[4], "bsz") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); + if (strcmp(tokens[3], "profile") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); return; } - if (softnic_parser_read_uint32(&p.burst_size, tokens[5]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "burst_size"); - return; - } + name = tokens[4]; - if (strcmp(tokens[6], "link") == 0) { - if (n_tokens != 10) { - snprintf(out, out_size, MSG_ARG_MISMATCH, - "pipeline port out link"); + t0 = 5; + + if (t0 < n_tokens && + (strcmp(tokens[t0], "filter") == 0)) { + uint32_t size; + + if (n_tokens < t0 + 10) { + snprintf(out, out_size, MSG_ARG_MISMATCH, "port in action profile filter"); return; } - p.type = PORT_OUT_TXQ; - - p.dev_name = tokens[7]; + if (strcmp(tokens[t0 + 1], "match") == 0) { + p.fltr.filter_on_match = 1; + } else if (strcmp(tokens[t0 + 1], "mismatch") == 0) { + p.fltr.filter_on_match = 0; + } else { + snprintf(out, out_size, MSG_ARG_INVALID, "match or mismatch"); + return; + } - if (strcmp(tokens[8], "txq") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq"); + if (strcmp(tokens[t0 + 2], "offset") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); return; } - if (softnic_parser_read_uint16(&p.txq.queue_id, - tokens[9]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "queue_id"); + if (softnic_parser_read_uint32(&p.fltr.key_offset, + tokens[t0 + 3]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); return; } - } else if (strcmp(tokens[6], "swq") == 0) { - if (n_tokens != 8) { - snprintf(out, out_size, MSG_ARG_MISMATCH, - "pipeline port out swq"); + + if (strcmp(tokens[t0 + 4], "mask") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); return; } - p.type = PORT_OUT_SWQ; + size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE; + if ((softnic_parse_hex_string(tokens[t0 + 5], + p.fltr.key_mask, &size) != 0) || + size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE) { + snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); + return; + } - p.dev_name = tokens[7]; - } else if (strcmp(tokens[6], "tmgr") == 0) { - if (n_tokens != 8) { - snprintf(out, out_size, MSG_ARG_MISMATCH, - "pipeline port out tmgr"); + if (strcmp(tokens[t0 + 6], "key") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key"); return; } - p.type = PORT_OUT_TMGR; + size = RTE_PORT_IN_ACTION_FLTR_KEY_SIZE; + if ((softnic_parse_hex_string(tokens[t0 + 7], + p.fltr.key, &size) != 0) || + size != RTE_PORT_IN_ACTION_FLTR_KEY_SIZE) { + snprintf(out, out_size, MSG_ARG_INVALID, "key_value"); + return; + } - p.dev_name = tokens[7]; - } else if (strcmp(tokens[6], "tap") == 0) { - if (n_tokens != 8) { - snprintf(out, out_size, MSG_ARG_MISMATCH, - "pipeline port out tap"); + if (strcmp(tokens[t0 + 8], "port") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); return; } - p.type = PORT_OUT_TAP; + if (softnic_parser_read_uint32(&p.fltr.port_id, + tokens[t0 + 9]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); + return; + } - p.dev_name = tokens[7]; - } else if (strcmp(tokens[6], "sink") == 0) { - if ((n_tokens != 7) && (n_tokens != 11)) { + p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_FLTR; + t0 += 10; + } /* filter */ + + if (t0 < n_tokens && + (strcmp(tokens[t0], "balance") == 0)) { + uint32_t i; + + if (n_tokens < t0 + 22) { snprintf(out, out_size, MSG_ARG_MISMATCH, - "pipeline port out sink"); + "port in action profile balance"); return; } - p.type = PORT_OUT_SINK; + if (strcmp(tokens[t0 + 1], "offset") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); + return; + } - p.dev_name = NULL; + if (softnic_parser_read_uint32(&p.lb.key_offset, + tokens[t0 + 2]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); + return; + } - if (n_tokens == 7) { - p.sink.file_name = NULL; - p.sink.max_n_pkts = 0; - } else { - if (strcmp(tokens[7], "file") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, - "file"); - return; - } + if (strcmp(tokens[t0 + 3], "mask") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); + return; + } - p.sink.file_name = tokens[8]; + p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX; + if (softnic_parse_hex_string(tokens[t0 + 4], + p.lb.key_mask, &p.lb.key_size) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); + return; + } - if (strcmp(tokens[9], "pkts") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pkts"); - return; - } + if (strcmp(tokens[t0 + 5], "port") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); + return; + } - if (softnic_parser_read_uint32(&p.sink.max_n_pkts, - tokens[10]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "max_n_pkts"); + for (i = 0; i < 16; i++) + if (softnic_parser_read_uint32(&p.lb.port_id[i], + tokens[t0 + 6 + i]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); return; } - } - } else { - snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); + + p.action_mask |= 1LLU << RTE_PORT_IN_ACTION_LB; + t0 += 22; + } /* balance */ + + if (t0 < n_tokens) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } - status = softnic_pipeline_port_out_create(softnic, pipeline_name, &p); - if (status) { + ap = softnic_port_in_action_profile_create(softnic, name, &p); + if (ap == NULL) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } /** - * pipeline table - * match - * acl - * ipv4 | ipv6 - * offset - * size - * | array - * offset - * size - * | hash - * ext | lru - * key - * mask - * offset - * buckets - * size - * | lpm - * ipv4 | ipv6 - * offset - * size - * | stub - * [action ] + * table action profile + * ipv4 | ipv6 + * offset + * fwd + * [balance offset mask outoffset ] + * [meter srtcm | trtcm + * tc + * stats none | pkts | bytes | both] + * [tm spp pps ] + * [encap ether | vlan | qinq | mpls | pppoe | qinq_pppoe | + * vxlan offset ipv4 | ipv6 vlan on | off] + * [nat src | dst + * proto udp | tcp] + * [ttl drop | fwd + * stats none | pkts] + * [stats pkts | bytes | both] + * [time] + * [tag] + * [decap] + * */ static void -cmd_pipeline_table(struct pmd_internals *softnic, +cmd_table_action_profile(struct pmd_internals *softnic, char **tokens, uint32_t n_tokens, char *out, size_t out_size) { - uint8_t key_mask[TABLE_RULE_MATCH_SIZE_MAX]; - struct softnic_table_params p; - char *pipeline_name; + struct softnic_table_action_profile_params p; + struct softnic_table_action_profile *ap; + char *name; uint32_t t0; - int status; - if (n_tokens < 5) { + memset(&p, 0, sizeof(p)); + + if (n_tokens < 8) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } - pipeline_name = tokens[1]; + if (strcmp(tokens[1], "action") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action"); + return; + } - if (strcmp(tokens[2], "table") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); + if (strcmp(tokens[2], "profile") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); return; } - if (strcmp(tokens[3], "match") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); + name = tokens[3]; + + if (strcmp(tokens[4], "ipv4") == 0) { + p.common.ip_version = 1; + } else if (strcmp(tokens[4], "ipv6") == 0) { + p.common.ip_version = 0; + } else { + snprintf(out, out_size, MSG_ARG_INVALID, "ipv4 or ipv6"); return; } - t0 = 4; - if (strcmp(tokens[t0], "acl") == 0) { - if (n_tokens < t0 + 6) { - snprintf(out, out_size, MSG_ARG_MISMATCH, - "pipeline table acl"); - return; - } + if (strcmp(tokens[5], "offset") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); + return; + } - p.match_type = TABLE_ACL; + if (softnic_parser_read_uint32(&p.common.ip_offset, + tokens[6]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "ip_offset"); + return; + } - if (strcmp(tokens[t0 + 1], "ipv4") == 0) { - p.match.acl.ip_version = 1; - } else if (strcmp(tokens[t0 + 1], "ipv6") == 0) { - p.match.acl.ip_version = 0; - } else { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, - "ipv4 or ipv6"); - return; - } + if (strcmp(tokens[7], "fwd") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fwd"); + return; + } - if (strcmp(tokens[t0 + 2], "offset") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); - return; - } + p.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD; - if (softnic_parser_read_uint32(&p.match.acl.ip_header_offset, - tokens[t0 + 3]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, - "ip_header_offset"); + t0 = 8; + if (t0 < n_tokens && + (strcmp(tokens[t0], "balance") == 0)) { + if (n_tokens < t0 + 7) { + snprintf(out, out_size, MSG_ARG_MISMATCH, "table action profile balance"); return; } - if (strcmp(tokens[t0 + 4], "size") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); + if (strcmp(tokens[t0 + 1], "offset") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); return; } - if (softnic_parser_read_uint32(&p.match.acl.n_rules, - tokens[t0 + 5]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "n_rules"); + if (softnic_parser_read_uint32(&p.lb.key_offset, + tokens[t0 + 2]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); return; } - t0 += 6; - } else if (strcmp(tokens[t0], "array") == 0) { - if (n_tokens < t0 + 5) { - snprintf(out, out_size, MSG_ARG_MISMATCH, - "pipeline table array"); + if (strcmp(tokens[t0 + 3], "mask") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); return; } - p.match_type = TABLE_ARRAY; - - if (strcmp(tokens[t0 + 1], "offset") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); + p.lb.key_size = RTE_PORT_IN_ACTION_LB_KEY_SIZE_MAX; + if (softnic_parse_hex_string(tokens[t0 + 4], + p.lb.key_mask, &p.lb.key_size) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); return; } - if (softnic_parser_read_uint32(&p.match.array.key_offset, - tokens[t0 + 2]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); + if (strcmp(tokens[t0 + 5], "outoffset") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "outoffset"); return; } - if (strcmp(tokens[t0 + 3], "size") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); + if (softnic_parser_read_uint32(&p.lb.out_offset, + tokens[t0 + 6]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "out_offset"); return; } - if (softnic_parser_read_uint32(&p.match.array.n_keys, - tokens[t0 + 4]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "n_keys"); - return; - } - - t0 += 5; - } else if (strcmp(tokens[t0], "hash") == 0) { - uint32_t key_mask_size = TABLE_RULE_MATCH_SIZE_MAX; + p.action_mask |= 1LLU << RTE_TABLE_ACTION_LB; + t0 += 7; + } /* balance */ - if (n_tokens < t0 + 12) { + if (t0 < n_tokens && + (strcmp(tokens[t0], "meter") == 0)) { + if (n_tokens < t0 + 6) { snprintf(out, out_size, MSG_ARG_MISMATCH, - "pipeline table hash"); + "table action profile meter"); return; } - p.match_type = TABLE_HASH; - - if (strcmp(tokens[t0 + 1], "ext") == 0) { - p.match.hash.extendable_bucket = 1; - } else if (strcmp(tokens[t0 + 1], "lru") == 0) { - p.match.hash.extendable_bucket = 0; + if (strcmp(tokens[t0 + 1], "srtcm") == 0) { + p.mtr.alg = RTE_TABLE_ACTION_METER_SRTCM; + } else if (strcmp(tokens[t0 + 1], "trtcm") == 0) { + p.mtr.alg = RTE_TABLE_ACTION_METER_TRTCM; } else { snprintf(out, out_size, MSG_ARG_NOT_FOUND, - "ext or lru"); + "srtcm or trtcm"); return; } - if (strcmp(tokens[t0 + 2], "key") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key"); + if (strcmp(tokens[t0 + 2], "tc") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc"); return; } - if ((softnic_parser_read_uint32(&p.match.hash.key_size, - tokens[t0 + 3]) != 0) || - p.match.hash.key_size == 0 || - p.match.hash.key_size > TABLE_RULE_MATCH_SIZE_MAX) { - snprintf(out, out_size, MSG_ARG_INVALID, "key_size"); + if (softnic_parser_read_uint32(&p.mtr.n_tc, + tokens[t0 + 3]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "n_tc"); return; } - if (strcmp(tokens[t0 + 4], "mask") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); + if (strcmp(tokens[t0 + 4], "stats") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); return; } - if ((softnic_parse_hex_string(tokens[t0 + 5], - key_mask, &key_mask_size) != 0) || - key_mask_size != p.match.hash.key_size) { - snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); + if (strcmp(tokens[t0 + 5], "none") == 0) { + p.mtr.n_packets_enabled = 0; + p.mtr.n_bytes_enabled = 0; + } else if (strcmp(tokens[t0 + 5], "pkts") == 0) { + p.mtr.n_packets_enabled = 1; + p.mtr.n_bytes_enabled = 0; + } else if (strcmp(tokens[t0 + 5], "bytes") == 0) { + p.mtr.n_packets_enabled = 0; + p.mtr.n_bytes_enabled = 1; + } else if (strcmp(tokens[t0 + 5], "both") == 0) { + p.mtr.n_packets_enabled = 1; + p.mtr.n_bytes_enabled = 1; + } else { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "none or pkts or bytes or both"); return; } - p.match.hash.key_mask = key_mask; - if (strcmp(tokens[t0 + 6], "offset") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); + p.action_mask |= 1LLU << RTE_TABLE_ACTION_MTR; + t0 += 6; + } /* meter */ + + if (t0 < n_tokens && + (strcmp(tokens[t0], "tm") == 0)) { + if (n_tokens < t0 + 5) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "table action profile tm"); return; } - if (softnic_parser_read_uint32(&p.match.hash.key_offset, - tokens[t0 + 7]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); + if (strcmp(tokens[t0 + 1], "spp") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp"); return; } - if (strcmp(tokens[t0 + 8], "buckets") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buckets"); + if (softnic_parser_read_uint32(&p.tm.n_subports_per_port, + tokens[t0 + 2]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "n_subports_per_port"); return; } - if (softnic_parser_read_uint32(&p.match.hash.n_buckets, - tokens[t0 + 9]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "n_buckets"); + if (strcmp(tokens[t0 + 3], "pps") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps"); return; } - if (strcmp(tokens[t0 + 10], "size") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); + if (softnic_parser_read_uint32(&p.tm.n_pipes_per_subport, + tokens[t0 + 4]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "n_pipes_per_subport"); return; } - if (softnic_parser_read_uint32(&p.match.hash.n_keys, - tokens[t0 + 11]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "n_keys"); + p.action_mask |= 1LLU << RTE_TABLE_ACTION_TM; + t0 += 5; + } /* tm */ + + if (t0 < n_tokens && + (strcmp(tokens[t0], "encap") == 0)) { + uint32_t n_extra_tokens = 0; + + if (n_tokens < t0 + 2) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "action profile encap"); return; } - t0 += 12; - } else if (strcmp(tokens[t0], "lpm") == 0) { - if (n_tokens < t0 + 6) { - snprintf(out, out_size, MSG_ARG_MISMATCH, - "pipeline table lpm"); + if (strcmp(tokens[t0 + 1], "ether") == 0) { + p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_ETHER; + } else if (strcmp(tokens[t0 + 1], "vlan") == 0) { + p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VLAN; + } else if (strcmp(tokens[t0 + 1], "qinq") == 0) { + p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ; + } else if (strcmp(tokens[t0 + 1], "mpls") == 0) { + p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_MPLS; + } else if (strcmp(tokens[t0 + 1], "pppoe") == 0) { + p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_PPPOE; + } else if (strcmp(tokens[t0 + 1], "vxlan") == 0) { + if (n_tokens < t0 + 2 + 5) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "action profile encap vxlan"); + return; + } + + if (strcmp(tokens[t0 + 2], "offset") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "vxlan: offset"); + return; + } + + if (softnic_parser_read_uint32(&p.encap.vxlan.data_offset, + tokens[t0 + 2 + 1]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "vxlan: ether_offset"); + return; + } + + if (strcmp(tokens[t0 + 2 + 2], "ipv4") == 0) + p.encap.vxlan.ip_version = 1; + else if (strcmp(tokens[t0 + 2 + 2], "ipv6") == 0) + p.encap.vxlan.ip_version = 0; + else { + snprintf(out, out_size, MSG_ARG_INVALID, + "vxlan: ipv4 or ipv6"); + return; + } + + if (strcmp(tokens[t0 + 2 + 3], "vlan") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "vxlan: vlan"); + return; + } + + if (strcmp(tokens[t0 + 2 + 4], "on") == 0) + p.encap.vxlan.vlan = 1; + else if (strcmp(tokens[t0 + 2 + 4], "off") == 0) + p.encap.vxlan.vlan = 0; + else { + snprintf(out, out_size, MSG_ARG_INVALID, + "vxlan: on or off"); + return; + } + + p.encap.encap_mask = 1LLU << RTE_TABLE_ACTION_ENCAP_VXLAN; + n_extra_tokens = 5; + + } else if (strcmp(tokens[t0 + 1], "qinq_pppoe") == 0) { + p.encap.encap_mask = + 1LLU << RTE_TABLE_ACTION_ENCAP_QINQ_PPPOE; + } else { + snprintf(out, out_size, MSG_ARG_MISMATCH, "encap"); return; } - p.match_type = TABLE_LPM; + p.action_mask |= 1LLU << RTE_TABLE_ACTION_ENCAP; + t0 += 2 + n_extra_tokens; + } /* encap */ - if (strcmp(tokens[t0 + 1], "ipv4") == 0) { - p.match.lpm.key_size = 4; - } else if (strcmp(tokens[t0 + 1], "ipv6") == 0) { - p.match.lpm.key_size = 16; + if (t0 < n_tokens && + (strcmp(tokens[t0], "nat") == 0)) { + if (n_tokens < t0 + 4) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "table action profile nat"); + return; + } + + if (strcmp(tokens[t0 + 1], "src") == 0) { + p.nat.source_nat = 1; + } else if (strcmp(tokens[t0 + 1], "dst") == 0) { + p.nat.source_nat = 0; } else { snprintf(out, out_size, MSG_ARG_NOT_FOUND, - "ipv4 or ipv6"); + "src or dst"); return; } - if (strcmp(tokens[t0 + 2], "offset") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); + if (strcmp(tokens[t0 + 2], "proto") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "proto"); return; } - if (softnic_parser_read_uint32(&p.match.lpm.key_offset, - tokens[t0 + 3]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); + if (strcmp(tokens[t0 + 3], "tcp") == 0) { + p.nat.proto = 0x06; + } else if (strcmp(tokens[t0 + 3], "udp") == 0) { + p.nat.proto = 0x11; + } else { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "tcp or udp"); return; } - if (strcmp(tokens[t0 + 4], "size") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); + p.action_mask |= 1LLU << RTE_TABLE_ACTION_NAT; + t0 += 4; + } /* nat */ + + if (t0 < n_tokens && + (strcmp(tokens[t0], "ttl") == 0)) { + if (n_tokens < t0 + 4) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "table action profile ttl"); return; } - if (softnic_parser_read_uint32(&p.match.lpm.n_rules, - tokens[t0 + 5]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "n_rules"); + if (strcmp(tokens[t0 + 1], "drop") == 0) { + p.ttl.drop = 1; + } else if (strcmp(tokens[t0 + 1], "fwd") == 0) { + p.ttl.drop = 0; + } else { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "drop or fwd"); return; } - t0 += 6; - } else if (strcmp(tokens[t0], "stub") == 0) { - p.match_type = TABLE_STUB; + if (strcmp(tokens[t0 + 2], "stats") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); + return; + } - t0 += 1; - } else { - snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); - return; - } + if (strcmp(tokens[t0 + 3], "none") == 0) { + p.ttl.n_packets_enabled = 0; + } else if (strcmp(tokens[t0 + 3], "pkts") == 0) { + p.ttl.n_packets_enabled = 1; + } else { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "none or pkts"); + return; + } - p.action_profile_name = NULL; - if (n_tokens > t0 && - (strcmp(tokens[t0], "action") == 0)) { + p.action_mask |= 1LLU << RTE_TABLE_ACTION_TTL; + t0 += 4; + } /* ttl */ + + if (t0 < n_tokens && + (strcmp(tokens[t0], "stats") == 0)) { if (n_tokens < t0 + 2) { - snprintf(out, out_size, MSG_ARG_MISMATCH, "action"); + snprintf(out, out_size, MSG_ARG_MISMATCH, + "table action profile stats"); return; } - p.action_profile_name = tokens[t0 + 1]; + if (strcmp(tokens[t0 + 1], "pkts") == 0) { + p.stats.n_packets_enabled = 1; + p.stats.n_bytes_enabled = 0; + } else if (strcmp(tokens[t0 + 1], "bytes") == 0) { + p.stats.n_packets_enabled = 0; + p.stats.n_bytes_enabled = 1; + } else if (strcmp(tokens[t0 + 1], "both") == 0) { + p.stats.n_packets_enabled = 1; + p.stats.n_bytes_enabled = 1; + } else { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "pkts or bytes or both"); + return; + } + p.action_mask |= 1LLU << RTE_TABLE_ACTION_STATS; t0 += 2; - } + } /* stats */ - if (n_tokens > t0) { + if (t0 < n_tokens && + (strcmp(tokens[t0], "time") == 0)) { + p.action_mask |= 1LLU << RTE_TABLE_ACTION_TIME; + t0 += 1; + } /* time */ + + if (t0 < n_tokens && + (strcmp(tokens[t0], "tag") == 0)) { + p.action_mask |= 1LLU << RTE_TABLE_ACTION_TAG; + t0 += 1; + } /* tag */ + + if (t0 < n_tokens && + (strcmp(tokens[t0], "decap") == 0)) { + p.action_mask |= 1LLU << RTE_TABLE_ACTION_DECAP; + t0 += 1; + } /* decap */ + + if (t0 < n_tokens && (strcmp(tokens[t0], "sym_crypto") == 0)) { + struct softnic_cryptodev *cryptodev; + + if (n_tokens < t0 + 5 || + strcmp(tokens[t0 + 1], "dev") || + strcmp(tokens[t0 + 3], "offset")) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "table action profile sym_crypto"); + return; + } + + cryptodev = softnic_cryptodev_find(softnic, tokens[t0 + 2]); + if (cryptodev == NULL) { + snprintf(out, out_size, MSG_ARG_INVALID, + "table action profile sym_crypto"); + return; + } + + p.sym_crypto.cryptodev_id = cryptodev->dev_id; + + if (softnic_parser_read_uint32(&p.sym_crypto.op_offset, + tokens[t0 + 4]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "table action profile sym_crypto"); + return; + } + + p.sym_crypto.mp_create = cryptodev->mp_create; + p.sym_crypto.mp_init = cryptodev->mp_init; + + p.action_mask |= 1LLU << RTE_TABLE_ACTION_SYM_CRYPTO; + + t0 += 5; + } /* sym_crypto */ + + if (t0 < n_tokens) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } - status = softnic_pipeline_table_create(softnic, pipeline_name, &p); - if (status) { + ap = softnic_table_action_profile_create(softnic, name, &p); + if (ap == NULL) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } /** - * pipeline port in table + * pipeline + * period + * offset_port_id */ static void -cmd_pipeline_port_in_table(struct pmd_internals *softnic, +cmd_pipeline(struct pmd_internals *softnic, char **tokens, uint32_t n_tokens, char *out, size_t out_size) { - char *pipeline_name; - uint32_t port_id, table_id; - int status; + struct pipeline_params p; + char *name; + struct pipeline *pipeline; - if (n_tokens != 7) { + if (n_tokens != 6) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } - pipeline_name = tokens[1]; - - if (strcmp(tokens[2], "port") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); - return; - } + name = tokens[1]; - if (strcmp(tokens[3], "in") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); + if (strcmp(tokens[2], "period") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "period"); return; } - if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); + if (softnic_parser_read_uint32(&p.timer_period_ms, + tokens[3]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "timer_period_ms"); return; } - if (strcmp(tokens[5], "table") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); + if (strcmp(tokens[4], "offset_port_id") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset_port_id"); return; } - if (softnic_parser_read_uint32(&table_id, tokens[6]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); + if (softnic_parser_read_uint32(&p.offset_port_id, + tokens[5]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "offset_port_id"); return; } - status = softnic_pipeline_port_in_connect_to_table(softnic, - pipeline_name, - port_id, - table_id); - if (status) { + pipeline = softnic_pipeline_create(softnic, name, &p); + if (pipeline == NULL) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } /** - * pipeline port in stats read [clear] + * pipeline port in + * bsz + * link rxq + * | swq + * | tmgr + * | tap mempool mtu + * | source mempool file bpp + * | cryptodev rxq + * [action ] + * [disabled] */ - -#define MSG_PIPELINE_PORT_IN_STATS \ - "Pkts in: %" PRIu64 "\n" \ - "Pkts dropped by AH: %" PRIu64 "\n" \ - "Pkts dropped by other: %" PRIu64 "\n" - static void -cmd_pipeline_port_in_stats(struct pmd_internals *softnic, +cmd_pipeline_port_in(struct pmd_internals *softnic, char **tokens, uint32_t n_tokens, char *out, size_t out_size) { - struct rte_pipeline_port_in_stats stats; + struct softnic_port_in_params p; char *pipeline_name; - uint32_t port_id; - int clear, status; + uint32_t t0; + int enabled, status; - if (n_tokens != 7 && - n_tokens != 8) { + memset(&p, 0, sizeof(p)); + + if (n_tokens < 7) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } @@ -1538,1258 +2285,2573 @@ cmd_pipeline_port_in_stats(struct pmd_internals *softnic, return; } - if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); + if (strcmp(tokens[4], "bsz") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); return; } - if (strcmp(tokens[5], "stats") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); + if (softnic_parser_read_uint32(&p.burst_size, tokens[5]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "burst_size"); return; } - if (strcmp(tokens[6], "read") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); - return; - } + t0 = 6; - clear = 0; - if (n_tokens == 8) { - if (strcmp(tokens[7], "clear") != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "clear"); + if (strcmp(tokens[t0], "link") == 0) { + if (n_tokens < t0 + 4) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port in link"); return; } - clear = 1; - } + p.type = PORT_IN_RXQ; - status = softnic_pipeline_port_in_stats_read(softnic, - pipeline_name, - port_id, - &stats, - clear); - if (status) { - snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); - return; - } + strlcpy(p.dev_name, tokens[t0 + 1], sizeof(p.dev_name)); - snprintf(out, out_size, MSG_PIPELINE_PORT_IN_STATS, - stats.stats.n_pkts_in, - stats.n_pkts_dropped_by_ah, - stats.stats.n_pkts_drop); -} + if (strcmp(tokens[t0 + 2], "rxq") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "rxq"); + return; + } -/** - * pipeline port in enable - */ -static void -cmd_softnic_pipeline_port_in_enable(struct pmd_internals *softnic, - char **tokens, - uint32_t n_tokens, - char *out, - size_t out_size) -{ - char *pipeline_name; - uint32_t port_id; - int status; + if (softnic_parser_read_uint16(&p.rxq.queue_id, + tokens[t0 + 3]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "queue_id"); + return; + } + t0 += 4; + } else if (strcmp(tokens[t0], "swq") == 0) { + if (n_tokens < t0 + 2) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port in swq"); + return; + } - if (n_tokens != 6) { - snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); - return; - } + p.type = PORT_IN_SWQ; - pipeline_name = tokens[1]; + strlcpy(p.dev_name, tokens[t0 + 1], sizeof(p.dev_name)); - if (strcmp(tokens[2], "port") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); - return; - } + t0 += 2; + } else if (strcmp(tokens[t0], "tmgr") == 0) { + if (n_tokens < t0 + 2) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port in tmgr"); + return; + } - if (strcmp(tokens[3], "in") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); - return; - } + p.type = PORT_IN_TMGR; - if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); - return; - } + strlcpy(p.dev_name, tokens[t0 + 1], sizeof(p.dev_name)); - if (strcmp(tokens[5], "enable") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable"); - return; - } + t0 += 2; + } else if (strcmp(tokens[t0], "tap") == 0) { + if (n_tokens < t0 + 6) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port in tap"); + return; + } - status = softnic_pipeline_port_in_enable(softnic, pipeline_name, port_id); - if (status) { - snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); - return; - } -} + p.type = PORT_IN_TAP; -/** - * pipeline port in disable - */ -static void -cmd_softnic_pipeline_port_in_disable(struct pmd_internals *softnic, - char **tokens, - uint32_t n_tokens, - char *out, - size_t out_size) -{ - char *pipeline_name; - uint32_t port_id; - int status; + strlcpy(p.dev_name, tokens[t0 + 1], sizeof(p.dev_name)); - if (n_tokens != 6) { - snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); - return; - } + if (strcmp(tokens[t0 + 2], "mempool") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "mempool"); + return; + } - pipeline_name = tokens[1]; + p.tap.mempool_name = tokens[t0 + 3]; - if (strcmp(tokens[2], "port") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); - return; - } + if (strcmp(tokens[t0 + 4], "mtu") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "mtu"); + return; + } - if (strcmp(tokens[3], "in") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); - return; - } + if (softnic_parser_read_uint32(&p.tap.mtu, + tokens[t0 + 5]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "mtu"); + return; + } - if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); - return; - } + t0 += 6; + } else if (strcmp(tokens[t0], "source") == 0) { + if (n_tokens < t0 + 6) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port in source"); + return; + } - if (strcmp(tokens[5], "disable") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable"); - return; - } + p.type = PORT_IN_SOURCE; - status = softnic_pipeline_port_in_disable(softnic, pipeline_name, port_id); - if (status) { - snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); - return; - } -} + if (strcmp(tokens[t0 + 1], "mempool") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "mempool"); + return; + } -/** - * pipeline port out stats read [clear] - */ -#define MSG_PIPELINE_PORT_OUT_STATS \ - "Pkts in: %" PRIu64 "\n" \ - "Pkts dropped by AH: %" PRIu64 "\n" \ - "Pkts dropped by other: %" PRIu64 "\n" + p.source.mempool_name = tokens[t0 + 2]; -static void -cmd_pipeline_port_out_stats(struct pmd_internals *softnic, - char **tokens, - uint32_t n_tokens, - char *out, - size_t out_size) -{ - struct rte_pipeline_port_out_stats stats; - char *pipeline_name; - uint32_t port_id; - int clear, status; + if (strcmp(tokens[t0 + 3], "file") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "file"); + return; + } - if (n_tokens != 7 && - n_tokens != 8) { - snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); - return; - } + p.source.file_name = tokens[t0 + 4]; - pipeline_name = tokens[1]; + if (strcmp(tokens[t0 + 5], "bpp") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "bpp"); + return; + } - if (strcmp(tokens[2], "port") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); - return; - } + if (softnic_parser_read_uint32(&p.source.n_bytes_per_pkt, + tokens[t0 + 6]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "n_bytes_per_pkt"); + return; + } - if (strcmp(tokens[3], "out") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out"); - return; - } + t0 += 7; + } else if (strcmp(tokens[t0], "cryptodev") == 0) { + if (n_tokens < t0 + 3) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port in cryptodev"); + return; + } - if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); - return; - } + p.type = PORT_IN_CRYPTODEV; - if (strcmp(tokens[5], "stats") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); - return; - } + strlcpy(p.dev_name, tokens[t0 + 1], sizeof(p.dev_name)); + if (softnic_parser_read_uint16(&p.rxq.queue_id, + tokens[t0 + 3]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "rxq"); + return; + } - if (strcmp(tokens[6], "read") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); + p.cryptodev.arg_callback = NULL; + p.cryptodev.f_callback = NULL; + + t0 += 4; + } else { + snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); return; } - clear = 0; - if (n_tokens == 8) { - if (strcmp(tokens[7], "clear") != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "clear"); + if (n_tokens > t0 && + (strcmp(tokens[t0], "action") == 0)) { + if (n_tokens < t0 + 2) { + snprintf(out, out_size, MSG_ARG_MISMATCH, "action"); return; } - clear = 1; + strlcpy(p.action_profile_name, tokens[t0 + 1], + sizeof(p.action_profile_name)); + + t0 += 2; } - status = softnic_pipeline_port_out_stats_read(softnic, + enabled = 1; + if (n_tokens > t0 && + (strcmp(tokens[t0], "disabled") == 0)) { + enabled = 0; + + t0 += 1; + } + + if (n_tokens != t0) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + status = softnic_pipeline_port_in_create(softnic, pipeline_name, - port_id, - &stats, - clear); + &p, + enabled); if (status) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } - - snprintf(out, out_size, MSG_PIPELINE_PORT_OUT_STATS, - stats.stats.n_pkts_in, - stats.n_pkts_dropped_by_ah, - stats.stats.n_pkts_drop); } /** - * pipeline table stats read [clear] + * pipeline port out + * bsz + * link txq + * | swq + * | tmgr + * | tap + * | sink [file pkts ] + * | cryptodev txq offset */ -#define MSG_PIPELINE_TABLE_STATS \ - "Pkts in: %" PRIu64 "\n" \ - "Pkts in with lookup miss: %" PRIu64 "\n" \ - "Pkts in with lookup hit dropped by AH: %" PRIu64 "\n" \ - "Pkts in with lookup hit dropped by others: %" PRIu64 "\n" \ - "Pkts in with lookup miss dropped by AH: %" PRIu64 "\n" \ - "Pkts in with lookup miss dropped by others: %" PRIu64 "\n" - static void -cmd_pipeline_table_stats(struct pmd_internals *softnic, +cmd_pipeline_port_out(struct pmd_internals *softnic, char **tokens, uint32_t n_tokens, char *out, size_t out_size) { - struct rte_pipeline_table_stats stats; + struct softnic_port_out_params p; char *pipeline_name; - uint32_t table_id; - int clear, status; + int status; - if (n_tokens != 6 && - n_tokens != 7) { + memset(&p, 0, sizeof(p)); + + if (n_tokens < 7) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } pipeline_name = tokens[1]; - if (strcmp(tokens[2], "table") != 0) { + if (strcmp(tokens[2], "port") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); return; } - if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); + if (strcmp(tokens[3], "out") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out"); return; } - if (strcmp(tokens[4], "stats") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); + if (strcmp(tokens[4], "bsz") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); return; } - if (strcmp(tokens[5], "read") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); + if (softnic_parser_read_uint32(&p.burst_size, tokens[5]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "burst_size"); return; } - clear = 0; - if (n_tokens == 7) { - if (strcmp(tokens[6], "clear") != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "clear"); + if (strcmp(tokens[6], "link") == 0) { + if (n_tokens != 10) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port out link"); return; } - clear = 1; - } + p.type = PORT_OUT_TXQ; - status = softnic_pipeline_table_stats_read(softnic, - pipeline_name, - table_id, - &stats, - clear); - if (status) { - snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); - return; - } + strlcpy(p.dev_name, tokens[7], sizeof(p.dev_name)); - snprintf(out, out_size, MSG_PIPELINE_TABLE_STATS, - stats.stats.n_pkts_in, - stats.stats.n_pkts_lookup_miss, - stats.n_pkts_dropped_by_lkp_hit_ah, - stats.n_pkts_dropped_lkp_hit, - stats.n_pkts_dropped_by_lkp_miss_ah, - stats.n_pkts_dropped_lkp_miss); -} + if (strcmp(tokens[8], "txq") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq"); + return; + } -/** - * ::= - * - * match - * acl - * priority - * ipv4 | ipv6 - * - * | array - * | hash - * raw - * | ipv4_5tuple - * | ipv6_5tuple - * | ipv4_addr - * | ipv6_addr - * | qinq - * | lpm - * ipv4 | ipv6 - */ -struct pkt_key_qinq { - uint16_t ethertype_svlan; - uint16_t svlan; - uint16_t ethertype_cvlan; - uint16_t cvlan; -} __attribute__((__packed__)); + if (softnic_parser_read_uint16(&p.txq.queue_id, + tokens[9]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "queue_id"); + return; + } + } else if (strcmp(tokens[6], "swq") == 0) { + if (n_tokens != 8) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port out swq"); + return; + } -struct pkt_key_ipv4_5tuple { - uint8_t time_to_live; - uint8_t proto; - uint16_t hdr_checksum; - uint32_t sa; - uint32_t da; - uint16_t sp; - uint16_t dp; -} __attribute__((__packed__)); - -struct pkt_key_ipv6_5tuple { - uint16_t payload_length; - uint8_t proto; - uint8_t hop_limit; - uint8_t sa[16]; - uint8_t da[16]; - uint16_t sp; - uint16_t dp; -} __attribute__((__packed__)); - -struct pkt_key_ipv4_addr { - uint32_t addr; -} __attribute__((__packed__)); - -struct pkt_key_ipv6_addr { - uint8_t addr[16]; -} __attribute__((__packed__)); - -static uint32_t -parse_match(char **tokens, - uint32_t n_tokens, - char *out, - size_t out_size, - struct softnic_table_rule_match *m) -{ - memset(m, 0, sizeof(*m)); - - if (n_tokens < 2) - return 0; - - if (strcmp(tokens[0], "match") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); - return 0; - } + p.type = PORT_OUT_SWQ; - if (strcmp(tokens[1], "acl") == 0) { - if (n_tokens < 14) { - snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); - return 0; + strlcpy(p.dev_name, tokens[7], sizeof(p.dev_name)); + } else if (strcmp(tokens[6], "tmgr") == 0) { + if (n_tokens != 8) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port out tmgr"); + return; } - m->match_type = TABLE_ACL; - - if (strcmp(tokens[2], "priority") != 0) { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, "priority"); - return 0; - } + p.type = PORT_OUT_TMGR; - if (softnic_parser_read_uint32(&m->match.acl.priority, - tokens[3]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "priority"); - return 0; + strlcpy(p.dev_name, tokens[7], sizeof(p.dev_name)); + } else if (strcmp(tokens[6], "tap") == 0) { + if (n_tokens != 8) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port out tap"); + return; } - if (strcmp(tokens[4], "ipv4") == 0) { - struct in_addr saddr, daddr; + p.type = PORT_OUT_TAP; - m->match.acl.ip_version = 1; + strlcpy(p.dev_name, tokens[7], sizeof(p.dev_name)); + } else if (strcmp(tokens[6], "sink") == 0) { + if ((n_tokens != 7) && (n_tokens != 11)) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port out sink"); + return; + } - if (softnic_parse_ipv4_addr(tokens[5], &saddr) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "sa"); - return 0; - } - m->match.acl.ipv4.sa = rte_be_to_cpu_32(saddr.s_addr); + p.type = PORT_OUT_SINK; - if (softnic_parse_ipv4_addr(tokens[7], &daddr) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "da"); - return 0; + if (n_tokens == 7) { + p.sink.file_name = NULL; + p.sink.max_n_pkts = 0; + } else { + if (strcmp(tokens[7], "file") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "file"); + return; } - m->match.acl.ipv4.da = rte_be_to_cpu_32(daddr.s_addr); - } else if (strcmp(tokens[4], "ipv6") == 0) { - struct in6_addr saddr, daddr; - m->match.acl.ip_version = 0; + p.sink.file_name = tokens[8]; - if (softnic_parse_ipv6_addr(tokens[5], &saddr) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "sa"); - return 0; + if (strcmp(tokens[9], "pkts") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pkts"); + return; } - memcpy(m->match.acl.ipv6.sa, saddr.s6_addr, 16); - if (softnic_parse_ipv6_addr(tokens[7], &daddr) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "da"); - return 0; + if (softnic_parser_read_uint32(&p.sink.max_n_pkts, + tokens[10]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "max_n_pkts"); + return; } - memcpy(m->match.acl.ipv6.da, daddr.s6_addr, 16); - } else { - snprintf(out, out_size, MSG_ARG_NOT_FOUND, - "ipv4 or ipv6"); - return 0; } - - if (softnic_parser_read_uint32(&m->match.acl.sa_depth, - tokens[6]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "sa_depth"); - return 0; + } else if (strcmp(tokens[6], "cryptodev") == 0) { + if (n_tokens != 12) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port out cryptodev"); + return; } - if (softnic_parser_read_uint32(&m->match.acl.da_depth, - tokens[8]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "da_depth"); - return 0; - } + p.type = PORT_OUT_CRYPTODEV; - if (softnic_parser_read_uint16(&m->match.acl.sp0, tokens[9]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "sp0"); - return 0; - } + strlcpy(p.dev_name, tokens[7], sizeof(p.dev_name)); - if (softnic_parser_read_uint16(&m->match.acl.sp1, tokens[10]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "sp1"); - return 0; + if (strcmp(tokens[8], "txq")) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port out cryptodev"); + return; } - if (softnic_parser_read_uint16(&m->match.acl.dp0, tokens[11]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "dp0"); - return 0; + if (softnic_parser_read_uint16(&p.cryptodev.queue_id, tokens[9]) + != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "queue_id"); + return; } - if (softnic_parser_read_uint16(&m->match.acl.dp1, tokens[12]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "dp1"); - return 0; + if (strcmp(tokens[10], "offset")) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline port out cryptodev"); + return; } - if (softnic_parser_read_uint8(&m->match.acl.proto, tokens[13]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "proto"); - return 0; + if (softnic_parser_read_uint32(&p.cryptodev.op_offset, + tokens[11]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "queue_id"); + return; } + } else { + snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); + return; + } - m->match.acl.proto_mask = 0xff; + status = softnic_pipeline_port_out_create(softnic, pipeline_name, &p); + if (status) { + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); + return; + } +} - return 14; - } /* acl */ +/** + * pipeline table + * match + * acl + * ipv4 | ipv6 + * offset + * size + * | array + * offset + * size + * | hash + * ext | lru + * key + * mask + * offset + * buckets + * size + * | lpm + * ipv4 | ipv6 + * offset + * size + * | stub + * [action ] + */ +static void +cmd_pipeline_table(struct pmd_internals *softnic, + char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size) +{ + struct softnic_table_params p; + char *pipeline_name; + uint32_t t0; + int status; - if (strcmp(tokens[1], "array") == 0) { - if (n_tokens < 3) { - snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); - return 0; - } + memset(&p, 0, sizeof(p)); - m->match_type = TABLE_ARRAY; + if (n_tokens < 5) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } - if (softnic_parser_read_uint32(&m->match.array.pos, tokens[2]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "pos"); - return 0; - } + pipeline_name = tokens[1]; - return 3; - } /* array */ + if (strcmp(tokens[2], "table") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); + return; + } - if (strcmp(tokens[1], "hash") == 0) { - if (n_tokens < 3) { - snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); - return 0; + if (strcmp(tokens[3], "match") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); + return; + } + + t0 = 4; + if (strcmp(tokens[t0], "acl") == 0) { + if (n_tokens < t0 + 6) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline table acl"); + return; } - m->match_type = TABLE_HASH; + p.match_type = TABLE_ACL; - if (strcmp(tokens[2], "raw") == 0) { - uint32_t key_size = TABLE_RULE_MATCH_SIZE_MAX; + if (strcmp(tokens[t0 + 1], "ipv4") == 0) { + p.match.acl.ip_version = 1; + } else if (strcmp(tokens[t0 + 1], "ipv6") == 0) { + p.match.acl.ip_version = 0; + } else { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "ipv4 or ipv6"); + return; + } - if (n_tokens < 4) { - snprintf(out, out_size, MSG_ARG_MISMATCH, - tokens[0]); - return 0; - } - - if (softnic_parse_hex_string(tokens[3], - m->match.hash.key, &key_size) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "key"); - return 0; - } + if (strcmp(tokens[t0 + 2], "offset") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); + return; + } - return 4; - } /* hash raw */ + if (softnic_parser_read_uint32(&p.match.acl.ip_header_offset, + tokens[t0 + 3]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "ip_header_offset"); + return; + } - if (strcmp(tokens[2], "ipv4_5tuple") == 0) { - struct pkt_key_ipv4_5tuple *ipv4 = - (struct pkt_key_ipv4_5tuple *)m->match.hash.key; - struct in_addr saddr, daddr; - uint16_t sp, dp; - uint8_t proto; + if (strcmp(tokens[t0 + 4], "size") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); + return; + } - if (n_tokens < 8) { - snprintf(out, out_size, MSG_ARG_MISMATCH, - tokens[0]); - return 0; - } + if (softnic_parser_read_uint32(&p.match.acl.n_rules, + tokens[t0 + 5]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "n_rules"); + return; + } - if (softnic_parse_ipv4_addr(tokens[3], &saddr) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "sa"); - return 0; - } + t0 += 6; + } else if (strcmp(tokens[t0], "array") == 0) { + if (n_tokens < t0 + 5) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline table array"); + return; + } - if (softnic_parse_ipv4_addr(tokens[4], &daddr) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "da"); - return 0; - } + p.match_type = TABLE_ARRAY; - if (softnic_parser_read_uint16(&sp, tokens[5]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "sp"); - return 0; - } + if (strcmp(tokens[t0 + 1], "offset") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); + return; + } - if (softnic_parser_read_uint16(&dp, tokens[6]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "dp"); - return 0; - } + if (softnic_parser_read_uint32(&p.match.array.key_offset, + tokens[t0 + 2]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); + return; + } - if (softnic_parser_read_uint8(&proto, tokens[7]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, - "proto"); - return 0; - } + if (strcmp(tokens[t0 + 3], "size") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); + return; + } - ipv4->sa = saddr.s_addr; - ipv4->da = daddr.s_addr; - ipv4->sp = rte_cpu_to_be_16(sp); - ipv4->dp = rte_cpu_to_be_16(dp); - ipv4->proto = proto; + if (softnic_parser_read_uint32(&p.match.array.n_keys, + tokens[t0 + 4]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "n_keys"); + return; + } - return 8; - } /* hash ipv4_5tuple */ + t0 += 5; + } else if (strcmp(tokens[t0], "hash") == 0) { + uint32_t key_mask_size = TABLE_RULE_MATCH_SIZE_MAX; - if (strcmp(tokens[2], "ipv6_5tuple") == 0) { - struct pkt_key_ipv6_5tuple *ipv6 = - (struct pkt_key_ipv6_5tuple *)m->match.hash.key; - struct in6_addr saddr, daddr; - uint16_t sp, dp; - uint8_t proto; + if (n_tokens < t0 + 12) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline table hash"); + return; + } - if (n_tokens < 8) { - snprintf(out, out_size, MSG_ARG_MISMATCH, - tokens[0]); - return 0; - } + p.match_type = TABLE_HASH; - if (softnic_parse_ipv6_addr(tokens[3], &saddr) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "sa"); - return 0; - } + if (strcmp(tokens[t0 + 1], "ext") == 0) { + p.match.hash.extendable_bucket = 1; + } else if (strcmp(tokens[t0 + 1], "lru") == 0) { + p.match.hash.extendable_bucket = 0; + } else { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "ext or lru"); + return; + } - if (softnic_parse_ipv6_addr(tokens[4], &daddr) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "da"); - return 0; - } + if (strcmp(tokens[t0 + 2], "key") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key"); + return; + } - if (softnic_parser_read_uint16(&sp, tokens[5]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "sp"); - return 0; - } + if ((softnic_parser_read_uint32(&p.match.hash.key_size, + tokens[t0 + 3]) != 0) || + p.match.hash.key_size == 0 || + p.match.hash.key_size > TABLE_RULE_MATCH_SIZE_MAX) { + snprintf(out, out_size, MSG_ARG_INVALID, "key_size"); + return; + } - if (softnic_parser_read_uint16(&dp, tokens[6]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, "dp"); - return 0; - } + if (strcmp(tokens[t0 + 4], "mask") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); + return; + } - if (softnic_parser_read_uint8(&proto, tokens[7]) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, - "proto"); - return 0; - } + if ((softnic_parse_hex_string(tokens[t0 + 5], + p.match.hash.key_mask, &key_mask_size) != 0) || + key_mask_size != p.match.hash.key_size) { + snprintf(out, out_size, MSG_ARG_INVALID, "key_mask"); + return; + } - memcpy(ipv6->sa, saddr.s6_addr, 16); - memcpy(ipv6->da, daddr.s6_addr, 16); - ipv6->sp = rte_cpu_to_be_16(sp); - ipv6->dp = rte_cpu_to_be_16(dp); - ipv6->proto = proto; + if (strcmp(tokens[t0 + 6], "offset") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); + return; + } - return 8; - } /* hash ipv6_5tuple */ + if (softnic_parser_read_uint32(&p.match.hash.key_offset, + tokens[t0 + 7]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); + return; + } - if (strcmp(tokens[2], "ipv4_addr") == 0) { - struct pkt_key_ipv4_addr *ipv4_addr = - (struct pkt_key_ipv4_addr *)m->match.hash.key; - struct in_addr addr; + if (strcmp(tokens[t0 + 8], "buckets") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buckets"); + return; + } - if (n_tokens < 4) { - snprintf(out, out_size, MSG_ARG_MISMATCH, - tokens[0]); - return 0; - } + if (softnic_parser_read_uint32(&p.match.hash.n_buckets, + tokens[t0 + 9]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "n_buckets"); + return; + } - if (softnic_parse_ipv4_addr(tokens[3], &addr) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, - "addr"); - return 0; - } + if (strcmp(tokens[t0 + 10], "size") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); + return; + } - ipv4_addr->addr = addr.s_addr; + if (softnic_parser_read_uint32(&p.match.hash.n_keys, + tokens[t0 + 11]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "n_keys"); + return; + } - return 4; - } /* hash ipv4_addr */ + t0 += 12; + } else if (strcmp(tokens[t0], "lpm") == 0) { + if (n_tokens < t0 + 6) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "pipeline table lpm"); + return; + } - if (strcmp(tokens[2], "ipv6_addr") == 0) { - struct pkt_key_ipv6_addr *ipv6_addr = - (struct pkt_key_ipv6_addr *)m->match.hash.key; - struct in6_addr addr; + p.match_type = TABLE_LPM; - if (n_tokens < 4) { - snprintf(out, out_size, MSG_ARG_MISMATCH, - tokens[0]); - return 0; - } + if (strcmp(tokens[t0 + 1], "ipv4") == 0) { + p.match.lpm.key_size = 4; + } else if (strcmp(tokens[t0 + 1], "ipv6") == 0) { + p.match.lpm.key_size = 16; + } else { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "ipv4 or ipv6"); + return; + } - if (softnic_parse_ipv6_addr(tokens[3], &addr) != 0) { - snprintf(out, out_size, MSG_ARG_INVALID, - "addr"); - return 0; - } + if (strcmp(tokens[t0 + 2], "offset") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); + return; + } - memcpy(ipv6_addr->addr, addr.s6_addr, 16); + if (softnic_parser_read_uint32(&p.match.lpm.key_offset, + tokens[t0 + 3]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); + return; + } + + if (strcmp(tokens[t0 + 4], "size") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); + return; + } + + if (softnic_parser_read_uint32(&p.match.lpm.n_rules, + tokens[t0 + 5]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "n_rules"); + return; + } + + t0 += 6; + } else if (strcmp(tokens[t0], "stub") == 0) { + p.match_type = TABLE_STUB; + + t0 += 1; + } else { + snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); + return; + } + + if (n_tokens > t0 && + (strcmp(tokens[t0], "action") == 0)) { + if (n_tokens < t0 + 2) { + snprintf(out, out_size, MSG_ARG_MISMATCH, "action"); + return; + } + + strlcpy(p.action_profile_name, tokens[t0 + 1], + sizeof(p.action_profile_name)); + + t0 += 2; + } + + if (n_tokens > t0) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + status = softnic_pipeline_table_create(softnic, pipeline_name, &p); + if (status) { + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); + return; + } +} + +/** + * pipeline port in table + */ +static void +cmd_pipeline_port_in_table(struct pmd_internals *softnic, + char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size) +{ + char *pipeline_name; + uint32_t port_id, table_id; + int status; + + if (n_tokens != 7) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + pipeline_name = tokens[1]; + + if (strcmp(tokens[2], "port") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); + return; + } + + if (strcmp(tokens[3], "in") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); + return; + } + + if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); + return; + } + + if (strcmp(tokens[5], "table") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "table"); + return; + } + + if (softnic_parser_read_uint32(&table_id, tokens[6]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); + return; + } + + status = softnic_pipeline_port_in_connect_to_table(softnic, + pipeline_name, + port_id, + table_id); + if (status) { + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); + return; + } +} + +/** + * pipeline port in stats read [clear] + */ + +#define MSG_PIPELINE_PORT_IN_STATS \ + "Pkts in: %" PRIu64 "\n" \ + "Pkts dropped by AH: %" PRIu64 "\n" \ + "Pkts dropped by other: %" PRIu64 "\n" + +static void +cmd_pipeline_port_in_stats(struct pmd_internals *softnic, + char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size) +{ + struct rte_pipeline_port_in_stats stats; + char *pipeline_name; + uint32_t port_id; + int clear, status; + + if (n_tokens != 7 && + n_tokens != 8) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + pipeline_name = tokens[1]; + + if (strcmp(tokens[2], "port") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); + return; + } + + if (strcmp(tokens[3], "in") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); + return; + } + + if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); + return; + } + + if (strcmp(tokens[5], "stats") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); + return; + } + + if (strcmp(tokens[6], "read") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); + return; + } + + clear = 0; + if (n_tokens == 8) { + if (strcmp(tokens[7], "clear") != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "clear"); + return; + } + + clear = 1; + } + + status = softnic_pipeline_port_in_stats_read(softnic, + pipeline_name, + port_id, + &stats, + clear); + if (status) { + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); + return; + } + + snprintf(out, out_size, MSG_PIPELINE_PORT_IN_STATS, + stats.stats.n_pkts_in, + stats.n_pkts_dropped_by_ah, + stats.stats.n_pkts_drop); +} + +/** + * pipeline port in enable + */ +static void +cmd_softnic_pipeline_port_in_enable(struct pmd_internals *softnic, + char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size) +{ + char *pipeline_name; + uint32_t port_id; + int status; + + if (n_tokens != 6) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + pipeline_name = tokens[1]; + + if (strcmp(tokens[2], "port") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); + return; + } + + if (strcmp(tokens[3], "in") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); + return; + } + + if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); + return; + } + + if (strcmp(tokens[5], "enable") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "enable"); + return; + } + + status = softnic_pipeline_port_in_enable(softnic, pipeline_name, port_id); + if (status) { + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); + return; + } +} + +/** + * pipeline port in disable + */ +static void +cmd_softnic_pipeline_port_in_disable(struct pmd_internals *softnic, + char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size) +{ + char *pipeline_name; + uint32_t port_id; + int status; + + if (n_tokens != 6) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + pipeline_name = tokens[1]; + + if (strcmp(tokens[2], "port") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); + return; + } + + if (strcmp(tokens[3], "in") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "in"); + return; + } + + if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); + return; + } + + if (strcmp(tokens[5], "disable") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "disable"); + return; + } + + status = softnic_pipeline_port_in_disable(softnic, pipeline_name, port_id); + if (status) { + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); + return; + } +} + +/** + * pipeline port out stats read [clear] + */ +#define MSG_PIPELINE_PORT_OUT_STATS \ + "Pkts in: %" PRIu64 "\n" \ + "Pkts dropped by AH: %" PRIu64 "\n" \ + "Pkts dropped by other: %" PRIu64 "\n" + +static void +cmd_pipeline_port_out_stats(struct pmd_internals *softnic, + char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size) +{ + struct rte_pipeline_port_out_stats stats; + char *pipeline_name; + uint32_t port_id; + int clear, status; + + if (n_tokens != 7 && + n_tokens != 8) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + pipeline_name = tokens[1]; + + if (strcmp(tokens[2], "port") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); + return; + } + + if (strcmp(tokens[3], "out") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "out"); + return; + } + + if (softnic_parser_read_uint32(&port_id, tokens[4]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); + return; + } + + if (strcmp(tokens[5], "stats") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); + return; + } + + if (strcmp(tokens[6], "read") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); + return; + } + + clear = 0; + if (n_tokens == 8) { + if (strcmp(tokens[7], "clear") != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "clear"); + return; + } + + clear = 1; + } + + status = softnic_pipeline_port_out_stats_read(softnic, + pipeline_name, + port_id, + &stats, + clear); + if (status) { + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); + return; + } + + snprintf(out, out_size, MSG_PIPELINE_PORT_OUT_STATS, + stats.stats.n_pkts_in, + stats.n_pkts_dropped_by_ah, + stats.stats.n_pkts_drop); +} + +/** + * pipeline table stats read [clear] + */ +#define MSG_PIPELINE_TABLE_STATS \ + "Pkts in: %" PRIu64 "\n" \ + "Pkts in with lookup miss: %" PRIu64 "\n" \ + "Pkts in with lookup hit dropped by AH: %" PRIu64 "\n" \ + "Pkts in with lookup hit dropped by others: %" PRIu64 "\n" \ + "Pkts in with lookup miss dropped by AH: %" PRIu64 "\n" \ + "Pkts in with lookup miss dropped by others: %" PRIu64 "\n" + +static void +cmd_pipeline_table_stats(struct pmd_internals *softnic, + char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size) +{ + struct rte_pipeline_table_stats stats; + char *pipeline_name; + uint32_t table_id; + int clear, status; + + if (n_tokens != 6 && + n_tokens != 7) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return; + } + + pipeline_name = tokens[1]; + + if (strcmp(tokens[2], "table") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); + return; + } + + if (softnic_parser_read_uint32(&table_id, tokens[3]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "table_id"); + return; + } + + if (strcmp(tokens[4], "stats") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); + return; + } + + if (strcmp(tokens[5], "read") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "read"); + return; + } + + clear = 0; + if (n_tokens == 7) { + if (strcmp(tokens[6], "clear") != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "clear"); + return; + } + + clear = 1; + } + + status = softnic_pipeline_table_stats_read(softnic, + pipeline_name, + table_id, + &stats, + clear); + if (status) { + snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); + return; + } + + snprintf(out, out_size, MSG_PIPELINE_TABLE_STATS, + stats.stats.n_pkts_in, + stats.stats.n_pkts_lookup_miss, + stats.n_pkts_dropped_by_lkp_hit_ah, + stats.n_pkts_dropped_lkp_hit, + stats.n_pkts_dropped_by_lkp_miss_ah, + stats.n_pkts_dropped_lkp_miss); +} + +/** + * ::= + * + * match + * acl + * priority + * ipv4 | ipv6 + * + * | array + * | hash + * raw + * | ipv4_5tuple + * | ipv6_5tuple + * | ipv4_addr + * | ipv6_addr + * | qinq + * | lpm + * ipv4 | ipv6 + */ +struct pkt_key_qinq { + uint16_t ethertype_svlan; + uint16_t svlan; + uint16_t ethertype_cvlan; + uint16_t cvlan; +} __attribute__((__packed__)); + +struct pkt_key_ipv4_5tuple { + uint8_t time_to_live; + uint8_t proto; + uint16_t hdr_checksum; + uint32_t sa; + uint32_t da; + uint16_t sp; + uint16_t dp; +} __attribute__((__packed__)); + +struct pkt_key_ipv6_5tuple { + uint16_t payload_length; + uint8_t proto; + uint8_t hop_limit; + uint8_t sa[16]; + uint8_t da[16]; + uint16_t sp; + uint16_t dp; +} __attribute__((__packed__)); + +struct pkt_key_ipv4_addr { + uint32_t addr; +} __attribute__((__packed__)); + +struct pkt_key_ipv6_addr { + uint8_t addr[16]; +} __attribute__((__packed__)); + +static uint32_t +parse_match(char **tokens, + uint32_t n_tokens, + char *out, + size_t out_size, + struct softnic_table_rule_match *m) +{ + memset(m, 0, sizeof(*m)); + + if (n_tokens < 2) + return 0; + + if (strcmp(tokens[0], "match") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "match"); + return 0; + } + + if (strcmp(tokens[1], "acl") == 0) { + if (n_tokens < 14) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return 0; + } + + m->match_type = TABLE_ACL; + + if (strcmp(tokens[2], "priority") != 0) { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, "priority"); + return 0; + } + + if (softnic_parser_read_uint32(&m->match.acl.priority, + tokens[3]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "priority"); + return 0; + } + + if (strcmp(tokens[4], "ipv4") == 0) { + struct in_addr saddr, daddr; + + m->match.acl.ip_version = 1; + + if (softnic_parse_ipv4_addr(tokens[5], &saddr) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "sa"); + return 0; + } + m->match.acl.ipv4.sa = rte_be_to_cpu_32(saddr.s_addr); + + if (softnic_parse_ipv4_addr(tokens[7], &daddr) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "da"); + return 0; + } + m->match.acl.ipv4.da = rte_be_to_cpu_32(daddr.s_addr); + } else if (strcmp(tokens[4], "ipv6") == 0) { + struct in6_addr saddr, daddr; + + m->match.acl.ip_version = 0; + + if (softnic_parse_ipv6_addr(tokens[5], &saddr) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "sa"); + return 0; + } + memcpy(m->match.acl.ipv6.sa, saddr.s6_addr, 16); + + if (softnic_parse_ipv6_addr(tokens[7], &daddr) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "da"); + return 0; + } + memcpy(m->match.acl.ipv6.da, daddr.s6_addr, 16); + } else { + snprintf(out, out_size, MSG_ARG_NOT_FOUND, + "ipv4 or ipv6"); + return 0; + } + + if (softnic_parser_read_uint32(&m->match.acl.sa_depth, + tokens[6]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "sa_depth"); + return 0; + } + + if (softnic_parser_read_uint32(&m->match.acl.da_depth, + tokens[8]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "da_depth"); + return 0; + } + + if (softnic_parser_read_uint16(&m->match.acl.sp0, tokens[9]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "sp0"); + return 0; + } + + if (softnic_parser_read_uint16(&m->match.acl.sp1, tokens[10]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "sp1"); + return 0; + } + + if (softnic_parser_read_uint16(&m->match.acl.dp0, tokens[11]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "dp0"); + return 0; + } + + if (softnic_parser_read_uint16(&m->match.acl.dp1, tokens[12]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "dp1"); + return 0; + } + + if (softnic_parser_read_uint8(&m->match.acl.proto, tokens[13]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "proto"); + return 0; + } + + m->match.acl.proto_mask = 0xff; + + return 14; + } /* acl */ + + if (strcmp(tokens[1], "array") == 0) { + if (n_tokens < 3) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return 0; + } + + m->match_type = TABLE_ARRAY; + + if (softnic_parser_read_uint32(&m->match.array.pos, tokens[2]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "pos"); + return 0; + } + + return 3; + } /* array */ + + if (strcmp(tokens[1], "hash") == 0) { + if (n_tokens < 3) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return 0; + } + + m->match_type = TABLE_HASH; + + if (strcmp(tokens[2], "raw") == 0) { + uint32_t key_size = TABLE_RULE_MATCH_SIZE_MAX; + + if (n_tokens < 4) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + tokens[0]); + return 0; + } + + if (softnic_parse_hex_string(tokens[3], + m->match.hash.key, &key_size) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "key"); + return 0; + } + + return 4; + } /* hash raw */ + + if (strcmp(tokens[2], "ipv4_5tuple") == 0) { + struct pkt_key_ipv4_5tuple *ipv4 = + (struct pkt_key_ipv4_5tuple *)m->match.hash.key; + struct in_addr saddr, daddr; + uint16_t sp, dp; + uint8_t proto; + + if (n_tokens < 8) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + tokens[0]); + return 0; + } + + if (softnic_parse_ipv4_addr(tokens[3], &saddr) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "sa"); + return 0; + } + + if (softnic_parse_ipv4_addr(tokens[4], &daddr) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "da"); + return 0; + } + + if (softnic_parser_read_uint16(&sp, tokens[5]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "sp"); + return 0; + } + + if (softnic_parser_read_uint16(&dp, tokens[6]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "dp"); + return 0; + } + + if (softnic_parser_read_uint8(&proto, tokens[7]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "proto"); + return 0; + } + + ipv4->sa = saddr.s_addr; + ipv4->da = daddr.s_addr; + ipv4->sp = rte_cpu_to_be_16(sp); + ipv4->dp = rte_cpu_to_be_16(dp); + ipv4->proto = proto; + + return 8; + } /* hash ipv4_5tuple */ + + if (strcmp(tokens[2], "ipv6_5tuple") == 0) { + struct pkt_key_ipv6_5tuple *ipv6 = + (struct pkt_key_ipv6_5tuple *)m->match.hash.key; + struct in6_addr saddr, daddr; + uint16_t sp, dp; + uint8_t proto; + + if (n_tokens < 8) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + tokens[0]); + return 0; + } + + if (softnic_parse_ipv6_addr(tokens[3], &saddr) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "sa"); + return 0; + } + + if (softnic_parse_ipv6_addr(tokens[4], &daddr) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "da"); + return 0; + } + + if (softnic_parser_read_uint16(&sp, tokens[5]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "sp"); + return 0; + } + + if (softnic_parser_read_uint16(&dp, tokens[6]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "dp"); + return 0; + } + + if (softnic_parser_read_uint8(&proto, tokens[7]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "proto"); + return 0; + } + + memcpy(ipv6->sa, saddr.s6_addr, 16); + memcpy(ipv6->da, daddr.s6_addr, 16); + ipv6->sp = rte_cpu_to_be_16(sp); + ipv6->dp = rte_cpu_to_be_16(dp); + ipv6->proto = proto; + + return 8; + } /* hash ipv6_5tuple */ + + if (strcmp(tokens[2], "ipv4_addr") == 0) { + struct pkt_key_ipv4_addr *ipv4_addr = + (struct pkt_key_ipv4_addr *)m->match.hash.key; + struct in_addr addr; + + if (n_tokens < 4) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + tokens[0]); + return 0; + } + + if (softnic_parse_ipv4_addr(tokens[3], &addr) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "addr"); + return 0; + } + + ipv4_addr->addr = addr.s_addr; + + return 4; + } /* hash ipv4_addr */ + + if (strcmp(tokens[2], "ipv6_addr") == 0) { + struct pkt_key_ipv6_addr *ipv6_addr = + (struct pkt_key_ipv6_addr *)m->match.hash.key; + struct in6_addr addr; + + if (n_tokens < 4) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + tokens[0]); + return 0; + } + + if (softnic_parse_ipv6_addr(tokens[3], &addr) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "addr"); + return 0; + } + + memcpy(ipv6_addr->addr, addr.s6_addr, 16); return 4; } /* hash ipv6_5tuple */ - if (strcmp(tokens[2], "qinq") == 0) { - struct pkt_key_qinq *qinq = - (struct pkt_key_qinq *)m->match.hash.key; - uint16_t svlan, cvlan; + if (strcmp(tokens[2], "qinq") == 0) { + struct pkt_key_qinq *qinq = + (struct pkt_key_qinq *)m->match.hash.key; + uint16_t svlan, cvlan; + + if (n_tokens < 5) { + snprintf(out, out_size, MSG_ARG_MISMATCH, + tokens[0]); + return 0; + } + + if ((softnic_parser_read_uint16(&svlan, tokens[3]) != 0) || + svlan > 0xFFF) { + snprintf(out, out_size, MSG_ARG_INVALID, + "svlan"); + return 0; + } + + if ((softnic_parser_read_uint16(&cvlan, tokens[4]) != 0) || + cvlan > 0xFFF) { + snprintf(out, out_size, MSG_ARG_INVALID, + "cvlan"); + return 0; + } + + qinq->svlan = rte_cpu_to_be_16(svlan); + qinq->cvlan = rte_cpu_to_be_16(cvlan); + + return 5; + } /* hash qinq */ + + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return 0; + } /* hash */ + + if (strcmp(tokens[1], "lpm") == 0) { + if (n_tokens < 5) { + snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); + return 0; + } + + m->match_type = TABLE_LPM; + + if (strcmp(tokens[2], "ipv4") == 0) { + struct in_addr addr; + + m->match.lpm.ip_version = 1; + + if (softnic_parse_ipv4_addr(tokens[3], &addr) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "addr"); + return 0; + } + + m->match.lpm.ipv4 = rte_be_to_cpu_32(addr.s_addr); + } else if (strcmp(tokens[2], "ipv6") == 0) { + struct in6_addr addr; + + m->match.lpm.ip_version = 0; + + if (softnic_parse_ipv6_addr(tokens[3], &addr) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, + "addr"); + return 0; + } + + memcpy(m->match.lpm.ipv6, addr.s6_addr, 16); + } else { + snprintf(out, out_size, MSG_ARG_MISMATCH, + "ipv4 or ipv6"); + return 0; + } + + if (softnic_parser_read_uint8(&m->match.lpm.depth, tokens[4]) != 0) { + snprintf(out, out_size, MSG_ARG_INVALID, "depth"); + return 0; + } + + return 5; + } /* lpm */ + + snprintf(out, out_size, MSG_ARG_MISMATCH, + "acl or array or hash or lpm"); + return 0; +} + +/** + * table_action ::= + * + * action + * fwd + * drop + * | port + * | meta + * | table + * [balance ... ] + * [meter + * tc0 meter policer g y r + * [tc1 meter policer g y r + * tc2 meter policer g y r + * tc3 meter policer g y r ]] + * [tm subport pipe ] + * [encap + * ether + * | vlan + * | qinq + * | qinq_pppoe + * | mpls unicast | multicast + * + * label0