+/**
+ * tmgr shaper profile
+ * id <profile_id>
+ * rate <tb_rate> size <tb_size>
+ * adj <packet_length_adjust>
+ */
+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 <shared_shaper_id>
+ * profile <shaper_profile_id>
+ */
+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 <node_id>
+ * parent <parent_node_id | none>
+ * priority <priority>
+ * weight <weight>
+ * [shaper profile <shaper_profile_id>]
+ * [shared shaper <shared_shaper_id>]
+ * [nonleaf sp <n_sp_priorities>]
+ */
+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 <n_sp_priorities> */
+
+ 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 +
+ (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 <n_subports_per_port>
+ * pps <n_pipes_per_subport>
+ * shaper profile
+ * port <profile_id>
+ * subport <profile_id>
+ * pipe <profile_id>
+ * tc0 <profile_id>
+ * tc1 <profile_id>
+ * tc2 <profile_id>
+ * tc3 <profile_id>
+ * tc4 <profile_id>
+ * tc5 <profile_id>
+ * tc6 <profile_id>
+ * tc7 <profile_id>
+ * tc8 <profile_id>
+ * tc9 <profile_id>
+ * tc10 <profile_id>
+ * tc11 <profile_id>
+ * tc12 <profile_id>
+ * shared shaper
+ * tc0 <id | none>
+ * tc1 <id | none>
+ * tc2 <id | none>
+ * tc3 <id | none>
+ * tc4 <id | none>
+ * tc5 <id | none>
+ * tc6 <id | none>
+ * tc7 <id | none>
+ * tc8 <id | none>
+ * tc9 <id | none>
+ * tc10 <id | none>
+ * tc11 <id | none>
+ * tc12 <id | none>
+ * weight
+ * queue <q12> ... <q15>
+ */
+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[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;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ 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.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;
+ }
+
+ 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;
+ }
+
+ 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.shared_shaper_id.tc_valid[5] = 1;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ 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;
+ }
+
+ p.shared_shaper_id.tc_valid[8] = 1;
+ }
+
+ if (strcmp(tokens[60], "tc9") != 0) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc9");
+ return;
+ }
+
+ 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;
+ }
+
+ p.shared_shaper_id.tc_valid[9] = 1;
+ }
+
+ if (strcmp(tokens[62], "tc10") != 0) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc10");
+ return;
+ }
+
+ 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;
+ }
+
+ p.shared_shaper_id.tc_valid[10] = 1;
+ }
+
+ if (strcmp(tokens[64], "tc11") != 0) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc11");
+ return;
+ }
+
+ 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.shared_shaper_id.tc_valid[11] = 1;
+ }
+
+ if (strcmp(tokens[66], "tc12") != 0) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "tc12");
+ return;
+ }
+
+ 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;
+ }
+
+ p.shared_shaper_id.tc_valid[12] = 1;
+ }
+
+ /* Weight */
+
+ if (strcmp(tokens[68], "weight") != 0) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "weight");
+ return;
+ }
+
+ if (strcmp(tokens[69], "queue") != 0) {
+ snprintf(out, out_size, MSG_ARG_NOT_FOUND, "queue");
+ return;
+ }
+
+ for (i = 0, j = 0; i < 16; i++) {
+ if (i < RTE_SCHED_TRAFFIC_CLASS_BE) {
+ p.weight.queue[i] = 1;
+ } else {
+ if (softnic_parser_read_uint32(&p.weight.queue[i],
+ tokens[70 + j]) != 0) {
+ snprintf(out, out_size, MSG_ARG_INVALID, "weight queue");
+ return;
+ }
+ j++;
+ }
+ }
+
+ 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 <tmgr_name>
+ */
+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;
+ }
+}
+