/* SPDX-License-Identifier: BSD-3-Clause * Copyright(c) 2010-2018 Intel Corporation */ #include #include #include #include #include #include #include "rte_eth_softnic_internals.h" #include "parser.h" #ifndef CMD_MAX_TOKENS #define CMD_MAX_TOKENS 256 #endif #define MSG_OUT_OF_MEMORY "Not enough memory.\n" #define MSG_CMD_UNKNOWN "Unknown command \"%s\".\n" #define MSG_CMD_UNIMPLEM "Command \"%s\" not implemented.\n" #define MSG_ARG_NOT_ENOUGH "Not enough arguments for command \"%s\".\n" #define MSG_ARG_TOO_MANY "Too many arguments for command \"%s\".\n" #define MSG_ARG_MISMATCH "Wrong number of arguments for command \"%s\".\n" #define MSG_ARG_NOT_FOUND "Argument \"%s\" not found.\n" #define MSG_ARG_INVALID "Invalid value for argument \"%s\".\n" #define MSG_FILE_ERR "Error in file \"%s\" at line %u.\n" #define MSG_FILE_NOT_ENOUGH "Not enough rules in file \"%s\".\n" #define MSG_CMD_FAIL "Command \"%s\" failed.\n" static int is_comment(char *in) { if ((strlen(in) && index("!#%;", in[0])) || (strncmp(in, "//", 2) == 0) || (strncmp(in, "--", 2) == 0)) return 1; return 0; } /** * mempool * buffer * pool * cache */ static void cmd_mempool(struct pmd_internals *softnic, char **tokens, uint32_t n_tokens, char *out, size_t out_size) { struct softnic_mempool_params p; char *name; struct softnic_mempool *mempool; if (n_tokens != 8) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } name = tokens[1]; if (strcmp(tokens[2], "buffer") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buffer"); return; } if (softnic_parser_read_uint32(&p.buffer_size, tokens[3]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "buffer_size"); return; } if (strcmp(tokens[4], "pool") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pool"); return; } if (softnic_parser_read_uint32(&p.pool_size, tokens[5]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "pool_size"); return; } if (strcmp(tokens[6], "cache") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cache"); return; } if (softnic_parser_read_uint32(&p.cache_size, tokens[7]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "cache_size"); return; } mempool = softnic_mempool_create(softnic, name, &p); if (mempool == NULL) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } /** * link * dev | port */ static void cmd_link(struct pmd_internals *softnic, char **tokens, uint32_t n_tokens, char *out, size_t out_size) { struct softnic_link_params p; struct softnic_link *link; char *name; memset(&p, 0, sizeof(p)); if (n_tokens != 4) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } name = tokens[1]; if (strcmp(tokens[2], "dev") == 0) { p.dev_name = tokens[3]; } else if (strcmp(tokens[2], "port") == 0) { p.dev_name = NULL; if (softnic_parser_read_uint16(&p.port_id, tokens[3]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); return; } } else { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "dev or port"); return; } link = softnic_link_create(softnic, name, &p); if (link == NULL) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } /** * swq * size */ static void cmd_swq(struct pmd_internals *softnic, char **tokens, uint32_t n_tokens, char *out, size_t out_size) { struct softnic_swq_params p; char *name; struct softnic_swq *swq; if (n_tokens != 4) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } name = tokens[1]; if (strcmp(tokens[2], "size") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); return; } if (softnic_parser_read_uint32(&p.size, tokens[3]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "size"); return; } swq = softnic_swq_create(softnic, name, &p); if (swq == NULL) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } /** * tmgr shaper profile * id * rate size * adj */ static void cmd_tmgr_shaper_profile(struct pmd_internals *softnic, char **tokens, uint32_t n_tokens, char *out, size_t out_size) { struct rte_tm_shaper_params sp; struct rte_tm_error error; uint32_t shaper_profile_id; uint16_t port_id; int status; memset(&sp, 0, sizeof(struct rte_tm_shaper_params)); if (n_tokens != 11) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } if (strcmp(tokens[1], "shaper") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "shaper"); return; } 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; } } /** * tmgr shared shaper * id * profile */ static void cmd_tmgr_shared_shaper(struct pmd_internals *softnic, char **tokens, uint32_t n_tokens, char *out, size_t out_size) { struct rte_tm_error error; uint32_t shared_shaper_id, shaper_profile_id; uint16_t port_id; int status; if (n_tokens != 7) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } if (strcmp(tokens[1], "shared") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "shared"); return; } if (strcmp(tokens[2], "shaper") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "shaper"); return; } 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; } if (softnic_parser_read_uint32(&shaper_profile_id, tokens[6]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "shaper_profile_id"); return; } status = rte_eth_dev_get_port_by_name(softnic->params.name, &port_id); if (status) return; 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; } } /** * 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; 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 (n_tokens < 10) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } if (strcmp(tokens[1], "node") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "node"); return; } if (strcmp(tokens[2], "id") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "id"); return; } if (softnic_parser_read_uint32(&node_id, tokens[3]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "node_id"); return; } if (strcmp(tokens[4], "parent") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "parent"); return; } 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[6], "priority") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "priority"); return; } if (softnic_parser_read_uint32(&priority, tokens[7]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "priority"); return; } if (strcmp(tokens[8], "weight") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "weight"); return; } if (softnic_parser_read_uint32(&weight, tokens[9]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "weight"); return; } 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[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; } } 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 (softnic_parser_read_uint32(&shared_shaper_id, tokens[2]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "shared_shaper_id"); return; } 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 (softnic_parser_read_uint32(&np.nonleaf.n_sp_priorities, tokens[2]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "n_sp_priorities"); return; } tokens += 3; n_tokens -= 3; } /* nonleaf sp */ if (n_tokens) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } 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; } } static uint32_t root_node_id(uint32_t n_spp, uint32_t n_pps) { 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; return n_queues + n_tc + n_pipes + n_spp; } 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; return n_queues + n_tc + n_pipes + subport_id; } 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; } 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 * RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE + (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, }, }; struct rte_tm_node_params tc_node_params[] = { [0] = { .shaper_profile_id = params->shaper_profile_id.tc[0], .shared_shaper_id = ¶ms->shared_shaper_id.tc[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 = ¶ms->shared_shaper_id.tc[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 = ¶ms->shared_shaper_id.tc[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 = ¶ms->shared_shaper_id.tc[3], .n_shared_shapers = (¶ms->shared_shaper_id.tc_valid[3]) ? 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 */ for (q = 0; q < RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS; 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; } /* Queue */ } /* TC */ } /* Pipe */ } /* Subport */ return 0; } /** * tmgr hierarchy-default * spp * pps * shaper profile * port * subport * pipe * tc0 * tc1 * tc2 * tc3 * shared shaper * tc0 * tc1 * tc2 * tc3 * 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, status; memset(&p, 0, sizeof(p)); if (n_tokens != 50) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } if (strcmp(tokens[1], "hierarchy-default") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "hierarchy-default"); return; } if (strcmp(tokens[2], "spp") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp"); return; } if (softnic_parser_read_uint32(&p.n_spp, tokens[3]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "n_subports_per_port"); return; } if (strcmp(tokens[4], "pps") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps"); return; } if (softnic_parser_read_uint32(&p.n_pps, tokens[5]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport"); return; } /* 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; } /* Shared shaper */ if (strcmp(tokens[22], "shared") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "shared"); return; } if (strcmp(tokens[23], "shaper") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "shaper"); return; } if (strcmp(tokens[24], "tc0") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc0"); return; } if (strcmp(tokens[25], "none") == 0) p.shared_shaper_id.tc_valid[0] = 0; else { if (softnic_parser_read_uint32(&p.shared_shaper_id.tc[0], tokens[25]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "shared shaper tc0"); return; } p.shared_shaper_id.tc_valid[0] = 1; } if (strcmp(tokens[26], "tc1") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc1"); return; } if (strcmp(tokens[27], "none") == 0) p.shared_shaper_id.tc_valid[1] = 0; else { if (softnic_parser_read_uint32(&p.shared_shaper_id.tc[1], tokens[27]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "shared shaper tc1"); return; } p.shared_shaper_id.tc_valid[1] = 1; } if (strcmp(tokens[28], "tc2") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc2"); return; } if (strcmp(tokens[29], "none") == 0) p.shared_shaper_id.tc_valid[2] = 0; else { if (softnic_parser_read_uint32(&p.shared_shaper_id.tc[2], tokens[29]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "shared shaper tc2"); return; } p.shared_shaper_id.tc_valid[2] = 1; } if (strcmp(tokens[30], "tc3") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc3"); return; } if (strcmp(tokens[31], "none") == 0) p.shared_shaper_id.tc_valid[3] = 0; else { if (softnic_parser_read_uint32(&p.shared_shaper_id.tc[3], tokens[31]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "shared shaper tc3"); return; } p.shared_shaper_id.tc_valid[3] = 1; } /* Weight */ if (strcmp(tokens[32], "weight") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "weight"); return; } if (strcmp(tokens[33], "queue") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "queue"); return; } for (i = 0; i < 16; i++) { if (softnic_parser_read_uint32(&p.weight.queue[i], tokens[34 + i]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "weight queue"); return; } } status = tmgr_hierarchy_default(softnic, &p); if (status != 0) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } /** * tmgr hierarchy commit */ static void cmd_tmgr_hierarchy_commit(struct pmd_internals *softnic, char **tokens, uint32_t n_tokens, char *out, size_t out_size) { struct rte_tm_error error; uint16_t port_id; int status; if (n_tokens != 3) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } if (strcmp(tokens[1], "hierarchy") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "hierarchy"); return; } if (strcmp(tokens[2], "commit") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "commit"); return; } status = rte_eth_dev_get_port_by_name(softnic->params.name, &port_id); if (status != 0) return; status = rte_tm_hierarchy_commit(port_id, 1, &error); if (status) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } /** * tmgr */ static void cmd_tmgr(struct pmd_internals *softnic, char **tokens, uint32_t n_tokens, char *out, size_t out_size) { char *name; struct softnic_tmgr_port *tmgr_port; if (n_tokens != 2) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } name = tokens[1]; tmgr_port = softnic_tmgr_port_create(softnic, name); if (tmgr_port == NULL) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); 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 (n_tokens != 2) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } name = tokens[1]; tap = softnic_tap_create(softnic, name); if (tap == NULL) { 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 ... ] */ static void cmd_port_in_action_profile(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)); if (n_tokens < 5) { 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"); return; } if (strcmp(tokens[2], "action") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action"); return; } if (strcmp(tokens[3], "profile") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); return; } name = tokens[4]; 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; } 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[t0 + 2], "offset") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); 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[t0 + 4], "mask") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); 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 (strcmp(tokens[t0 + 6], "key") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key"); 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"); return; } if (strcmp(tokens[t0 + 8], "port") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); return; } if (softnic_parser_read_uint32(&p.fltr.port_id, tokens[t0 + 9]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "port_id"); return; } 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, "port in action profile balance"); return; } if (strcmp(tokens[t0 + 1], "offset") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); return; } if (softnic_parser_read_uint32(&p.lb.key_offset, tokens[t0 + 2]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); return; } if (strcmp(tokens[t0 + 3], "mask") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); 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"); return; } if (strcmp(tokens[t0 + 5], "port") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "port"); 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 */ if (t0 < 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) { 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) { struct softnic_table_action_profile_params p; struct softnic_table_action_profile *ap; char *name; uint32_t t0; memset(&p, 0, sizeof(p)); if (n_tokens < 8) { snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]); return; } if (strcmp(tokens[1], "action") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "action"); return; } if (strcmp(tokens[2], "profile") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "profile"); return; } 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; } if (strcmp(tokens[5], "offset") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); return; } 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[7], "fwd") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fwd"); return; } p.action_mask |= 1LLU << RTE_TABLE_ACTION_FWD; 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 + 1], "offset") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); return; } if (softnic_parser_read_uint32(&p.lb.key_offset, tokens[t0 + 2]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "key_offset"); return; } if (strcmp(tokens[t0 + 3], "mask") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); 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"); return; } if (strcmp(tokens[t0 + 5], "outoffset") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "outoffset"); return; } if (softnic_parser_read_uint32(&p.lb.out_offset, tokens[t0 + 6]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "out_offset"); return; } p.action_mask |= 1LLU << RTE_TABLE_ACTION_LB; t0 += 7; } /* balance */ 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"); 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"); return; } if (strcmp(tokens[t0 + 2], "tc") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc"); 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.action_mask |= 1LLU << RTE_TABLE_ACTION_TM; t0 += 5; } /* tm */ if (t0 < n_tokens && (strcmp(tokens[t0], "encap") == 0)) { if (n_tokens < t0 + 2) { snprintf(out, out_size, MSG_ARG_MISMATCH, "action profile encap"); 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.action_mask |= 1LLU << RTE_TABLE_ACTION_ENCAP; t0 += 2; } /* encap */ 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, "src or dst"); return; } if (strcmp(tokens[t0 + 2], "proto") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "proto"); 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"); return; } 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 (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; } if (strcmp(tokens[t0 + 2], "stats") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "stats"); 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_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, "table action profile stats"); 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; } 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 (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) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } /** * pipeline * period * offset_port_id */ static void cmd_pipeline(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; if (n_tokens != 6) { 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"); return; } 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(&p.offset_port_id, tokens[5]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "offset_port_id"); return; } pipeline = softnic_pipeline_create(softnic, name, &p); if (pipeline == NULL) { 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] */ static void cmd_pipeline_port_in(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; 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 (strcmp(tokens[4], "bsz") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); return; } if (softnic_parser_read_uint32(&p.burst_size, tokens[5]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "burst_size"); 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]; if (strcmp(tokens[t0 + 3], "file") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "file"); return; } p.source.file_name = tokens[t0 + 4]; if (strcmp(tokens[t0 + 5], "bpp") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bpp"); 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; } t0 += 7; } else { snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); 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]; t0 += 2; } 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, &p, enabled); if (status) { snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]); return; } } /** * pipeline port out * bsz * link txq * | swq * | tmgr * | tap * | sink [file pkts ] */ static void cmd_pipeline_port_out(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; 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], "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 (strcmp(tokens[4], "bsz") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "bsz"); return; } 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], "link") == 0) { if (n_tokens != 10) { snprintf(out, out_size, MSG_ARG_MISMATCH, "pipeline port out link"); return; } p.type = PORT_OUT_TXQ; p.dev_name = tokens[7]; if (strcmp(tokens[8], "txq") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "txq"); return; } 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; } p.type = PORT_OUT_SWQ; 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"); return; } p.type = PORT_OUT_TMGR; 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"); return; } p.type = PORT_OUT_TAP; p.dev_name = tokens[7]; } 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; } p.type = PORT_OUT_SINK; p.dev_name = NULL; 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; } p.sink.file_name = tokens[8]; if (strcmp(tokens[9], "pkts") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pkts"); return; } if (softnic_parser_read_uint32(&p.sink.max_n_pkts, tokens[10]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "max_n_pkts"); return; } } } else { snprintf(out, out_size, MSG_ARG_INVALID, tokens[0]); return; } status = softnic_pipeline_port_out_create(softnic, pipeline_name, &p); if (status) { 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 ] */ static void cmd_pipeline_table(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; uint32_t t0; int status; if (n_tokens < 5) { 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, "table"); return; } 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; } p.match_type = TABLE_ACL; 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[t0 + 2], "offset") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); return; } 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[t0 + 4], "size") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); return; } if (softnic_parser_read_uint32(&p.match.acl.n_rules, tokens[t0 + 5]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "n_rules"); 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"); return; } p.match_type = TABLE_ARRAY; if (strcmp(tokens[t0 + 1], "offset") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); return; } 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 (strcmp(tokens[t0 + 3], "size") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); 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; if (n_tokens < t0 + 12) { snprintf(out, out_size, MSG_ARG_MISMATCH, "pipeline table hash"); 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; } else { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "ext or lru"); return; } if (strcmp(tokens[t0 + 2], "key") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "key"); 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"); return; } if (strcmp(tokens[t0 + 4], "mask") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mask"); 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"); return; } p.match.hash.key_mask = key_mask; if (strcmp(tokens[t0 + 6], "offset") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); return; } 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[t0 + 8], "buckets") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "buckets"); return; } 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 (strcmp(tokens[t0 + 10], "size") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "size"); return; } if (softnic_parser_read_uint32(&p.match.hash.n_keys, tokens[t0 + 11]) != 0) { snprintf(out, out_size, MSG_ARG_INVALID, "n_keys"); 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"); return; } p.match_type = TABLE_LPM; 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 (strcmp(tokens[t0 + 2], "offset") != 0) { snprintf(out, out_size, MSG_ARG_NOT_FOUND, "offset"); return; } 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; } 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]; 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 (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 * | mpls unicast | multicast * * label0