All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/2] app/testpmd: add traffic management forwarding mode
@ 2017-08-22 17:02 Jasvinder Singh
  2017-08-22 17:02 ` [PATCH 2/2] app/testpmd: add CLI for tm mode Jasvinder Singh
  2017-09-14 11:53 ` [PATCH v2 1/2] app/testpmd: add traffic management forwarding mode Jasvinder Singh
  0 siblings, 2 replies; 49+ messages in thread
From: Jasvinder Singh @ 2017-08-22 17:02 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu

This commit extends the testpmd application with new forwarding engine
that demonstrates the use of ethdev traffic management APIs and softnic
PMD for QoS traffic management.

In this mode, 5-level hierarchical tree of the QoS scheduler is built
with the help of ethdev TM APIs such as shaper profile add/delete,
shared shaper add/update, node add/delete, hierarchy commit, etc.
The hierarchical tree has following nodes; root node(x1, level 0),
subport node(x1, level 1), pipe node(x4096, level 2),
tc node(x16348, level 3), queue node(x65536, level 4).

During runtime, each received packet is first classified by mapping the
packet fields information to 5-tuples (HQoS subport, pipe, traffic class,
queue within traffic class, and color) and storing it in the packet mbuf
sched field. After classification, each packet is sent to softnic port
which prioritizes the transmission of the received packets, and
accordingly sends them on to the output interface.

To enable traffic management mode, following testpmd command is used;

$ ./testpmd -c c -n 4 --vdev 'net_softnic0,hard_name=0000:06:00.1,soft_tm=on'
  -- -i --forward-mode=softnictm

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 app/test-pmd/Makefile    |   5 +
 app/test-pmd/softnictm.c | 870 +++++++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/testpmd.c   |  11 +
 app/test-pmd/testpmd.h   |  34 ++
 4 files changed, 920 insertions(+)
 create mode 100644 app/test-pmd/softnictm.c

diff --git a/app/test-pmd/Makefile b/app/test-pmd/Makefile
index c36be19..7c3f5e8 100644
--- a/app/test-pmd/Makefile
+++ b/app/test-pmd/Makefile
@@ -57,6 +57,7 @@ SRCS-y += rxonly.c
 SRCS-y += txonly.c
 SRCS-y += csumonly.c
 SRCS-y += icmpecho.c
+SRCS-y += softnictm.c
 SRCS-$(CONFIG_RTE_LIBRTE_IEEE1588) += ieee1588fwd.c
 
 ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
@@ -81,6 +82,10 @@ ifeq ($(CONFIG_RTE_LIBRTE_PMD_XENVIRT),y)
 LDLIBS += -lrte_pmd_xenvirt
 endif
 
+ifeq ($(CONFIG_RTE_LIBRTE_PMD_SOFTNIC),y)
+LDLIBS += -lrte_pmd_softnic
+endif
+
 endif
 
 CFLAGS_cmdline.o := -D_GNU_SOURCE
diff --git a/app/test-pmd/softnictm.c b/app/test-pmd/softnictm.c
new file mode 100644
index 0000000..5d1553e
--- /dev/null
+++ b/app/test-pmd/softnictm.c
@@ -0,0 +1,870 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <sys/stat.h>
+
+#include <rte_cycles.h>
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_flow.h>
+#include <rte_meter.h>
+#include <rte_eth_softnic.h>
+#include <rte_tm.h>
+
+#include "testpmd.h"
+
+#define SUBPORT_NODES_PER_PORT		1
+#define PIPE_NODES_PER_SUBPORT		4096
+#define TC_NODES_PER_PIPE			4
+#define QUEUE_NODES_PER_TC			4
+
+#define NUM_PIPE_NODES						\
+	(SUBPORT_NODES_PER_PORT * PIPE_NODES_PER_SUBPORT)
+
+#define NUM_TC_NODES						\
+	(NUM_PIPE_NODES * TC_NODES_PER_PIPE)
+
+#define ROOT_NODE_ID				1000000
+#define SUBPORT_NODES_START_ID		900000
+#define PIPE_NODES_START_ID			800000
+#define TC_NODES_START_ID			700000
+
+#define STATS_MASK_DEFAULT					\
+	(RTE_TM_STATS_N_PKTS |					\
+	RTE_TM_STATS_N_BYTES |					\
+	RTE_TM_STATS_N_PKTS_GREEN_DROPPED |			\
+	RTE_TM_STATS_N_BYTES_GREEN_DROPPED)
+
+#define STATS_MASK_QUEUE					\
+	(STATS_MASK_DEFAULT |					\
+	RTE_TM_STATS_N_PKTS_QUEUED)
+
+#define BYTES_IN_MBPS				(1000 * 1000 / 8)
+#define TOKEN_BUCKET_SIZE			1000000
+
+#ifndef IPV4_PKT_HDR_OFFSET
+#define IPV4_PKT_HDR_OFFSET			270
+#endif
+
+#define RTE_MBUF_METADATA_UINT8_PTR(mbuf, offset)		\
+		(&((uint8_t *)(mbuf))[offset])
+
+/* TM Hierarchy Levels */
+enum tm_hierarchy_level {
+	TM_NODE_LEVEL_PORT = 0,
+	TM_NODE_LEVEL_SUBPORT,
+	TM_NODE_LEVEL_PIPE,
+	TM_NODE_LEVEL_TC,
+	TM_NODE_LEVEL_QUEUE,
+	TM_NODE_LEVEL_MAX,
+};
+
+struct tm_hierarchy {
+	/* TM Nodes */
+	uint32_t root_node_id;
+	uint32_t subport_node_id[SUBPORT_NODES_PER_PORT];
+	uint32_t pipe_node_id[SUBPORT_NODES_PER_PORT][PIPE_NODES_PER_SUBPORT];
+	uint32_t tc_node_id[NUM_PIPE_NODES][TC_NODES_PER_PIPE];
+	uint32_t queue_node_id[NUM_TC_NODES][QUEUE_NODES_PER_TC];
+
+	/* TM Hierarchy Nodes Shaper Rates */
+	uint32_t root_node_shaper_rate;
+	uint32_t subport_node_shaper_rate;
+	uint32_t pipe_node_shaper_rate;
+	uint32_t tc_node_shaper_rate;
+	uint32_t tc_node_shared_shaper_rate;
+
+	uint32_t n_shapers;
+};
+
+#define BITFIELD(byte_array, slab_pos, slab_mask, slab_shr)	\
+({								\
+	uint64_t slab = *((uint64_t *) &byte_array[slab_pos]);	\
+	uint64_t val =				\
+		(rte_be_to_cpu_64(slab) & slab_mask) >> slab_shr;	\
+	val;						\
+})
+
+#define RTE_SCHED_PORT_HIERARCHY(subport, pipe,           \
+	traffic_class, queue, color)                          \
+	((((uint64_t) (queue)) & 0x3) |                       \
+	((((uint64_t) (traffic_class)) & 0x3) << 2) |         \
+	((((uint64_t) (color)) & 0x3) << 4) |                 \
+	((((uint64_t) (subport)) & 0xFFFF) << 16) |           \
+	((((uint64_t) (pipe)) & 0xFFFFFFFF) << 32))
+
+
+static void
+pkt_metadata_set(struct rte_port *p, struct rte_mbuf **pkts,
+	uint32_t n_pkts)
+{
+	struct softtm *tm = &p->softport.tm;
+	uint32_t i;
+
+	for (i = 0; i < (n_pkts & (~0x3)); i += 4) {
+		struct rte_mbuf *pkt0 = pkts[i];
+		struct rte_mbuf *pkt1 = pkts[i + 1];
+		struct rte_mbuf *pkt2 = pkts[i + 2];
+		struct rte_mbuf *pkt3 = pkts[i + 3];
+
+		uint8_t *pkt0_data = rte_pktmbuf_mtod(pkt0, uint8_t *);
+		uint8_t *pkt1_data = rte_pktmbuf_mtod(pkt1, uint8_t *);
+		uint8_t *pkt2_data = rte_pktmbuf_mtod(pkt2, uint8_t *);
+		uint8_t *pkt3_data = rte_pktmbuf_mtod(pkt3, uint8_t *);
+
+		uint64_t pkt0_subport = BITFIELD(pkt0_data,
+					tm->tm_pktfield0_slabpos,
+					tm->tm_pktfield0_slabmask,
+					tm->tm_pktfield0_slabshr);
+		uint64_t pkt0_pipe = BITFIELD(pkt0_data,
+					tm->tm_pktfield1_slabpos,
+					tm->tm_pktfield1_slabmask,
+					tm->tm_pktfield1_slabshr);
+		uint64_t pkt0_dscp = BITFIELD(pkt0_data,
+					tm->tm_pktfield2_slabpos,
+					tm->tm_pktfield2_slabmask,
+					tm->tm_pktfield2_slabshr);
+		uint32_t pkt0_tc = tm->tm_tc_table[pkt0_dscp & 0x3F] >> 2;
+		uint32_t pkt0_tc_q = tm->tm_tc_table[pkt0_dscp & 0x3F] & 0x3;
+		uint64_t pkt1_subport = BITFIELD(pkt1_data,
+					tm->tm_pktfield0_slabpos,
+					tm->tm_pktfield0_slabmask,
+					tm->tm_pktfield0_slabshr);
+		uint64_t pkt1_pipe = BITFIELD(pkt1_data,
+					tm->tm_pktfield1_slabpos,
+					tm->tm_pktfield1_slabmask,
+					tm->tm_pktfield1_slabshr);
+		uint64_t pkt1_dscp = BITFIELD(pkt1_data,
+					tm->tm_pktfield2_slabpos,
+					tm->tm_pktfield2_slabmask,
+					tm->tm_pktfield2_slabshr);
+		uint32_t pkt1_tc = tm->tm_tc_table[pkt1_dscp & 0x3F] >> 2;
+		uint32_t pkt1_tc_q = tm->tm_tc_table[pkt1_dscp & 0x3F] & 0x3;
+
+		uint64_t pkt2_subport = BITFIELD(pkt2_data,
+					tm->tm_pktfield0_slabpos,
+					tm->tm_pktfield0_slabmask,
+					tm->tm_pktfield0_slabshr);
+		uint64_t pkt2_pipe = BITFIELD(pkt2_data,
+					tm->tm_pktfield1_slabpos,
+					tm->tm_pktfield1_slabmask,
+					tm->tm_pktfield1_slabshr);
+		uint64_t pkt2_dscp = BITFIELD(pkt2_data,
+					tm->tm_pktfield2_slabpos,
+					tm->tm_pktfield2_slabmask,
+					tm->tm_pktfield2_slabshr);
+		uint32_t pkt2_tc = tm->tm_tc_table[pkt2_dscp & 0x3F] >> 2;
+		uint32_t pkt2_tc_q = tm->tm_tc_table[pkt2_dscp & 0x3F] & 0x3;
+
+		uint64_t pkt3_subport = BITFIELD(pkt3_data,
+					tm->tm_pktfield0_slabpos,
+					tm->tm_pktfield0_slabmask,
+					tm->tm_pktfield0_slabshr);
+		uint64_t pkt3_pipe = BITFIELD(pkt3_data,
+					tm->tm_pktfield1_slabpos,
+					tm->tm_pktfield1_slabmask,
+					tm->tm_pktfield1_slabshr);
+		uint64_t pkt3_dscp = BITFIELD(pkt3_data,
+					tm->tm_pktfield2_slabpos,
+					tm->tm_pktfield2_slabmask,
+					tm->tm_pktfield2_slabshr);
+		uint32_t pkt3_tc = tm->tm_tc_table[pkt3_dscp & 0x3F] >> 2;
+		uint32_t pkt3_tc_q = tm->tm_tc_table[pkt3_dscp & 0x3F] & 0x3;
+
+		uint64_t pkt0_sched = RTE_SCHED_PORT_HIERARCHY(pkt0_subport,
+						pkt0_pipe,
+						pkt0_tc,
+						pkt0_tc_q,
+						0);
+		uint64_t pkt1_sched = RTE_SCHED_PORT_HIERARCHY(pkt1_subport,
+						pkt1_pipe,
+						pkt1_tc,
+						pkt1_tc_q,
+						0);
+		uint64_t pkt2_sched = RTE_SCHED_PORT_HIERARCHY(pkt2_subport,
+						pkt2_pipe,
+						pkt2_tc,
+						pkt2_tc_q,
+						0);
+		uint64_t pkt3_sched = RTE_SCHED_PORT_HIERARCHY(pkt3_subport,
+						pkt3_pipe,
+						pkt3_tc,
+						pkt3_tc_q,
+						0);
+
+		pkt0->hash.sched.lo = pkt0_sched & 0xFFFFFFFF;
+		pkt0->hash.sched.hi = pkt0_sched >> 32;
+		pkt1->hash.sched.lo = pkt1_sched & 0xFFFFFFFF;
+		pkt1->hash.sched.hi = pkt1_sched >> 32;
+		pkt2->hash.sched.lo = pkt2_sched & 0xFFFFFFFF;
+		pkt2->hash.sched.hi = pkt2_sched >> 32;
+		pkt3->hash.sched.lo = pkt3_sched & 0xFFFFFFFF;
+		pkt3->hash.sched.hi = pkt3_sched >> 32;
+	}
+
+	for (; i < n_pkts; i++)	{
+		struct rte_mbuf *pkt = pkts[i];
+
+		uint8_t *pkt_data = rte_pktmbuf_mtod(pkt, uint8_t *);
+
+		uint64_t pkt_subport = BITFIELD(pkt_data,
+					tm->tm_pktfield0_slabpos,
+					tm->tm_pktfield0_slabmask,
+					tm->tm_pktfield0_slabshr);
+		uint64_t pkt_pipe = BITFIELD(pkt_data,
+					tm->tm_pktfield1_slabpos,
+					tm->tm_pktfield1_slabmask,
+					tm->tm_pktfield1_slabshr);
+		uint64_t pkt_dscp = BITFIELD(pkt_data,
+					tm->tm_pktfield2_slabpos,
+					tm->tm_pktfield2_slabmask,
+					tm->tm_pktfield2_slabshr);
+		uint32_t pkt_tc = tm->tm_tc_table[pkt_dscp & 0x3F] >> 2;
+		uint32_t pkt_tc_q = tm->tm_tc_table[pkt_dscp & 0x3F] & 0x3;
+
+		uint64_t pkt_sched = RTE_SCHED_PORT_HIERARCHY(pkt_subport,
+						pkt_pipe,
+						pkt_tc,
+						pkt_tc_q,
+						0);
+
+		pkt->hash.sched.lo = pkt_sched & 0xFFFFFFFF;
+		pkt->hash.sched.hi = pkt_sched >> 32;
+	}
+}
+
+/*
+ * Softnic Fwd
+ */
+static void
+softnic_fwd(struct fwd_stream *fs)
+{
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	struct rte_port *rte_tx_port = &ports[fs->tx_port];
+	uint16_t nb_rx;
+	uint16_t nb_tx;
+	uint32_t retry;
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+	uint64_t start_tsc;
+	uint64_t end_tsc;
+	uint64_t core_cycles;
+#endif
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+	start_tsc = rte_rdtsc();
+#endif
+
+	/*  Packets Receive */
+	nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue,
+			pkts_burst, nb_pkt_per_burst);
+	fs->rx_packets += nb_rx;
+
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+	fs->rx_burst_stats.pkt_burst_spread[nb_rx]++;
+#endif
+
+	if (rte_tx_port->softport.enable) {
+		/* Set packet metadata if tm flag enabled */
+		if (rte_tx_port->softport.tm_flag)
+			pkt_metadata_set(rte_tx_port, pkts_burst, nb_rx);
+
+		/* Softnic run */
+		rte_pmd_softnic_run(fs->tx_port);
+	}
+	nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
+			pkts_burst, nb_rx);
+
+	/* Retry if necessary */
+	if (unlikely(nb_tx < nb_rx) && fs->retry_enabled) {
+		retry = 0;
+		while (nb_tx < nb_rx && retry++ < burst_tx_retry_num) {
+			rte_delay_us(burst_tx_delay_time);
+			nb_tx += rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
+					&pkts_burst[nb_tx], nb_rx - nb_tx);
+		}
+	}
+	fs->tx_packets += nb_tx;
+
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+	fs->tx_burst_stats.pkt_burst_spread[nb_tx]++;
+#endif
+
+	if (unlikely(nb_tx < nb_rx)) {
+		fs->fwd_dropped += (nb_rx - nb_tx);
+		do {
+			rte_pktmbuf_free(pkts_burst[nb_tx]);
+		} while (++nb_tx < nb_rx);
+	}
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+	end_tsc = rte_rdtsc();
+	core_cycles = (end_tsc - start_tsc);
+	fs->core_cycles = (uint64_t) (fs->core_cycles + core_cycles);
+#endif
+}
+
+static void
+set_tm_hiearchy_nodes_shaper_rate(portid_t port_id, struct tm_hierarchy *h)
+{
+	struct rte_eth_link link_params;
+	uint64_t tm_port_rate;
+
+	memset(&link_params, 0, sizeof(link_params));
+
+	rte_eth_link_get(port_id, &link_params);
+	tm_port_rate = link_params.link_speed * BYTES_IN_MBPS;
+
+	if (tm_port_rate > UINT32_MAX)
+		tm_port_rate = UINT32_MAX;
+
+	/* Set tm hierarchy shapers rate */
+	h->root_node_shaper_rate = tm_port_rate;
+	h->subport_node_shaper_rate =
+		tm_port_rate / SUBPORT_NODES_PER_PORT;
+	h->pipe_node_shaper_rate
+		= h->subport_node_shaper_rate / PIPE_NODES_PER_SUBPORT;
+	h->tc_node_shaper_rate = h->pipe_node_shaper_rate;
+	h->tc_node_shared_shaper_rate = h->subport_node_shaper_rate;
+}
+
+static int
+softnic_tm_root_node_add(portid_t port_id, struct tm_hierarchy *h,
+	struct rte_tm_error *error)
+{
+	struct rte_tm_node_params rnp;
+	struct rte_tm_shaper_params rsp;
+	uint32_t priority, weight, level_id, shaper_profile_id;
+
+	memset(&rsp, 0, sizeof(struct rte_tm_shaper_params));
+	memset(&rnp, 0, sizeof(struct rte_tm_node_params));
+
+	/* Shaper profile Parameters */
+	rsp.peak.rate = h->root_node_shaper_rate;
+	rsp.peak.size = TOKEN_BUCKET_SIZE;
+	rsp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+	shaper_profile_id = 0;
+
+	if (rte_tm_shaper_profile_add(port_id, shaper_profile_id,
+		&rsp, error)) {
+		printf("%s ERROR(%d)-%s!(shaper_id %u)\n ",
+			__func__, error->type, error->message,
+			shaper_profile_id);
+		return -1;
+	}
+
+	/* Root Node Parameters */
+	h->root_node_id = ROOT_NODE_ID;
+	weight = 1;
+	priority = 0;
+	level_id = TM_NODE_LEVEL_PORT;
+	rnp.shaper_profile_id = shaper_profile_id;
+	rnp.nonleaf.n_sp_priorities = 1;
+	rnp.stats_mask = STATS_MASK_DEFAULT;
+
+	/* Add Node to TM Hierarchy */
+	if (rte_tm_node_add(port_id, h->root_node_id, RTE_TM_NODE_ID_NULL,
+		priority, weight, level_id, &rnp, error)) {
+		printf("%s ERROR(%d)-%s!(node_id %u, parent_id %u, level %u)\n",
+			__func__, error->type, error->message,
+			h->root_node_id, RTE_TM_NODE_ID_NULL,
+			level_id);
+		return -1;
+	}
+	/* Update */
+	h->n_shapers++;
+
+	printf("  Root node added (Start id %u, Count %u, level %u)\n",
+		h->root_node_id, 1, level_id);
+
+	return 0;
+}
+
+static int
+softnic_tm_subport_node_add(portid_t port_id, struct tm_hierarchy *h,
+	struct rte_tm_error *error)
+{
+	uint32_t subport_parent_node_id, subport_node_id;
+	struct rte_tm_node_params snp;
+	struct rte_tm_shaper_params ssp;
+	uint32_t priority, weight, level_id, shaper_profile_id;
+	uint32_t i;
+
+	memset(&ssp, 0, sizeof(struct rte_tm_shaper_params));
+	memset(&snp, 0, sizeof(struct rte_tm_node_params));
+
+	shaper_profile_id = h->n_shapers;
+
+	/* Add Shaper Profile to TM Hierarchy */
+	for (i = 0; i < SUBPORT_NODES_PER_PORT; i++) {
+		ssp.peak.rate = h->subport_node_shaper_rate;
+		ssp.peak.size = TOKEN_BUCKET_SIZE;
+		ssp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+		if (rte_tm_shaper_profile_add(port_id, shaper_profile_id,
+			&ssp, error)) {
+			printf("%s ERROR(%d)-%s!(shaper_id %u)\n ",
+				__func__, error->type, error->message,
+				shaper_profile_id);
+			return -1;
+		}
+
+		/* Node Parameters */
+		h->subport_node_id[i] = SUBPORT_NODES_START_ID + i;
+		subport_parent_node_id = h->root_node_id;
+		weight = 1;
+		priority = 0;
+		level_id = TM_NODE_LEVEL_SUBPORT;
+		snp.shaper_profile_id = shaper_profile_id;
+		snp.nonleaf.n_sp_priorities = 1;
+		snp.stats_mask = STATS_MASK_DEFAULT;
+
+		/* Add Node to TM Hiearchy */
+		if (rte_tm_node_add(port_id,
+				h->subport_node_id[i],
+				subport_parent_node_id,
+				priority, weight,
+				level_id,
+				&snp,
+				error)) {
+			printf("%s ERROR(%d)-%s!(node %u,parent %u,level %u)\n",
+					__func__,
+					error->type,
+					error->message,
+					h->subport_node_id[i],
+					subport_parent_node_id,
+					level_id);
+			return -1;
+		}
+		shaper_profile_id++;
+		subport_node_id++;
+	}
+	/* Update */
+	h->n_shapers = shaper_profile_id;
+
+	printf("  Subport nodes added (Start id %u, Count %u, level %u)\n",
+		h->subport_node_id[0], SUBPORT_NODES_PER_PORT, level_id);
+
+	return 0;
+}
+
+static int
+softnic_tm_pipe_node_add(portid_t port_id, struct tm_hierarchy *h,
+	struct rte_tm_error *error)
+{
+	uint32_t pipe_parent_node_id;
+	struct rte_tm_node_params pnp;
+	struct rte_tm_shaper_params psp;
+	uint32_t priority, weight, level_id, shaper_profile_id;
+	uint32_t i, j;
+
+	memset(&psp, 0, sizeof(struct rte_tm_shaper_params));
+	memset(&pnp, 0, sizeof(struct rte_tm_node_params));
+
+	shaper_profile_id = h->n_shapers;
+
+	/* Shaper Profile Parameters */
+	psp.peak.rate = h->pipe_node_shaper_rate;
+	psp.peak.size = TOKEN_BUCKET_SIZE;
+	psp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+	/* Pipe Node Parameters */
+	weight = 1;
+	priority = 0;
+	level_id = TM_NODE_LEVEL_PIPE;
+	pnp.nonleaf.n_sp_priorities = 4;
+	pnp.stats_mask = STATS_MASK_DEFAULT;
+
+	/* Add Shaper Profiles and Nodes to TM Hierarchy */
+	for (i = 0; i < SUBPORT_NODES_PER_PORT; i++) {
+		for (j = 0; j < PIPE_NODES_PER_SUBPORT; j++) {
+			if (rte_tm_shaper_profile_add(port_id,
+				shaper_profile_id, &psp, error)) {
+				printf("%s ERROR(%d)-%s!(shaper_id %u)\n ",
+					__func__, error->type, error->message,
+					shaper_profile_id);
+				return -1;
+			}
+			pnp.shaper_profile_id = shaper_profile_id;
+			pipe_parent_node_id = h->subport_node_id[i];
+			h->pipe_node_id[i][j] = PIPE_NODES_START_ID +
+				(i * PIPE_NODES_PER_SUBPORT) + j;
+
+			if (rte_tm_node_add(port_id,
+					h->pipe_node_id[i][j],
+					pipe_parent_node_id,
+					priority, weight, level_id,
+					&pnp,
+					error)) {
+				printf("%s ERROR(%d)-%s!(node %u,parent %u )\n",
+					__func__,
+					error->type,
+					error->message,
+					h->pipe_node_id[i][j],
+					pipe_parent_node_id);
+
+				return -1;
+			}
+			shaper_profile_id++;
+		}
+	}
+	/* Update */
+	h->n_shapers = shaper_profile_id;
+
+	printf("  Pipe nodes added (Start id %u, Count %u, level %u)\n",
+		h->pipe_node_id[0][0], NUM_PIPE_NODES, level_id);
+
+	return 0;
+}
+
+static int
+softnic_tm_tc_node_add(portid_t port_id, struct tm_hierarchy *h,
+	struct rte_tm_error *error)
+{
+	uint32_t tc_parent_node_id;
+	struct rte_tm_node_params tnp;
+	struct rte_tm_shaper_params tsp, tssp;
+	uint32_t shared_shaper_profile_id[TC_NODES_PER_PIPE];
+	uint32_t priority, weight, level_id, shaper_profile_id;
+	uint32_t pos, i, j, k, l;
+
+	memset(&tsp, 0, sizeof(struct rte_tm_shaper_params));
+	memset(&tssp, 0, sizeof(struct rte_tm_shaper_params));
+	memset(&tnp, 0, sizeof(struct rte_tm_node_params));
+
+	shaper_profile_id = h->n_shapers;
+
+	/* Private Shaper Profile (TC) Parameters */
+	tsp.peak.rate = h->tc_node_shaper_rate;
+	tsp.peak.size = TOKEN_BUCKET_SIZE;
+	tsp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+	/* Shared Shaper Profile (TC) Parameters */
+	tssp.peak.rate = h->tc_node_shared_shaper_rate;
+	tssp.peak.size = TOKEN_BUCKET_SIZE;
+	tssp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+	/* TC Node Parameters */
+	weight = 1;
+	level_id = TM_NODE_LEVEL_TC;
+	tnp.n_shared_shapers = 1;
+	tnp.nonleaf.n_sp_priorities = 1;
+	tnp.stats_mask = STATS_MASK_DEFAULT;
+
+	/* Add Shared Shaper Profiles to TM Hierarchy */
+	for (i = 0; i < TC_NODES_PER_PIPE; i++) {
+		shared_shaper_profile_id[i] = shaper_profile_id;
+
+		if (rte_tm_shaper_profile_add(port_id,
+			shared_shaper_profile_id[i], &tssp, error)) {
+			printf("%s ERROR(%d)-%s!(Shared shaper profileid %u)\n",
+				__func__, error->type, error->message,
+				shared_shaper_profile_id[i]);
+
+			return -1;
+		}
+		if (rte_tm_shared_shaper_add_update(port_id,  i,
+			shared_shaper_profile_id[i], error)) {
+			printf("%s ERROR(%d)-%s!(Shared shaper id %u)\n",
+				__func__, error->type, error->message, i);
+
+			return -1;
+		}
+		shaper_profile_id++;
+	}
+
+	/* Add Shaper Profiles and Nodes to TM Hierarchy */
+	l = 0;
+	for (i = 0; i < SUBPORT_NODES_PER_PORT; i++) {
+		for (j = 0; j < PIPE_NODES_PER_SUBPORT; j++) {
+			for (k = 0; k < TC_NODES_PER_PIPE ; k++) {
+				priority = k;
+				tc_parent_node_id = h->pipe_node_id[i][j];
+				tnp.shared_shaper_id =
+					(uint32_t *)calloc(1, sizeof(uint32_t));
+				tnp.shared_shaper_id[0] = k;
+				pos = j + (i * PIPE_NODES_PER_SUBPORT);
+				h->tc_node_id[pos][k] = TC_NODES_START_ID + l;
+
+				if (rte_tm_shaper_profile_add(port_id,
+					shaper_profile_id, &tsp, error)) {
+					printf("%s ERROR(%d)-%s!(shaper %u)\n",
+						__func__, error->type,
+						error->message,
+						shaper_profile_id);
+
+					return -1;
+				}
+				tnp.shaper_profile_id = shaper_profile_id;
+				if (rte_tm_node_add(port_id,
+						h->tc_node_id[pos][k],
+						tc_parent_node_id,
+						priority, weight,
+						level_id,
+						&tnp, error)) {
+					printf("%s ERROR(%d)-%s!(node id %u)\n",
+						__func__,
+						error->type,
+						error->message,
+						h->tc_node_id[pos][k]);
+
+					return -1;
+				}
+				shaper_profile_id++;
+				l++;
+			}
+		}
+	}
+	/* Update */
+	h->n_shapers = shaper_profile_id;
+
+	printf("  TC nodes added (Start id %u, Count %u, level %u)\n",
+		h->tc_node_id[0][0], l, level_id);
+
+	return 0;
+}
+
+static int
+softnic_tm_queue_node_add(portid_t port_id, struct tm_hierarchy *h,
+	struct rte_tm_error *error)
+{
+	uint32_t queue_parent_node_id;
+	struct rte_tm_node_params qnp;
+	uint32_t priority, weight, level_id, pos;
+	uint32_t i, j, k, l;
+
+	memset(&qnp, 0, sizeof(struct rte_tm_node_params));
+
+	/* Queue Node Parameters */
+	priority = 0;
+	weight = 1;
+	level_id = TM_NODE_LEVEL_QUEUE;
+	qnp.shaper_profile_id = RTE_TM_SHAPER_PROFILE_ID_NONE;
+	qnp.leaf.cman = RTE_TM_CMAN_TAIL_DROP;
+	qnp.stats_mask = STATS_MASK_QUEUE;
+
+	/* Add Queue Nodes to TM Hierarchy */
+	l = 0;
+	for (i = 0; i < NUM_PIPE_NODES; i++) {
+		for (j = 0; j < TC_NODES_PER_PIPE; j++) {
+			queue_parent_node_id = h->tc_node_id[i][j];
+			for (k = 0; k < QUEUE_NODES_PER_TC; k++) {
+				pos = j + (i * TC_NODES_PER_PIPE);
+				h->queue_node_id[pos][k] = l;
+				if (rte_tm_node_add(port_id,
+						h->queue_node_id[pos][k],
+						queue_parent_node_id,
+						priority,
+						weight,
+						level_id,
+						&qnp, error)) {
+					printf("%s ERROR(%d)-%s!(node %u)\n",
+						__func__,
+						error->type,
+						error->message,
+						h->queue_node_id[pos][k]);
+
+					return -1;
+				}
+				l++;
+			}
+		}
+	}
+	printf("  Queue nodes added (Start id %u, Count %u, level %u)\n",
+		h->queue_node_id[0][0], l, level_id);
+
+	return 0;
+}
+
+/*
+ * TM Packet Field Setup
+ */
+static void
+softnic_tm_pktfield_setup(portid_t port_id)
+{
+	struct rte_port *p = &ports[port_id];
+	uint64_t pktfield0_mask = 0;
+	uint64_t pktfield1_mask = 0x0000000FFF000000LLU;
+	uint64_t pktfield2_mask = 0x00000000000000FCLLU;
+
+	p->softport.tm = (struct softtm) {
+		.n_subports_per_port = SUBPORT_NODES_PER_PORT,
+		.n_pipes_per_subport = PIPE_NODES_PER_SUBPORT,
+
+		/* Packet field to identify subport
+		 *
+		 * Default configuration assumes only one subport, thus
+		 * the subport ID is hardcoded to 0
+		 */
+		.tm_pktfield0_slabpos = 0,
+		.tm_pktfield0_slabmask = pktfield0_mask,
+		.tm_pktfield0_slabshr =
+			__builtin_ctzll(pktfield0_mask),
+
+		/* Packet field to identify pipe.
+		 *
+		 * Default value assumes Ethernet/IPv4/UDP packets,
+		 * UDP payload bits 12 .. 23
+		 */
+		.tm_pktfield1_slabpos = 40,
+		.tm_pktfield1_slabmask = pktfield1_mask,
+		.tm_pktfield1_slabshr =
+			__builtin_ctzll(pktfield1_mask),
+
+		/* Packet field used as index into TC translation table
+		 * to identify the traffic class and queue.
+		 *
+		 * Default value assumes Ethernet/IPv4 packets, IPv4
+		 * DSCP field
+		 */
+		.tm_pktfield2_slabpos = 8,
+		.tm_pktfield2_slabmask = pktfield2_mask,
+		.tm_pktfield2_slabshr =
+			__builtin_ctzll(pktfield2_mask),
+
+		.tm_tc_table = {
+			0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+			0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+			0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+			0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+		}, /**< TC translation table */
+	};
+}
+
+static int
+softnic_tm_hierarchy_specify(portid_t port_id, struct rte_tm_error *error)
+{
+
+	struct tm_hierarchy h;
+	int status;
+
+	memset(&h, 0, sizeof(struct tm_hierarchy));
+
+	/* TM hierarchy shapers rate */
+	set_tm_hiearchy_nodes_shaper_rate(port_id, &h);
+
+	/* Add root node (level 0) */
+	status = softnic_tm_root_node_add(port_id, &h, error);
+	if (status)
+		return status;
+
+	/* Add subport node (level 1) */
+	status = softnic_tm_subport_node_add(port_id, &h, error);
+	if (status)
+		return status;
+
+	/* Add pipe nodes (level 2) */
+	status = softnic_tm_pipe_node_add(port_id, &h, error);
+	if (status)
+		return status;
+
+	/* Add traffic class nodes (level 3) */
+	status = softnic_tm_tc_node_add(port_id, &h, error);
+	if (status)
+		return status;
+
+	/* Add queue nodes (level 4) */
+	status = softnic_tm_queue_node_add(port_id, &h, error);
+	if (status)
+		return status;
+
+	/* TM packet fields setup */
+	softnic_tm_pktfield_setup(port_id);
+
+	return 0;
+}
+
+/*
+ * Softnic Initialisation
+ */
+static void
+softnic_begin(portid_t pi)
+{
+	struct rte_port *port = &ports[pi];
+
+	/* Softnic TM flag */
+	if (port->softport.tm_flag == 1) {
+		printf("\n\n  TM feature available on port %u\n", pi);
+
+		/* Softnic TM hierarchy frozen */
+		if (port->softport.tm.hierarchy_frozen == 0) {
+			struct rte_tm_error error;
+			int status;
+
+			/* Stop port */
+			rte_eth_dev_stop(pi);
+
+			/* TM hierarchy specification */
+			status = softnic_tm_hierarchy_specify(pi, &error);
+			if (status) {
+				printf("  TM Hierarchy built error(%d) - %s\n",
+					error.type, error.message);
+				return;
+			}
+			printf("\n  TM Hierarchy Specified!\n\v");
+
+			/* TM hierarchy commit */
+			status = rte_tm_hierarchy_commit(pi, 0, &error);
+			if (status) {
+				printf("  Hierarchy commit error(%d) - %s\n",
+					error.type, error.message);
+				return;
+			}
+			printf("  Hierarchy Committed (port %u)!", pi);
+			port->softport.tm.hierarchy_frozen = 1;
+
+			/* Start port */
+			status = rte_eth_dev_start(pi);
+			if (status) {
+				printf("\n  Port %u start error!\n", pi);
+				return;
+			}
+			printf("\n  Port %u started!\n", pi);
+			return;
+		}
+	}
+	printf("\n  TM feature not available on port %u", pi);
+}
+
+struct fwd_engine softnic_tm_engine = {
+	.fwd_mode_name  = "softnictm",
+	.port_fwd_begin = softnic_begin,
+	.port_fwd_end   = NULL,
+	.packet_fwd     = softnic_fwd,
+};
+
+struct fwd_engine softnic_fwd_engine = {
+	.fwd_mode_name  = "softnicfwd",
+	.port_fwd_begin = NULL,
+	.port_fwd_end   = NULL,
+	.packet_fwd     = softnic_fwd,
+};
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index 7d40139..8cc0c13 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -167,6 +167,8 @@ struct fwd_engine * fwd_engines[] = {
 	&tx_only_engine,
 	&csum_fwd_engine,
 	&icmp_echo_engine,
+	&softnic_tm_engine,
+	&softnic_fwd_engine,
 #ifdef RTE_LIBRTE_IEEE1588
 	&ieee1588_fwd_engine,
 #endif
@@ -2044,6 +2046,15 @@ init_port_config(void)
 		    (rte_eth_devices[pid].data->dev_flags &
 		     RTE_ETH_DEV_INTR_RMV))
 			port->dev_conf.intr_conf.rmv = 1;
+
+		/* Detect softnic port */
+		if (!strcmp(port->dev_info.driver_name, "net_softnic")) {
+			memset(&port->softport, 0, sizeof(struct softnic_port));
+				port->softport.enable = 1;
+
+			if (!strcmp(cur_fwd_eng->fwd_mode_name, "softnictm"))
+				port->softport.tm_flag = 1;
+		}
 	}
 }
 
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index c9d7739..32481d5 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -163,6 +163,37 @@ struct port_flow {
 };
 
 /**
+ * Softnic tm related parameters
+ */
+struct softtm {
+	uint32_t hierarchy_frozen;  /**< flag for tm hierarchy status */
+
+	uint32_t n_subports_per_port;  /**< Num of subport nodes per port */
+	uint32_t n_pipes_per_subport;  /**< Num of pipe nodes per subport */
+
+	uint64_t tm_pktfield0_slabpos;	/**< Pkt field position for subport */
+	uint64_t tm_pktfield0_slabmask; /**< Pkt field mask for the subport */
+	uint64_t tm_pktfield0_slabshr;
+	uint64_t tm_pktfield1_slabpos; /**< Pkt field position for the pipe */
+	uint64_t tm_pktfield1_slabmask; /**< Pkt field mask for the pipe */
+	uint64_t tm_pktfield1_slabshr;
+	uint64_t tm_pktfield2_slabpos; /**< Pkt field position table index */
+	uint64_t tm_pktfield2_slabmask;	/**< Pkt field mask for tc table idx */
+	uint64_t tm_pktfield2_slabshr;
+	uint64_t tm_tc_table[64];  /**< TC translation table */
+};
+
+/**
+ * The data structure associate with softnic port
+ */
+struct softnic_port {
+	unsigned int enable; /**< set to 1 if softnic port detected */
+
+	unsigned int tm_flag;  /**< set to 1 if tm feature is enabled */
+	struct softtm tm; /**< softnic port tm parameters */
+};
+
+/**
  * The data structure associated with each port.
  */
 struct rte_port {
@@ -195,6 +226,7 @@ struct rte_port {
 	uint32_t                mc_addr_nb; /**< nb. of addr. in mc_addr_pool */
 	uint8_t                 slave_flag; /**< bonding slave port */
 	struct port_flow        *flow_list; /**< Associated flows. */
+	struct softnic_port     softport;  /**< softnic port params > */
 };
 
 /**
@@ -253,6 +285,8 @@ extern struct fwd_engine rx_only_engine;
 extern struct fwd_engine tx_only_engine;
 extern struct fwd_engine csum_fwd_engine;
 extern struct fwd_engine icmp_echo_engine;
+extern struct fwd_engine softnic_tm_engine;
+extern struct fwd_engine softnic_fwd_engine;
 #ifdef RTE_LIBRTE_IEEE1588
 extern struct fwd_engine ieee1588_fwd_engine;
 #endif
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH 2/2] app/testpmd: add CLI for tm mode
  2017-08-22 17:02 [PATCH 1/2] app/testpmd: add traffic management forwarding mode Jasvinder Singh
@ 2017-08-22 17:02 ` Jasvinder Singh
  2017-09-14 11:53 ` [PATCH v2 1/2] app/testpmd: add traffic management forwarding mode Jasvinder Singh
  1 sibling, 0 replies; 49+ messages in thread
From: Jasvinder Singh @ 2017-08-22 17:02 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu

Add following CLIs in testpmd application;
- commands to build hierarchical tree for the QoS Scheduler.
- commands for runtime update of the hierarchical tree.
- commands to display TM capability information.
  (per port, per hierarchy level and per hierarchy node)
- command to set the packet field mask and offset value for
  classification.
- command to set traffic class translation table entry
- stats collection

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 app/test-pmd/cmdline.c | 2975 ++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 2785 insertions(+), 190 deletions(-)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index cd8c358..87a9c7b 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -98,6 +98,19 @@
 #ifdef RTE_LIBRTE_BNXT_PMD
 #include <rte_pmd_bnxt.h>
 #endif
+
+#if defined RTE_LIBRTE_PMD_SOFTNIC && defined RTE_LIBRTE_SCHED
+#define SOFTNIC_TM_FEATURE			1
+#else
+#define SOFTNIC_TM_FEATURE			0
+#endif
+
+#ifdef SOFTNIC_TM_FEATURE
+#include <rte_sched.h>
+#include <rte_eth_softnic.h>
+#include <rte_tm.h>
+#endif
+
 #include "testpmd.h"
 
 static struct cmdline *testpmd_cl;
@@ -230,6 +243,23 @@ static void cmd_help_long_parsed(void *parsed_result,
 
 			"clear vf stats (port_id) (vf_id)\n"
 			"    Reset a VF's statistics.\n\n"
+
+#ifdef SOFTNIC_TM_FEATURE
+			"show port tm cap (port_id)\n"
+			"	Display the port TM capability.\n\n"
+
+			"show port tm level cap (port_id) (level_id)\n"
+			"	Display the port TM hierarchical level capability.\n\n"
+
+			"show port tm node cap (port_id) (node_id)\n"
+			"	Display the port TM node capability.\n\n"
+
+			"show port tm node type (port_id) (node_id)\n"
+			"	Display the port TM node type.\n\n"
+
+			"show port tm node stats (port_id) (node_id) (clear)\n"
+			"	Display the port TM node stats.\n\n"
+#endif
 		);
 	}
 
@@ -637,6 +667,61 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"ptype mapping update (port_id) (hw_ptype) (sw_ptype)\n"
 			"    Update a ptype mapping item on a port\n\n"
 
+#ifdef SOFTNIC_TM_FEATURE
+			"add port tm node shaper profile (port_id) (shaper_profile_id)"
+			" (tb_rate) (tb_size)\n"
+			"	Add port tm node private shaper profile.\n\n"
+
+			"del port tm node shaper profile (port_id) (shaper_profile_id)\n"
+			"	Delete port tm node private shaper profile.\n\n"
+
+			"add port tm node shared shaper (port_id) (shared_shaper_id)"
+			" (shaper_profile_id)\n"
+			"	Add/update port tm node shared shaper.\n\n"
+
+			"del port tm node shared shaper (port_id) (shared_shaper_id)\n"
+			"	Delete port tm node shared shaper.\n\n"
+
+			"add port tm node wred profile (port_id) (wred_profile_id)"
+			" (color_g) (min_th_g) (max_th_g) (maxp_inv_g) (wq_log2_g)"
+			" (color_y) (min_th_y) (max_th_y) (maxp_inv_y) (wq_log2_y)"
+			" (color_r) (min_th_r) (max_th_r) (maxp_inv_r) (wq_log2_r)\n"
+			"	Add port tm node wred profile.\n\n"
+
+			"del port tm node wred profile (port_id) (wred_profile_id)\n"
+			"	Delete port tm node wred profile.\n\n"
+
+			"add port tm nonleaf node shared shaper (port_id) (node_id)"
+			" (parent_node_id) (priority) (weight) (level_id)"
+			" (shaper_profile_id) (shared_shaper_id) (n_shared_shapers)"
+			" (n_sp_priorities)\n"
+			"	Add port tm nonleaf node.\n\n"
+
+			"add port tm leaf node shared shaper (port_id) (node_id)"
+			" (parent_node_id) (priority) (weight) (level_id)"
+			" (cman_mode) (wred_profile_id)\n"
+			"	Add port tm leaf node.\n\n"
+
+			"del port tm node (port_id) (node_id)\n"
+			"	Delete port tm node.\n\n"
+
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+			"set port tm node parent (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight)\n"
+			"	Set port tm node parent.\n\n"
+#endif
+			"set port tm node shaper profile (port_id) (node_id)"
+			" (shaper_profile_id)\n"
+			"	Set port tm node shaper profile.\n\n"
+
+			"set port tm pktfield (subport|pipe|tc) (port_id) offset"
+			" (offset) mask (mask)\n"
+			"	Set port tm packet field.\n\n"
+
+			"set port tm tc table (port_id) index (tb_index) tc (tc_id)"
+			" queue (queue id)\n"
+			"	Set port tm traffic class table entry.\n\n"
+#endif
 			, list_pkt_forwarding_modes()
 		);
 	}
@@ -14185,197 +14270,2707 @@ cmdline_parse_inst_t cmd_load_from_file = {
 	},
 };
 
-/* ******************************************************************************** */
+#ifdef SOFTNIC_TM_FEATURE
 
-/* list of instructions */
-cmdline_parse_ctx_t main_ctx[] = {
-	(cmdline_parse_inst_t *)&cmd_help_brief,
-	(cmdline_parse_inst_t *)&cmd_help_long,
-	(cmdline_parse_inst_t *)&cmd_quit,
-	(cmdline_parse_inst_t *)&cmd_load_from_file,
-	(cmdline_parse_inst_t *)&cmd_showport,
-	(cmdline_parse_inst_t *)&cmd_showqueue,
-	(cmdline_parse_inst_t *)&cmd_showportall,
-	(cmdline_parse_inst_t *)&cmd_showcfg,
-	(cmdline_parse_inst_t *)&cmd_start,
-	(cmdline_parse_inst_t *)&cmd_start_tx_first,
-	(cmdline_parse_inst_t *)&cmd_start_tx_first_n,
-	(cmdline_parse_inst_t *)&cmd_set_link_up,
-	(cmdline_parse_inst_t *)&cmd_set_link_down,
-	(cmdline_parse_inst_t *)&cmd_reset,
-	(cmdline_parse_inst_t *)&cmd_set_numbers,
-	(cmdline_parse_inst_t *)&cmd_set_txpkts,
-	(cmdline_parse_inst_t *)&cmd_set_txsplit,
-	(cmdline_parse_inst_t *)&cmd_set_fwd_list,
-	(cmdline_parse_inst_t *)&cmd_set_fwd_mask,
-	(cmdline_parse_inst_t *)&cmd_set_fwd_mode,
-	(cmdline_parse_inst_t *)&cmd_set_fwd_retry_mode,
-	(cmdline_parse_inst_t *)&cmd_set_burst_tx_retry,
-	(cmdline_parse_inst_t *)&cmd_set_promisc_mode_one,
-	(cmdline_parse_inst_t *)&cmd_set_promisc_mode_all,
-	(cmdline_parse_inst_t *)&cmd_set_allmulti_mode_one,
-	(cmdline_parse_inst_t *)&cmd_set_allmulti_mode_all,
-	(cmdline_parse_inst_t *)&cmd_set_flush_rx,
-	(cmdline_parse_inst_t *)&cmd_set_link_check,
-	(cmdline_parse_inst_t *)&cmd_set_bypass_mode,
-	(cmdline_parse_inst_t *)&cmd_set_bypass_event,
-	(cmdline_parse_inst_t *)&cmd_set_bypass_timeout,
-	(cmdline_parse_inst_t *)&cmd_show_bypass_config,
-#ifdef RTE_LIBRTE_PMD_BOND
-	(cmdline_parse_inst_t *) &cmd_set_bonding_mode,
-	(cmdline_parse_inst_t *) &cmd_show_bonding_config,
-	(cmdline_parse_inst_t *) &cmd_set_bonding_primary,
-	(cmdline_parse_inst_t *) &cmd_add_bonding_slave,
-	(cmdline_parse_inst_t *) &cmd_remove_bonding_slave,
-	(cmdline_parse_inst_t *) &cmd_create_bonded_device,
-	(cmdline_parse_inst_t *) &cmd_set_bond_mac_addr,
-	(cmdline_parse_inst_t *) &cmd_set_balance_xmit_policy,
-	(cmdline_parse_inst_t *) &cmd_set_bond_mon_period,
-	(cmdline_parse_inst_t *) &cmd_set_lacp_dedicated_queues,
-	(cmdline_parse_inst_t *) &cmd_set_bonding_agg_mode_policy,
-#endif
-	(cmdline_parse_inst_t *)&cmd_vlan_offload,
-	(cmdline_parse_inst_t *)&cmd_vlan_tpid,
-	(cmdline_parse_inst_t *)&cmd_rx_vlan_filter_all,
-	(cmdline_parse_inst_t *)&cmd_rx_vlan_filter,
-	(cmdline_parse_inst_t *)&cmd_tx_vlan_set,
-	(cmdline_parse_inst_t *)&cmd_tx_vlan_set_qinq,
-	(cmdline_parse_inst_t *)&cmd_tx_vlan_reset,
-	(cmdline_parse_inst_t *)&cmd_tx_vlan_set_pvid,
-	(cmdline_parse_inst_t *)&cmd_csum_set,
-	(cmdline_parse_inst_t *)&cmd_csum_show,
-	(cmdline_parse_inst_t *)&cmd_csum_tunnel,
-	(cmdline_parse_inst_t *)&cmd_tso_set,
-	(cmdline_parse_inst_t *)&cmd_tso_show,
-	(cmdline_parse_inst_t *)&cmd_tunnel_tso_set,
-	(cmdline_parse_inst_t *)&cmd_tunnel_tso_show,
-	(cmdline_parse_inst_t *)&cmd_enable_gro,
-	(cmdline_parse_inst_t *)&cmd_gro_set,
-	(cmdline_parse_inst_t *)&cmd_link_flow_control_set,
-	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_rx,
-	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_tx,
-	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_hw,
-	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_lw,
-	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_pt,
-	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_xon,
-	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_macfwd,
-	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_autoneg,
-	(cmdline_parse_inst_t *)&cmd_priority_flow_control_set,
-	(cmdline_parse_inst_t *)&cmd_config_dcb,
-	(cmdline_parse_inst_t *)&cmd_read_reg,
-	(cmdline_parse_inst_t *)&cmd_read_reg_bit_field,
-	(cmdline_parse_inst_t *)&cmd_read_reg_bit,
-	(cmdline_parse_inst_t *)&cmd_write_reg,
-	(cmdline_parse_inst_t *)&cmd_write_reg_bit_field,
-	(cmdline_parse_inst_t *)&cmd_write_reg_bit,
-	(cmdline_parse_inst_t *)&cmd_read_rxd_txd,
-	(cmdline_parse_inst_t *)&cmd_stop,
-	(cmdline_parse_inst_t *)&cmd_mac_addr,
-	(cmdline_parse_inst_t *)&cmd_set_qmap,
-	(cmdline_parse_inst_t *)&cmd_operate_port,
-	(cmdline_parse_inst_t *)&cmd_operate_specific_port,
-	(cmdline_parse_inst_t *)&cmd_operate_attach_port,
-	(cmdline_parse_inst_t *)&cmd_operate_detach_port,
-	(cmdline_parse_inst_t *)&cmd_config_speed_all,
-	(cmdline_parse_inst_t *)&cmd_config_speed_specific,
-	(cmdline_parse_inst_t *)&cmd_config_rx_tx,
-	(cmdline_parse_inst_t *)&cmd_config_mtu,
-	(cmdline_parse_inst_t *)&cmd_config_max_pkt_len,
-	(cmdline_parse_inst_t *)&cmd_config_rx_mode_flag,
-	(cmdline_parse_inst_t *)&cmd_config_rss,
-	(cmdline_parse_inst_t *)&cmd_config_rxtx_queue,
-	(cmdline_parse_inst_t *)&cmd_config_txqflags,
-	(cmdline_parse_inst_t *)&cmd_config_rss_reta,
-	(cmdline_parse_inst_t *)&cmd_showport_reta,
-	(cmdline_parse_inst_t *)&cmd_config_burst,
-	(cmdline_parse_inst_t *)&cmd_config_thresh,
-	(cmdline_parse_inst_t *)&cmd_config_threshold,
-	(cmdline_parse_inst_t *)&cmd_set_uc_hash_filter,
-	(cmdline_parse_inst_t *)&cmd_set_uc_all_hash_filter,
-	(cmdline_parse_inst_t *)&cmd_vf_mac_addr_filter,
-	(cmdline_parse_inst_t *)&cmd_set_vf_macvlan_filter,
-	(cmdline_parse_inst_t *)&cmd_queue_rate_limit,
-	(cmdline_parse_inst_t *)&cmd_tunnel_filter,
-	(cmdline_parse_inst_t *)&cmd_tunnel_udp_config,
-	(cmdline_parse_inst_t *)&cmd_global_config,
-	(cmdline_parse_inst_t *)&cmd_set_mirror_mask,
-	(cmdline_parse_inst_t *)&cmd_set_mirror_link,
-	(cmdline_parse_inst_t *)&cmd_reset_mirror_rule,
-	(cmdline_parse_inst_t *)&cmd_showport_rss_hash,
-	(cmdline_parse_inst_t *)&cmd_showport_rss_hash_key,
-	(cmdline_parse_inst_t *)&cmd_config_rss_hash_key,
-	(cmdline_parse_inst_t *)&cmd_dump,
-	(cmdline_parse_inst_t *)&cmd_dump_one,
-	(cmdline_parse_inst_t *)&cmd_ethertype_filter,
-	(cmdline_parse_inst_t *)&cmd_syn_filter,
-	(cmdline_parse_inst_t *)&cmd_2tuple_filter,
-	(cmdline_parse_inst_t *)&cmd_5tuple_filter,
-	(cmdline_parse_inst_t *)&cmd_flex_filter,
-	(cmdline_parse_inst_t *)&cmd_add_del_ip_flow_director,
-	(cmdline_parse_inst_t *)&cmd_add_del_udp_flow_director,
-	(cmdline_parse_inst_t *)&cmd_add_del_sctp_flow_director,
-	(cmdline_parse_inst_t *)&cmd_add_del_l2_flow_director,
-	(cmdline_parse_inst_t *)&cmd_add_del_mac_vlan_flow_director,
-	(cmdline_parse_inst_t *)&cmd_add_del_tunnel_flow_director,
-	(cmdline_parse_inst_t *)&cmd_flush_flow_director,
-	(cmdline_parse_inst_t *)&cmd_set_flow_director_ip_mask,
-	(cmdline_parse_inst_t *)&cmd_set_flow_director_mac_vlan_mask,
-	(cmdline_parse_inst_t *)&cmd_set_flow_director_tunnel_mask,
-	(cmdline_parse_inst_t *)&cmd_set_flow_director_flex_mask,
-	(cmdline_parse_inst_t *)&cmd_set_flow_director_flex_payload,
-	(cmdline_parse_inst_t *)&cmd_get_sym_hash_ena_per_port,
-	(cmdline_parse_inst_t *)&cmd_set_sym_hash_ena_per_port,
-	(cmdline_parse_inst_t *)&cmd_get_hash_global_config,
-	(cmdline_parse_inst_t *)&cmd_set_hash_global_config,
-	(cmdline_parse_inst_t *)&cmd_set_hash_input_set,
-	(cmdline_parse_inst_t *)&cmd_set_fdir_input_set,
-	(cmdline_parse_inst_t *)&cmd_flow,
-	(cmdline_parse_inst_t *)&cmd_mcast_addr,
-	(cmdline_parse_inst_t *)&cmd_config_l2_tunnel_eth_type_all,
-	(cmdline_parse_inst_t *)&cmd_config_l2_tunnel_eth_type_specific,
-	(cmdline_parse_inst_t *)&cmd_config_l2_tunnel_en_dis_all,
-	(cmdline_parse_inst_t *)&cmd_config_l2_tunnel_en_dis_specific,
-	(cmdline_parse_inst_t *)&cmd_config_e_tag_insertion_en,
-	(cmdline_parse_inst_t *)&cmd_config_e_tag_insertion_dis,
-	(cmdline_parse_inst_t *)&cmd_config_e_tag_stripping_en_dis,
-	(cmdline_parse_inst_t *)&cmd_config_e_tag_forwarding_en_dis,
-	(cmdline_parse_inst_t *)&cmd_config_e_tag_filter_add,
-	(cmdline_parse_inst_t *)&cmd_config_e_tag_filter_del,
-	(cmdline_parse_inst_t *)&cmd_set_vf_vlan_anti_spoof,
-	(cmdline_parse_inst_t *)&cmd_set_vf_mac_anti_spoof,
-	(cmdline_parse_inst_t *)&cmd_set_vf_vlan_stripq,
-	(cmdline_parse_inst_t *)&cmd_set_vf_vlan_insert,
-	(cmdline_parse_inst_t *)&cmd_set_tx_loopback,
-	(cmdline_parse_inst_t *)&cmd_set_all_queues_drop_en,
-	(cmdline_parse_inst_t *)&cmd_set_vf_split_drop_en,
-	(cmdline_parse_inst_t *)&cmd_set_macsec_offload_on,
-	(cmdline_parse_inst_t *)&cmd_set_macsec_offload_off,
-	(cmdline_parse_inst_t *)&cmd_set_macsec_sc,
-	(cmdline_parse_inst_t *)&cmd_set_macsec_sa,
-	(cmdline_parse_inst_t *)&cmd_set_vf_traffic,
-	(cmdline_parse_inst_t *)&cmd_set_vf_rxmode,
-	(cmdline_parse_inst_t *)&cmd_vf_rate_limit,
-	(cmdline_parse_inst_t *)&cmd_vf_rxvlan_filter,
-	(cmdline_parse_inst_t *)&cmd_set_vf_mac_addr,
-	(cmdline_parse_inst_t *)&cmd_set_vf_promisc,
-	(cmdline_parse_inst_t *)&cmd_set_vf_allmulti,
-	(cmdline_parse_inst_t *)&cmd_set_vf_broadcast,
-	(cmdline_parse_inst_t *)&cmd_set_vf_vlan_tag,
-	(cmdline_parse_inst_t *)&cmd_vf_max_bw,
-	(cmdline_parse_inst_t *)&cmd_vf_tc_min_bw,
-	(cmdline_parse_inst_t *)&cmd_vf_tc_max_bw,
-	(cmdline_parse_inst_t *)&cmd_strict_link_prio,
-	(cmdline_parse_inst_t *)&cmd_tc_min_bw,
-	(cmdline_parse_inst_t *)&cmd_ddp_add,
-	(cmdline_parse_inst_t *)&cmd_ddp_del,
-	(cmdline_parse_inst_t *)&cmd_ddp_get_list,
-	(cmdline_parse_inst_t *)&cmd_ddp_get_info,
-	(cmdline_parse_inst_t *)&cmd_show_vf_stats,
-	(cmdline_parse_inst_t *)&cmd_clear_vf_stats,
-	(cmdline_parse_inst_t *)&cmd_ptype_mapping_get,
-	(cmdline_parse_inst_t *)&cmd_ptype_mapping_replace,
-	(cmdline_parse_inst_t *)&cmd_ptype_mapping_reset,
-	(cmdline_parse_inst_t *)&cmd_ptype_mapping_update,
+/** Display TM Error Message */
+static void
+print_err_msg(struct rte_tm_error *error)
+{
+	static const char *const errstrlist[] = {
+		[RTE_TM_ERROR_TYPE_NONE] = "no error",
+		[RTE_TM_ERROR_TYPE_UNSPECIFIED] = "cause unspecified",
+		[RTE_TM_ERROR_TYPE_CAPABILITIES]
+			= "capability parameter null",
+		[RTE_TM_ERROR_TYPE_LEVEL_ID] = "level id",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE]
+			= "wred profile null",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_GREEN] = "wred profile(green)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_YELLOW]
+			= "wred profile(yellow)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_RED] = "wred profile(red)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_ID] = "wred profile id",
+		[RTE_TM_ERROR_TYPE_SHARED_WRED_CONTEXT_ID]
+			= "shared wred context id",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE] = "shaper profile null",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE]
+			= "committed rate field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE]
+			= "committed size field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE]
+			= "peak rate field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE]
+			= "peak size field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN]
+			= "packet adjust length field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID] = "shaper profile id",
+		[RTE_TM_ERROR_TYPE_SHARED_SHAPER_ID] = "shared shaper id",
+		[RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID] = "parent node id",
+		[RTE_TM_ERROR_TYPE_NODE_PRIORITY] = "node priority",
+		[RTE_TM_ERROR_TYPE_NODE_WEIGHT] = "node weight",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS] = "node parameter null",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID]
+			= "shaper profile id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID]
+			= "shared shaper id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS]
+			= "num shared shapers field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE]
+			= "wfq weght mode field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES]
+			= "num strict priorities field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN]
+			= "congestion management mode field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID] =
+			"wred profile id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID]
+			= "shared wred context id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS]
+			= "num shared wred contexts field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS]
+			= "stats field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_ID] = "node id",
+	};
+
+	const char *errstr;
+	char buf[64];
+
+	if ((unsigned int)error->type >= RTE_DIM(errstrlist) ||
+		!errstrlist[error->type])
+		errstr = "unknown type";
+	else
+		errstr = errstrlist[error->type];
+
+	if (error->cause)
+		snprintf(buf, sizeof(buf), "cause: %p, ", error->cause);
+
+	printf("%s: %s%s (error %d)\n", errstr, error->cause ? buf : "",
+		error->message ? error->message : "(no stated reason)",
+		error->type);
+}
+
+/* *** Port TM Capability *** */
+struct cmd_show_port_tm_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t cap;
+	uint8_t port_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		 port_id, UINT8);
+
+static void cmd_show_port_tm_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_cap_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_capabilities cap;
+	struct rte_tm_error error;
+	uint8_t port_id = res->port_id;
+	uint32_t i;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Softnic tm port */
+	if (port->softport.tm_flag == 0) {
+		printf("  port %u is not a softnic tm port(error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: softnictm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "softnictm")) {
+		printf("  softnictm mode not enabled(error)\n");
+		return;
+	}
+
+	memset(&cap, 0, sizeof(struct rte_tm_capabilities));
+	ret = rte_tm_capabilities_get(port_id, &cap, &error);
+	if (ret) {
+		print_err_msg(&error);
+		return;
+	}
+
+	printf("\n****   Port TM Capabilities ****\n\n");
+	printf("cap.n_nodes_max %u\n", cap.n_nodes_max);
+	printf("cap.n_levels_max %u\n", cap.n_levels_max);
+	printf("cap.non_leaf_nodes_identical %d\n",
+		cap.non_leaf_nodes_identical);
+	printf("cap.leaf_nodes_identical %d\n", cap.leaf_nodes_identical);
+	printf("cap.shaper_n_max %u\n", cap.shaper_n_max);
+	printf("cap.shaper_private_n_max %u\n", cap.shaper_private_n_max);
+	printf("cap.shaper_private_dual_rate_n_max %d\n",
+		cap.shaper_private_dual_rate_n_max);
+	printf("cap.shaper_private_rate_min %lu\n",
+		cap.shaper_private_rate_min);
+	printf("cap.shaper_private_rate_max %lu\n",
+		cap.shaper_private_rate_max);
+	printf("cap.shaper_shared_n_max %u\n", cap.shaper_shared_n_max);
+	printf("cap.shaper_shared_n_nodes_per_shaper_max %u\n",
+		cap.shaper_shared_n_nodes_per_shaper_max);
+	printf("cap.shaper_shared_n_shapers_per_node_max %u\n",
+		cap.shaper_shared_n_shapers_per_node_max);
+	printf("cap.shaper_shared_dual_rate_n_max %u\n",
+		cap.shaper_shared_dual_rate_n_max);
+	printf("cap.shaper_shared_rate_min %lu\n",
+		cap.shaper_shared_rate_min);
+	printf("cap.shaper_shared_rate_max %lu\n",
+		cap.shaper_shared_rate_max);
+	printf("cap.shaper_pkt_length_adjust_min %d\n",
+		cap.shaper_pkt_length_adjust_min);
+	printf("cap.shaper_pkt_length_adjust_max %d\n",
+		cap.shaper_pkt_length_adjust_max);
+	printf("cap.sched_n_children_max %u\n", cap.sched_n_children_max);
+	printf("cap.sched_sp_n_priorities_max %u\n",
+		cap.sched_sp_n_priorities_max);
+	printf("cap.sched_wfq_n_children_per_group_max %u\n",
+		cap.sched_wfq_n_children_per_group_max);
+	printf("cap.sched_wfq_n_groups_max %u\n", cap.sched_wfq_n_groups_max);
+	printf("cap.sched_wfq_weight_max %u\n", cap.sched_wfq_weight_max);
+	printf("cap.cman_head_drop_supported %d\n",
+		cap.cman_head_drop_supported);
+	printf("cap.cman_wred_context_n_max %u\n", cap.cman_wred_context_n_max);
+	printf("cap.cman_wred_context_private_n_max %u\n",
+		cap.cman_wred_context_private_n_max);
+	printf("cap.cman_wred_context_shared_n_max %u\n",
+		cap.cman_wred_context_shared_n_max);
+	printf("cap.cman_wred_context_shared_n_nodes_per_context_max %u\n",
+		cap.cman_wred_context_shared_n_nodes_per_context_max);
+	printf("cap.cman_wred_context_shared_n_contexts_per_node_max %u\n",
+		cap.cman_wred_context_shared_n_contexts_per_node_max);
+
+	for (i = 0; i < RTE_TM_COLORS; i++) {
+		printf("cap.mark_vlan_dei_supported %d\n",
+			cap.mark_vlan_dei_supported[i]);
+		printf("cap.mark_ip_ecn_tcp_supported %d\n",
+			cap.mark_ip_ecn_tcp_supported[i]);
+		printf("cap.mark_ip_ecn_sctp_supported %d\n",
+			cap.mark_ip_ecn_sctp_supported[i]);
+		printf("cap.mark_ip_dscp_supported %d\n",
+			cap.mark_ip_dscp_supported[i]);
+	}
+
+	printf("cap.dynamic_update_mask %lu\n", cap.dynamic_update_mask);
+	printf("cap.stats_mask %lu\n", cap.stats_mask);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_cap = {
+	.f = cmd_show_port_tm_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_cap_show,
+		(void *)&cmd_show_port_tm_cap_port,
+		(void *)&cmd_show_port_tm_cap_tm,
+		(void *)&cmd_show_port_tm_cap_cap,
+		(void *)&cmd_show_port_tm_cap_port_id,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchical Level Capability *** */
+struct cmd_show_port_tm_level_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t level;
+	cmdline_fixed_string_t cap;
+	uint8_t port_id;
+	uint32_t level_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_level =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		level, "level");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_level_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		 port_id, UINT8);
+cmdline_parse_token_num_t cmd_show_port_tm_level_cap_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		 level_id, UINT32);
+
+
+static void cmd_show_port_tm_level_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_level_cap_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_level_capabilities lcap;
+	struct rte_tm_error error;
+	uint8_t port_id = res->port_id;
+	int ret, level_id = res->level_id;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Softnic tm port */
+	if (port->softport.tm_flag == 0) {
+		printf("  port %u is not a softnic tm port(error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: softnictm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "softnictm")) {
+		printf("  softnictm mode not enabled(error)\n");
+		return;
+	}
+
+	if ((level_id > 4) || (level_id < 0)) {
+		printf("  TM hierarchical level invalid !! ");
+		return;
+	}
+
+	memset(&lcap, 0, sizeof(struct rte_tm_level_capabilities));
+	ret = rte_tm_level_capabilities_get(port_id, level_id, &lcap, &error);
+	if (ret) {
+		print_err_msg(&error);
+		return;
+	}
+	printf("\n****   Port TM Hierarchy level %u Capability ****\n\n",
+		level_id);
+
+	printf("cap.n_nodes_max %u\n", lcap.n_nodes_max);
+	printf("cap.n_nodes_nonleaf_max %u\n", lcap.n_nodes_nonleaf_max);
+	printf("cap.n_nodes_leaf_max %u\n", lcap.n_nodes_leaf_max);
+	printf("cap.non_leaf_nodes_identical %d\n",
+		lcap.non_leaf_nodes_identical);
+	printf("cap.leaf_nodes_identical %d\n", lcap.leaf_nodes_identical);
+	if (level_id <= 3) {
+		printf("cap.nonleaf.shaper_private_supported %d\n",
+			lcap.nonleaf.shaper_private_supported);
+		printf("cap.nonleaf.shaper_private_dual_rate_supported %d\n",
+			lcap.nonleaf.shaper_private_dual_rate_supported);
+		printf("cap.nonleaf.shaper_private_rate_min %lu\n",
+			lcap.nonleaf.shaper_private_rate_min);
+		printf("cap.nonleaf.shaper_private_rate_max %lu\n",
+			lcap.nonleaf.shaper_private_rate_max);
+		printf("cap.nonleaf.shaper_shared_n_max %u\n",
+			lcap.nonleaf.shaper_shared_n_max);
+		printf("cap.nonleaf.sched_n_children_max %u\n",
+			lcap.nonleaf.sched_n_children_max);
+		printf("cap.nonleaf.sched_sp_n_priorities_max %u\n",
+			lcap.nonleaf.sched_sp_n_priorities_max);
+		printf("cap.nonleaf.sched_wfq_n_children_per_group_max %u\n",
+			lcap.nonleaf.sched_wfq_n_children_per_group_max);
+		printf("cap.nonleaf.sched_wfq_n_groups_max %u\n",
+			lcap.nonleaf.sched_wfq_n_groups_max);
+		printf("cap.nonleaf.sched_wfq_weight_max %u\n",
+			lcap.nonleaf.sched_wfq_weight_max);
+		printf("cap.nonleaf.stats_mask %lu\n", lcap.nonleaf.stats_mask);
+	} else {
+		printf("cap.leaf.shaper_private_supported %d\n",
+			lcap.leaf.shaper_private_supported);
+		printf("cap.leaf.shaper_private_dual_rate_supported %d\n",
+			lcap.leaf.shaper_private_dual_rate_supported);
+		printf("cap.leaf.shaper_private_rate_min %lu\n",
+			lcap.leaf.shaper_private_rate_min);
+		printf("cap.leaf.shaper_private_rate_max %lu\n",
+			lcap.leaf.shaper_private_rate_max);
+		printf("cap.leaf.shaper_shared_n_max %u\n",
+			lcap.leaf.shaper_shared_n_max);
+		printf("cap.leaf.cman_head_drop_supported %d\n",
+			lcap.leaf.cman_head_drop_supported);
+		printf("cap.leaf.cman_wred_context_private_supported %d\n",
+			lcap.leaf.cman_wred_context_private_supported);
+		printf("cap.leaf.cman_wred_context_shared_n_max %u\n",
+			lcap.leaf.cman_wred_context_shared_n_max);
+		printf("cap.leaf.stats_mask %lu\n",
+			lcap.leaf.stats_mask);
+	}
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_level_cap = {
+	.f = cmd_show_port_tm_level_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Hierarhical level Capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_level_cap_show,
+		(void *)&cmd_show_port_tm_level_cap_port,
+		(void *)&cmd_show_port_tm_level_cap_tm,
+		(void *)&cmd_show_port_tm_level_cap_level,
+		(void *)&cmd_show_port_tm_level_cap_cap,
+		(void *)&cmd_show_port_tm_level_cap_port_id,
+		(void *)&cmd_show_port_tm_level_cap_level_id,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchy Node Capability *** */
+struct cmd_show_port_tm_node_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t cap;
+	uint8_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_node =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_node_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		 port_id, UINT8);
+cmdline_parse_token_num_t cmd_show_port_tm_node_cap_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		 node_id, UINT32);
+
+static void cmd_show_port_tm_node_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_cap_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_node_capabilities ncap;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint8_t port_id = res->port_id;
+	int ret, is_leaf = 0;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Softnic tm port */
+	if (port->softport.tm_flag == 0) {
+		printf("  port %u is not a softnic tm port(error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: softnictm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "softnictm")) {
+		printf("  softnictm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Node id must be valid */
+	ret = rte_tm_node_type_get(port_id, node_id, &is_leaf, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	memset(&ncap, 0, sizeof(struct rte_tm_node_capabilities));
+	ret = rte_tm_node_capabilities_get(port_id, node_id, &ncap, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+	printf("\n****   Port TM Hierarchy node %u Capability ****\n\n",
+		node_id);
+	printf("cap.shaper_private_supported %d\n",
+		ncap.shaper_private_supported);
+	printf("cap.shaper_private_dual_rate_supported %d\n",
+		ncap.shaper_private_dual_rate_supported);
+	printf("cap.shaper_private_rate_min %lu\n",
+		ncap.shaper_private_rate_min);
+	printf("cap.shaper_private_rate_max %lu\n",
+		ncap.shaper_private_rate_max);
+	printf("cap.shaper_shared_n_max %u\n",
+		ncap.shaper_shared_n_max);
+	if (!is_leaf) {
+		printf("cap.nonleaf.sched_n_children_max %u\n",
+			ncap.nonleaf.sched_n_children_max);
+		printf("cap.nonleaf.sched_sp_n_priorities_max %u\n",
+			ncap.nonleaf.sched_sp_n_priorities_max);
+		printf("cap.nonleaf.sched_wfq_n_children_per_group_max %u\n",
+			ncap.nonleaf.sched_wfq_n_children_per_group_max);
+		printf("cap.nonleaf.sched_wfq_n_groups_max %u\n",
+			ncap.nonleaf.sched_wfq_n_groups_max);
+		printf("cap.nonleaf.sched_wfq_weight_max %u\n",
+			ncap.nonleaf.sched_wfq_weight_max);
+	} else {
+		printf("cap.leaf.cman_head_drop_supported %d\n",
+			ncap.leaf.cman_head_drop_supported);
+		printf("cap.leaf.cman_wred_context_private_supported %d\n",
+			ncap.leaf.cman_wred_context_private_supported);
+		printf("cap.leaf.cman_wred_context_shared_n_max %u\n",
+			ncap.leaf.cman_wred_context_shared_n_max);
+	}
+	printf("cap.stats_mask %lu\n", ncap.stats_mask);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_cap = {
+	.f = cmd_show_port_tm_node_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Hierarchy node capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_cap_show,
+		(void *)&cmd_show_port_tm_node_cap_port,
+		(void *)&cmd_show_port_tm_node_cap_tm,
+		(void *)&cmd_show_port_tm_node_cap_node,
+		(void *)&cmd_show_port_tm_node_cap_cap,
+		(void *)&cmd_show_port_tm_node_cap_port_id,
+		(void *)&cmd_show_port_tm_node_cap_node_id,
+		NULL,
+	},
+};
+
+/* *** Add Port TM Private Shaper Profile *** */
+struct cmd_add_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint8_t port_id;
+	uint32_t shaper_id;
+	uint64_t tb_rate;
+	uint64_t tb_size;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_tb_rate =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tb_rate, UINT64);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_tb_size =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tb_size, UINT64);
+
+static void cmd_add_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_shaper_params sp;
+	struct rte_tm_error error;
+	uint32_t shaper_id = res->shaper_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Softnic tm port */
+	if (port->softport.tm_flag == 0) {
+		printf("  port %u is not a softnic tm port(error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: softnictm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "softnictm")) {
+		printf("  softnictm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Private shaper profile params */
+	memset(&sp, 0, sizeof(struct rte_tm_shaper_params));
+	sp.peak.rate = res->tb_rate;
+	sp.peak.size = res->tb_size;
+	sp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+	ret = rte_tm_shaper_profile_add(port_id, shaper_id, &sp, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_shaper_profile = {
+	.f = cmd_add_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Add port tm node private shaper profile",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_shaper_profile_add,
+		(void *)&cmd_add_port_tm_node_shaper_profile_port,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_add_port_tm_node_shaper_profile_node,
+		(void *)&cmd_add_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_add_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_add_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_add_port_tm_node_shaper_profile_shaper_id,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tb_rate,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tb_size,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM Private Shaper Profile *** */
+struct cmd_del_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint8_t port_id;
+	uint32_t shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_del_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_del_port_tm_node_shaper_profile_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			shaper_id, UINT32);
+
+static void cmd_del_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_error error;
+	uint32_t shaper_id = res->shaper_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Softnic tm port */
+	if (port->softport.tm_flag == 0) {
+		printf("  port %u is not a softnic tm port(error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: softnictm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "softnictm")) {
+		printf("  softnictm mode not enabled(error)\n");
+		return;
+	}
+
+	ret = rte_tm_shaper_profile_delete(port_id, shaper_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_shaper_profile = {
+	.f = cmd_del_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node private shaper profile",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_shaper_profile_del,
+		(void *)&cmd_del_port_tm_node_shaper_profile_port,
+		(void *)&cmd_del_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_del_port_tm_node_shaper_profile_node,
+		(void *)&cmd_del_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_del_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_del_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_del_port_tm_node_shaper_profile_shaper_id,
+		NULL,
+	},
+};
+
+/* *** Add/Update Port TM shared Shaper *** */
+struct cmd_add_port_tm_node_shared_shaper_result {
+	cmdline_fixed_string_t cmd_type;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shared;
+	cmdline_fixed_string_t shaper;
+	uint8_t port_id;
+	uint32_t shared_shaper_id;
+	uint32_t shaper_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_cmd_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			cmd_type, "add#set");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_shared =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shared, "shared");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shaper, "shaper");
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shared_shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shaper_profile_id, UINT32);
+
+static void cmd_add_port_tm_node_shared_shaper_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_shared_shaper_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_error error;
+	struct rte_eth_link link;
+	uint32_t shared_shaper_id = res->shared_shaper_id;
+	uint32_t shaper_profile_id = res->shaper_profile_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+	memset(&link, 0, sizeof(link));
+
+	/* Softnic tm port */
+	if (port->softport.tm_flag == 0) {
+		printf("  port %u is not a softnic tm port(error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: softnictm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "softnictm")) {
+		printf("  softnictm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Command type: add */
+	if (strcmp(res->cmd_type, "add") == 0) {
+		/* Port link status */
+		rte_eth_link_get_nowait(port_id, &link);
+		if (link.link_status == ETH_LINK_UP) {
+			printf(" Port %u link up (error)\n", port_id);
+			return;
+		}
+
+		/* TM hierarchy status */
+		if (port->softport.tm.hierarchy_frozen == 1)
+			port->softport.tm.hierarchy_frozen = 0;
+	}
+
+	/* Command type: set (update) */
+	if (strcmp(res->cmd_type, "set") == 0) {
+		/* TM hierarchy status */
+		if (port->softport.tm.hierarchy_frozen == 0) {
+			printf(" hierarchy not frozen (error)\n");
+			return;
+		}
+
+		rte_eth_link_get_nowait(port_id, &link);
+		if (link.link_status == ETH_LINK_DOWN) {
+			printf(" Port %u link down (error)\n", port_id);
+			return;
+		}
+	}
+
+	ret = rte_tm_shared_shaper_add_update(port_id, shared_shaper_id,
+		shaper_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_shared_shaper = {
+	.f = cmd_add_port_tm_node_shared_shaper_parsed,
+	.data = NULL,
+	.help_str = "add/update port tm node shared shaper",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_shared_shaper_cmd_type,
+		(void *)&cmd_add_port_tm_node_shared_shaper_port,
+		(void *)&cmd_add_port_tm_node_shared_shaper_tm,
+		(void *)&cmd_add_port_tm_node_shared_shaper_node,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shared,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shaper,
+		(void *)&cmd_add_port_tm_node_shared_shaper_port_id,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shared_shaper_id,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shaper_profile_id,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM shared Shaper *** */
+struct cmd_del_port_tm_node_shared_shaper_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shared;
+	cmdline_fixed_string_t shaper;
+	uint8_t port_id;
+	uint32_t shared_shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_shared =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shared, "shared");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shaper, "shaper");
+cmdline_parse_token_num_t cmd_del_port_tm_node_shared_shaper_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_del_port_tm_node_shared_shaper_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shared_shaper_id, UINT32);
+
+static void cmd_del_port_tm_node_shared_shaper_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_shared_shaper_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_error error;
+	uint32_t shared_shaper_id = res->shared_shaper_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Softnic tm port */
+	if (port->softport.tm_flag == 0) {
+		printf("  port %u is not a softnic tm port(error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: softnictm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "softnictm")) {
+		printf("  softnictm mode not enabled(error)\n");
+		return;
+	}
+
+	ret = rte_tm_shared_shaper_delete(port_id, shared_shaper_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper = {
+	.f = cmd_del_port_tm_node_shared_shaper_parsed,
+	.data = NULL,
+	.help_str = "delete port tm node shared shaper",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_shared_shaper_del,
+		(void *)&cmd_del_port_tm_node_shared_shaper_port,
+		(void *)&cmd_del_port_tm_node_shared_shaper_tm,
+		(void *)&cmd_del_port_tm_node_shared_shaper_node,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shared,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shaper,
+		(void *)&cmd_del_port_tm_node_shared_shaper_port_id,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shared_shaper_id,
+		NULL,
+	},
+};
+
+/* *** Add Port TM Node WRED Profile *** */
+struct cmd_add_port_tm_node_wred_profile_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t wred;
+	cmdline_fixed_string_t profile;
+	uint8_t port_id;
+	uint32_t wred_profile_id;
+	cmdline_fixed_string_t color_g;
+	uint16_t min_th_g;
+	uint16_t max_th_g;
+	uint16_t maxp_inv_g;
+	uint16_t wq_log2_g;
+	cmdline_fixed_string_t color_y;
+	uint16_t min_th_y;
+	uint16_t max_th_y;
+	uint16_t maxp_inv_y;
+	uint16_t wq_log2_y;
+	cmdline_fixed_string_t color_r;
+	uint16_t min_th_r;
+	uint16_t max_th_r;
+	uint16_t maxp_inv_r;
+	uint16_t wq_log2_r;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_wred =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, wred, "wred");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wred_profile_id, UINT32);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_g =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_g, "G#g");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_g, UINT16);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_y =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_y, "Y#y");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_y, UINT16);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_r =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_r, "R#r");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_r, UINT16);
+
+
+static void cmd_add_port_tm_node_wred_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_wred_profile_result *res = parsed_result;
+	struct rte_tm_wred_params wp;
+	enum rte_tm_color color;
+	struct rte_port *port;
+	struct rte_tm_error error;
+	uint32_t wred_profile_id = res->wred_profile_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Softnic tm port */
+	if (port->softport.tm_flag == 0) {
+		printf("  port %u is not a softnic tm port(error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: softnictm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "softnictm")) {
+		printf("  softnictm mode not enabled(error)\n");
+		return;
+	}
+
+	memset(&wp, 0, sizeof(struct rte_tm_wred_params));
+
+	/* WRED Params  (Green Color)*/
+	if ((strcmp(res->color_g, "G") == 0) ||
+		(strcmp(res->color_g, "g") == 0)) {
+		color = RTE_TM_GREEN;
+		wp.red_params[color].min_th = res->min_th_g;
+		wp.red_params[color].max_th = res->max_th_g;
+		wp.red_params[color].maxp_inv = res->maxp_inv_g;
+		wp.red_params[color].wq_log2 = res->wq_log2_g;
+	} else {
+		printf("WRED profile error(G or g for green color)!\n");
+		return;
+	}
+
+	/* WRED Params  (Yellow Color)*/
+	if ((strcmp(res->color_y, "Y") == 0) ||
+		(strcmp(res->color_y, "y") == 0)) {
+		color = RTE_TM_YELLOW;
+		wp.red_params[color].min_th = res->min_th_y;
+		wp.red_params[color].max_th = res->max_th_y;
+		wp.red_params[color].maxp_inv = res->maxp_inv_y;
+		wp.red_params[color].wq_log2 = res->wq_log2_y;
+	} else {
+		printf("WRED profile error(Y or y for yellow color)!\n");
+		return;
+	}
+
+	/* WRED Params  (Red Color)*/
+	if ((strcmp(res->color_r, "R") == 0) ||
+		(strcmp(res->color_r, "r") == 0)) {
+		color = RTE_TM_RED;
+		wp.red_params[color].min_th = res->min_th_r;
+		wp.red_params[color].max_th = res->max_th_r;
+		wp.red_params[color].maxp_inv = res->maxp_inv_r;
+		wp.red_params[color].wq_log2 = res->wq_log2_r;
+	} else {
+		printf("WRED profile error(R or r for red color)!\n");
+		return;
+	}
+
+	ret = rte_tm_wred_profile_add(port_id, wred_profile_id, &wp, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile = {
+	.f = cmd_add_port_tm_node_wred_profile_parsed,
+	.data = NULL,
+	.help_str = "Add port tm node wred profile",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_wred_profile_add,
+		(void *)&cmd_add_port_tm_node_wred_profile_port,
+		(void *)&cmd_add_port_tm_node_wred_profile_tm,
+		(void *)&cmd_add_port_tm_node_wred_profile_node,
+		(void *)&cmd_add_port_tm_node_wred_profile_wred,
+		(void *)&cmd_add_port_tm_node_wred_profile_profile,
+		(void *)&cmd_add_port_tm_node_wred_profile_port_id,
+		(void *)&cmd_add_port_tm_node_wred_profile_wred_profile_id,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_r,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM node WRED Profile *** */
+struct cmd_del_port_tm_node_wred_profile_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t wred;
+	cmdline_fixed_string_t profile;
+	uint8_t port_id;
+	uint32_t wred_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_wred =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, wred, "wred");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_del_port_tm_node_wred_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_del_port_tm_node_wred_profile_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			wred_profile_id, UINT32);
+
+static void cmd_del_port_tm_node_wred_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_wred_profile_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_error error;
+	uint32_t wred_profile_id = res->wred_profile_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Softnic tm port */
+	if (port->softport.tm_flag == 0) {
+		printf("  port %u is not a softnic tm port(error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: softnictm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "softnictm")) {
+		printf("  softnictm mode not enabled(error)\n");
+		return;
+	}
+
+	ret = rte_tm_wred_profile_delete(port_id, wred_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile = {
+	.f = cmd_del_port_tm_node_wred_profile_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node wred profile",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_wred_profile_del,
+		(void *)&cmd_del_port_tm_node_wred_profile_port,
+		(void *)&cmd_del_port_tm_node_wred_profile_tm,
+		(void *)&cmd_del_port_tm_node_wred_profile_node,
+		(void *)&cmd_del_port_tm_node_wred_profile_wred,
+		(void *)&cmd_del_port_tm_node_wred_profile_profile,
+		(void *)&cmd_del_port_tm_node_wred_profile_port_id,
+		(void *)&cmd_del_port_tm_node_wred_profile_wred_profile_id,
+		NULL,
+	},
+};
+
+/* *** Add Port TM nonleaf node *** */
+struct cmd_add_port_tm_nonleaf_node_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t nonleaf;
+	cmdline_fixed_string_t node;
+	uint8_t port_id;
+	uint32_t node_id;
+	int32_t parent_node_id;
+	uint32_t priority;
+	uint32_t weight;
+	uint32_t level_id;
+	uint32_t shaper_profile_id;
+	uint32_t shared_shaper_id;
+	uint32_t n_shared_shapers;
+	uint32_t n_sp_priorities;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_nonleaf =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, nonleaf, "nonleaf");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, node, "node");
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result,
+		 port_id, UINT8);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 node_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 parent_node_id, INT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 priority, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 weight, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 level_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 shaper_profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 shared_shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_n_shared_shapers =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 n_shared_shapers, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_n_sp_priorities =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 n_sp_priorities, UINT32);
+
+static void cmd_add_port_tm_nonleaf_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_nonleaf_node_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_eth_link link;
+	struct rte_tm_error error;
+	struct rte_tm_node_params np;
+	uint32_t parent_node_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Softnic tm port */
+	if (port->softport.tm_flag == 0) {
+		printf("  port %u is not a softnic tm port(error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: softnictm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "softnictm")) {
+		printf("  softnictm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Port link status */
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get_nowait(port_id, &link);
+	if (link.link_status == ETH_LINK_UP) {
+		printf(" Port %u link up (error)\n", port_id);
+		return;
+	}
+
+	/* TM hierarchy status */
+	if (port->softport.tm.hierarchy_frozen == 1)
+		port->softport.tm.hierarchy_frozen = 0;
+
+	/* Node parameters */
+	if (res->parent_node_id < 0)
+		parent_node_id = UINT32_MAX;
+	else
+		parent_node_id = res->parent_node_id;
+
+	memset(&np, 0, sizeof(struct rte_tm_node_params));
+	np.shaper_profile_id = res->shaper_profile_id;
+	np.n_shared_shapers = res->n_shared_shapers;
+	np.shared_shaper_id = &res->shared_shaper_id;
+	np.nonleaf.n_sp_priorities = res->n_sp_priorities;
+	np.nonleaf.wfq_weight_mode = NULL;
+	np.stats_mask = RTE_TM_STATS_N_PKTS |
+		RTE_TM_STATS_N_BYTES |
+		RTE_TM_STATS_N_PKTS_GREEN_DROPPED |
+		RTE_TM_STATS_N_BYTES_GREEN_DROPPED;
+
+	ret = rte_tm_node_add(port_id, res->node_id, parent_node_id,
+				res->priority, res->weight, res->level_id,
+				&np, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_nonleaf_node = {
+	.f = cmd_add_port_tm_nonleaf_node_parsed,
+	.data = NULL,
+	.help_str = "Add port tm nonleaf node",
+	.tokens = {
+		(void *)&cmd_add_port_tm_nonleaf_node_add,
+		(void *)&cmd_add_port_tm_nonleaf_node_port,
+		(void *)&cmd_add_port_tm_nonleaf_node_tm,
+		(void *)&cmd_add_port_tm_nonleaf_node_nonleaf,
+		(void *)&cmd_add_port_tm_nonleaf_node_node,
+		(void *)&cmd_add_port_tm_nonleaf_node_port_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_node_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_parent_node_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_priority,
+		(void *)&cmd_add_port_tm_nonleaf_node_weight,
+		(void *)&cmd_add_port_tm_nonleaf_node_level_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_shaper_profile_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_shared_shaper_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_n_shared_shapers,
+		(void *)&cmd_add_port_tm_nonleaf_node_n_sp_priorities,
+		NULL,
+	},
+};
+
+/* *** Add Port TM leaf node *** */
+struct cmd_add_port_tm_leaf_node_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t leaf;
+	cmdline_fixed_string_t node;
+	uint8_t port_id;
+	uint32_t node_id;
+	int32_t parent_node_id;
+	uint32_t priority;
+	uint32_t weight;
+	uint32_t level_id;
+	uint32_t cman_mode;
+	uint32_t wred_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_nonleaf =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, leaf, "leaf");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, node, "node");
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 port_id, UINT8);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 node_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 parent_node_id, INT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 priority, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 weight, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 level_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_cman_mode =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 cman_mode, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 wred_profile_id, UINT32);
+
+static void cmd_add_port_tm_leaf_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_leaf_node_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_eth_link link;
+	struct rte_tm_error error;
+	struct rte_tm_node_params np;
+	uint32_t parent_node_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Softnic tm port */
+	if (port->softport.tm_flag == 0) {
+		printf("  port %u is not a softnic tm port(error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: softnictm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "softnictm")) {
+		printf("  softnictm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Port link status */
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get_nowait(port_id, &link);
+	if (link.link_status == ETH_LINK_UP) {
+		printf(" Port %u link up (error)\n", port_id);
+		return;
+	}
+
+	/* TM hierarchy status */
+	if (port->softport.tm.hierarchy_frozen == 1)
+		port->softport.tm.hierarchy_frozen = 0;
+
+	/* Node parameters */
+	if (res->parent_node_id < 0)
+		parent_node_id = UINT32_MAX;
+	else
+		parent_node_id = res->parent_node_id;
+
+	memset(&np, 0, sizeof(struct rte_tm_node_params));
+	np.shaper_profile_id = RTE_TM_SHAPER_PROFILE_ID_NONE;
+	np.n_shared_shapers = 0;
+	np.leaf.cman = res->cman_mode;
+	np.leaf.wred.wred_profile_id = res->wred_profile_id;
+	np.stats_mask = RTE_TM_STATS_N_PKTS |
+		RTE_TM_STATS_N_BYTES |
+		RTE_TM_STATS_N_PKTS_GREEN_DROPPED |
+		RTE_TM_STATS_N_BYTES_GREEN_DROPPED |
+		RTE_TM_STATS_N_PKTS_QUEUED;
+
+	ret = rte_tm_node_add(port_id, res->node_id, parent_node_id,
+				res->priority, res->weight, res->level_id,
+				&np, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_leaf_node = {
+	.f = cmd_add_port_tm_leaf_node_parsed,
+	.data = NULL,
+	.help_str = "Add port tm leaf node",
+	.tokens = {
+		(void *)&cmd_add_port_tm_leaf_node_add,
+		(void *)&cmd_add_port_tm_leaf_node_port,
+		(void *)&cmd_add_port_tm_leaf_node_tm,
+		(void *)&cmd_add_port_tm_leaf_node_nonleaf,
+		(void *)&cmd_add_port_tm_leaf_node_node,
+		(void *)&cmd_add_port_tm_leaf_node_port_id,
+		(void *)&cmd_add_port_tm_leaf_node_node_id,
+		(void *)&cmd_add_port_tm_leaf_node_parent_node_id,
+		(void *)&cmd_add_port_tm_leaf_node_priority,
+		(void *)&cmd_add_port_tm_leaf_node_weight,
+		(void *)&cmd_add_port_tm_leaf_node_level_id,
+		(void *)&cmd_add_port_tm_leaf_node_cman_mode,
+		(void *)&cmd_add_port_tm_leaf_node_wred_profile_id,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM Node *** */
+struct cmd_del_port_tm_node_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	uint8_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, node, "node");
+cmdline_parse_token_num_t cmd_del_port_tm_node_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_del_port_tm_node_result,
+		 port_id, UINT8);
+cmdline_parse_token_num_t cmd_del_port_tm_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_del_port_tm_node_result,
+		node_id, UINT32);
+
+static void cmd_del_port_tm_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_eth_link link;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Softnic tm port */
+	if (port->softport.tm_flag == 0) {
+		printf("  port %u is not a softnic tm port(error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: softnictm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "softnictm")) {
+		printf("  softnictm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Port link status */
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get_nowait(port_id, &link);
+	if (link.link_status == ETH_LINK_UP) {
+		printf(" Port %u link up (error)\n", port_id);
+		return;
+	}
+
+	/* TM hierarchy status */
+	if (port->softport.tm.hierarchy_frozen == 1)
+		port->softport.tm.hierarchy_frozen = 0;
+
+	ret = rte_tm_node_delete(port_id, node_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node = {
+	.f = cmd_del_port_tm_node_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_del,
+		(void *)&cmd_del_port_tm_node_port,
+		(void *)&cmd_del_port_tm_node_tm,
+		(void *)&cmd_del_port_tm_node_node,
+		(void *)&cmd_del_port_tm_node_port_id,
+		(void *)&cmd_del_port_tm_node_node_id,
+		NULL,
+	},
+};
+
+/* *** Show Port TM Node Type *** */
+struct cmd_show_port_tm_node_type_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t type;
+	uint8_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_show =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, type, "type");
+cmdline_parse_token_num_t cmd_show_port_tm_node_type_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_show_port_tm_node_type_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result,
+			node_id, UINT32);
+
+static void cmd_show_port_tm_node_type_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_type_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint8_t port_id = res->port_id;
+	int ret, is_leaf = 0;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Softnic tm port */
+	if (port->softport.tm_flag == 0) {
+		printf("  port %u is not a softnic tm port(error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: softnictm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "softnictm")) {
+		printf("  softnictm mode not enabled(error)\n");
+		return;
+	}
+
+	ret = rte_tm_node_type_get(port_id, node_id, &is_leaf, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	if (is_leaf == 1)
+		printf("leaf node\n");
+	else
+		printf("nonleaf node\n");
+
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_type = {
+	.f = cmd_show_port_tm_node_type_parsed,
+	.data = NULL,
+	.help_str = "Show port tm node type",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_type_show,
+		(void *)&cmd_show_port_tm_node_type_port,
+		(void *)&cmd_show_port_tm_node_type_tm,
+		(void *)&cmd_show_port_tm_node_type_node,
+		(void *)&cmd_show_port_tm_node_type_type,
+		(void *)&cmd_show_port_tm_node_type_port_id,
+		(void *)&cmd_show_port_tm_node_type_node_id,
+		NULL,
+	},
+};
+
+/* *** Show Port TM Node Statistics *** */
+struct cmd_show_port_tm_node_stats_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t stats;
+	uint8_t port_id;
+	uint32_t node_id;
+	uint32_t clear;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_show =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_stats =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, stats, "stats");
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_stats_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result,
+			node_id, UINT32);
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_clear =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, clear, UINT32);
+
+static void cmd_show_port_tm_node_stats_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_stats_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_eth_link link;
+	struct rte_tm_node_stats stats;
+	struct rte_tm_error error;
+	uint64_t stats_mask = 0, leaf_stats_mask;
+	uint32_t node_id = res->node_id;
+	uint32_t clear = res->clear;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Softnic tm port */
+	if (port->softport.tm_flag == 0) {
+		printf("  port %u is not a softnic tm port(error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: softnictm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "softnictm")) {
+		printf("  softnictm mode not enabled(error)\n");
+		return;
+	}
+
+	/* TM hierarchy status */
+	if (port->softport.tm.hierarchy_frozen == 0) {
+		printf(" hierarchy not frozen(error)\n");
+		return;
+	}
+
+	/* Port link status */
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get_nowait(port_id, &link);
+	if (link.link_status == ETH_LINK_DOWN) {
+		printf(" Port %u link down (error)\n", port_id);
+		return;
+	}
+
+	memset(&stats, 0, sizeof(struct rte_tm_node_stats));
+	ret = rte_tm_node_stats_read(port_id, node_id, &stats,
+			&stats_mask, clear, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	leaf_stats_mask = RTE_TM_STATS_N_PKTS |
+		RTE_TM_STATS_N_BYTES |
+		RTE_TM_STATS_N_PKTS_GREEN_DROPPED |
+		RTE_TM_STATS_N_BYTES_GREEN_DROPPED |
+		RTE_TM_STATS_N_PKTS_QUEUED;
+
+	printf("pkts scheduled from node %lu\n", stats.n_pkts);
+	printf("bytes scheduled from node %lu\n", stats.n_bytes);
+	printf("pkts dropped %lu\n ", stats.leaf.n_pkts_dropped[RTE_TM_GREEN]);
+	printf("bytes dropped %lu\n ",
+		stats.leaf.n_bytes_dropped[RTE_TM_GREEN]);
+
+	if (stats_mask == leaf_stats_mask)
+		printf("packets enqueued %lu\n", stats.leaf.n_pkts_queued);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_stats = {
+	.f = cmd_show_port_tm_node_stats_parsed,
+	.data = NULL,
+	.help_str = "Show port tm node stats",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_stats_show,
+		(void *)&cmd_show_port_tm_node_stats_port,
+		(void *)&cmd_show_port_tm_node_stats_tm,
+		(void *)&cmd_show_port_tm_node_stats_node,
+		(void *)&cmd_show_port_tm_node_stats_stats,
+		(void *)&cmd_show_port_tm_node_stats_port_id,
+		(void *)&cmd_show_port_tm_node_stats_node_id,
+		(void *)&cmd_show_port_tm_node_stats_clear,
+		NULL,
+	},
+};
+
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+/* *** Update Port TM Node Parent *** */
+struct cmd_set_port_tm_node_parent_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t parent;
+	uint8_t port_id;
+	uint32_t node_id;
+	uint32_t parent_id;
+	uint32_t priority;
+	uint32_t weight;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, node, "node");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_parent =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, parent, "parent");
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, port_id, UINT8);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, node_id, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_parent_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		parent_id, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		priority, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		weight, UINT32);
+
+static void cmd_set_port_tm_node_parent_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_node_parent_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_eth_link link;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint32_t parent_id = res->parent_id;
+	uint32_t priority = res->priority;
+	uint32_t weight = res->weight;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Softnic tm port */
+	if (port->softport.tm_flag == 0) {
+		printf("  port %u is not a softnic tm port(error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: softnictm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "softnictm")) {
+		printf("  softnictm mode not enabled(error)\n");
+		return;
+	}
+
+	/* TM hierarchy status */
+	if (port->softport.tm.hierarchy_frozen == 0) {
+		printf(" hierarchy not frozen(error)\n");
+		return;
+	}
+
+	/* Port link status */
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get_nowait(port_id, &link);
+	if (link.link_status == ETH_LINK_DOWN) {
+		printf(" Port %u link down (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_parent_update(port_id, node_id,
+		parent_id, priority, weight, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_node_parent = {
+	.f = cmd_set_port_tm_node_parent_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node parent",
+	.tokens = {
+		(void *)&cmd_set_port_tm_node_parent_set,
+		(void *)&cmd_set_port_tm_node_parent_port,
+		(void *)&cmd_set_port_tm_node_parent_tm,
+		(void *)&cmd_set_port_tm_node_parent_node,
+		(void *)&cmd_set_port_tm_node_parent_parent,
+		(void *)&cmd_set_port_tm_node_parent_port_id,
+		(void *)&cmd_set_port_tm_node_parent_node_id,
+		(void *)&cmd_set_port_tm_node_parent_parent_id,
+		(void *)&cmd_set_port_tm_node_parent_priority,
+		(void *)&cmd_set_port_tm_node_parent_weight,
+		NULL,
+	},
+};
+#endif
+
+/* *** Update Port TM Node Shaper profile *** */
+struct cmd_set_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint8_t port_id;
+	uint32_t node_id;
+	uint32_t shaper_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_set_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_set_port_tm_node_shaper_profile_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_shaper_profile_result,
+		node_id, UINT32);
+cmdline_parse_token_num_t
+	cmd_set_port_tm_node_shaper_shaper_profile_profile_id =
+		TOKEN_NUM_INITIALIZER(
+			struct cmd_set_port_tm_node_shaper_profile_result,
+			shaper_profile_id, UINT32);
+
+static void cmd_set_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_eth_link link;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint32_t shaper_profile_id = res->shaper_profile_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Softnic tm port */
+	if (port->softport.tm_flag == 0) {
+		printf("  port %u is not a softnic tm port(error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: softnictm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "softnictm")) {
+		printf("  softnictm mode not enabled(error)\n");
+		return;
+	}
+
+	/* TM hierarchy status */
+	if (port->softport.tm.hierarchy_frozen == 0) {
+		printf(" hierarchy not frozen(error)\n");
+		return;
+	}
+
+	/* Port link status */
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get_nowait(port_id, &link);
+	if (link.link_status == ETH_LINK_DOWN) {
+		printf(" Port %u link down (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_shaper_update(port_id, node_id,
+		shaper_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile = {
+	.f = cmd_set_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node shaper profile",
+	.tokens = {
+		(void *)&cmd_set_port_tm_node_shaper_profile_set,
+		(void *)&cmd_set_port_tm_node_shaper_profile_port,
+		(void *)&cmd_set_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_set_port_tm_node_shaper_profile_node,
+		(void *)&cmd_set_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_set_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_set_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_set_port_tm_node_shaper_profile_node_id,
+		(void *)&cmd_set_port_tm_node_shaper_shaper_profile_profile_id,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchy Commit *** */
+struct cmd_port_tm_hierarchy_commit_result {
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t hierarchy;
+	cmdline_fixed_string_t commit;
+	uint8_t port_id;
+	uint32_t clean_on_fail;
+};
+
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, port, "port");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, tm, "tm");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_hierarchy =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result,
+			hierarchy, "hierarchy");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_commit =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, commit, "commit");
+cmdline_parse_token_num_t cmd_port_tm_hierarchy_commit_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_port_tm_hierarchy_commit_clean_on_fail =
+	TOKEN_NUM_INITIALIZER(struct cmd_port_tm_hierarchy_commit_result,
+		 clean_on_fail, UINT32);
+
+static void cmd_port_tm_hierarchy_commit_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_port_tm_hierarchy_commit_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_eth_link link;
+	struct rte_tm_error error;
+	uint32_t clean_on_fail = res->clean_on_fail;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Softnic tm port */
+	if (port->softport.tm_flag == 0) {
+		printf("  port %u is not a softnic tm port(error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: softnictm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "softnictm")) {
+		printf("  softnictm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Port link status */
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get_nowait(port_id, &link);
+	if (link.link_status == ETH_LINK_UP) {
+		printf(" Port %u link up (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_hierarchy_commit(port_id, clean_on_fail, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+	/* Set TM hierarchy commit flag */
+	port->softport.tm.hierarchy_frozen = 1;
+}
+
+cmdline_parse_inst_t cmd_port_tm_hierarchy_commit = {
+	.f = cmd_port_tm_hierarchy_commit_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node shaper profile",
+	.tokens = {
+		(void *)&cmd_port_tm_hierarchy_commit_port,
+		(void *)&cmd_port_tm_hierarchy_commit_tm,
+		(void *)&cmd_port_tm_hierarchy_commit_hierarchy,
+		(void *)&cmd_port_tm_hierarchy_commit_commit,
+		(void *)&cmd_port_tm_hierarchy_commit_port_id,
+		(void *)&cmd_port_tm_hierarchy_commit_clean_on_fail,
+		NULL,
+	},
+};
+
+static int
+port_tm_pktfield_validate_mask(uint64_t mask, uint64_t n)
+{
+	int count = __builtin_popcountll(mask);
+	int pos_lead = sizeof(uint64_t) * 8 - __builtin_clzll(mask);
+	int pos_trail = __builtin_ctzll(mask);
+	int count_expected = __builtin_popcount(n - 1);
+
+	/* Handle the exceptions */
+	if (n == 0)
+		return -1;			/* Error */
+
+	if ((mask == 0) && (n == 1))
+		return 0;			/* OK */
+
+	if (((mask == 0) && (n != 1)) || ((mask != 0) && (n == 1)))
+		return -2;			/* Error */
+
+	/* Check that mask is contiguous */
+	if ((pos_lead - pos_trail) != count)
+		return -3;			/* Error */
+
+	/* Check that mask contains the expected number of bits set */
+	if (count != count_expected)
+		return -4;			/* Error */
+
+	return 0;			/* OK */
+	}
+
+/* *** Set Port TM Packet Fields *** */
+struct cmd_set_port_tm_pktfield_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t pktfield;
+	cmdline_fixed_string_t type;
+	uint8_t port_id;
+	cmdline_fixed_string_t offset_string;
+	uint32_t offset;
+	cmdline_fixed_string_t mask_string;
+	uint64_t mask;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result, port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,	tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_pktfield =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			pktfield, "pktfield");
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			type, "subport#pipe#tc");
+cmdline_parse_token_num_t cmd_set_port_tm_pktfield_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_offset_string =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			offset_string, "offset");
+cmdline_parse_token_num_t cmd_set_port_tm_pktfield_offset =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			offset, UINT32);
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_mask_string =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			mask_string, "mask");
+cmdline_parse_token_num_t cmd_set_port_tm_pktfield_mask =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			mask, UINT64);
+
+static void cmd_set_port_tm_pktfield_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_pktfield_result *res = parsed_result;
+	struct rte_port *p;
+	uint32_t offset = res->offset;
+	uint64_t mask = res->mask;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	p = &ports[port_id];
+
+	/* Softnic tm port */
+	if (p->softport.tm_flag == 0) {
+		printf("  port %u is not a softnic tm port(error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: softnictm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "softnictm")) {
+		printf("  softnictm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Subport */
+	if (strcmp(res->type, "subport") == 0) {
+		uint32_t n = p->softport.tm.n_subports_per_port;
+
+		ret = port_tm_pktfield_validate_mask(mask, n);
+		if (ret) {
+			printf(" invalid subport mask(error %d)", ret);
+			return;
+		}
+		/* Set packet field */
+		p->softport.tm.tm_pktfield0_slabpos = offset;
+		p->softport.tm.tm_pktfield0_slabmask = mask;
+		p->softport.tm.tm_pktfield0_slabshr = __builtin_ctzll(mask);
+		return;
+	}
+
+	/* Pipe */
+	if (strcmp(res->type, "pipe") == 0) {
+		uint32_t n = p->softport.tm.n_pipes_per_subport;
+
+		ret = port_tm_pktfield_validate_mask(mask, n);
+		if (ret) {
+			printf(" invalid pipe mask(error %d)", ret);
+			return;
+		}
+		/* Set packet field */
+		p->softport.tm.tm_pktfield1_slabpos = offset;
+		p->softport.tm.tm_pktfield1_slabmask = mask;
+		p->softport.tm.tm_pktfield1_slabshr = __builtin_ctzll(mask);
+		return;
+	}
+
+	/* Traffic class */
+	if (strcmp(res->type, "tc") == 0) {
+		uint32_t n = RTE_DIM(p->softport.tm.tm_tc_table);
+
+		ret = port_tm_pktfield_validate_mask(mask, n);
+		if (ret) {
+			printf(" invalid tc mask(error %d)", ret);
+			return;
+		}
+		/* Set packet field */
+		p->softport.tm.tm_pktfield1_slabpos = offset;
+		p->softport.tm.tm_pktfield1_slabmask = mask;
+		p->softport.tm.tm_pktfield1_slabshr = __builtin_ctzll(mask);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_pktfield = {
+	.f = cmd_set_port_tm_pktfield_parsed,
+	.data = NULL,
+	.help_str = "Set port tm pktfield",
+	.tokens = {
+		(void *)&cmd_set_port_tm_pktfield_set,
+		(void *)&cmd_set_port_tm_pktfield_port,
+		(void *)&cmd_set_port_tm_pktfield_tm,
+		(void *)&cmd_set_port_tm_pktfield_pktfield,
+		(void *)&cmd_set_port_tm_pktfield_type,
+		(void *)&cmd_set_port_tm_pktfield_port_id,
+		(void *)&cmd_set_port_tm_pktfield_offset_string,
+		(void *)&cmd_set_port_tm_pktfield_offset,
+		(void *)&cmd_set_port_tm_pktfield_mask_string,
+		(void *)&cmd_set_port_tm_pktfield_mask,
+		NULL,
+	},
+};
+
+/* *** Set Port TM Traffic Class Table Entry *** */
+struct cmd_set_port_tm_tc_table_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t tc_table;
+	uint8_t port_id;
+	cmdline_fixed_string_t index_string;
+	uint32_t index;
+	cmdline_fixed_string_t tc_string;
+	uint32_t tc;
+	cmdline_fixed_string_t queue_string;
+	uint32_t queue;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result, port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,	tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_tc_table =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			tc_table, "tc table");
+cmdline_parse_token_num_t cmd_set_port_tm_tc_table_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_index_string =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			index_string, "index");
+cmdline_parse_token_num_t cmd_set_port_tm_tc_table_index =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			index, UINT32);
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_tc_string =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			tc_string, "tc");
+cmdline_parse_token_num_t cmd_set_port_tm_tc_table_tc =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			tc, UINT32);
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_queue_string =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			queue_string, "queue");
+cmdline_parse_token_num_t cmd_set_port_tm_tc_table_queue =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			queue, UINT32);
+
+static void cmd_set_port_tm_tc_table_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_tc_table_result *res = parsed_result;
+	struct rte_port *p;
+	uint32_t tc = res->tc;
+	uint32_t index = res->index;
+	uint32_t queue = res->queue;
+	uint32_t val;
+	uint8_t port_id = res->port_id;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	p = &ports[port_id];
+
+	/* Softnic tm port */
+	if (p->softport.tm_flag == 0) {
+		printf("  port %u is not a softnic tm port(error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: softnictm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "softnictm")) {
+		printf("  softnictm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Traffic class table index */
+	if (tc >= RTE_DIM(p->softport.tm.tm_tc_table)) {
+		printf("  invalid traffic class table index(error)\n");
+		return;
+	}
+
+	/* Traffic class id */
+	if (tc >= RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE) {
+		printf("  invalid traffic class id(error)\n");
+		return;
+	}
+
+	/* Traffic class queue */
+	if (queue >= RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS) {
+		printf("  invalid traffic class queue(error)\n");
+		return;
+	}
+
+	val = tc * RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS + queue;
+	p->softport.tm.tm_tc_table[index] = val;
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_tc_table = {
+	.f = cmd_set_port_tm_tc_table_parsed,
+	.data = NULL,
+	.help_str = "Set port tm TC table entry",
+	.tokens = {
+		(void *)&cmd_set_port_tm_tc_table_set,
+		(void *)&cmd_set_port_tm_tc_table_port,
+		(void *)&cmd_set_port_tm_tc_table_tm,
+		(void *)&cmd_set_port_tm_tc_table_tc_table,
+		(void *)&cmd_set_port_tm_tc_table_port_id,
+		(void *)&cmd_set_port_tm_tc_table_index_string,
+		(void *)&cmd_set_port_tm_tc_table_index,
+		(void *)&cmd_set_port_tm_tc_table_tc_string,
+		(void *)&cmd_set_port_tm_tc_table_tc,
+		(void *)&cmd_set_port_tm_tc_table_queue_string,
+		(void *)&cmd_set_port_tm_tc_table_queue,
+		NULL,
+	},
+};
+
+#endif
+/* *********************************************************************** */
+
+/* list of instructions */
+cmdline_parse_ctx_t main_ctx[] = {
+	(cmdline_parse_inst_t *)&cmd_help_brief,
+	(cmdline_parse_inst_t *)&cmd_help_long,
+	(cmdline_parse_inst_t *)&cmd_quit,
+	(cmdline_parse_inst_t *)&cmd_load_from_file,
+	(cmdline_parse_inst_t *)&cmd_showport,
+	(cmdline_parse_inst_t *)&cmd_showqueue,
+	(cmdline_parse_inst_t *)&cmd_showportall,
+	(cmdline_parse_inst_t *)&cmd_showcfg,
+	(cmdline_parse_inst_t *)&cmd_start,
+	(cmdline_parse_inst_t *)&cmd_start_tx_first,
+	(cmdline_parse_inst_t *)&cmd_start_tx_first_n,
+	(cmdline_parse_inst_t *)&cmd_set_link_up,
+	(cmdline_parse_inst_t *)&cmd_set_link_down,
+	(cmdline_parse_inst_t *)&cmd_reset,
+	(cmdline_parse_inst_t *)&cmd_set_numbers,
+	(cmdline_parse_inst_t *)&cmd_set_txpkts,
+	(cmdline_parse_inst_t *)&cmd_set_txsplit,
+	(cmdline_parse_inst_t *)&cmd_set_fwd_list,
+	(cmdline_parse_inst_t *)&cmd_set_fwd_mask,
+	(cmdline_parse_inst_t *)&cmd_set_fwd_mode,
+	(cmdline_parse_inst_t *)&cmd_set_fwd_retry_mode,
+	(cmdline_parse_inst_t *)&cmd_set_burst_tx_retry,
+	(cmdline_parse_inst_t *)&cmd_set_promisc_mode_one,
+	(cmdline_parse_inst_t *)&cmd_set_promisc_mode_all,
+	(cmdline_parse_inst_t *)&cmd_set_allmulti_mode_one,
+	(cmdline_parse_inst_t *)&cmd_set_allmulti_mode_all,
+	(cmdline_parse_inst_t *)&cmd_set_flush_rx,
+	(cmdline_parse_inst_t *)&cmd_set_link_check,
+	(cmdline_parse_inst_t *)&cmd_set_bypass_mode,
+	(cmdline_parse_inst_t *)&cmd_set_bypass_event,
+	(cmdline_parse_inst_t *)&cmd_set_bypass_timeout,
+	(cmdline_parse_inst_t *)&cmd_show_bypass_config,
+#ifdef RTE_LIBRTE_PMD_BOND
+	(cmdline_parse_inst_t *) &cmd_set_bonding_mode,
+	(cmdline_parse_inst_t *) &cmd_show_bonding_config,
+	(cmdline_parse_inst_t *) &cmd_set_bonding_primary,
+	(cmdline_parse_inst_t *) &cmd_add_bonding_slave,
+	(cmdline_parse_inst_t *) &cmd_remove_bonding_slave,
+	(cmdline_parse_inst_t *) &cmd_create_bonded_device,
+	(cmdline_parse_inst_t *) &cmd_set_bond_mac_addr,
+	(cmdline_parse_inst_t *) &cmd_set_balance_xmit_policy,
+	(cmdline_parse_inst_t *) &cmd_set_bond_mon_period,
+	(cmdline_parse_inst_t *) &cmd_set_lacp_dedicated_queues,
+	(cmdline_parse_inst_t *) &cmd_set_bonding_agg_mode_policy,
+#endif
+	(cmdline_parse_inst_t *)&cmd_vlan_offload,
+	(cmdline_parse_inst_t *)&cmd_vlan_tpid,
+	(cmdline_parse_inst_t *)&cmd_rx_vlan_filter_all,
+	(cmdline_parse_inst_t *)&cmd_rx_vlan_filter,
+	(cmdline_parse_inst_t *)&cmd_tx_vlan_set,
+	(cmdline_parse_inst_t *)&cmd_tx_vlan_set_qinq,
+	(cmdline_parse_inst_t *)&cmd_tx_vlan_reset,
+	(cmdline_parse_inst_t *)&cmd_tx_vlan_set_pvid,
+	(cmdline_parse_inst_t *)&cmd_csum_set,
+	(cmdline_parse_inst_t *)&cmd_csum_show,
+	(cmdline_parse_inst_t *)&cmd_csum_tunnel,
+	(cmdline_parse_inst_t *)&cmd_tso_set,
+	(cmdline_parse_inst_t *)&cmd_tso_show,
+	(cmdline_parse_inst_t *)&cmd_tunnel_tso_set,
+	(cmdline_parse_inst_t *)&cmd_tunnel_tso_show,
+	(cmdline_parse_inst_t *)&cmd_enable_gro,
+	(cmdline_parse_inst_t *)&cmd_gro_set,
+	(cmdline_parse_inst_t *)&cmd_link_flow_control_set,
+	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_rx,
+	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_tx,
+	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_hw,
+	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_lw,
+	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_pt,
+	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_xon,
+	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_macfwd,
+	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_autoneg,
+	(cmdline_parse_inst_t *)&cmd_priority_flow_control_set,
+	(cmdline_parse_inst_t *)&cmd_config_dcb,
+	(cmdline_parse_inst_t *)&cmd_read_reg,
+	(cmdline_parse_inst_t *)&cmd_read_reg_bit_field,
+	(cmdline_parse_inst_t *)&cmd_read_reg_bit,
+	(cmdline_parse_inst_t *)&cmd_write_reg,
+	(cmdline_parse_inst_t *)&cmd_write_reg_bit_field,
+	(cmdline_parse_inst_t *)&cmd_write_reg_bit,
+	(cmdline_parse_inst_t *)&cmd_read_rxd_txd,
+	(cmdline_parse_inst_t *)&cmd_stop,
+	(cmdline_parse_inst_t *)&cmd_mac_addr,
+	(cmdline_parse_inst_t *)&cmd_set_qmap,
+	(cmdline_parse_inst_t *)&cmd_operate_port,
+	(cmdline_parse_inst_t *)&cmd_operate_specific_port,
+	(cmdline_parse_inst_t *)&cmd_operate_attach_port,
+	(cmdline_parse_inst_t *)&cmd_operate_detach_port,
+	(cmdline_parse_inst_t *)&cmd_config_speed_all,
+	(cmdline_parse_inst_t *)&cmd_config_speed_specific,
+	(cmdline_parse_inst_t *)&cmd_config_rx_tx,
+	(cmdline_parse_inst_t *)&cmd_config_mtu,
+	(cmdline_parse_inst_t *)&cmd_config_max_pkt_len,
+	(cmdline_parse_inst_t *)&cmd_config_rx_mode_flag,
+	(cmdline_parse_inst_t *)&cmd_config_rss,
+	(cmdline_parse_inst_t *)&cmd_config_rxtx_queue,
+	(cmdline_parse_inst_t *)&cmd_config_txqflags,
+	(cmdline_parse_inst_t *)&cmd_config_rss_reta,
+	(cmdline_parse_inst_t *)&cmd_showport_reta,
+	(cmdline_parse_inst_t *)&cmd_config_burst,
+	(cmdline_parse_inst_t *)&cmd_config_thresh,
+	(cmdline_parse_inst_t *)&cmd_config_threshold,
+	(cmdline_parse_inst_t *)&cmd_set_uc_hash_filter,
+	(cmdline_parse_inst_t *)&cmd_set_uc_all_hash_filter,
+	(cmdline_parse_inst_t *)&cmd_vf_mac_addr_filter,
+	(cmdline_parse_inst_t *)&cmd_set_vf_macvlan_filter,
+	(cmdline_parse_inst_t *)&cmd_queue_rate_limit,
+	(cmdline_parse_inst_t *)&cmd_tunnel_filter,
+	(cmdline_parse_inst_t *)&cmd_tunnel_udp_config,
+	(cmdline_parse_inst_t *)&cmd_global_config,
+	(cmdline_parse_inst_t *)&cmd_set_mirror_mask,
+	(cmdline_parse_inst_t *)&cmd_set_mirror_link,
+	(cmdline_parse_inst_t *)&cmd_reset_mirror_rule,
+	(cmdline_parse_inst_t *)&cmd_showport_rss_hash,
+	(cmdline_parse_inst_t *)&cmd_showport_rss_hash_key,
+	(cmdline_parse_inst_t *)&cmd_config_rss_hash_key,
+	(cmdline_parse_inst_t *)&cmd_dump,
+	(cmdline_parse_inst_t *)&cmd_dump_one,
+	(cmdline_parse_inst_t *)&cmd_ethertype_filter,
+	(cmdline_parse_inst_t *)&cmd_syn_filter,
+	(cmdline_parse_inst_t *)&cmd_2tuple_filter,
+	(cmdline_parse_inst_t *)&cmd_5tuple_filter,
+	(cmdline_parse_inst_t *)&cmd_flex_filter,
+	(cmdline_parse_inst_t *)&cmd_add_del_ip_flow_director,
+	(cmdline_parse_inst_t *)&cmd_add_del_udp_flow_director,
+	(cmdline_parse_inst_t *)&cmd_add_del_sctp_flow_director,
+	(cmdline_parse_inst_t *)&cmd_add_del_l2_flow_director,
+	(cmdline_parse_inst_t *)&cmd_add_del_mac_vlan_flow_director,
+	(cmdline_parse_inst_t *)&cmd_add_del_tunnel_flow_director,
+	(cmdline_parse_inst_t *)&cmd_flush_flow_director,
+	(cmdline_parse_inst_t *)&cmd_set_flow_director_ip_mask,
+	(cmdline_parse_inst_t *)&cmd_set_flow_director_mac_vlan_mask,
+	(cmdline_parse_inst_t *)&cmd_set_flow_director_tunnel_mask,
+	(cmdline_parse_inst_t *)&cmd_set_flow_director_flex_mask,
+	(cmdline_parse_inst_t *)&cmd_set_flow_director_flex_payload,
+	(cmdline_parse_inst_t *)&cmd_get_sym_hash_ena_per_port,
+	(cmdline_parse_inst_t *)&cmd_set_sym_hash_ena_per_port,
+	(cmdline_parse_inst_t *)&cmd_get_hash_global_config,
+	(cmdline_parse_inst_t *)&cmd_set_hash_global_config,
+	(cmdline_parse_inst_t *)&cmd_set_hash_input_set,
+	(cmdline_parse_inst_t *)&cmd_set_fdir_input_set,
+	(cmdline_parse_inst_t *)&cmd_flow,
+	(cmdline_parse_inst_t *)&cmd_mcast_addr,
+	(cmdline_parse_inst_t *)&cmd_config_l2_tunnel_eth_type_all,
+	(cmdline_parse_inst_t *)&cmd_config_l2_tunnel_eth_type_specific,
+	(cmdline_parse_inst_t *)&cmd_config_l2_tunnel_en_dis_all,
+	(cmdline_parse_inst_t *)&cmd_config_l2_tunnel_en_dis_specific,
+	(cmdline_parse_inst_t *)&cmd_config_e_tag_insertion_en,
+	(cmdline_parse_inst_t *)&cmd_config_e_tag_insertion_dis,
+	(cmdline_parse_inst_t *)&cmd_config_e_tag_stripping_en_dis,
+	(cmdline_parse_inst_t *)&cmd_config_e_tag_forwarding_en_dis,
+	(cmdline_parse_inst_t *)&cmd_config_e_tag_filter_add,
+	(cmdline_parse_inst_t *)&cmd_config_e_tag_filter_del,
+	(cmdline_parse_inst_t *)&cmd_set_vf_vlan_anti_spoof,
+	(cmdline_parse_inst_t *)&cmd_set_vf_mac_anti_spoof,
+	(cmdline_parse_inst_t *)&cmd_set_vf_vlan_stripq,
+	(cmdline_parse_inst_t *)&cmd_set_vf_vlan_insert,
+	(cmdline_parse_inst_t *)&cmd_set_tx_loopback,
+	(cmdline_parse_inst_t *)&cmd_set_all_queues_drop_en,
+	(cmdline_parse_inst_t *)&cmd_set_vf_split_drop_en,
+	(cmdline_parse_inst_t *)&cmd_set_macsec_offload_on,
+	(cmdline_parse_inst_t *)&cmd_set_macsec_offload_off,
+	(cmdline_parse_inst_t *)&cmd_set_macsec_sc,
+	(cmdline_parse_inst_t *)&cmd_set_macsec_sa,
+	(cmdline_parse_inst_t *)&cmd_set_vf_traffic,
+	(cmdline_parse_inst_t *)&cmd_set_vf_rxmode,
+	(cmdline_parse_inst_t *)&cmd_vf_rate_limit,
+	(cmdline_parse_inst_t *)&cmd_vf_rxvlan_filter,
+	(cmdline_parse_inst_t *)&cmd_set_vf_mac_addr,
+	(cmdline_parse_inst_t *)&cmd_set_vf_promisc,
+	(cmdline_parse_inst_t *)&cmd_set_vf_allmulti,
+	(cmdline_parse_inst_t *)&cmd_set_vf_broadcast,
+	(cmdline_parse_inst_t *)&cmd_set_vf_vlan_tag,
+	(cmdline_parse_inst_t *)&cmd_vf_max_bw,
+	(cmdline_parse_inst_t *)&cmd_vf_tc_min_bw,
+	(cmdline_parse_inst_t *)&cmd_vf_tc_max_bw,
+	(cmdline_parse_inst_t *)&cmd_strict_link_prio,
+	(cmdline_parse_inst_t *)&cmd_tc_min_bw,
+	(cmdline_parse_inst_t *)&cmd_ddp_add,
+	(cmdline_parse_inst_t *)&cmd_ddp_del,
+	(cmdline_parse_inst_t *)&cmd_ddp_get_list,
+	(cmdline_parse_inst_t *)&cmd_ddp_get_info,
+	(cmdline_parse_inst_t *)&cmd_show_vf_stats,
+	(cmdline_parse_inst_t *)&cmd_clear_vf_stats,
+	(cmdline_parse_inst_t *)&cmd_ptype_mapping_get,
+	(cmdline_parse_inst_t *)&cmd_ptype_mapping_replace,
+	(cmdline_parse_inst_t *)&cmd_ptype_mapping_reset,
+	(cmdline_parse_inst_t *)&cmd_ptype_mapping_update,
+#ifdef SOFTNIC_TM_FEATURE
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_level_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_cap,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_shared_shaper,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_shared_shaper,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_wred_profile,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_wred_profile,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_nonleaf_node,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_leaf_node,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_type,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_stats,
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_parent,
+#endif
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_port_tm_hierarchy_commit,
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_pktfield,
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_tc_table,
+#endif
 	NULL,
 };
 
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v2 1/2] app/testpmd: add traffic management forwarding mode
  2017-08-22 17:02 [PATCH 1/2] app/testpmd: add traffic management forwarding mode Jasvinder Singh
  2017-08-22 17:02 ` [PATCH 2/2] app/testpmd: add CLI for tm mode Jasvinder Singh
@ 2017-09-14 11:53 ` Jasvinder Singh
  2017-09-14 11:53   ` [PATCH v2 2/2] app/testpmd: add CLI for tm mode Jasvinder Singh
                     ` (2 more replies)
  1 sibling, 3 replies; 49+ messages in thread
From: Jasvinder Singh @ 2017-09-14 11:53 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu

This commit extends the testpmd application with new forwarding engine
that demonstrates the use of ethdev traffic management APIs and softnic
PMD for QoS traffic management.

In this mode, 5-level hierarchical tree of the QoS scheduler is built
with the help of ethdev TM APIs such as shaper profile add/delete,
shared shaper add/update, node add/delete, hierarchy commit, etc.
The hierarchical tree has following nodes; root node(x1, level 0),
subport node(x1, level 1), pipe node(x4096, level 2),
tc node(x16348, level 3), queue node(x65536, level 4).

During runtime, each received packet is first classified by mapping the
packet fields information to 5-tuples (HQoS subport, pipe, traffic class,
queue within traffic class, and color) and storing it in the packet mbuf
sched field. After classification, each packet is sent to softnic port
which prioritizes the transmission of the received packets, and
accordingly sends them on to the output interface.

To enable traffic management mode, following testpmd command is used;

$ ./testpmd -c c -n 4 --vdev
	'net_softnic0,hard_name=0000:06:00.1,soft_tm=on' -- -i
	--forward-mode=tm

This patchset has dependency on following patch series;
http://www.dpdk.org/dev/patchwork/patch/27517/
http://www.dpdk.org/dev/patchwork/patch/27518/
http://www.dpdk.org/dev/patchwork/patch/27519/
http://www.dpdk.org/dev/patchwork/patch/27520/

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
v2 change:
- change file name softnictm.c to tm.c
- change forward mode name to "tm"
- code clean up

 app/test-pmd/Makefile  |   5 +
 app/test-pmd/testpmd.c |  11 +
 app/test-pmd/testpmd.h |  34 ++
 app/test-pmd/tm.c      | 863 +++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 913 insertions(+)
 create mode 100644 app/test-pmd/tm.c

diff --git a/app/test-pmd/Makefile b/app/test-pmd/Makefile
index c36be19..925787f 100644
--- a/app/test-pmd/Makefile
+++ b/app/test-pmd/Makefile
@@ -57,6 +57,7 @@ SRCS-y += rxonly.c
 SRCS-y += txonly.c
 SRCS-y += csumonly.c
 SRCS-y += icmpecho.c
+SRCS-y += tm.c
 SRCS-$(CONFIG_RTE_LIBRTE_IEEE1588) += ieee1588fwd.c
 
 ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
@@ -81,6 +82,10 @@ ifeq ($(CONFIG_RTE_LIBRTE_PMD_XENVIRT),y)
 LDLIBS += -lrte_pmd_xenvirt
 endif
 
+ifeq ($(CONFIG_RTE_LIBRTE_PMD_SOFTNIC),y)
+LDLIBS += -lrte_pmd_softnic
+endif
+
 endif
 
 CFLAGS_cmdline.o := -D_GNU_SOURCE
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index 7d40139..996e982 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -167,6 +167,8 @@ struct fwd_engine * fwd_engines[] = {
 	&tx_only_engine,
 	&csum_fwd_engine,
 	&icmp_echo_engine,
+	&softnic_tm_engine,
+	&softnic_tm_bypass_engine,
 #ifdef RTE_LIBRTE_IEEE1588
 	&ieee1588_fwd_engine,
 #endif
@@ -2044,6 +2046,15 @@ init_port_config(void)
 		    (rte_eth_devices[pid].data->dev_flags &
 		     RTE_ETH_DEV_INTR_RMV))
 			port->dev_conf.intr_conf.rmv = 1;
+
+		/* Detect softnic port */
+		if (!strcmp(port->dev_info.driver_name, "net_softnic")) {
+			memset(&port->softport, 0, sizeof(struct softnic_port));
+				port->softport.enable = 1;
+
+			if (!strcmp(cur_fwd_eng->fwd_mode_name, "tm"))
+				port->softport.tm_flag = 1;
+		}
 	}
 }
 
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index c9d7739..c8fa180 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -163,6 +163,37 @@ struct port_flow {
 };
 
 /**
+ * Soft port tm related parameters
+ */
+struct softnic_port_tm {
+	uint32_t hierarchy_frozen;  /**< flag for tm hierarchy status */
+
+	uint32_t n_subports_per_port;  /**< Num of subport nodes per port */
+	uint32_t n_pipes_per_subport;  /**< Num of pipe nodes per subport */
+
+	uint64_t tm_pktfield0_slabpos;	/**< Pkt field position for subport */
+	uint64_t tm_pktfield0_slabmask; /**< Pkt field mask for the subport */
+	uint64_t tm_pktfield0_slabshr;
+	uint64_t tm_pktfield1_slabpos; /**< Pkt field position for the pipe */
+	uint64_t tm_pktfield1_slabmask; /**< Pkt field mask for the pipe */
+	uint64_t tm_pktfield1_slabshr;
+	uint64_t tm_pktfield2_slabpos; /**< Pkt field position table index */
+	uint64_t tm_pktfield2_slabmask;	/**< Pkt field mask for tc table idx */
+	uint64_t tm_pktfield2_slabshr;
+	uint64_t tm_tc_table[64];  /**< TC translation table */
+};
+
+/**
+ * The data structure associate with softnic port
+ */
+struct softnic_port {
+	unsigned int enable;	/**< set to 1 if softnic port detected */
+
+	unsigned int tm_flag;	/**< set to 1 if tm feature is enabled */
+	struct softnic_port_tm tm;	/**< softnic port tm parameters */
+};
+
+/**
  * The data structure associated with each port.
  */
 struct rte_port {
@@ -195,6 +226,7 @@ struct rte_port {
 	uint32_t                mc_addr_nb; /**< nb. of addr. in mc_addr_pool */
 	uint8_t                 slave_flag; /**< bonding slave port */
 	struct port_flow        *flow_list; /**< Associated flows. */
+	struct softnic_port     softport;  /**< softnic port params > */
 };
 
 /**
@@ -253,6 +285,8 @@ extern struct fwd_engine rx_only_engine;
 extern struct fwd_engine tx_only_engine;
 extern struct fwd_engine csum_fwd_engine;
 extern struct fwd_engine icmp_echo_engine;
+extern struct fwd_engine softnic_tm_engine;
+extern struct fwd_engine softnic_tm_bypass_engine;
 #ifdef RTE_LIBRTE_IEEE1588
 extern struct fwd_engine ieee1588_fwd_engine;
 #endif
diff --git a/app/test-pmd/tm.c b/app/test-pmd/tm.c
new file mode 100644
index 0000000..a227c6c
--- /dev/null
+++ b/app/test-pmd/tm.c
@@ -0,0 +1,863 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <sys/stat.h>
+
+#include <rte_cycles.h>
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_flow.h>
+#include <rte_meter.h>
+#include <rte_eth_softnic.h>
+#include <rte_tm.h>
+
+#include "testpmd.h"
+
+#define SUBPORT_NODES_PER_PORT		1
+#define PIPE_NODES_PER_SUBPORT		4096
+#define TC_NODES_PER_PIPE			4
+#define QUEUE_NODES_PER_TC			4
+
+#define NUM_PIPE_NODES						\
+	(SUBPORT_NODES_PER_PORT * PIPE_NODES_PER_SUBPORT)
+
+#define NUM_TC_NODES						\
+	(NUM_PIPE_NODES * TC_NODES_PER_PIPE)
+
+#define ROOT_NODE_ID				1000000
+#define SUBPORT_NODES_START_ID		900000
+#define PIPE_NODES_START_ID			800000
+#define TC_NODES_START_ID			700000
+
+#define STATS_MASK_DEFAULT					\
+	(RTE_TM_STATS_N_PKTS |					\
+	RTE_TM_STATS_N_BYTES |					\
+	RTE_TM_STATS_N_PKTS_GREEN_DROPPED |			\
+	RTE_TM_STATS_N_BYTES_GREEN_DROPPED)
+
+#define STATS_MASK_QUEUE					\
+	(STATS_MASK_DEFAULT |					\
+	RTE_TM_STATS_N_PKTS_QUEUED)
+
+#define BYTES_IN_MBPS				(1000 * 1000 / 8)
+#define TOKEN_BUCKET_SIZE			1000000
+
+/* TM Hierarchy Levels */
+enum tm_hierarchy_level {
+	TM_NODE_LEVEL_PORT = 0,
+	TM_NODE_LEVEL_SUBPORT,
+	TM_NODE_LEVEL_PIPE,
+	TM_NODE_LEVEL_TC,
+	TM_NODE_LEVEL_QUEUE,
+	TM_NODE_LEVEL_MAX,
+};
+
+struct tm_hierarchy {
+	/* TM Nodes */
+	uint32_t root_node_id;
+	uint32_t subport_node_id[SUBPORT_NODES_PER_PORT];
+	uint32_t pipe_node_id[SUBPORT_NODES_PER_PORT][PIPE_NODES_PER_SUBPORT];
+	uint32_t tc_node_id[NUM_PIPE_NODES][TC_NODES_PER_PIPE];
+	uint32_t queue_node_id[NUM_TC_NODES][QUEUE_NODES_PER_TC];
+
+	/* TM Hierarchy Nodes Shaper Rates */
+	uint32_t root_node_shaper_rate;
+	uint32_t subport_node_shaper_rate;
+	uint32_t pipe_node_shaper_rate;
+	uint32_t tc_node_shaper_rate;
+	uint32_t tc_node_shared_shaper_rate;
+
+	uint32_t n_shapers;
+};
+
+#define BITFIELD(byte_array, slab_pos, slab_mask, slab_shr)	\
+({								\
+	uint64_t slab = *((uint64_t *) &byte_array[slab_pos]);	\
+	uint64_t val =				\
+		(rte_be_to_cpu_64(slab) & slab_mask) >> slab_shr;	\
+	val;						\
+})
+
+#define RTE_SCHED_PORT_HIERARCHY(subport, pipe,           \
+	traffic_class, queue, color)                          \
+	((((uint64_t) (queue)) & 0x3) |                       \
+	((((uint64_t) (traffic_class)) & 0x3) << 2) |         \
+	((((uint64_t) (color)) & 0x3) << 4) |                 \
+	((((uint64_t) (subport)) & 0xFFFF) << 16) |           \
+	((((uint64_t) (pipe)) & 0xFFFFFFFF) << 32))
+
+
+static void
+pkt_metadata_set(struct rte_port *p, struct rte_mbuf **pkts,
+	uint32_t n_pkts)
+{
+	struct softnic_port_tm *tm = &p->softport.tm;
+	uint32_t i;
+
+	for (i = 0; i < (n_pkts & (~0x3)); i += 4) {
+		struct rte_mbuf *pkt0 = pkts[i];
+		struct rte_mbuf *pkt1 = pkts[i + 1];
+		struct rte_mbuf *pkt2 = pkts[i + 2];
+		struct rte_mbuf *pkt3 = pkts[i + 3];
+
+		uint8_t *pkt0_data = rte_pktmbuf_mtod(pkt0, uint8_t *);
+		uint8_t *pkt1_data = rte_pktmbuf_mtod(pkt1, uint8_t *);
+		uint8_t *pkt2_data = rte_pktmbuf_mtod(pkt2, uint8_t *);
+		uint8_t *pkt3_data = rte_pktmbuf_mtod(pkt3, uint8_t *);
+
+		uint64_t pkt0_subport = BITFIELD(pkt0_data,
+					tm->tm_pktfield0_slabpos,
+					tm->tm_pktfield0_slabmask,
+					tm->tm_pktfield0_slabshr);
+		uint64_t pkt0_pipe = BITFIELD(pkt0_data,
+					tm->tm_pktfield1_slabpos,
+					tm->tm_pktfield1_slabmask,
+					tm->tm_pktfield1_slabshr);
+		uint64_t pkt0_dscp = BITFIELD(pkt0_data,
+					tm->tm_pktfield2_slabpos,
+					tm->tm_pktfield2_slabmask,
+					tm->tm_pktfield2_slabshr);
+		uint32_t pkt0_tc = tm->tm_tc_table[pkt0_dscp & 0x3F] >> 2;
+		uint32_t pkt0_tc_q = tm->tm_tc_table[pkt0_dscp & 0x3F] & 0x3;
+		uint64_t pkt1_subport = BITFIELD(pkt1_data,
+					tm->tm_pktfield0_slabpos,
+					tm->tm_pktfield0_slabmask,
+					tm->tm_pktfield0_slabshr);
+		uint64_t pkt1_pipe = BITFIELD(pkt1_data,
+					tm->tm_pktfield1_slabpos,
+					tm->tm_pktfield1_slabmask,
+					tm->tm_pktfield1_slabshr);
+		uint64_t pkt1_dscp = BITFIELD(pkt1_data,
+					tm->tm_pktfield2_slabpos,
+					tm->tm_pktfield2_slabmask,
+					tm->tm_pktfield2_slabshr);
+		uint32_t pkt1_tc = tm->tm_tc_table[pkt1_dscp & 0x3F] >> 2;
+		uint32_t pkt1_tc_q = tm->tm_tc_table[pkt1_dscp & 0x3F] & 0x3;
+
+		uint64_t pkt2_subport = BITFIELD(pkt2_data,
+					tm->tm_pktfield0_slabpos,
+					tm->tm_pktfield0_slabmask,
+					tm->tm_pktfield0_slabshr);
+		uint64_t pkt2_pipe = BITFIELD(pkt2_data,
+					tm->tm_pktfield1_slabpos,
+					tm->tm_pktfield1_slabmask,
+					tm->tm_pktfield1_slabshr);
+		uint64_t pkt2_dscp = BITFIELD(pkt2_data,
+					tm->tm_pktfield2_slabpos,
+					tm->tm_pktfield2_slabmask,
+					tm->tm_pktfield2_slabshr);
+		uint32_t pkt2_tc = tm->tm_tc_table[pkt2_dscp & 0x3F] >> 2;
+		uint32_t pkt2_tc_q = tm->tm_tc_table[pkt2_dscp & 0x3F] & 0x3;
+
+		uint64_t pkt3_subport = BITFIELD(pkt3_data,
+					tm->tm_pktfield0_slabpos,
+					tm->tm_pktfield0_slabmask,
+					tm->tm_pktfield0_slabshr);
+		uint64_t pkt3_pipe = BITFIELD(pkt3_data,
+					tm->tm_pktfield1_slabpos,
+					tm->tm_pktfield1_slabmask,
+					tm->tm_pktfield1_slabshr);
+		uint64_t pkt3_dscp = BITFIELD(pkt3_data,
+					tm->tm_pktfield2_slabpos,
+					tm->tm_pktfield2_slabmask,
+					tm->tm_pktfield2_slabshr);
+		uint32_t pkt3_tc = tm->tm_tc_table[pkt3_dscp & 0x3F] >> 2;
+		uint32_t pkt3_tc_q = tm->tm_tc_table[pkt3_dscp & 0x3F] & 0x3;
+
+		uint64_t pkt0_sched = RTE_SCHED_PORT_HIERARCHY(pkt0_subport,
+						pkt0_pipe,
+						pkt0_tc,
+						pkt0_tc_q,
+						0);
+		uint64_t pkt1_sched = RTE_SCHED_PORT_HIERARCHY(pkt1_subport,
+						pkt1_pipe,
+						pkt1_tc,
+						pkt1_tc_q,
+						0);
+		uint64_t pkt2_sched = RTE_SCHED_PORT_HIERARCHY(pkt2_subport,
+						pkt2_pipe,
+						pkt2_tc,
+						pkt2_tc_q,
+						0);
+		uint64_t pkt3_sched = RTE_SCHED_PORT_HIERARCHY(pkt3_subport,
+						pkt3_pipe,
+						pkt3_tc,
+						pkt3_tc_q,
+						0);
+
+		pkt0->hash.sched.lo = pkt0_sched & 0xFFFFFFFF;
+		pkt0->hash.sched.hi = pkt0_sched >> 32;
+		pkt1->hash.sched.lo = pkt1_sched & 0xFFFFFFFF;
+		pkt1->hash.sched.hi = pkt1_sched >> 32;
+		pkt2->hash.sched.lo = pkt2_sched & 0xFFFFFFFF;
+		pkt2->hash.sched.hi = pkt2_sched >> 32;
+		pkt3->hash.sched.lo = pkt3_sched & 0xFFFFFFFF;
+		pkt3->hash.sched.hi = pkt3_sched >> 32;
+	}
+
+	for (; i < n_pkts; i++)	{
+		struct rte_mbuf *pkt = pkts[i];
+
+		uint8_t *pkt_data = rte_pktmbuf_mtod(pkt, uint8_t *);
+
+		uint64_t pkt_subport = BITFIELD(pkt_data,
+					tm->tm_pktfield0_slabpos,
+					tm->tm_pktfield0_slabmask,
+					tm->tm_pktfield0_slabshr);
+		uint64_t pkt_pipe = BITFIELD(pkt_data,
+					tm->tm_pktfield1_slabpos,
+					tm->tm_pktfield1_slabmask,
+					tm->tm_pktfield1_slabshr);
+		uint64_t pkt_dscp = BITFIELD(pkt_data,
+					tm->tm_pktfield2_slabpos,
+					tm->tm_pktfield2_slabmask,
+					tm->tm_pktfield2_slabshr);
+		uint32_t pkt_tc = tm->tm_tc_table[pkt_dscp & 0x3F] >> 2;
+		uint32_t pkt_tc_q = tm->tm_tc_table[pkt_dscp & 0x3F] & 0x3;
+
+		uint64_t pkt_sched = RTE_SCHED_PORT_HIERARCHY(pkt_subport,
+						pkt_pipe,
+						pkt_tc,
+						pkt_tc_q,
+						0);
+
+		pkt->hash.sched.lo = pkt_sched & 0xFFFFFFFF;
+		pkt->hash.sched.hi = pkt_sched >> 32;
+	}
+}
+
+/*
+ * Soft port packet forward
+ */
+static void
+softport_packet_fwd(struct fwd_stream *fs)
+{
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	struct rte_port *rte_tx_port = &ports[fs->tx_port];
+	uint16_t nb_rx;
+	uint16_t nb_tx;
+	uint32_t retry;
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+	uint64_t start_tsc;
+	uint64_t end_tsc;
+	uint64_t core_cycles;
+#endif
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+	start_tsc = rte_rdtsc();
+#endif
+
+	/*  Packets Receive */
+	nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue,
+			pkts_burst, nb_pkt_per_burst);
+	fs->rx_packets += nb_rx;
+
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+	fs->rx_burst_stats.pkt_burst_spread[nb_rx]++;
+#endif
+
+	if (rte_tx_port->softport.enable) {
+		/* Set packet metadata if tm flag enabled */
+		if (rte_tx_port->softport.tm_flag)
+			pkt_metadata_set(rte_tx_port, pkts_burst, nb_rx);
+
+		/* Softport run */
+		rte_pmd_softnic_run(fs->tx_port);
+	}
+	nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
+			pkts_burst, nb_rx);
+
+	/* Retry if necessary */
+	if (unlikely(nb_tx < nb_rx) && fs->retry_enabled) {
+		retry = 0;
+		while (nb_tx < nb_rx && retry++ < burst_tx_retry_num) {
+			rte_delay_us(burst_tx_delay_time);
+			nb_tx += rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
+					&pkts_burst[nb_tx], nb_rx - nb_tx);
+		}
+	}
+	fs->tx_packets += nb_tx;
+
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+	fs->tx_burst_stats.pkt_burst_spread[nb_tx]++;
+#endif
+
+	if (unlikely(nb_tx < nb_rx)) {
+		fs->fwd_dropped += (nb_rx - nb_tx);
+		do {
+			rte_pktmbuf_free(pkts_burst[nb_tx]);
+		} while (++nb_tx < nb_rx);
+	}
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+	end_tsc = rte_rdtsc();
+	core_cycles = (end_tsc - start_tsc);
+	fs->core_cycles = (uint64_t) (fs->core_cycles + core_cycles);
+#endif
+}
+
+static void
+set_tm_hiearchy_nodes_shaper_rate(portid_t port_id, struct tm_hierarchy *h)
+{
+	struct rte_eth_link link_params;
+	uint64_t tm_port_rate;
+
+	memset(&link_params, 0, sizeof(link_params));
+
+	rte_eth_link_get(port_id, &link_params);
+	tm_port_rate = link_params.link_speed * BYTES_IN_MBPS;
+
+	if (tm_port_rate > UINT32_MAX)
+		tm_port_rate = UINT32_MAX;
+
+	/* Set tm hierarchy shapers rate */
+	h->root_node_shaper_rate = tm_port_rate;
+	h->subport_node_shaper_rate =
+		tm_port_rate / SUBPORT_NODES_PER_PORT;
+	h->pipe_node_shaper_rate
+		= h->subport_node_shaper_rate / PIPE_NODES_PER_SUBPORT;
+	h->tc_node_shaper_rate = h->pipe_node_shaper_rate;
+	h->tc_node_shared_shaper_rate = h->subport_node_shaper_rate;
+}
+
+static int
+softport_tm_root_node_add(portid_t port_id, struct tm_hierarchy *h,
+	struct rte_tm_error *error)
+{
+	struct rte_tm_node_params rnp;
+	struct rte_tm_shaper_params rsp;
+	uint32_t priority, weight, level_id, shaper_profile_id;
+
+	memset(&rsp, 0, sizeof(struct rte_tm_shaper_params));
+	memset(&rnp, 0, sizeof(struct rte_tm_node_params));
+
+	/* Shaper profile Parameters */
+	rsp.peak.rate = h->root_node_shaper_rate;
+	rsp.peak.size = TOKEN_BUCKET_SIZE;
+	rsp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+	shaper_profile_id = 0;
+
+	if (rte_tm_shaper_profile_add(port_id, shaper_profile_id,
+		&rsp, error)) {
+		printf("%s ERROR(%d)-%s!(shaper_id %u)\n ",
+			__func__, error->type, error->message,
+			shaper_profile_id);
+		return -1;
+	}
+
+	/* Root Node Parameters */
+	h->root_node_id = ROOT_NODE_ID;
+	weight = 1;
+	priority = 0;
+	level_id = TM_NODE_LEVEL_PORT;
+	rnp.shaper_profile_id = shaper_profile_id;
+	rnp.nonleaf.n_sp_priorities = 1;
+	rnp.stats_mask = STATS_MASK_DEFAULT;
+
+	/* Add Node to TM Hierarchy */
+	if (rte_tm_node_add(port_id, h->root_node_id, RTE_TM_NODE_ID_NULL,
+		priority, weight, level_id, &rnp, error)) {
+		printf("%s ERROR(%d)-%s!(node_id %u, parent_id %u, level %u)\n",
+			__func__, error->type, error->message,
+			h->root_node_id, RTE_TM_NODE_ID_NULL,
+			level_id);
+		return -1;
+	}
+	/* Update */
+	h->n_shapers++;
+
+	printf("  Root node added (Start id %u, Count %u, level %u)\n",
+		h->root_node_id, 1, level_id);
+
+	return 0;
+}
+
+static int
+softport_tm_subport_node_add(portid_t port_id, struct tm_hierarchy *h,
+	struct rte_tm_error *error)
+{
+	uint32_t subport_parent_node_id, subport_node_id;
+	struct rte_tm_node_params snp;
+	struct rte_tm_shaper_params ssp;
+	uint32_t priority, weight, level_id, shaper_profile_id;
+	uint32_t i;
+
+	memset(&ssp, 0, sizeof(struct rte_tm_shaper_params));
+	memset(&snp, 0, sizeof(struct rte_tm_node_params));
+
+	shaper_profile_id = h->n_shapers;
+
+	/* Add Shaper Profile to TM Hierarchy */
+	for (i = 0; i < SUBPORT_NODES_PER_PORT; i++) {
+		ssp.peak.rate = h->subport_node_shaper_rate;
+		ssp.peak.size = TOKEN_BUCKET_SIZE;
+		ssp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+		if (rte_tm_shaper_profile_add(port_id, shaper_profile_id,
+			&ssp, error)) {
+			printf("%s ERROR(%d)-%s!(shaper_id %u)\n ",
+				__func__, error->type, error->message,
+				shaper_profile_id);
+			return -1;
+		}
+
+		/* Node Parameters */
+		h->subport_node_id[i] = SUBPORT_NODES_START_ID + i;
+		subport_parent_node_id = h->root_node_id;
+		weight = 1;
+		priority = 0;
+		level_id = TM_NODE_LEVEL_SUBPORT;
+		snp.shaper_profile_id = shaper_profile_id;
+		snp.nonleaf.n_sp_priorities = 1;
+		snp.stats_mask = STATS_MASK_DEFAULT;
+
+		/* Add Node to TM Hiearchy */
+		if (rte_tm_node_add(port_id,
+				h->subport_node_id[i],
+				subport_parent_node_id,
+				priority, weight,
+				level_id,
+				&snp,
+				error)) {
+			printf("%s ERROR(%d)-%s!(node %u,parent %u,level %u)\n",
+					__func__,
+					error->type,
+					error->message,
+					h->subport_node_id[i],
+					subport_parent_node_id,
+					level_id);
+			return -1;
+		}
+		shaper_profile_id++;
+		subport_node_id++;
+	}
+	/* Update */
+	h->n_shapers = shaper_profile_id;
+
+	printf("  Subport nodes added (Start id %u, Count %u, level %u)\n",
+		h->subport_node_id[0], SUBPORT_NODES_PER_PORT, level_id);
+
+	return 0;
+}
+
+static int
+softport_tm_pipe_node_add(portid_t port_id, struct tm_hierarchy *h,
+	struct rte_tm_error *error)
+{
+	uint32_t pipe_parent_node_id;
+	struct rte_tm_node_params pnp;
+	struct rte_tm_shaper_params psp;
+	uint32_t priority, weight, level_id, shaper_profile_id;
+	uint32_t i, j;
+
+	memset(&psp, 0, sizeof(struct rte_tm_shaper_params));
+	memset(&pnp, 0, sizeof(struct rte_tm_node_params));
+
+	shaper_profile_id = h->n_shapers;
+
+	/* Shaper Profile Parameters */
+	psp.peak.rate = h->pipe_node_shaper_rate;
+	psp.peak.size = TOKEN_BUCKET_SIZE;
+	psp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+	/* Pipe Node Parameters */
+	weight = 1;
+	priority = 0;
+	level_id = TM_NODE_LEVEL_PIPE;
+	pnp.nonleaf.n_sp_priorities = 4;
+	pnp.stats_mask = STATS_MASK_DEFAULT;
+
+	/* Add Shaper Profiles and Nodes to TM Hierarchy */
+	for (i = 0; i < SUBPORT_NODES_PER_PORT; i++) {
+		for (j = 0; j < PIPE_NODES_PER_SUBPORT; j++) {
+			if (rte_tm_shaper_profile_add(port_id,
+				shaper_profile_id, &psp, error)) {
+				printf("%s ERROR(%d)-%s!(shaper_id %u)\n ",
+					__func__, error->type, error->message,
+					shaper_profile_id);
+				return -1;
+			}
+			pnp.shaper_profile_id = shaper_profile_id;
+			pipe_parent_node_id = h->subport_node_id[i];
+			h->pipe_node_id[i][j] = PIPE_NODES_START_ID +
+				(i * PIPE_NODES_PER_SUBPORT) + j;
+
+			if (rte_tm_node_add(port_id,
+					h->pipe_node_id[i][j],
+					pipe_parent_node_id,
+					priority, weight, level_id,
+					&pnp,
+					error)) {
+				printf("%s ERROR(%d)-%s!(node %u,parent %u )\n",
+					__func__,
+					error->type,
+					error->message,
+					h->pipe_node_id[i][j],
+					pipe_parent_node_id);
+
+				return -1;
+			}
+			shaper_profile_id++;
+		}
+	}
+	/* Update */
+	h->n_shapers = shaper_profile_id;
+
+	printf("  Pipe nodes added (Start id %u, Count %u, level %u)\n",
+		h->pipe_node_id[0][0], NUM_PIPE_NODES, level_id);
+
+	return 0;
+}
+
+static int
+softport_tm_tc_node_add(portid_t port_id, struct tm_hierarchy *h,
+	struct rte_tm_error *error)
+{
+	uint32_t tc_parent_node_id;
+	struct rte_tm_node_params tnp;
+	struct rte_tm_shaper_params tsp, tssp;
+	uint32_t shared_shaper_profile_id[TC_NODES_PER_PIPE];
+	uint32_t priority, weight, level_id, shaper_profile_id;
+	uint32_t pos, i, j, k, l;
+
+	memset(&tsp, 0, sizeof(struct rte_tm_shaper_params));
+	memset(&tssp, 0, sizeof(struct rte_tm_shaper_params));
+	memset(&tnp, 0, sizeof(struct rte_tm_node_params));
+
+	shaper_profile_id = h->n_shapers;
+
+	/* Private Shaper Profile (TC) Parameters */
+	tsp.peak.rate = h->tc_node_shaper_rate;
+	tsp.peak.size = TOKEN_BUCKET_SIZE;
+	tsp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+	/* Shared Shaper Profile (TC) Parameters */
+	tssp.peak.rate = h->tc_node_shared_shaper_rate;
+	tssp.peak.size = TOKEN_BUCKET_SIZE;
+	tssp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+	/* TC Node Parameters */
+	weight = 1;
+	level_id = TM_NODE_LEVEL_TC;
+	tnp.n_shared_shapers = 1;
+	tnp.nonleaf.n_sp_priorities = 1;
+	tnp.stats_mask = STATS_MASK_DEFAULT;
+
+	/* Add Shared Shaper Profiles to TM Hierarchy */
+	for (i = 0; i < TC_NODES_PER_PIPE; i++) {
+		shared_shaper_profile_id[i] = shaper_profile_id;
+
+		if (rte_tm_shaper_profile_add(port_id,
+			shared_shaper_profile_id[i], &tssp, error)) {
+			printf("%s ERROR(%d)-%s!(Shared shaper profileid %u)\n",
+				__func__, error->type, error->message,
+				shared_shaper_profile_id[i]);
+
+			return -1;
+		}
+		if (rte_tm_shared_shaper_add_update(port_id,  i,
+			shared_shaper_profile_id[i], error)) {
+			printf("%s ERROR(%d)-%s!(Shared shaper id %u)\n",
+				__func__, error->type, error->message, i);
+
+			return -1;
+		}
+		shaper_profile_id++;
+	}
+
+	/* Add Shaper Profiles and Nodes to TM Hierarchy */
+	l = 0;
+	for (i = 0; i < SUBPORT_NODES_PER_PORT; i++) {
+		for (j = 0; j < PIPE_NODES_PER_SUBPORT; j++) {
+			for (k = 0; k < TC_NODES_PER_PIPE ; k++) {
+				priority = k;
+				tc_parent_node_id = h->pipe_node_id[i][j];
+				tnp.shared_shaper_id =
+					(uint32_t *)calloc(1, sizeof(uint32_t));
+				tnp.shared_shaper_id[0] = k;
+				pos = j + (i * PIPE_NODES_PER_SUBPORT);
+				h->tc_node_id[pos][k] = TC_NODES_START_ID + l;
+
+				if (rte_tm_shaper_profile_add(port_id,
+					shaper_profile_id, &tsp, error)) {
+					printf("%s ERROR(%d)-%s!(shaper %u)\n",
+						__func__, error->type,
+						error->message,
+						shaper_profile_id);
+
+					return -1;
+				}
+				tnp.shaper_profile_id = shaper_profile_id;
+				if (rte_tm_node_add(port_id,
+						h->tc_node_id[pos][k],
+						tc_parent_node_id,
+						priority, weight,
+						level_id,
+						&tnp, error)) {
+					printf("%s ERROR(%d)-%s!(node id %u)\n",
+						__func__,
+						error->type,
+						error->message,
+						h->tc_node_id[pos][k]);
+
+					return -1;
+				}
+				shaper_profile_id++;
+				l++;
+			}
+		}
+	}
+	/* Update */
+	h->n_shapers = shaper_profile_id;
+
+	printf("  TC nodes added (Start id %u, Count %u, level %u)\n",
+		h->tc_node_id[0][0], l, level_id);
+
+	return 0;
+}
+
+static int
+softport_tm_queue_node_add(portid_t port_id, struct tm_hierarchy *h,
+	struct rte_tm_error *error)
+{
+	uint32_t queue_parent_node_id;
+	struct rte_tm_node_params qnp;
+	uint32_t priority, weight, level_id, pos;
+	uint32_t i, j, k, l;
+
+	memset(&qnp, 0, sizeof(struct rte_tm_node_params));
+
+	/* Queue Node Parameters */
+	priority = 0;
+	weight = 1;
+	level_id = TM_NODE_LEVEL_QUEUE;
+	qnp.shaper_profile_id = RTE_TM_SHAPER_PROFILE_ID_NONE;
+	qnp.leaf.cman = RTE_TM_CMAN_TAIL_DROP;
+	qnp.stats_mask = STATS_MASK_QUEUE;
+
+	/* Add Queue Nodes to TM Hierarchy */
+	l = 0;
+	for (i = 0; i < NUM_PIPE_NODES; i++) {
+		for (j = 0; j < TC_NODES_PER_PIPE; j++) {
+			queue_parent_node_id = h->tc_node_id[i][j];
+			for (k = 0; k < QUEUE_NODES_PER_TC; k++) {
+				pos = j + (i * TC_NODES_PER_PIPE);
+				h->queue_node_id[pos][k] = l;
+				if (rte_tm_node_add(port_id,
+						h->queue_node_id[pos][k],
+						queue_parent_node_id,
+						priority,
+						weight,
+						level_id,
+						&qnp, error)) {
+					printf("%s ERROR(%d)-%s!(node %u)\n",
+						__func__,
+						error->type,
+						error->message,
+						h->queue_node_id[pos][k]);
+
+					return -1;
+				}
+				l++;
+			}
+		}
+	}
+	printf("  Queue nodes added (Start id %u, Count %u, level %u)\n",
+		h->queue_node_id[0][0], l, level_id);
+
+	return 0;
+}
+
+/*
+ * TM Packet Field Setup
+ */
+static void
+softport_tm_pktfield_setup(portid_t port_id)
+{
+	struct rte_port *p = &ports[port_id];
+	uint64_t pktfield0_mask = 0;
+	uint64_t pktfield1_mask = 0x0000000FFF000000LLU;
+	uint64_t pktfield2_mask = 0x00000000000000FCLLU;
+
+	p->softport.tm = (struct softnic_port_tm) {
+		.n_subports_per_port = SUBPORT_NODES_PER_PORT,
+		.n_pipes_per_subport = PIPE_NODES_PER_SUBPORT,
+
+		/* Packet field to identify subport
+		 *
+		 * Default configuration assumes only one subport, thus
+		 * the subport ID is hardcoded to 0
+		 */
+		.tm_pktfield0_slabpos = 0,
+		.tm_pktfield0_slabmask = pktfield0_mask,
+		.tm_pktfield0_slabshr =
+			__builtin_ctzll(pktfield0_mask),
+
+		/* Packet field to identify pipe.
+		 *
+		 * Default value assumes Ethernet/IPv4/UDP packets,
+		 * UDP payload bits 12 .. 23
+		 */
+		.tm_pktfield1_slabpos = 40,
+		.tm_pktfield1_slabmask = pktfield1_mask,
+		.tm_pktfield1_slabshr =
+			__builtin_ctzll(pktfield1_mask),
+
+		/* Packet field used as index into TC translation table
+		 * to identify the traffic class and queue.
+		 *
+		 * Default value assumes Ethernet/IPv4 packets, IPv4
+		 * DSCP field
+		 */
+		.tm_pktfield2_slabpos = 8,
+		.tm_pktfield2_slabmask = pktfield2_mask,
+		.tm_pktfield2_slabshr =
+			__builtin_ctzll(pktfield2_mask),
+
+		.tm_tc_table = {
+			0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+			0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+			0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+			0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+		}, /**< TC translation table */
+	};
+}
+
+static int
+softport_tm_hierarchy_specify(portid_t port_id, struct rte_tm_error *error)
+{
+
+	struct tm_hierarchy h;
+	int status;
+
+	memset(&h, 0, sizeof(struct tm_hierarchy));
+
+	/* TM hierarchy shapers rate */
+	set_tm_hiearchy_nodes_shaper_rate(port_id, &h);
+
+	/* Add root node (level 0) */
+	status = softport_tm_root_node_add(port_id, &h, error);
+	if (status)
+		return status;
+
+	/* Add subport node (level 1) */
+	status = softport_tm_subport_node_add(port_id, &h, error);
+	if (status)
+		return status;
+
+	/* Add pipe nodes (level 2) */
+	status = softport_tm_pipe_node_add(port_id, &h, error);
+	if (status)
+		return status;
+
+	/* Add traffic class nodes (level 3) */
+	status = softport_tm_tc_node_add(port_id, &h, error);
+	if (status)
+		return status;
+
+	/* Add queue nodes (level 4) */
+	status = softport_tm_queue_node_add(port_id, &h, error);
+	if (status)
+		return status;
+
+	/* TM packet fields setup */
+	softport_tm_pktfield_setup(port_id);
+
+	return 0;
+}
+
+/*
+ * Soft port Init
+ */
+static void
+softport_tm_begin(portid_t pi)
+{
+	struct rte_port *port = &ports[pi];
+
+	/* Soft port TM flag */
+	if (port->softport.tm_flag == 1) {
+		printf("\n\n  TM feature available on port %u\n", pi);
+
+		/* Soft port TM hierarchy frozen */
+		if (port->softport.tm.hierarchy_frozen == 0) {
+			struct rte_tm_error error;
+			int status;
+
+			/* Stop port */
+			rte_eth_dev_stop(pi);
+
+			/* TM hierarchy specification */
+			status = softport_tm_hierarchy_specify(pi, &error);
+			if (status) {
+				printf("  TM Hierarchy built error(%d) - %s\n",
+					error.type, error.message);
+				return;
+			}
+			printf("\n  TM Hierarchy Specified!\n\v");
+
+			/* TM hierarchy commit */
+			status = rte_tm_hierarchy_commit(pi, 0, &error);
+			if (status) {
+				printf("  Hierarchy commit error(%d) - %s\n",
+					error.type, error.message);
+				return;
+			}
+			printf("  Hierarchy Committed (port %u)!", pi);
+			port->softport.tm.hierarchy_frozen = 1;
+
+			/* Start port */
+			status = rte_eth_dev_start(pi);
+			if (status) {
+				printf("\n  Port %u start error!\n", pi);
+				return;
+			}
+			printf("\n  Port %u started!\n", pi);
+			return;
+		}
+	}
+	printf("\n  TM feature not available on port %u", pi);
+}
+
+struct fwd_engine softnic_tm_engine = {
+	.fwd_mode_name  = "tm",
+	.port_fwd_begin = softport_tm_begin,
+	.port_fwd_end   = NULL,
+	.packet_fwd     = softport_packet_fwd,
+};
+
+struct fwd_engine softnic_tm_bypass_engine = {
+	.fwd_mode_name  = "tm-bypass",
+	.port_fwd_begin = NULL,
+	.port_fwd_end   = NULL,
+	.packet_fwd     = softport_packet_fwd,
+};
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v2 2/2] app/testpmd: add CLI for tm mode
  2017-09-14 11:53 ` [PATCH v2 1/2] app/testpmd: add traffic management forwarding mode Jasvinder Singh
@ 2017-09-14 11:53   ` Jasvinder Singh
  2017-09-18 14:03     ` De Lara Guarch, Pablo
  2017-09-18 13:54   ` [PATCH v2 1/2] app/testpmd: add traffic management forwarding mode De Lara Guarch, Pablo
  2017-09-20  9:56   ` [PATCH v3 1/5] " Jasvinder Singh
  2 siblings, 1 reply; 49+ messages in thread
From: Jasvinder Singh @ 2017-09-14 11:53 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu

Add following CLIs in testpmd application;
- commands to build hierarchical tree for the QoS Scheduler.
- commands for runtime update of the hierarchical tree.
- commands to display TM capability information.
  (per port, per hierarchy level and per hierarchy node)
- command to set the packet field mask and offset value for
  classification.
- command to set traffic class translation table entry
- stats collection

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 app/test-pmd/cmdline.c | 2975 ++++++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 2785 insertions(+), 190 deletions(-)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index cd8c358..cb837ce 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -98,6 +98,19 @@
 #ifdef RTE_LIBRTE_BNXT_PMD
 #include <rte_pmd_bnxt.h>
 #endif
+
+#if defined RTE_LIBRTE_PMD_SOFTNIC && defined RTE_LIBRTE_SCHED
+#define TM_MODE			1
+#else
+#define TM_MODE			0
+#endif
+
+#ifdef TM_MODE
+#include <rte_sched.h>
+#include <rte_eth_softnic.h>
+#include <rte_tm.h>
+#endif
+
 #include "testpmd.h"
 
 static struct cmdline *testpmd_cl;
@@ -230,6 +243,23 @@ static void cmd_help_long_parsed(void *parsed_result,
 
 			"clear vf stats (port_id) (vf_id)\n"
 			"    Reset a VF's statistics.\n\n"
+
+#ifdef TM_MODE
+			"show port tm cap (port_id)\n"
+			"	Display the port TM capability.\n\n"
+
+			"show port tm level cap (port_id) (level_id)\n"
+			"	Display the port TM hierarchical level capability.\n\n"
+
+			"show port tm node cap (port_id) (node_id)\n"
+			"	Display the port TM node capability.\n\n"
+
+			"show port tm node type (port_id) (node_id)\n"
+			"	Display the port TM node type.\n\n"
+
+			"show port tm node stats (port_id) (node_id) (clear)\n"
+			"	Display the port TM node stats.\n\n"
+#endif
 		);
 	}
 
@@ -637,6 +667,61 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"ptype mapping update (port_id) (hw_ptype) (sw_ptype)\n"
 			"    Update a ptype mapping item on a port\n\n"
 
+#ifdef TM_MODE
+			"add port tm node shaper profile (port_id) (shaper_profile_id)"
+			" (tb_rate) (tb_size)\n"
+			"	Add port tm node private shaper profile.\n\n"
+
+			"del port tm node shaper profile (port_id) (shaper_profile_id)\n"
+			"	Delete port tm node private shaper profile.\n\n"
+
+			"add port tm node shared shaper (port_id) (shared_shaper_id)"
+			" (shaper_profile_id)\n"
+			"	Add/update port tm node shared shaper.\n\n"
+
+			"del port tm node shared shaper (port_id) (shared_shaper_id)\n"
+			"	Delete port tm node shared shaper.\n\n"
+
+			"add port tm node wred profile (port_id) (wred_profile_id)"
+			" (color_g) (min_th_g) (max_th_g) (maxp_inv_g) (wq_log2_g)"
+			" (color_y) (min_th_y) (max_th_y) (maxp_inv_y) (wq_log2_y)"
+			" (color_r) (min_th_r) (max_th_r) (maxp_inv_r) (wq_log2_r)\n"
+			"	Add port tm node wred profile.\n\n"
+
+			"del port tm node wred profile (port_id) (wred_profile_id)\n"
+			"	Delete port tm node wred profile.\n\n"
+
+			"add port tm nonleaf node shared shaper (port_id) (node_id)"
+			" (parent_node_id) (priority) (weight) (level_id)"
+			" (shaper_profile_id) (shared_shaper_id) (n_shared_shapers)"
+			" (n_sp_priorities)\n"
+			"	Add port tm nonleaf node.\n\n"
+
+			"add port tm leaf node shared shaper (port_id) (node_id)"
+			" (parent_node_id) (priority) (weight) (level_id)"
+			" (cman_mode) (wred_profile_id)\n"
+			"	Add port tm leaf node.\n\n"
+
+			"del port tm node (port_id) (node_id)\n"
+			"	Delete port tm node.\n\n"
+
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+			"set port tm node parent (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight)\n"
+			"	Set port tm node parent.\n\n"
+#endif
+			"set port tm node shaper profile (port_id) (node_id)"
+			" (shaper_profile_id)\n"
+			"	Set port tm node shaper profile.\n\n"
+
+			"set port tm pktfield (subport|pipe|tc) (port_id) offset"
+			" (offset) mask (mask)\n"
+			"	Set port tm packet field.\n\n"
+
+			"set port tm tc table (port_id) index (tb_index) tc (tc_id)"
+			" queue (queue id)\n"
+			"	Set port tm traffic class table entry.\n\n"
+#endif
 			, list_pkt_forwarding_modes()
 		);
 	}
@@ -14185,197 +14270,2707 @@ cmdline_parse_inst_t cmd_load_from_file = {
 	},
 };
 
-/* ******************************************************************************** */
+#ifdef TM_MODE
 
-/* list of instructions */
-cmdline_parse_ctx_t main_ctx[] = {
-	(cmdline_parse_inst_t *)&cmd_help_brief,
-	(cmdline_parse_inst_t *)&cmd_help_long,
-	(cmdline_parse_inst_t *)&cmd_quit,
-	(cmdline_parse_inst_t *)&cmd_load_from_file,
-	(cmdline_parse_inst_t *)&cmd_showport,
-	(cmdline_parse_inst_t *)&cmd_showqueue,
-	(cmdline_parse_inst_t *)&cmd_showportall,
-	(cmdline_parse_inst_t *)&cmd_showcfg,
-	(cmdline_parse_inst_t *)&cmd_start,
-	(cmdline_parse_inst_t *)&cmd_start_tx_first,
-	(cmdline_parse_inst_t *)&cmd_start_tx_first_n,
-	(cmdline_parse_inst_t *)&cmd_set_link_up,
-	(cmdline_parse_inst_t *)&cmd_set_link_down,
-	(cmdline_parse_inst_t *)&cmd_reset,
-	(cmdline_parse_inst_t *)&cmd_set_numbers,
-	(cmdline_parse_inst_t *)&cmd_set_txpkts,
-	(cmdline_parse_inst_t *)&cmd_set_txsplit,
-	(cmdline_parse_inst_t *)&cmd_set_fwd_list,
-	(cmdline_parse_inst_t *)&cmd_set_fwd_mask,
-	(cmdline_parse_inst_t *)&cmd_set_fwd_mode,
-	(cmdline_parse_inst_t *)&cmd_set_fwd_retry_mode,
-	(cmdline_parse_inst_t *)&cmd_set_burst_tx_retry,
-	(cmdline_parse_inst_t *)&cmd_set_promisc_mode_one,
-	(cmdline_parse_inst_t *)&cmd_set_promisc_mode_all,
-	(cmdline_parse_inst_t *)&cmd_set_allmulti_mode_one,
-	(cmdline_parse_inst_t *)&cmd_set_allmulti_mode_all,
-	(cmdline_parse_inst_t *)&cmd_set_flush_rx,
-	(cmdline_parse_inst_t *)&cmd_set_link_check,
-	(cmdline_parse_inst_t *)&cmd_set_bypass_mode,
-	(cmdline_parse_inst_t *)&cmd_set_bypass_event,
-	(cmdline_parse_inst_t *)&cmd_set_bypass_timeout,
-	(cmdline_parse_inst_t *)&cmd_show_bypass_config,
-#ifdef RTE_LIBRTE_PMD_BOND
-	(cmdline_parse_inst_t *) &cmd_set_bonding_mode,
-	(cmdline_parse_inst_t *) &cmd_show_bonding_config,
-	(cmdline_parse_inst_t *) &cmd_set_bonding_primary,
-	(cmdline_parse_inst_t *) &cmd_add_bonding_slave,
-	(cmdline_parse_inst_t *) &cmd_remove_bonding_slave,
-	(cmdline_parse_inst_t *) &cmd_create_bonded_device,
-	(cmdline_parse_inst_t *) &cmd_set_bond_mac_addr,
-	(cmdline_parse_inst_t *) &cmd_set_balance_xmit_policy,
-	(cmdline_parse_inst_t *) &cmd_set_bond_mon_period,
-	(cmdline_parse_inst_t *) &cmd_set_lacp_dedicated_queues,
-	(cmdline_parse_inst_t *) &cmd_set_bonding_agg_mode_policy,
-#endif
-	(cmdline_parse_inst_t *)&cmd_vlan_offload,
-	(cmdline_parse_inst_t *)&cmd_vlan_tpid,
-	(cmdline_parse_inst_t *)&cmd_rx_vlan_filter_all,
-	(cmdline_parse_inst_t *)&cmd_rx_vlan_filter,
-	(cmdline_parse_inst_t *)&cmd_tx_vlan_set,
-	(cmdline_parse_inst_t *)&cmd_tx_vlan_set_qinq,
-	(cmdline_parse_inst_t *)&cmd_tx_vlan_reset,
-	(cmdline_parse_inst_t *)&cmd_tx_vlan_set_pvid,
-	(cmdline_parse_inst_t *)&cmd_csum_set,
-	(cmdline_parse_inst_t *)&cmd_csum_show,
-	(cmdline_parse_inst_t *)&cmd_csum_tunnel,
-	(cmdline_parse_inst_t *)&cmd_tso_set,
-	(cmdline_parse_inst_t *)&cmd_tso_show,
-	(cmdline_parse_inst_t *)&cmd_tunnel_tso_set,
-	(cmdline_parse_inst_t *)&cmd_tunnel_tso_show,
-	(cmdline_parse_inst_t *)&cmd_enable_gro,
-	(cmdline_parse_inst_t *)&cmd_gro_set,
-	(cmdline_parse_inst_t *)&cmd_link_flow_control_set,
-	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_rx,
-	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_tx,
-	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_hw,
-	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_lw,
-	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_pt,
-	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_xon,
-	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_macfwd,
-	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_autoneg,
-	(cmdline_parse_inst_t *)&cmd_priority_flow_control_set,
-	(cmdline_parse_inst_t *)&cmd_config_dcb,
-	(cmdline_parse_inst_t *)&cmd_read_reg,
-	(cmdline_parse_inst_t *)&cmd_read_reg_bit_field,
-	(cmdline_parse_inst_t *)&cmd_read_reg_bit,
-	(cmdline_parse_inst_t *)&cmd_write_reg,
-	(cmdline_parse_inst_t *)&cmd_write_reg_bit_field,
-	(cmdline_parse_inst_t *)&cmd_write_reg_bit,
-	(cmdline_parse_inst_t *)&cmd_read_rxd_txd,
-	(cmdline_parse_inst_t *)&cmd_stop,
-	(cmdline_parse_inst_t *)&cmd_mac_addr,
-	(cmdline_parse_inst_t *)&cmd_set_qmap,
-	(cmdline_parse_inst_t *)&cmd_operate_port,
-	(cmdline_parse_inst_t *)&cmd_operate_specific_port,
-	(cmdline_parse_inst_t *)&cmd_operate_attach_port,
-	(cmdline_parse_inst_t *)&cmd_operate_detach_port,
-	(cmdline_parse_inst_t *)&cmd_config_speed_all,
-	(cmdline_parse_inst_t *)&cmd_config_speed_specific,
-	(cmdline_parse_inst_t *)&cmd_config_rx_tx,
-	(cmdline_parse_inst_t *)&cmd_config_mtu,
-	(cmdline_parse_inst_t *)&cmd_config_max_pkt_len,
-	(cmdline_parse_inst_t *)&cmd_config_rx_mode_flag,
-	(cmdline_parse_inst_t *)&cmd_config_rss,
-	(cmdline_parse_inst_t *)&cmd_config_rxtx_queue,
-	(cmdline_parse_inst_t *)&cmd_config_txqflags,
-	(cmdline_parse_inst_t *)&cmd_config_rss_reta,
-	(cmdline_parse_inst_t *)&cmd_showport_reta,
-	(cmdline_parse_inst_t *)&cmd_config_burst,
-	(cmdline_parse_inst_t *)&cmd_config_thresh,
-	(cmdline_parse_inst_t *)&cmd_config_threshold,
-	(cmdline_parse_inst_t *)&cmd_set_uc_hash_filter,
-	(cmdline_parse_inst_t *)&cmd_set_uc_all_hash_filter,
-	(cmdline_parse_inst_t *)&cmd_vf_mac_addr_filter,
-	(cmdline_parse_inst_t *)&cmd_set_vf_macvlan_filter,
-	(cmdline_parse_inst_t *)&cmd_queue_rate_limit,
-	(cmdline_parse_inst_t *)&cmd_tunnel_filter,
-	(cmdline_parse_inst_t *)&cmd_tunnel_udp_config,
-	(cmdline_parse_inst_t *)&cmd_global_config,
-	(cmdline_parse_inst_t *)&cmd_set_mirror_mask,
-	(cmdline_parse_inst_t *)&cmd_set_mirror_link,
-	(cmdline_parse_inst_t *)&cmd_reset_mirror_rule,
-	(cmdline_parse_inst_t *)&cmd_showport_rss_hash,
-	(cmdline_parse_inst_t *)&cmd_showport_rss_hash_key,
-	(cmdline_parse_inst_t *)&cmd_config_rss_hash_key,
-	(cmdline_parse_inst_t *)&cmd_dump,
-	(cmdline_parse_inst_t *)&cmd_dump_one,
-	(cmdline_parse_inst_t *)&cmd_ethertype_filter,
-	(cmdline_parse_inst_t *)&cmd_syn_filter,
-	(cmdline_parse_inst_t *)&cmd_2tuple_filter,
-	(cmdline_parse_inst_t *)&cmd_5tuple_filter,
-	(cmdline_parse_inst_t *)&cmd_flex_filter,
-	(cmdline_parse_inst_t *)&cmd_add_del_ip_flow_director,
-	(cmdline_parse_inst_t *)&cmd_add_del_udp_flow_director,
-	(cmdline_parse_inst_t *)&cmd_add_del_sctp_flow_director,
-	(cmdline_parse_inst_t *)&cmd_add_del_l2_flow_director,
-	(cmdline_parse_inst_t *)&cmd_add_del_mac_vlan_flow_director,
-	(cmdline_parse_inst_t *)&cmd_add_del_tunnel_flow_director,
-	(cmdline_parse_inst_t *)&cmd_flush_flow_director,
-	(cmdline_parse_inst_t *)&cmd_set_flow_director_ip_mask,
-	(cmdline_parse_inst_t *)&cmd_set_flow_director_mac_vlan_mask,
-	(cmdline_parse_inst_t *)&cmd_set_flow_director_tunnel_mask,
-	(cmdline_parse_inst_t *)&cmd_set_flow_director_flex_mask,
-	(cmdline_parse_inst_t *)&cmd_set_flow_director_flex_payload,
-	(cmdline_parse_inst_t *)&cmd_get_sym_hash_ena_per_port,
-	(cmdline_parse_inst_t *)&cmd_set_sym_hash_ena_per_port,
-	(cmdline_parse_inst_t *)&cmd_get_hash_global_config,
-	(cmdline_parse_inst_t *)&cmd_set_hash_global_config,
-	(cmdline_parse_inst_t *)&cmd_set_hash_input_set,
-	(cmdline_parse_inst_t *)&cmd_set_fdir_input_set,
-	(cmdline_parse_inst_t *)&cmd_flow,
-	(cmdline_parse_inst_t *)&cmd_mcast_addr,
-	(cmdline_parse_inst_t *)&cmd_config_l2_tunnel_eth_type_all,
-	(cmdline_parse_inst_t *)&cmd_config_l2_tunnel_eth_type_specific,
-	(cmdline_parse_inst_t *)&cmd_config_l2_tunnel_en_dis_all,
-	(cmdline_parse_inst_t *)&cmd_config_l2_tunnel_en_dis_specific,
-	(cmdline_parse_inst_t *)&cmd_config_e_tag_insertion_en,
-	(cmdline_parse_inst_t *)&cmd_config_e_tag_insertion_dis,
-	(cmdline_parse_inst_t *)&cmd_config_e_tag_stripping_en_dis,
-	(cmdline_parse_inst_t *)&cmd_config_e_tag_forwarding_en_dis,
-	(cmdline_parse_inst_t *)&cmd_config_e_tag_filter_add,
-	(cmdline_parse_inst_t *)&cmd_config_e_tag_filter_del,
-	(cmdline_parse_inst_t *)&cmd_set_vf_vlan_anti_spoof,
-	(cmdline_parse_inst_t *)&cmd_set_vf_mac_anti_spoof,
-	(cmdline_parse_inst_t *)&cmd_set_vf_vlan_stripq,
-	(cmdline_parse_inst_t *)&cmd_set_vf_vlan_insert,
-	(cmdline_parse_inst_t *)&cmd_set_tx_loopback,
-	(cmdline_parse_inst_t *)&cmd_set_all_queues_drop_en,
-	(cmdline_parse_inst_t *)&cmd_set_vf_split_drop_en,
-	(cmdline_parse_inst_t *)&cmd_set_macsec_offload_on,
-	(cmdline_parse_inst_t *)&cmd_set_macsec_offload_off,
-	(cmdline_parse_inst_t *)&cmd_set_macsec_sc,
-	(cmdline_parse_inst_t *)&cmd_set_macsec_sa,
-	(cmdline_parse_inst_t *)&cmd_set_vf_traffic,
-	(cmdline_parse_inst_t *)&cmd_set_vf_rxmode,
-	(cmdline_parse_inst_t *)&cmd_vf_rate_limit,
-	(cmdline_parse_inst_t *)&cmd_vf_rxvlan_filter,
-	(cmdline_parse_inst_t *)&cmd_set_vf_mac_addr,
-	(cmdline_parse_inst_t *)&cmd_set_vf_promisc,
-	(cmdline_parse_inst_t *)&cmd_set_vf_allmulti,
-	(cmdline_parse_inst_t *)&cmd_set_vf_broadcast,
-	(cmdline_parse_inst_t *)&cmd_set_vf_vlan_tag,
-	(cmdline_parse_inst_t *)&cmd_vf_max_bw,
-	(cmdline_parse_inst_t *)&cmd_vf_tc_min_bw,
-	(cmdline_parse_inst_t *)&cmd_vf_tc_max_bw,
-	(cmdline_parse_inst_t *)&cmd_strict_link_prio,
-	(cmdline_parse_inst_t *)&cmd_tc_min_bw,
-	(cmdline_parse_inst_t *)&cmd_ddp_add,
-	(cmdline_parse_inst_t *)&cmd_ddp_del,
-	(cmdline_parse_inst_t *)&cmd_ddp_get_list,
-	(cmdline_parse_inst_t *)&cmd_ddp_get_info,
-	(cmdline_parse_inst_t *)&cmd_show_vf_stats,
-	(cmdline_parse_inst_t *)&cmd_clear_vf_stats,
-	(cmdline_parse_inst_t *)&cmd_ptype_mapping_get,
-	(cmdline_parse_inst_t *)&cmd_ptype_mapping_replace,
-	(cmdline_parse_inst_t *)&cmd_ptype_mapping_reset,
-	(cmdline_parse_inst_t *)&cmd_ptype_mapping_update,
+/** Display TM Error Message */
+static void
+print_err_msg(struct rte_tm_error *error)
+{
+	static const char *const errstrlist[] = {
+		[RTE_TM_ERROR_TYPE_NONE] = "no error",
+		[RTE_TM_ERROR_TYPE_UNSPECIFIED] = "cause unspecified",
+		[RTE_TM_ERROR_TYPE_CAPABILITIES]
+			= "capability parameter null",
+		[RTE_TM_ERROR_TYPE_LEVEL_ID] = "level id",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE]
+			= "wred profile null",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_GREEN] = "wred profile(green)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_YELLOW]
+			= "wred profile(yellow)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_RED] = "wred profile(red)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_ID] = "wred profile id",
+		[RTE_TM_ERROR_TYPE_SHARED_WRED_CONTEXT_ID]
+			= "shared wred context id",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE] = "shaper profile null",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE]
+			= "committed rate field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE]
+			= "committed size field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE]
+			= "peak rate field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE]
+			= "peak size field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN]
+			= "packet adjust length field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID] = "shaper profile id",
+		[RTE_TM_ERROR_TYPE_SHARED_SHAPER_ID] = "shared shaper id",
+		[RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID] = "parent node id",
+		[RTE_TM_ERROR_TYPE_NODE_PRIORITY] = "node priority",
+		[RTE_TM_ERROR_TYPE_NODE_WEIGHT] = "node weight",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS] = "node parameter null",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID]
+			= "shaper profile id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID]
+			= "shared shaper id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS]
+			= "num shared shapers field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE]
+			= "wfq weght mode field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES]
+			= "num strict priorities field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN]
+			= "congestion management mode field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID] =
+			"wred profile id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID]
+			= "shared wred context id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS]
+			= "num shared wred contexts field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS]
+			= "stats field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_ID] = "node id",
+	};
+
+	const char *errstr;
+	char buf[64];
+
+	if ((unsigned int)error->type >= RTE_DIM(errstrlist) ||
+		!errstrlist[error->type])
+		errstr = "unknown type";
+	else
+		errstr = errstrlist[error->type];
+
+	if (error->cause)
+		snprintf(buf, sizeof(buf), "cause: %p, ", error->cause);
+
+	printf("%s: %s%s (error %d)\n", errstr, error->cause ? buf : "",
+		error->message ? error->message : "(no stated reason)",
+		error->type);
+}
+
+/* *** Port TM Capability *** */
+struct cmd_show_port_tm_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t cap;
+	uint8_t port_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		 port_id, UINT8);
+
+static void cmd_show_port_tm_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_cap_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_capabilities cap;
+	struct rte_tm_error error;
+	uint8_t port_id = res->port_id;
+	uint32_t i;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	memset(&cap, 0, sizeof(struct rte_tm_capabilities));
+	ret = rte_tm_capabilities_get(port_id, &cap, &error);
+	if (ret) {
+		print_err_msg(&error);
+		return;
+	}
+
+	printf("\n****   Port TM Capabilities ****\n\n");
+	printf("cap.n_nodes_max %u\n", cap.n_nodes_max);
+	printf("cap.n_levels_max %u\n", cap.n_levels_max);
+	printf("cap.non_leaf_nodes_identical %d\n",
+		cap.non_leaf_nodes_identical);
+	printf("cap.leaf_nodes_identical %d\n", cap.leaf_nodes_identical);
+	printf("cap.shaper_n_max %u\n", cap.shaper_n_max);
+	printf("cap.shaper_private_n_max %u\n", cap.shaper_private_n_max);
+	printf("cap.shaper_private_dual_rate_n_max %d\n",
+		cap.shaper_private_dual_rate_n_max);
+	printf("cap.shaper_private_rate_min %lu\n",
+		cap.shaper_private_rate_min);
+	printf("cap.shaper_private_rate_max %lu\n",
+		cap.shaper_private_rate_max);
+	printf("cap.shaper_shared_n_max %u\n", cap.shaper_shared_n_max);
+	printf("cap.shaper_shared_n_nodes_per_shaper_max %u\n",
+		cap.shaper_shared_n_nodes_per_shaper_max);
+	printf("cap.shaper_shared_n_shapers_per_node_max %u\n",
+		cap.shaper_shared_n_shapers_per_node_max);
+	printf("cap.shaper_shared_dual_rate_n_max %u\n",
+		cap.shaper_shared_dual_rate_n_max);
+	printf("cap.shaper_shared_rate_min %lu\n",
+		cap.shaper_shared_rate_min);
+	printf("cap.shaper_shared_rate_max %lu\n",
+		cap.shaper_shared_rate_max);
+	printf("cap.shaper_pkt_length_adjust_min %d\n",
+		cap.shaper_pkt_length_adjust_min);
+	printf("cap.shaper_pkt_length_adjust_max %d\n",
+		cap.shaper_pkt_length_adjust_max);
+	printf("cap.sched_n_children_max %u\n", cap.sched_n_children_max);
+	printf("cap.sched_sp_n_priorities_max %u\n",
+		cap.sched_sp_n_priorities_max);
+	printf("cap.sched_wfq_n_children_per_group_max %u\n",
+		cap.sched_wfq_n_children_per_group_max);
+	printf("cap.sched_wfq_n_groups_max %u\n", cap.sched_wfq_n_groups_max);
+	printf("cap.sched_wfq_weight_max %u\n", cap.sched_wfq_weight_max);
+	printf("cap.cman_head_drop_supported %d\n",
+		cap.cman_head_drop_supported);
+	printf("cap.cman_wred_context_n_max %u\n", cap.cman_wred_context_n_max);
+	printf("cap.cman_wred_context_private_n_max %u\n",
+		cap.cman_wred_context_private_n_max);
+	printf("cap.cman_wred_context_shared_n_max %u\n",
+		cap.cman_wred_context_shared_n_max);
+	printf("cap.cman_wred_context_shared_n_nodes_per_context_max %u\n",
+		cap.cman_wred_context_shared_n_nodes_per_context_max);
+	printf("cap.cman_wred_context_shared_n_contexts_per_node_max %u\n",
+		cap.cman_wred_context_shared_n_contexts_per_node_max);
+
+	for (i = 0; i < RTE_TM_COLORS; i++) {
+		printf("cap.mark_vlan_dei_supported %d\n",
+			cap.mark_vlan_dei_supported[i]);
+		printf("cap.mark_ip_ecn_tcp_supported %d\n",
+			cap.mark_ip_ecn_tcp_supported[i]);
+		printf("cap.mark_ip_ecn_sctp_supported %d\n",
+			cap.mark_ip_ecn_sctp_supported[i]);
+		printf("cap.mark_ip_dscp_supported %d\n",
+			cap.mark_ip_dscp_supported[i]);
+	}
+
+	printf("cap.dynamic_update_mask %lu\n", cap.dynamic_update_mask);
+	printf("cap.stats_mask %lu\n", cap.stats_mask);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_cap = {
+	.f = cmd_show_port_tm_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_cap_show,
+		(void *)&cmd_show_port_tm_cap_port,
+		(void *)&cmd_show_port_tm_cap_tm,
+		(void *)&cmd_show_port_tm_cap_cap,
+		(void *)&cmd_show_port_tm_cap_port_id,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchical Level Capability *** */
+struct cmd_show_port_tm_level_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t level;
+	cmdline_fixed_string_t cap;
+	uint8_t port_id;
+	uint32_t level_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_level =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		level, "level");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_level_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		 port_id, UINT8);
+cmdline_parse_token_num_t cmd_show_port_tm_level_cap_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		 level_id, UINT32);
+
+
+static void cmd_show_port_tm_level_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_level_cap_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_level_capabilities lcap;
+	struct rte_tm_error error;
+	uint8_t port_id = res->port_id;
+	int ret, level_id = res->level_id;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	if ((level_id > 4) || (level_id < 0)) {
+		printf("  TM hierarchical level invalid !! ");
+		return;
+	}
+
+	memset(&lcap, 0, sizeof(struct rte_tm_level_capabilities));
+	ret = rte_tm_level_capabilities_get(port_id, level_id, &lcap, &error);
+	if (ret) {
+		print_err_msg(&error);
+		return;
+	}
+	printf("\n****   Port TM Hierarchy level %u Capability ****\n\n",
+		level_id);
+
+	printf("cap.n_nodes_max %u\n", lcap.n_nodes_max);
+	printf("cap.n_nodes_nonleaf_max %u\n", lcap.n_nodes_nonleaf_max);
+	printf("cap.n_nodes_leaf_max %u\n", lcap.n_nodes_leaf_max);
+	printf("cap.non_leaf_nodes_identical %d\n",
+		lcap.non_leaf_nodes_identical);
+	printf("cap.leaf_nodes_identical %d\n", lcap.leaf_nodes_identical);
+	if (level_id <= 3) {
+		printf("cap.nonleaf.shaper_private_supported %d\n",
+			lcap.nonleaf.shaper_private_supported);
+		printf("cap.nonleaf.shaper_private_dual_rate_supported %d\n",
+			lcap.nonleaf.shaper_private_dual_rate_supported);
+		printf("cap.nonleaf.shaper_private_rate_min %lu\n",
+			lcap.nonleaf.shaper_private_rate_min);
+		printf("cap.nonleaf.shaper_private_rate_max %lu\n",
+			lcap.nonleaf.shaper_private_rate_max);
+		printf("cap.nonleaf.shaper_shared_n_max %u\n",
+			lcap.nonleaf.shaper_shared_n_max);
+		printf("cap.nonleaf.sched_n_children_max %u\n",
+			lcap.nonleaf.sched_n_children_max);
+		printf("cap.nonleaf.sched_sp_n_priorities_max %u\n",
+			lcap.nonleaf.sched_sp_n_priorities_max);
+		printf("cap.nonleaf.sched_wfq_n_children_per_group_max %u\n",
+			lcap.nonleaf.sched_wfq_n_children_per_group_max);
+		printf("cap.nonleaf.sched_wfq_n_groups_max %u\n",
+			lcap.nonleaf.sched_wfq_n_groups_max);
+		printf("cap.nonleaf.sched_wfq_weight_max %u\n",
+			lcap.nonleaf.sched_wfq_weight_max);
+		printf("cap.nonleaf.stats_mask %lu\n", lcap.nonleaf.stats_mask);
+	} else {
+		printf("cap.leaf.shaper_private_supported %d\n",
+			lcap.leaf.shaper_private_supported);
+		printf("cap.leaf.shaper_private_dual_rate_supported %d\n",
+			lcap.leaf.shaper_private_dual_rate_supported);
+		printf("cap.leaf.shaper_private_rate_min %lu\n",
+			lcap.leaf.shaper_private_rate_min);
+		printf("cap.leaf.shaper_private_rate_max %lu\n",
+			lcap.leaf.shaper_private_rate_max);
+		printf("cap.leaf.shaper_shared_n_max %u\n",
+			lcap.leaf.shaper_shared_n_max);
+		printf("cap.leaf.cman_head_drop_supported %d\n",
+			lcap.leaf.cman_head_drop_supported);
+		printf("cap.leaf.cman_wred_context_private_supported %d\n",
+			lcap.leaf.cman_wred_context_private_supported);
+		printf("cap.leaf.cman_wred_context_shared_n_max %u\n",
+			lcap.leaf.cman_wred_context_shared_n_max);
+		printf("cap.leaf.stats_mask %lu\n",
+			lcap.leaf.stats_mask);
+	}
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_level_cap = {
+	.f = cmd_show_port_tm_level_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Hierarhical level Capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_level_cap_show,
+		(void *)&cmd_show_port_tm_level_cap_port,
+		(void *)&cmd_show_port_tm_level_cap_tm,
+		(void *)&cmd_show_port_tm_level_cap_level,
+		(void *)&cmd_show_port_tm_level_cap_cap,
+		(void *)&cmd_show_port_tm_level_cap_port_id,
+		(void *)&cmd_show_port_tm_level_cap_level_id,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchy Node Capability *** */
+struct cmd_show_port_tm_node_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t cap;
+	uint8_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_node =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_node_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		 port_id, UINT8);
+cmdline_parse_token_num_t cmd_show_port_tm_node_cap_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		 node_id, UINT32);
+
+static void cmd_show_port_tm_node_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_cap_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_node_capabilities ncap;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint8_t port_id = res->port_id;
+	int ret, is_leaf = 0;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Node id must be valid */
+	ret = rte_tm_node_type_get(port_id, node_id, &is_leaf, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	memset(&ncap, 0, sizeof(struct rte_tm_node_capabilities));
+	ret = rte_tm_node_capabilities_get(port_id, node_id, &ncap, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+	printf("\n****   Port TM Hierarchy node %u Capability ****\n\n",
+		node_id);
+	printf("cap.shaper_private_supported %d\n",
+		ncap.shaper_private_supported);
+	printf("cap.shaper_private_dual_rate_supported %d\n",
+		ncap.shaper_private_dual_rate_supported);
+	printf("cap.shaper_private_rate_min %lu\n",
+		ncap.shaper_private_rate_min);
+	printf("cap.shaper_private_rate_max %lu\n",
+		ncap.shaper_private_rate_max);
+	printf("cap.shaper_shared_n_max %u\n",
+		ncap.shaper_shared_n_max);
+	if (!is_leaf) {
+		printf("cap.nonleaf.sched_n_children_max %u\n",
+			ncap.nonleaf.sched_n_children_max);
+		printf("cap.nonleaf.sched_sp_n_priorities_max %u\n",
+			ncap.nonleaf.sched_sp_n_priorities_max);
+		printf("cap.nonleaf.sched_wfq_n_children_per_group_max %u\n",
+			ncap.nonleaf.sched_wfq_n_children_per_group_max);
+		printf("cap.nonleaf.sched_wfq_n_groups_max %u\n",
+			ncap.nonleaf.sched_wfq_n_groups_max);
+		printf("cap.nonleaf.sched_wfq_weight_max %u\n",
+			ncap.nonleaf.sched_wfq_weight_max);
+	} else {
+		printf("cap.leaf.cman_head_drop_supported %d\n",
+			ncap.leaf.cman_head_drop_supported);
+		printf("cap.leaf.cman_wred_context_private_supported %d\n",
+			ncap.leaf.cman_wred_context_private_supported);
+		printf("cap.leaf.cman_wred_context_shared_n_max %u\n",
+			ncap.leaf.cman_wred_context_shared_n_max);
+	}
+	printf("cap.stats_mask %lu\n", ncap.stats_mask);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_cap = {
+	.f = cmd_show_port_tm_node_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Hierarchy node capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_cap_show,
+		(void *)&cmd_show_port_tm_node_cap_port,
+		(void *)&cmd_show_port_tm_node_cap_tm,
+		(void *)&cmd_show_port_tm_node_cap_node,
+		(void *)&cmd_show_port_tm_node_cap_cap,
+		(void *)&cmd_show_port_tm_node_cap_port_id,
+		(void *)&cmd_show_port_tm_node_cap_node_id,
+		NULL,
+	},
+};
+
+/* *** Add Port TM Private Shaper Profile *** */
+struct cmd_add_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint8_t port_id;
+	uint32_t shaper_id;
+	uint64_t tb_rate;
+	uint64_t tb_size;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_tb_rate =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tb_rate, UINT64);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_tb_size =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tb_size, UINT64);
+
+static void cmd_add_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_shaper_params sp;
+	struct rte_tm_error error;
+	uint32_t shaper_id = res->shaper_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Private shaper profile params */
+	memset(&sp, 0, sizeof(struct rte_tm_shaper_params));
+	sp.peak.rate = res->tb_rate;
+	sp.peak.size = res->tb_size;
+	sp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+	ret = rte_tm_shaper_profile_add(port_id, shaper_id, &sp, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_shaper_profile = {
+	.f = cmd_add_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Add port tm node private shaper profile",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_shaper_profile_add,
+		(void *)&cmd_add_port_tm_node_shaper_profile_port,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_add_port_tm_node_shaper_profile_node,
+		(void *)&cmd_add_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_add_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_add_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_add_port_tm_node_shaper_profile_shaper_id,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tb_rate,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tb_size,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM Private Shaper Profile *** */
+struct cmd_del_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint8_t port_id;
+	uint32_t shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_del_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_del_port_tm_node_shaper_profile_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			shaper_id, UINT32);
+
+static void cmd_del_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_error error;
+	uint32_t shaper_id = res->shaper_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	ret = rte_tm_shaper_profile_delete(port_id, shaper_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_shaper_profile = {
+	.f = cmd_del_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node private shaper profile",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_shaper_profile_del,
+		(void *)&cmd_del_port_tm_node_shaper_profile_port,
+		(void *)&cmd_del_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_del_port_tm_node_shaper_profile_node,
+		(void *)&cmd_del_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_del_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_del_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_del_port_tm_node_shaper_profile_shaper_id,
+		NULL,
+	},
+};
+
+/* *** Add/Update Port TM shared Shaper *** */
+struct cmd_add_port_tm_node_shared_shaper_result {
+	cmdline_fixed_string_t cmd_type;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shared;
+	cmdline_fixed_string_t shaper;
+	uint8_t port_id;
+	uint32_t shared_shaper_id;
+	uint32_t shaper_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_cmd_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			cmd_type, "add#set");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_shared =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shared, "shared");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shaper, "shaper");
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shared_shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shaper_profile_id, UINT32);
+
+static void cmd_add_port_tm_node_shared_shaper_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_shared_shaper_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_error error;
+	struct rte_eth_link link;
+	uint32_t shared_shaper_id = res->shared_shaper_id;
+	uint32_t shaper_profile_id = res->shaper_profile_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+	memset(&link, 0, sizeof(link));
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Command type: add */
+	if (strcmp(res->cmd_type, "add") == 0) {
+		/* Port link status */
+		rte_eth_link_get_nowait(port_id, &link);
+		if (link.link_status == ETH_LINK_UP) {
+			printf(" Port %u link up (error)\n", port_id);
+			return;
+		}
+
+		/* TM hierarchy status */
+		if (port->softport.tm.hierarchy_frozen == 1)
+			port->softport.tm.hierarchy_frozen = 0;
+	}
+
+	/* Command type: set (update) */
+	if (strcmp(res->cmd_type, "set") == 0) {
+		/* TM hierarchy status */
+		if (port->softport.tm.hierarchy_frozen == 0) {
+			printf(" hierarchy not frozen (error)\n");
+			return;
+		}
+
+		rte_eth_link_get_nowait(port_id, &link);
+		if (link.link_status == ETH_LINK_DOWN) {
+			printf(" Port %u link down (error)\n", port_id);
+			return;
+		}
+	}
+
+	ret = rte_tm_shared_shaper_add_update(port_id, shared_shaper_id,
+		shaper_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_shared_shaper = {
+	.f = cmd_add_port_tm_node_shared_shaper_parsed,
+	.data = NULL,
+	.help_str = "add/update port tm node shared shaper",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_shared_shaper_cmd_type,
+		(void *)&cmd_add_port_tm_node_shared_shaper_port,
+		(void *)&cmd_add_port_tm_node_shared_shaper_tm,
+		(void *)&cmd_add_port_tm_node_shared_shaper_node,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shared,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shaper,
+		(void *)&cmd_add_port_tm_node_shared_shaper_port_id,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shared_shaper_id,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shaper_profile_id,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM shared Shaper *** */
+struct cmd_del_port_tm_node_shared_shaper_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shared;
+	cmdline_fixed_string_t shaper;
+	uint8_t port_id;
+	uint32_t shared_shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_shared =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shared, "shared");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shaper, "shaper");
+cmdline_parse_token_num_t cmd_del_port_tm_node_shared_shaper_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_del_port_tm_node_shared_shaper_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shared_shaper_id, UINT32);
+
+static void cmd_del_port_tm_node_shared_shaper_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_shared_shaper_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_error error;
+	uint32_t shared_shaper_id = res->shared_shaper_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	ret = rte_tm_shared_shaper_delete(port_id, shared_shaper_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper = {
+	.f = cmd_del_port_tm_node_shared_shaper_parsed,
+	.data = NULL,
+	.help_str = "delete port tm node shared shaper",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_shared_shaper_del,
+		(void *)&cmd_del_port_tm_node_shared_shaper_port,
+		(void *)&cmd_del_port_tm_node_shared_shaper_tm,
+		(void *)&cmd_del_port_tm_node_shared_shaper_node,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shared,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shaper,
+		(void *)&cmd_del_port_tm_node_shared_shaper_port_id,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shared_shaper_id,
+		NULL,
+	},
+};
+
+/* *** Add Port TM Node WRED Profile *** */
+struct cmd_add_port_tm_node_wred_profile_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t wred;
+	cmdline_fixed_string_t profile;
+	uint8_t port_id;
+	uint32_t wred_profile_id;
+	cmdline_fixed_string_t color_g;
+	uint16_t min_th_g;
+	uint16_t max_th_g;
+	uint16_t maxp_inv_g;
+	uint16_t wq_log2_g;
+	cmdline_fixed_string_t color_y;
+	uint16_t min_th_y;
+	uint16_t max_th_y;
+	uint16_t maxp_inv_y;
+	uint16_t wq_log2_y;
+	cmdline_fixed_string_t color_r;
+	uint16_t min_th_r;
+	uint16_t max_th_r;
+	uint16_t maxp_inv_r;
+	uint16_t wq_log2_r;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_wred =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, wred, "wred");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wred_profile_id, UINT32);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_g =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_g, "G#g");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_g, UINT16);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_y =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_y, "Y#y");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_y, UINT16);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_r =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_r, "R#r");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_r, UINT16);
+
+
+static void cmd_add_port_tm_node_wred_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_wred_profile_result *res = parsed_result;
+	struct rte_tm_wred_params wp;
+	enum rte_tm_color color;
+	struct rte_port *port;
+	struct rte_tm_error error;
+	uint32_t wred_profile_id = res->wred_profile_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	memset(&wp, 0, sizeof(struct rte_tm_wred_params));
+
+	/* WRED Params  (Green Color)*/
+	if ((strcmp(res->color_g, "G") == 0) ||
+		(strcmp(res->color_g, "g") == 0)) {
+		color = RTE_TM_GREEN;
+		wp.red_params[color].min_th = res->min_th_g;
+		wp.red_params[color].max_th = res->max_th_g;
+		wp.red_params[color].maxp_inv = res->maxp_inv_g;
+		wp.red_params[color].wq_log2 = res->wq_log2_g;
+	} else {
+		printf("WRED profile error(G or g for green color)!\n");
+		return;
+	}
+
+	/* WRED Params  (Yellow Color)*/
+	if ((strcmp(res->color_y, "Y") == 0) ||
+		(strcmp(res->color_y, "y") == 0)) {
+		color = RTE_TM_YELLOW;
+		wp.red_params[color].min_th = res->min_th_y;
+		wp.red_params[color].max_th = res->max_th_y;
+		wp.red_params[color].maxp_inv = res->maxp_inv_y;
+		wp.red_params[color].wq_log2 = res->wq_log2_y;
+	} else {
+		printf("WRED profile error(Y or y for yellow color)!\n");
+		return;
+	}
+
+	/* WRED Params  (Red Color)*/
+	if ((strcmp(res->color_r, "R") == 0) ||
+		(strcmp(res->color_r, "r") == 0)) {
+		color = RTE_TM_RED;
+		wp.red_params[color].min_th = res->min_th_r;
+		wp.red_params[color].max_th = res->max_th_r;
+		wp.red_params[color].maxp_inv = res->maxp_inv_r;
+		wp.red_params[color].wq_log2 = res->wq_log2_r;
+	} else {
+		printf("WRED profile error(R or r for red color)!\n");
+		return;
+	}
+
+	ret = rte_tm_wred_profile_add(port_id, wred_profile_id, &wp, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile = {
+	.f = cmd_add_port_tm_node_wred_profile_parsed,
+	.data = NULL,
+	.help_str = "Add port tm node wred profile",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_wred_profile_add,
+		(void *)&cmd_add_port_tm_node_wred_profile_port,
+		(void *)&cmd_add_port_tm_node_wred_profile_tm,
+		(void *)&cmd_add_port_tm_node_wred_profile_node,
+		(void *)&cmd_add_port_tm_node_wred_profile_wred,
+		(void *)&cmd_add_port_tm_node_wred_profile_profile,
+		(void *)&cmd_add_port_tm_node_wred_profile_port_id,
+		(void *)&cmd_add_port_tm_node_wred_profile_wred_profile_id,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_r,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM node WRED Profile *** */
+struct cmd_del_port_tm_node_wred_profile_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t wred;
+	cmdline_fixed_string_t profile;
+	uint8_t port_id;
+	uint32_t wred_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_wred =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, wred, "wred");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_del_port_tm_node_wred_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_del_port_tm_node_wred_profile_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			wred_profile_id, UINT32);
+
+static void cmd_del_port_tm_node_wred_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_wred_profile_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_error error;
+	uint32_t wred_profile_id = res->wred_profile_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	ret = rte_tm_wred_profile_delete(port_id, wred_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile = {
+	.f = cmd_del_port_tm_node_wred_profile_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node wred profile",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_wred_profile_del,
+		(void *)&cmd_del_port_tm_node_wred_profile_port,
+		(void *)&cmd_del_port_tm_node_wred_profile_tm,
+		(void *)&cmd_del_port_tm_node_wred_profile_node,
+		(void *)&cmd_del_port_tm_node_wred_profile_wred,
+		(void *)&cmd_del_port_tm_node_wred_profile_profile,
+		(void *)&cmd_del_port_tm_node_wred_profile_port_id,
+		(void *)&cmd_del_port_tm_node_wred_profile_wred_profile_id,
+		NULL,
+	},
+};
+
+/* *** Add Port TM nonleaf node *** */
+struct cmd_add_port_tm_nonleaf_node_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t nonleaf;
+	cmdline_fixed_string_t node;
+	uint8_t port_id;
+	uint32_t node_id;
+	int32_t parent_node_id;
+	uint32_t priority;
+	uint32_t weight;
+	uint32_t level_id;
+	uint32_t shaper_profile_id;
+	uint32_t shared_shaper_id;
+	uint32_t n_shared_shapers;
+	uint32_t n_sp_priorities;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_nonleaf =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, nonleaf, "nonleaf");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, node, "node");
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result,
+		 port_id, UINT8);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 node_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 parent_node_id, INT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 priority, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 weight, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 level_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 shaper_profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 shared_shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_n_shared_shapers =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 n_shared_shapers, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_n_sp_priorities =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 n_sp_priorities, UINT32);
+
+static void cmd_add_port_tm_nonleaf_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_nonleaf_node_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_eth_link link;
+	struct rte_tm_error error;
+	struct rte_tm_node_params np;
+	uint32_t parent_node_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Port link status */
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get_nowait(port_id, &link);
+	if (link.link_status == ETH_LINK_UP) {
+		printf(" Port %u link up (error)\n", port_id);
+		return;
+	}
+
+	/* TM hierarchy status */
+	if (port->softport.tm.hierarchy_frozen == 1)
+		port->softport.tm.hierarchy_frozen = 0;
+
+	/* Node parameters */
+	if (res->parent_node_id < 0)
+		parent_node_id = UINT32_MAX;
+	else
+		parent_node_id = res->parent_node_id;
+
+	memset(&np, 0, sizeof(struct rte_tm_node_params));
+	np.shaper_profile_id = res->shaper_profile_id;
+	np.n_shared_shapers = res->n_shared_shapers;
+	np.shared_shaper_id = &res->shared_shaper_id;
+	np.nonleaf.n_sp_priorities = res->n_sp_priorities;
+	np.nonleaf.wfq_weight_mode = NULL;
+	np.stats_mask = RTE_TM_STATS_N_PKTS |
+		RTE_TM_STATS_N_BYTES |
+		RTE_TM_STATS_N_PKTS_GREEN_DROPPED |
+		RTE_TM_STATS_N_BYTES_GREEN_DROPPED;
+
+	ret = rte_tm_node_add(port_id, res->node_id, parent_node_id,
+				res->priority, res->weight, res->level_id,
+				&np, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_nonleaf_node = {
+	.f = cmd_add_port_tm_nonleaf_node_parsed,
+	.data = NULL,
+	.help_str = "Add port tm nonleaf node",
+	.tokens = {
+		(void *)&cmd_add_port_tm_nonleaf_node_add,
+		(void *)&cmd_add_port_tm_nonleaf_node_port,
+		(void *)&cmd_add_port_tm_nonleaf_node_tm,
+		(void *)&cmd_add_port_tm_nonleaf_node_nonleaf,
+		(void *)&cmd_add_port_tm_nonleaf_node_node,
+		(void *)&cmd_add_port_tm_nonleaf_node_port_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_node_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_parent_node_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_priority,
+		(void *)&cmd_add_port_tm_nonleaf_node_weight,
+		(void *)&cmd_add_port_tm_nonleaf_node_level_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_shaper_profile_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_shared_shaper_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_n_shared_shapers,
+		(void *)&cmd_add_port_tm_nonleaf_node_n_sp_priorities,
+		NULL,
+	},
+};
+
+/* *** Add Port TM leaf node *** */
+struct cmd_add_port_tm_leaf_node_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t leaf;
+	cmdline_fixed_string_t node;
+	uint8_t port_id;
+	uint32_t node_id;
+	int32_t parent_node_id;
+	uint32_t priority;
+	uint32_t weight;
+	uint32_t level_id;
+	uint32_t cman_mode;
+	uint32_t wred_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_nonleaf =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, leaf, "leaf");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, node, "node");
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 port_id, UINT8);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 node_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 parent_node_id, INT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 priority, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 weight, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 level_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_cman_mode =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 cman_mode, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 wred_profile_id, UINT32);
+
+static void cmd_add_port_tm_leaf_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_leaf_node_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_eth_link link;
+	struct rte_tm_error error;
+	struct rte_tm_node_params np;
+	uint32_t parent_node_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Port link status */
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get_nowait(port_id, &link);
+	if (link.link_status == ETH_LINK_UP) {
+		printf(" Port %u link up (error)\n", port_id);
+		return;
+	}
+
+	/* TM hierarchy status */
+	if (port->softport.tm.hierarchy_frozen == 1)
+		port->softport.tm.hierarchy_frozen = 0;
+
+	/* Node parameters */
+	if (res->parent_node_id < 0)
+		parent_node_id = UINT32_MAX;
+	else
+		parent_node_id = res->parent_node_id;
+
+	memset(&np, 0, sizeof(struct rte_tm_node_params));
+	np.shaper_profile_id = RTE_TM_SHAPER_PROFILE_ID_NONE;
+	np.n_shared_shapers = 0;
+	np.leaf.cman = res->cman_mode;
+	np.leaf.wred.wred_profile_id = res->wred_profile_id;
+	np.stats_mask = RTE_TM_STATS_N_PKTS |
+		RTE_TM_STATS_N_BYTES |
+		RTE_TM_STATS_N_PKTS_GREEN_DROPPED |
+		RTE_TM_STATS_N_BYTES_GREEN_DROPPED |
+		RTE_TM_STATS_N_PKTS_QUEUED;
+
+	ret = rte_tm_node_add(port_id, res->node_id, parent_node_id,
+				res->priority, res->weight, res->level_id,
+				&np, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_leaf_node = {
+	.f = cmd_add_port_tm_leaf_node_parsed,
+	.data = NULL,
+	.help_str = "Add port tm leaf node",
+	.tokens = {
+		(void *)&cmd_add_port_tm_leaf_node_add,
+		(void *)&cmd_add_port_tm_leaf_node_port,
+		(void *)&cmd_add_port_tm_leaf_node_tm,
+		(void *)&cmd_add_port_tm_leaf_node_nonleaf,
+		(void *)&cmd_add_port_tm_leaf_node_node,
+		(void *)&cmd_add_port_tm_leaf_node_port_id,
+		(void *)&cmd_add_port_tm_leaf_node_node_id,
+		(void *)&cmd_add_port_tm_leaf_node_parent_node_id,
+		(void *)&cmd_add_port_tm_leaf_node_priority,
+		(void *)&cmd_add_port_tm_leaf_node_weight,
+		(void *)&cmd_add_port_tm_leaf_node_level_id,
+		(void *)&cmd_add_port_tm_leaf_node_cman_mode,
+		(void *)&cmd_add_port_tm_leaf_node_wred_profile_id,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM Node *** */
+struct cmd_del_port_tm_node_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	uint8_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, node, "node");
+cmdline_parse_token_num_t cmd_del_port_tm_node_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_del_port_tm_node_result,
+		 port_id, UINT8);
+cmdline_parse_token_num_t cmd_del_port_tm_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_del_port_tm_node_result,
+		node_id, UINT32);
+
+static void cmd_del_port_tm_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_eth_link link;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Port link status */
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get_nowait(port_id, &link);
+	if (link.link_status == ETH_LINK_UP) {
+		printf(" Port %u link up (error)\n", port_id);
+		return;
+	}
+
+	/* TM hierarchy status */
+	if (port->softport.tm.hierarchy_frozen == 1)
+		port->softport.tm.hierarchy_frozen = 0;
+
+	ret = rte_tm_node_delete(port_id, node_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node = {
+	.f = cmd_del_port_tm_node_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_del,
+		(void *)&cmd_del_port_tm_node_port,
+		(void *)&cmd_del_port_tm_node_tm,
+		(void *)&cmd_del_port_tm_node_node,
+		(void *)&cmd_del_port_tm_node_port_id,
+		(void *)&cmd_del_port_tm_node_node_id,
+		NULL,
+	},
+};
+
+/* *** Show Port TM Node Type *** */
+struct cmd_show_port_tm_node_type_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t type;
+	uint8_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_show =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, type, "type");
+cmdline_parse_token_num_t cmd_show_port_tm_node_type_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_show_port_tm_node_type_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result,
+			node_id, UINT32);
+
+static void cmd_show_port_tm_node_type_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_type_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint8_t port_id = res->port_id;
+	int ret, is_leaf = 0;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	ret = rte_tm_node_type_get(port_id, node_id, &is_leaf, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	if (is_leaf == 1)
+		printf("leaf node\n");
+	else
+		printf("nonleaf node\n");
+
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_type = {
+	.f = cmd_show_port_tm_node_type_parsed,
+	.data = NULL,
+	.help_str = "Show port tm node type",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_type_show,
+		(void *)&cmd_show_port_tm_node_type_port,
+		(void *)&cmd_show_port_tm_node_type_tm,
+		(void *)&cmd_show_port_tm_node_type_node,
+		(void *)&cmd_show_port_tm_node_type_type,
+		(void *)&cmd_show_port_tm_node_type_port_id,
+		(void *)&cmd_show_port_tm_node_type_node_id,
+		NULL,
+	},
+};
+
+/* *** Show Port TM Node Statistics *** */
+struct cmd_show_port_tm_node_stats_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t stats;
+	uint8_t port_id;
+	uint32_t node_id;
+	uint32_t clear;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_show =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_stats =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, stats, "stats");
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_stats_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result,
+			node_id, UINT32);
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_clear =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, clear, UINT32);
+
+static void cmd_show_port_tm_node_stats_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_stats_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_eth_link link;
+	struct rte_tm_node_stats stats;
+	struct rte_tm_error error;
+	uint64_t stats_mask = 0, leaf_stats_mask;
+	uint32_t node_id = res->node_id;
+	uint32_t clear = res->clear;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	/* TM hierarchy status */
+	if (port->softport.tm.hierarchy_frozen == 0) {
+		printf(" hierarchy not frozen(error)\n");
+		return;
+	}
+
+	/* Port link status */
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get_nowait(port_id, &link);
+	if (link.link_status == ETH_LINK_DOWN) {
+		printf(" Port %u link down (error)\n", port_id);
+		return;
+	}
+
+	memset(&stats, 0, sizeof(struct rte_tm_node_stats));
+	ret = rte_tm_node_stats_read(port_id, node_id, &stats,
+			&stats_mask, clear, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	leaf_stats_mask = RTE_TM_STATS_N_PKTS |
+		RTE_TM_STATS_N_BYTES |
+		RTE_TM_STATS_N_PKTS_GREEN_DROPPED |
+		RTE_TM_STATS_N_BYTES_GREEN_DROPPED |
+		RTE_TM_STATS_N_PKTS_QUEUED;
+
+	printf("pkts scheduled from node %lu\n", stats.n_pkts);
+	printf("bytes scheduled from node %lu\n", stats.n_bytes);
+	printf("pkts dropped %lu\n ", stats.leaf.n_pkts_dropped[RTE_TM_GREEN]);
+	printf("bytes dropped %lu\n ",
+		stats.leaf.n_bytes_dropped[RTE_TM_GREEN]);
+
+	if (stats_mask == leaf_stats_mask)
+		printf("packets enqueued %lu\n", stats.leaf.n_pkts_queued);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_stats = {
+	.f = cmd_show_port_tm_node_stats_parsed,
+	.data = NULL,
+	.help_str = "Show port tm node stats",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_stats_show,
+		(void *)&cmd_show_port_tm_node_stats_port,
+		(void *)&cmd_show_port_tm_node_stats_tm,
+		(void *)&cmd_show_port_tm_node_stats_node,
+		(void *)&cmd_show_port_tm_node_stats_stats,
+		(void *)&cmd_show_port_tm_node_stats_port_id,
+		(void *)&cmd_show_port_tm_node_stats_node_id,
+		(void *)&cmd_show_port_tm_node_stats_clear,
+		NULL,
+	},
+};
+
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+/* *** Update Port TM Node Parent *** */
+struct cmd_set_port_tm_node_parent_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t parent;
+	uint8_t port_id;
+	uint32_t node_id;
+	uint32_t parent_id;
+	uint32_t priority;
+	uint32_t weight;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, node, "node");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_parent =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, parent, "parent");
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, port_id, UINT8);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, node_id, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_parent_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		parent_id, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		priority, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		weight, UINT32);
+
+static void cmd_set_port_tm_node_parent_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_node_parent_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_eth_link link;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint32_t parent_id = res->parent_id;
+	uint32_t priority = res->priority;
+	uint32_t weight = res->weight;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	/* TM hierarchy status */
+	if (port->softport.tm.hierarchy_frozen == 0) {
+		printf(" hierarchy not frozen(error)\n");
+		return;
+	}
+
+	/* Port link status */
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get_nowait(port_id, &link);
+	if (link.link_status == ETH_LINK_DOWN) {
+		printf(" Port %u link down (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_parent_update(port_id, node_id,
+		parent_id, priority, weight, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_node_parent = {
+	.f = cmd_set_port_tm_node_parent_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node parent",
+	.tokens = {
+		(void *)&cmd_set_port_tm_node_parent_set,
+		(void *)&cmd_set_port_tm_node_parent_port,
+		(void *)&cmd_set_port_tm_node_parent_tm,
+		(void *)&cmd_set_port_tm_node_parent_node,
+		(void *)&cmd_set_port_tm_node_parent_parent,
+		(void *)&cmd_set_port_tm_node_parent_port_id,
+		(void *)&cmd_set_port_tm_node_parent_node_id,
+		(void *)&cmd_set_port_tm_node_parent_parent_id,
+		(void *)&cmd_set_port_tm_node_parent_priority,
+		(void *)&cmd_set_port_tm_node_parent_weight,
+		NULL,
+	},
+};
+#endif
+
+/* *** Update Port TM Node Shaper profile *** */
+struct cmd_set_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint8_t port_id;
+	uint32_t node_id;
+	uint32_t shaper_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_set_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_set_port_tm_node_shaper_profile_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_shaper_profile_result,
+		node_id, UINT32);
+cmdline_parse_token_num_t
+	cmd_set_port_tm_node_shaper_shaper_profile_profile_id =
+		TOKEN_NUM_INITIALIZER(
+			struct cmd_set_port_tm_node_shaper_profile_result,
+			shaper_profile_id, UINT32);
+
+static void cmd_set_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_eth_link link;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint32_t shaper_profile_id = res->shaper_profile_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	/* TM hierarchy status */
+	if (port->softport.tm.hierarchy_frozen == 0) {
+		printf(" hierarchy not frozen(error)\n");
+		return;
+	}
+
+	/* Port link status */
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get_nowait(port_id, &link);
+	if (link.link_status == ETH_LINK_DOWN) {
+		printf(" Port %u link down (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_shaper_update(port_id, node_id,
+		shaper_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile = {
+	.f = cmd_set_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node shaper profile",
+	.tokens = {
+		(void *)&cmd_set_port_tm_node_shaper_profile_set,
+		(void *)&cmd_set_port_tm_node_shaper_profile_port,
+		(void *)&cmd_set_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_set_port_tm_node_shaper_profile_node,
+		(void *)&cmd_set_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_set_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_set_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_set_port_tm_node_shaper_profile_node_id,
+		(void *)&cmd_set_port_tm_node_shaper_shaper_profile_profile_id,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchy Commit *** */
+struct cmd_port_tm_hierarchy_commit_result {
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t hierarchy;
+	cmdline_fixed_string_t commit;
+	uint8_t port_id;
+	uint32_t clean_on_fail;
+};
+
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, port, "port");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, tm, "tm");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_hierarchy =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result,
+			hierarchy, "hierarchy");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_commit =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, commit, "commit");
+cmdline_parse_token_num_t cmd_port_tm_hierarchy_commit_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_port_tm_hierarchy_commit_clean_on_fail =
+	TOKEN_NUM_INITIALIZER(struct cmd_port_tm_hierarchy_commit_result,
+		 clean_on_fail, UINT32);
+
+static void cmd_port_tm_hierarchy_commit_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_port_tm_hierarchy_commit_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_eth_link link;
+	struct rte_tm_error error;
+	uint32_t clean_on_fail = res->clean_on_fail;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Port link status */
+	memset(&link, 0, sizeof(link));
+	rte_eth_link_get_nowait(port_id, &link);
+	if (link.link_status == ETH_LINK_UP) {
+		printf(" Port %u link up (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_hierarchy_commit(port_id, clean_on_fail, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+	/* Set TM hierarchy commit flag */
+	port->softport.tm.hierarchy_frozen = 1;
+}
+
+cmdline_parse_inst_t cmd_port_tm_hierarchy_commit = {
+	.f = cmd_port_tm_hierarchy_commit_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node shaper profile",
+	.tokens = {
+		(void *)&cmd_port_tm_hierarchy_commit_port,
+		(void *)&cmd_port_tm_hierarchy_commit_tm,
+		(void *)&cmd_port_tm_hierarchy_commit_hierarchy,
+		(void *)&cmd_port_tm_hierarchy_commit_commit,
+		(void *)&cmd_port_tm_hierarchy_commit_port_id,
+		(void *)&cmd_port_tm_hierarchy_commit_clean_on_fail,
+		NULL,
+	},
+};
+
+static int
+port_tm_pktfield_validate_mask(uint64_t mask, uint64_t n)
+{
+	int count = __builtin_popcountll(mask);
+	int pos_lead = sizeof(uint64_t) * 8 - __builtin_clzll(mask);
+	int pos_trail = __builtin_ctzll(mask);
+	int count_expected = __builtin_popcount(n - 1);
+
+	/* Handle the exceptions */
+	if (n == 0)
+		return -1;			/* Error */
+
+	if ((mask == 0) && (n == 1))
+		return 0;			/* OK */
+
+	if (((mask == 0) && (n != 1)) || ((mask != 0) && (n == 1)))
+		return -2;			/* Error */
+
+	/* Check that mask is contiguous */
+	if ((pos_lead - pos_trail) != count)
+		return -3;			/* Error */
+
+	/* Check that mask contains the expected number of bits set */
+	if (count != count_expected)
+		return -4;			/* Error */
+
+	return 0;			/* OK */
+	}
+
+/* *** Set Port TM Packet Fields *** */
+struct cmd_set_port_tm_pktfield_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t pktfield;
+	cmdline_fixed_string_t type;
+	uint8_t port_id;
+	cmdline_fixed_string_t offset_string;
+	uint32_t offset;
+	cmdline_fixed_string_t mask_string;
+	uint64_t mask;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result, port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,	tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_pktfield =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			pktfield, "pktfield");
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			type, "subport#pipe#tc");
+cmdline_parse_token_num_t cmd_set_port_tm_pktfield_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_offset_string =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			offset_string, "offset");
+cmdline_parse_token_num_t cmd_set_port_tm_pktfield_offset =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			offset, UINT32);
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_mask_string =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			mask_string, "mask");
+cmdline_parse_token_num_t cmd_set_port_tm_pktfield_mask =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			mask, UINT64);
+
+static void cmd_set_port_tm_pktfield_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_pktfield_result *res = parsed_result;
+	struct rte_port *p;
+	uint32_t offset = res->offset;
+	uint64_t mask = res->mask;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	p = &ports[port_id];
+
+	/* Port tm flag */
+	if (p->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Subport */
+	if (strcmp(res->type, "subport") == 0) {
+		uint32_t n = p->softport.tm.n_subports_per_port;
+
+		ret = port_tm_pktfield_validate_mask(mask, n);
+		if (ret) {
+			printf(" invalid subport mask(error %d)", ret);
+			return;
+		}
+		/* Set packet field */
+		p->softport.tm.tm_pktfield0_slabpos = offset;
+		p->softport.tm.tm_pktfield0_slabmask = mask;
+		p->softport.tm.tm_pktfield0_slabshr = __builtin_ctzll(mask);
+		return;
+	}
+
+	/* Pipe */
+	if (strcmp(res->type, "pipe") == 0) {
+		uint32_t n = p->softport.tm.n_pipes_per_subport;
+
+		ret = port_tm_pktfield_validate_mask(mask, n);
+		if (ret) {
+			printf(" invalid pipe mask(error %d)", ret);
+			return;
+		}
+		/* Set packet field */
+		p->softport.tm.tm_pktfield1_slabpos = offset;
+		p->softport.tm.tm_pktfield1_slabmask = mask;
+		p->softport.tm.tm_pktfield1_slabshr = __builtin_ctzll(mask);
+		return;
+	}
+
+	/* Traffic class */
+	if (strcmp(res->type, "tc") == 0) {
+		uint32_t n = RTE_DIM(p->softport.tm.tm_tc_table);
+
+		ret = port_tm_pktfield_validate_mask(mask, n);
+		if (ret) {
+			printf(" invalid tc mask(error %d)", ret);
+			return;
+		}
+		/* Set packet field */
+		p->softport.tm.tm_pktfield1_slabpos = offset;
+		p->softport.tm.tm_pktfield1_slabmask = mask;
+		p->softport.tm.tm_pktfield1_slabshr = __builtin_ctzll(mask);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_pktfield = {
+	.f = cmd_set_port_tm_pktfield_parsed,
+	.data = NULL,
+	.help_str = "Set port tm pktfield",
+	.tokens = {
+		(void *)&cmd_set_port_tm_pktfield_set,
+		(void *)&cmd_set_port_tm_pktfield_port,
+		(void *)&cmd_set_port_tm_pktfield_tm,
+		(void *)&cmd_set_port_tm_pktfield_pktfield,
+		(void *)&cmd_set_port_tm_pktfield_type,
+		(void *)&cmd_set_port_tm_pktfield_port_id,
+		(void *)&cmd_set_port_tm_pktfield_offset_string,
+		(void *)&cmd_set_port_tm_pktfield_offset,
+		(void *)&cmd_set_port_tm_pktfield_mask_string,
+		(void *)&cmd_set_port_tm_pktfield_mask,
+		NULL,
+	},
+};
+
+/* *** Set Port TM Traffic Class Table Entry *** */
+struct cmd_set_port_tm_tc_table_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t tc_table;
+	uint8_t port_id;
+	cmdline_fixed_string_t index_string;
+	uint32_t index;
+	cmdline_fixed_string_t tc_string;
+	uint32_t tc;
+	cmdline_fixed_string_t queue_string;
+	uint32_t queue;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result, port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,	tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_tc_table =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			tc_table, "tc table");
+cmdline_parse_token_num_t cmd_set_port_tm_tc_table_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_index_string =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			index_string, "index");
+cmdline_parse_token_num_t cmd_set_port_tm_tc_table_index =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			index, UINT32);
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_tc_string =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			tc_string, "tc");
+cmdline_parse_token_num_t cmd_set_port_tm_tc_table_tc =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			tc, UINT32);
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_queue_string =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			queue_string, "queue");
+cmdline_parse_token_num_t cmd_set_port_tm_tc_table_queue =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			queue, UINT32);
+
+static void cmd_set_port_tm_tc_table_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_tc_table_result *res = parsed_result;
+	struct rte_port *p;
+	uint32_t tc = res->tc;
+	uint32_t index = res->index;
+	uint32_t queue = res->queue;
+	uint32_t val;
+	uint8_t port_id = res->port_id;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	p = &ports[port_id];
+
+	/* Port tm flag */
+	if (p->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Traffic class table index */
+	if (tc >= RTE_DIM(p->softport.tm.tm_tc_table)) {
+		printf("  invalid traffic class table index(error)\n");
+		return;
+	}
+
+	/* Traffic class id */
+	if (tc >= RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE) {
+		printf("  invalid traffic class id(error)\n");
+		return;
+	}
+
+	/* Traffic class queue */
+	if (queue >= RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS) {
+		printf("  invalid traffic class queue(error)\n");
+		return;
+	}
+
+	val = tc * RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS + queue;
+	p->softport.tm.tm_tc_table[index] = val;
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_tc_table = {
+	.f = cmd_set_port_tm_tc_table_parsed,
+	.data = NULL,
+	.help_str = "Set port tm TC table entry",
+	.tokens = {
+		(void *)&cmd_set_port_tm_tc_table_set,
+		(void *)&cmd_set_port_tm_tc_table_port,
+		(void *)&cmd_set_port_tm_tc_table_tm,
+		(void *)&cmd_set_port_tm_tc_table_tc_table,
+		(void *)&cmd_set_port_tm_tc_table_port_id,
+		(void *)&cmd_set_port_tm_tc_table_index_string,
+		(void *)&cmd_set_port_tm_tc_table_index,
+		(void *)&cmd_set_port_tm_tc_table_tc_string,
+		(void *)&cmd_set_port_tm_tc_table_tc,
+		(void *)&cmd_set_port_tm_tc_table_queue_string,
+		(void *)&cmd_set_port_tm_tc_table_queue,
+		NULL,
+	},
+};
+
+#endif
+/* *********************************************************************** */
+
+/* list of instructions */
+cmdline_parse_ctx_t main_ctx[] = {
+	(cmdline_parse_inst_t *)&cmd_help_brief,
+	(cmdline_parse_inst_t *)&cmd_help_long,
+	(cmdline_parse_inst_t *)&cmd_quit,
+	(cmdline_parse_inst_t *)&cmd_load_from_file,
+	(cmdline_parse_inst_t *)&cmd_showport,
+	(cmdline_parse_inst_t *)&cmd_showqueue,
+	(cmdline_parse_inst_t *)&cmd_showportall,
+	(cmdline_parse_inst_t *)&cmd_showcfg,
+	(cmdline_parse_inst_t *)&cmd_start,
+	(cmdline_parse_inst_t *)&cmd_start_tx_first,
+	(cmdline_parse_inst_t *)&cmd_start_tx_first_n,
+	(cmdline_parse_inst_t *)&cmd_set_link_up,
+	(cmdline_parse_inst_t *)&cmd_set_link_down,
+	(cmdline_parse_inst_t *)&cmd_reset,
+	(cmdline_parse_inst_t *)&cmd_set_numbers,
+	(cmdline_parse_inst_t *)&cmd_set_txpkts,
+	(cmdline_parse_inst_t *)&cmd_set_txsplit,
+	(cmdline_parse_inst_t *)&cmd_set_fwd_list,
+	(cmdline_parse_inst_t *)&cmd_set_fwd_mask,
+	(cmdline_parse_inst_t *)&cmd_set_fwd_mode,
+	(cmdline_parse_inst_t *)&cmd_set_fwd_retry_mode,
+	(cmdline_parse_inst_t *)&cmd_set_burst_tx_retry,
+	(cmdline_parse_inst_t *)&cmd_set_promisc_mode_one,
+	(cmdline_parse_inst_t *)&cmd_set_promisc_mode_all,
+	(cmdline_parse_inst_t *)&cmd_set_allmulti_mode_one,
+	(cmdline_parse_inst_t *)&cmd_set_allmulti_mode_all,
+	(cmdline_parse_inst_t *)&cmd_set_flush_rx,
+	(cmdline_parse_inst_t *)&cmd_set_link_check,
+	(cmdline_parse_inst_t *)&cmd_set_bypass_mode,
+	(cmdline_parse_inst_t *)&cmd_set_bypass_event,
+	(cmdline_parse_inst_t *)&cmd_set_bypass_timeout,
+	(cmdline_parse_inst_t *)&cmd_show_bypass_config,
+#ifdef RTE_LIBRTE_PMD_BOND
+	(cmdline_parse_inst_t *) &cmd_set_bonding_mode,
+	(cmdline_parse_inst_t *) &cmd_show_bonding_config,
+	(cmdline_parse_inst_t *) &cmd_set_bonding_primary,
+	(cmdline_parse_inst_t *) &cmd_add_bonding_slave,
+	(cmdline_parse_inst_t *) &cmd_remove_bonding_slave,
+	(cmdline_parse_inst_t *) &cmd_create_bonded_device,
+	(cmdline_parse_inst_t *) &cmd_set_bond_mac_addr,
+	(cmdline_parse_inst_t *) &cmd_set_balance_xmit_policy,
+	(cmdline_parse_inst_t *) &cmd_set_bond_mon_period,
+	(cmdline_parse_inst_t *) &cmd_set_lacp_dedicated_queues,
+	(cmdline_parse_inst_t *) &cmd_set_bonding_agg_mode_policy,
+#endif
+	(cmdline_parse_inst_t *)&cmd_vlan_offload,
+	(cmdline_parse_inst_t *)&cmd_vlan_tpid,
+	(cmdline_parse_inst_t *)&cmd_rx_vlan_filter_all,
+	(cmdline_parse_inst_t *)&cmd_rx_vlan_filter,
+	(cmdline_parse_inst_t *)&cmd_tx_vlan_set,
+	(cmdline_parse_inst_t *)&cmd_tx_vlan_set_qinq,
+	(cmdline_parse_inst_t *)&cmd_tx_vlan_reset,
+	(cmdline_parse_inst_t *)&cmd_tx_vlan_set_pvid,
+	(cmdline_parse_inst_t *)&cmd_csum_set,
+	(cmdline_parse_inst_t *)&cmd_csum_show,
+	(cmdline_parse_inst_t *)&cmd_csum_tunnel,
+	(cmdline_parse_inst_t *)&cmd_tso_set,
+	(cmdline_parse_inst_t *)&cmd_tso_show,
+	(cmdline_parse_inst_t *)&cmd_tunnel_tso_set,
+	(cmdline_parse_inst_t *)&cmd_tunnel_tso_show,
+	(cmdline_parse_inst_t *)&cmd_enable_gro,
+	(cmdline_parse_inst_t *)&cmd_gro_set,
+	(cmdline_parse_inst_t *)&cmd_link_flow_control_set,
+	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_rx,
+	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_tx,
+	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_hw,
+	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_lw,
+	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_pt,
+	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_xon,
+	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_macfwd,
+	(cmdline_parse_inst_t *)&cmd_link_flow_control_set_autoneg,
+	(cmdline_parse_inst_t *)&cmd_priority_flow_control_set,
+	(cmdline_parse_inst_t *)&cmd_config_dcb,
+	(cmdline_parse_inst_t *)&cmd_read_reg,
+	(cmdline_parse_inst_t *)&cmd_read_reg_bit_field,
+	(cmdline_parse_inst_t *)&cmd_read_reg_bit,
+	(cmdline_parse_inst_t *)&cmd_write_reg,
+	(cmdline_parse_inst_t *)&cmd_write_reg_bit_field,
+	(cmdline_parse_inst_t *)&cmd_write_reg_bit,
+	(cmdline_parse_inst_t *)&cmd_read_rxd_txd,
+	(cmdline_parse_inst_t *)&cmd_stop,
+	(cmdline_parse_inst_t *)&cmd_mac_addr,
+	(cmdline_parse_inst_t *)&cmd_set_qmap,
+	(cmdline_parse_inst_t *)&cmd_operate_port,
+	(cmdline_parse_inst_t *)&cmd_operate_specific_port,
+	(cmdline_parse_inst_t *)&cmd_operate_attach_port,
+	(cmdline_parse_inst_t *)&cmd_operate_detach_port,
+	(cmdline_parse_inst_t *)&cmd_config_speed_all,
+	(cmdline_parse_inst_t *)&cmd_config_speed_specific,
+	(cmdline_parse_inst_t *)&cmd_config_rx_tx,
+	(cmdline_parse_inst_t *)&cmd_config_mtu,
+	(cmdline_parse_inst_t *)&cmd_config_max_pkt_len,
+	(cmdline_parse_inst_t *)&cmd_config_rx_mode_flag,
+	(cmdline_parse_inst_t *)&cmd_config_rss,
+	(cmdline_parse_inst_t *)&cmd_config_rxtx_queue,
+	(cmdline_parse_inst_t *)&cmd_config_txqflags,
+	(cmdline_parse_inst_t *)&cmd_config_rss_reta,
+	(cmdline_parse_inst_t *)&cmd_showport_reta,
+	(cmdline_parse_inst_t *)&cmd_config_burst,
+	(cmdline_parse_inst_t *)&cmd_config_thresh,
+	(cmdline_parse_inst_t *)&cmd_config_threshold,
+	(cmdline_parse_inst_t *)&cmd_set_uc_hash_filter,
+	(cmdline_parse_inst_t *)&cmd_set_uc_all_hash_filter,
+	(cmdline_parse_inst_t *)&cmd_vf_mac_addr_filter,
+	(cmdline_parse_inst_t *)&cmd_set_vf_macvlan_filter,
+	(cmdline_parse_inst_t *)&cmd_queue_rate_limit,
+	(cmdline_parse_inst_t *)&cmd_tunnel_filter,
+	(cmdline_parse_inst_t *)&cmd_tunnel_udp_config,
+	(cmdline_parse_inst_t *)&cmd_global_config,
+	(cmdline_parse_inst_t *)&cmd_set_mirror_mask,
+	(cmdline_parse_inst_t *)&cmd_set_mirror_link,
+	(cmdline_parse_inst_t *)&cmd_reset_mirror_rule,
+	(cmdline_parse_inst_t *)&cmd_showport_rss_hash,
+	(cmdline_parse_inst_t *)&cmd_showport_rss_hash_key,
+	(cmdline_parse_inst_t *)&cmd_config_rss_hash_key,
+	(cmdline_parse_inst_t *)&cmd_dump,
+	(cmdline_parse_inst_t *)&cmd_dump_one,
+	(cmdline_parse_inst_t *)&cmd_ethertype_filter,
+	(cmdline_parse_inst_t *)&cmd_syn_filter,
+	(cmdline_parse_inst_t *)&cmd_2tuple_filter,
+	(cmdline_parse_inst_t *)&cmd_5tuple_filter,
+	(cmdline_parse_inst_t *)&cmd_flex_filter,
+	(cmdline_parse_inst_t *)&cmd_add_del_ip_flow_director,
+	(cmdline_parse_inst_t *)&cmd_add_del_udp_flow_director,
+	(cmdline_parse_inst_t *)&cmd_add_del_sctp_flow_director,
+	(cmdline_parse_inst_t *)&cmd_add_del_l2_flow_director,
+	(cmdline_parse_inst_t *)&cmd_add_del_mac_vlan_flow_director,
+	(cmdline_parse_inst_t *)&cmd_add_del_tunnel_flow_director,
+	(cmdline_parse_inst_t *)&cmd_flush_flow_director,
+	(cmdline_parse_inst_t *)&cmd_set_flow_director_ip_mask,
+	(cmdline_parse_inst_t *)&cmd_set_flow_director_mac_vlan_mask,
+	(cmdline_parse_inst_t *)&cmd_set_flow_director_tunnel_mask,
+	(cmdline_parse_inst_t *)&cmd_set_flow_director_flex_mask,
+	(cmdline_parse_inst_t *)&cmd_set_flow_director_flex_payload,
+	(cmdline_parse_inst_t *)&cmd_get_sym_hash_ena_per_port,
+	(cmdline_parse_inst_t *)&cmd_set_sym_hash_ena_per_port,
+	(cmdline_parse_inst_t *)&cmd_get_hash_global_config,
+	(cmdline_parse_inst_t *)&cmd_set_hash_global_config,
+	(cmdline_parse_inst_t *)&cmd_set_hash_input_set,
+	(cmdline_parse_inst_t *)&cmd_set_fdir_input_set,
+	(cmdline_parse_inst_t *)&cmd_flow,
+	(cmdline_parse_inst_t *)&cmd_mcast_addr,
+	(cmdline_parse_inst_t *)&cmd_config_l2_tunnel_eth_type_all,
+	(cmdline_parse_inst_t *)&cmd_config_l2_tunnel_eth_type_specific,
+	(cmdline_parse_inst_t *)&cmd_config_l2_tunnel_en_dis_all,
+	(cmdline_parse_inst_t *)&cmd_config_l2_tunnel_en_dis_specific,
+	(cmdline_parse_inst_t *)&cmd_config_e_tag_insertion_en,
+	(cmdline_parse_inst_t *)&cmd_config_e_tag_insertion_dis,
+	(cmdline_parse_inst_t *)&cmd_config_e_tag_stripping_en_dis,
+	(cmdline_parse_inst_t *)&cmd_config_e_tag_forwarding_en_dis,
+	(cmdline_parse_inst_t *)&cmd_config_e_tag_filter_add,
+	(cmdline_parse_inst_t *)&cmd_config_e_tag_filter_del,
+	(cmdline_parse_inst_t *)&cmd_set_vf_vlan_anti_spoof,
+	(cmdline_parse_inst_t *)&cmd_set_vf_mac_anti_spoof,
+	(cmdline_parse_inst_t *)&cmd_set_vf_vlan_stripq,
+	(cmdline_parse_inst_t *)&cmd_set_vf_vlan_insert,
+	(cmdline_parse_inst_t *)&cmd_set_tx_loopback,
+	(cmdline_parse_inst_t *)&cmd_set_all_queues_drop_en,
+	(cmdline_parse_inst_t *)&cmd_set_vf_split_drop_en,
+	(cmdline_parse_inst_t *)&cmd_set_macsec_offload_on,
+	(cmdline_parse_inst_t *)&cmd_set_macsec_offload_off,
+	(cmdline_parse_inst_t *)&cmd_set_macsec_sc,
+	(cmdline_parse_inst_t *)&cmd_set_macsec_sa,
+	(cmdline_parse_inst_t *)&cmd_set_vf_traffic,
+	(cmdline_parse_inst_t *)&cmd_set_vf_rxmode,
+	(cmdline_parse_inst_t *)&cmd_vf_rate_limit,
+	(cmdline_parse_inst_t *)&cmd_vf_rxvlan_filter,
+	(cmdline_parse_inst_t *)&cmd_set_vf_mac_addr,
+	(cmdline_parse_inst_t *)&cmd_set_vf_promisc,
+	(cmdline_parse_inst_t *)&cmd_set_vf_allmulti,
+	(cmdline_parse_inst_t *)&cmd_set_vf_broadcast,
+	(cmdline_parse_inst_t *)&cmd_set_vf_vlan_tag,
+	(cmdline_parse_inst_t *)&cmd_vf_max_bw,
+	(cmdline_parse_inst_t *)&cmd_vf_tc_min_bw,
+	(cmdline_parse_inst_t *)&cmd_vf_tc_max_bw,
+	(cmdline_parse_inst_t *)&cmd_strict_link_prio,
+	(cmdline_parse_inst_t *)&cmd_tc_min_bw,
+	(cmdline_parse_inst_t *)&cmd_ddp_add,
+	(cmdline_parse_inst_t *)&cmd_ddp_del,
+	(cmdline_parse_inst_t *)&cmd_ddp_get_list,
+	(cmdline_parse_inst_t *)&cmd_ddp_get_info,
+	(cmdline_parse_inst_t *)&cmd_show_vf_stats,
+	(cmdline_parse_inst_t *)&cmd_clear_vf_stats,
+	(cmdline_parse_inst_t *)&cmd_ptype_mapping_get,
+	(cmdline_parse_inst_t *)&cmd_ptype_mapping_replace,
+	(cmdline_parse_inst_t *)&cmd_ptype_mapping_reset,
+	(cmdline_parse_inst_t *)&cmd_ptype_mapping_update,
+#ifdef TM_MODE
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_level_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_cap,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_shared_shaper,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_shared_shaper,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_wred_profile,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_wred_profile,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_nonleaf_node,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_leaf_node,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_type,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_stats,
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_parent,
+#endif
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_port_tm_hierarchy_commit,
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_pktfield,
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_tc_table,
+#endif
 	NULL,
 };
 
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* Re: [PATCH v2 1/2] app/testpmd: add traffic management forwarding mode
  2017-09-14 11:53 ` [PATCH v2 1/2] app/testpmd: add traffic management forwarding mode Jasvinder Singh
  2017-09-14 11:53   ` [PATCH v2 2/2] app/testpmd: add CLI for tm mode Jasvinder Singh
@ 2017-09-18 13:54   ` De Lara Guarch, Pablo
  2017-09-19 15:04     ` Singh, Jasvinder
  2017-09-20  9:56   ` [PATCH v3 1/5] " Jasvinder Singh
  2 siblings, 1 reply; 49+ messages in thread
From: De Lara Guarch, Pablo @ 2017-09-18 13:54 UTC (permalink / raw)
  To: Singh, Jasvinder, dev; +Cc: Dumitrescu, Cristian, Wu, Jingjing



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jasvinder Singh
> Sent: Thursday, September 14, 2017 12:53 PM
> To: dev@dpdk.org
> Cc: Dumitrescu, Cristian <cristian.dumitrescu@intel.com>; Wu, Jingjing
> <jingjing.wu@intel.com>
> Subject: [dpdk-dev] [PATCH v2 1/2] app/testpmd: add traffic management
> forwarding mode
> 
> This commit extends the testpmd application with new forwarding engine
> that demonstrates the use of ethdev traffic management APIs and softnic
> PMD for QoS traffic management.
> 
> In this mode, 5-level hierarchical tree of the QoS scheduler is built with the
> help of ethdev TM APIs such as shaper profile add/delete, shared shaper
> add/update, node add/delete, hierarchy commit, etc.
> The hierarchical tree has following nodes; root node(x1, level 0), subport
> node(x1, level 1), pipe node(x4096, level 2), tc node(x16348, level 3), queue
> node(x65536, level 4).
> 
> During runtime, each received packet is first classified by mapping the
> packet fields information to 5-tuples (HQoS subport, pipe, traffic class,
> queue within traffic class, and color) and storing it in the packet mbuf sched
> field. After classification, each packet is sent to softnic port which prioritizes
> the transmission of the received packets, and accordingly sends them on to
> the output interface.
> 
> To enable traffic management mode, following testpmd command is used;
> 
> $ ./testpmd -c c -n 4 --vdev
> 	'net_softnic0,hard_name=0000:06:00.1,soft_tm=on' -- -i
> 	--forward-mode=tm
> 
> This patchset has dependency on following patch series;
> http://www.dpdk.org/dev/patchwork/patch/27517/
> http://www.dpdk.org/dev/patchwork/patch/27518/
> http://www.dpdk.org/dev/patchwork/patch/27519/
> http://www.dpdk.org/dev/patchwork/patch/27520/
> 
> Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> ---
> v2 change:
> - change file name softnictm.c to tm.c
> - change forward mode name to "tm"
> - code clean up
> 
>  app/test-pmd/Makefile  |   5 +
>  app/test-pmd/testpmd.c |  11 +
>  app/test-pmd/testpmd.h |  34 ++
>  app/test-pmd/tm.c      | 863
> +++++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 913 insertions(+)
>  create mode 100644 app/test-pmd/tm.c
> 
> diff --git a/app/test-pmd/Makefile b/app/test-pmd/Makefile index
> c36be19..925787f 100644
> --- a/app/test-pmd/Makefile
> +++ b/app/test-pmd/Makefile
> @@ -57,6 +57,7 @@ SRCS-y += rxonly.c
>  SRCS-y += txonly.c
>  SRCS-y += csumonly.c
>  SRCS-y += icmpecho.c
> +SRCS-y += tm.c
>  SRCS-$(CONFIG_RTE_LIBRTE_IEEE1588) += ieee1588fwd.c
> 
>  ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
> @@ -81,6 +82,10 @@ ifeq ($(CONFIG_RTE_LIBRTE_PMD_XENVIRT),y)
>  LDLIBS += -lrte_pmd_xenvirt
>  endif
> 
> +ifeq ($(CONFIG_RTE_LIBRTE_PMD_SOFTNIC),y)
> +LDLIBS += -lrte_pmd_softnic
> +endif
> +
>  endif
> 
>  CFLAGS_cmdline.o := -D_GNU_SOURCE
> diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index
> 7d40139..996e982 100644
> --- a/app/test-pmd/testpmd.c
> +++ b/app/test-pmd/testpmd.c
> @@ -167,6 +167,8 @@ struct fwd_engine * fwd_engines[] = {
>  	&tx_only_engine,
>  	&csum_fwd_engine,
>  	&icmp_echo_engine,
> +	&softnic_tm_engine,
> +	&softnic_tm_bypass_engine,
>  #ifdef RTE_LIBRTE_IEEE1588
>  	&ieee1588_fwd_engine,
>  #endif

If SCHED library is not set, I think these two modes should be disabled.
You can introduce the TM_MODE flag in testpmd.h, so you can use it everywhere.

> @@ -2044,6 +2046,15 @@ init_port_config(void)
>  		    (rte_eth_devices[pid].data->dev_flags &
>  		     RTE_ETH_DEV_INTR_RMV))
>  			port->dev_conf.intr_conf.rmv = 1;
> +
> +		/* Detect softnic port */
> +		if (!strcmp(port->dev_info.driver_name, "net_softnic")) {
> +			memset(&port->softport, 0, sizeof(struct
> softnic_port));
> +				port->softport.enable = 1;
> +
> +			if (!strcmp(cur_fwd_eng->fwd_mode_name, "tm"))
> +				port->softport.tm_flag = 1;
> +		}
>  	}
>  }
> 
> diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index
> c9d7739..c8fa180 100644
> --- a/app/test-pmd/testpmd.h
> +++ b/app/test-pmd/testpmd.h
> @@ -163,6 +163,37 @@ struct port_flow {

...

>  struct rte_port {
> @@ -195,6 +226,7 @@ struct rte_port {
>  	uint32_t                mc_addr_nb; /**< nb. of addr. in mc_addr_pool
> */
>  	uint8_t                 slave_flag; /**< bonding slave port */
>  	struct port_flow        *flow_list; /**< Associated flows. */
> +	struct softnic_port     softport;  /**< softnic port params > */

Remove last ">".

>  };
> 
>  /**

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v2 2/2] app/testpmd: add CLI for tm mode
  2017-09-14 11:53   ` [PATCH v2 2/2] app/testpmd: add CLI for tm mode Jasvinder Singh
@ 2017-09-18 14:03     ` De Lara Guarch, Pablo
  2017-09-19 15:06       ` Singh, Jasvinder
  0 siblings, 1 reply; 49+ messages in thread
From: De Lara Guarch, Pablo @ 2017-09-18 14:03 UTC (permalink / raw)
  To: Singh, Jasvinder, dev; +Cc: Dumitrescu, Cristian, Wu, Jingjing



> -----Original Message-----
> From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jasvinder Singh
> Sent: Thursday, September 14, 2017 12:53 PM
> To: dev@dpdk.org
> Cc: Dumitrescu, Cristian <cristian.dumitrescu@intel.com>; Wu, Jingjing
> <jingjing.wu@intel.com>
> Subject: [dpdk-dev] [PATCH v2 2/2] app/testpmd: add CLI for tm mode
> 
> Add following CLIs in testpmd application;
> - commands to build hierarchical tree for the QoS Scheduler.
> - commands for runtime update of the hierarchical tree.
> - commands to display TM capability information.
>   (per port, per hierarchy level and per hierarchy node)
> - command to set the packet field mask and offset value for
>   classification.
> - command to set traffic class translation table entry
> - stats collection

This patch should be split into multiple patches, as it is quite big
and it is adding multiple commands that can be arranged in different
categories, in different patches.

Also, as you are adding several commands about traffic management,
you could separate these in a different file (i.e. cmdline_tm.c).


> 
> Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> ---
>  app/test-pmd/cmdline.c | 2975
> ++++++++++++++++++++++++++++++++++++++++++++----
>  1 file changed, 2785 insertions(+), 190 deletions(-)
> 
> diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
> index cd8c358..cb837ce 100644
> --- a/app/test-pmd/cmdline.c
> +++ b/app/test-pmd/cmdline.c

...

> +
> +	/* Command type: add */
> +	if (strcmp(res->cmd_type, "add") == 0) {
> +		/* Port link status */
> +		rte_eth_link_get_nowait(port_id, &link);
> +		if (link.link_status == ETH_LINK_UP) {
> +			printf(" Port %u link up (error)\n", port_id);
> +			return;
> +		}

If you are checking if the device is started or stopped,
you should probably use "is_port_started" function.

> +
> +		/* TM hierarchy status */
> +		if (port->softport.tm.hierarchy_frozen == 1)
> +			port->softport.tm.hierarchy_frozen = 0;
> +	}
> +
> +	/* Command type: set (update) */

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v2 1/2] app/testpmd: add traffic management forwarding mode
  2017-09-18 13:54   ` [PATCH v2 1/2] app/testpmd: add traffic management forwarding mode De Lara Guarch, Pablo
@ 2017-09-19 15:04     ` Singh, Jasvinder
  0 siblings, 0 replies; 49+ messages in thread
From: Singh, Jasvinder @ 2017-09-19 15:04 UTC (permalink / raw)
  To: De Lara Guarch, Pablo, dev; +Cc: Dumitrescu, Cristian, Wu, Jingjing

Hi Pablo, 

Thanks for feedback and review.

<snip>
> >  app/test-pmd/Makefile  |   5 +
> >  app/test-pmd/testpmd.c |  11 +
> >  app/test-pmd/testpmd.h |  34 ++
> >  app/test-pmd/tm.c      | 863
> > +++++++++++++++++++++++++++++++++++++++++++++++++
> >  4 files changed, 913 insertions(+)
> >  create mode 100644 app/test-pmd/tm.c
> >
> > diff --git a/app/test-pmd/Makefile b/app/test-pmd/Makefile index
> > c36be19..925787f 100644
> > --- a/app/test-pmd/Makefile
> > +++ b/app/test-pmd/Makefile
> > @@ -57,6 +57,7 @@ SRCS-y += rxonly.c
> >  SRCS-y += txonly.c
> >  SRCS-y += csumonly.c
> >  SRCS-y += icmpecho.c
> > +SRCS-y += tm.c
> >  SRCS-$(CONFIG_RTE_LIBRTE_IEEE1588) += ieee1588fwd.c
> >
> >  ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
> > @@ -81,6 +82,10 @@ ifeq ($(CONFIG_RTE_LIBRTE_PMD_XENVIRT),y)
> >  LDLIBS += -lrte_pmd_xenvirt
> >  endif
> >
> > +ifeq ($(CONFIG_RTE_LIBRTE_PMD_SOFTNIC),y)
> > +LDLIBS += -lrte_pmd_softnic
> > +endif
> > +
> >  endif
> >
> >  CFLAGS_cmdline.o := -D_GNU_SOURCE
> > diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c index
> > 7d40139..996e982 100644
> > --- a/app/test-pmd/testpmd.c
> > +++ b/app/test-pmd/testpmd.c
> > @@ -167,6 +167,8 @@ struct fwd_engine * fwd_engines[] = {
> >  	&tx_only_engine,
> >  	&csum_fwd_engine,
> >  	&icmp_echo_engine,
> > +	&softnic_tm_engine,
> > +	&softnic_tm_bypass_engine,
> >  #ifdef RTE_LIBRTE_IEEE1588
> >  	&ieee1588_fwd_engine,
> >  #endif
> 
> If SCHED library is not set, I think these two modes should be disabled.
> You can introduce the TM_MODE flag in testpmd.h, so you can use it
> everywhere.

Ok. Will change this.

> > @@ -2044,6 +2046,15 @@ init_port_config(void)
> >  		    (rte_eth_devices[pid].data->dev_flags &
> >  		     RTE_ETH_DEV_INTR_RMV))
> >  			port->dev_conf.intr_conf.rmv = 1;
> > +
> > +		/* Detect softnic port */
> > +		if (!strcmp(port->dev_info.driver_name, "net_softnic")) {
> > +			memset(&port->softport, 0, sizeof(struct
> > softnic_port));
> > +				port->softport.enable = 1;
> > +
> > +			if (!strcmp(cur_fwd_eng->fwd_mode_name, "tm"))
> > +				port->softport.tm_flag = 1;
> > +		}
> >  	}
> >  }
> >
> > diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h index
> > c9d7739..c8fa180 100644
> > --- a/app/test-pmd/testpmd.h
> > +++ b/app/test-pmd/testpmd.h
> > @@ -163,6 +163,37 @@ struct port_flow {
> 
> ...
> 
> >  struct rte_port {
> > @@ -195,6 +226,7 @@ struct rte_port {
> >  	uint32_t                mc_addr_nb; /**< nb. of addr. in mc_addr_pool
> > */
> >  	uint8_t                 slave_flag; /**< bonding slave port */
> >  	struct port_flow        *flow_list; /**< Associated flows. */
> > +	struct softnic_port     softport;  /**< softnic port params > */
> 
> Remove last ">".

Will remove.

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v2 2/2] app/testpmd: add CLI for tm mode
  2017-09-18 14:03     ` De Lara Guarch, Pablo
@ 2017-09-19 15:06       ` Singh, Jasvinder
  0 siblings, 0 replies; 49+ messages in thread
From: Singh, Jasvinder @ 2017-09-19 15:06 UTC (permalink / raw)
  To: De Lara Guarch, Pablo, dev; +Cc: Dumitrescu, Cristian, Wu, Jingjing

<snip>
> > Add following CLIs in testpmd application;
> > - commands to build hierarchical tree for the QoS Scheduler.
> > - commands for runtime update of the hierarchical tree.
> > - commands to display TM capability information.
> >   (per port, per hierarchy level and per hierarchy node)
> > - command to set the packet field mask and offset value for
> >   classification.
> > - command to set traffic class translation table entry
> > - stats collection
> 
> This patch should be split into multiple patches, as it is quite big and it is
> adding multiple commands that can be arranged in different categories, in
> different patches.
> 
> Also, as you are adding several commands about traffic management, you
> could separate these in a different file (i.e. cmdline_tm.c).

Will split the patch into multiple. Thanks.

> >
> > Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> > ---
> >  app/test-pmd/cmdline.c | 2975
> > ++++++++++++++++++++++++++++++++++++++++++++----
> >  1 file changed, 2785 insertions(+), 190 deletions(-)
> >
> > diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index
> > cd8c358..cb837ce 100644
> > --- a/app/test-pmd/cmdline.c
> > +++ b/app/test-pmd/cmdline.c
> 
> ...
> 
> > +
> > +	/* Command type: add */
> > +	if (strcmp(res->cmd_type, "add") == 0) {
> > +		/* Port link status */
> > +		rte_eth_link_get_nowait(port_id, &link);
> > +		if (link.link_status == ETH_LINK_UP) {
> > +			printf(" Port %u link up (error)\n", port_id);
> > +			return;
> > +		}
> 
> If you are checking if the device is started or stopped, you should probably
> use "is_port_started" function.

Ok, will change this.
 
> > +
> > +		/* TM hierarchy status */
> > +		if (port->softport.tm.hierarchy_frozen == 1)
> > +			port->softport.tm.hierarchy_frozen = 0;
> > +	}
> > +
> > +	/* Command type: set (update) */

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [PATCH v3 1/5] app/testpmd: add traffic management forwarding mode
  2017-09-14 11:53 ` [PATCH v2 1/2] app/testpmd: add traffic management forwarding mode Jasvinder Singh
  2017-09-14 11:53   ` [PATCH v2 2/2] app/testpmd: add CLI for tm mode Jasvinder Singh
  2017-09-18 13:54   ` [PATCH v2 1/2] app/testpmd: add traffic management forwarding mode De Lara Guarch, Pablo
@ 2017-09-20  9:56   ` Jasvinder Singh
  2017-09-20  9:56     ` [PATCH v3 2/5] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
                       ` (4 more replies)
  2 siblings, 5 replies; 49+ messages in thread
From: Jasvinder Singh @ 2017-09-20  9:56 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu, pablo.de.lara.guarch

This commit extends the testpmd application with new forwarding engine
that demonstrates the use of ethdev traffic management APIs and softnic
PMD for QoS traffic management.

In this mode, 5-level hierarchical tree of the QoS scheduler is built
with the help of ethdev TM APIs such as shaper profile add/delete,
shared shaper add/update, node add/delete, hierarchy commit, etc.
The hierarchical tree has following nodes; root node(x1, level 0),
subport node(x1, level 1), pipe node(x4096, level 2),
tc node(x16348, level 3), queue node(x65536, level 4).

During runtime, each received packet is first classified by mapping the
packet fields information to 5-tuples (HQoS subport, pipe, traffic class,
queue within traffic class, and color) and storing it in the packet mbuf
sched field. After classification, each packet is sent to softnic port
which prioritizes the transmission of the received packets, and
accordingly sends them on to the output interface.

To enable traffic management mode, following testpmd command is used;

$ ./testpmd -c c -n 4 --vdev
	'net_softnic0,hard_name=0000:06:00.1,soft_tm=on' -- -i
	--forward-mode=tm

This patchset has dependency on following patch series;
http://dpdk.org/ml/archives/dev/2017-September/075655.html
http://dpdk.org/ml/archives/dev/2017-September/075656.html
http://dpdk.org/ml/archives/dev/2017-September/075657.html
http://dpdk.org/ml/archives/dev/2017-September/075658.html

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
v3 change:
- Implements feedback from Pablo[1]
  - add flag to check required librte_sched lib and softnic pmd
  - code cleanup

v2 change:
- change file name softnictm.c to tm.c
- change forward mode name to "tm"
- code clean up

[1] http://dpdk.org/ml/archives/dev/2017-September/075744.html
  
 app/test-pmd/Makefile  |   8 +
 app/test-pmd/testpmd.c |  15 +
 app/test-pmd/testpmd.h |  45 +++
 app/test-pmd/tm.c      | 863 +++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 931 insertions(+)
 create mode 100644 app/test-pmd/tm.c

diff --git a/app/test-pmd/Makefile b/app/test-pmd/Makefile
index c36be19..2c50f68 100644
--- a/app/test-pmd/Makefile
+++ b/app/test-pmd/Makefile
@@ -59,6 +59,10 @@ SRCS-y += csumonly.c
 SRCS-y += icmpecho.c
 SRCS-$(CONFIG_RTE_LIBRTE_IEEE1588) += ieee1588fwd.c
 
+ifeq ($(CONFIG_RTE_LIBRTE_PMD_SOFTNIC)$(CONFIG_RTE_LIBRTE_SCHED),yy)
+SRCS-y += tm.c
+endif
+
 ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
 
 ifeq ($(CONFIG_RTE_LIBRTE_PMD_BOND),y)
@@ -81,6 +85,10 @@ ifeq ($(CONFIG_RTE_LIBRTE_PMD_XENVIRT),y)
 LDLIBS += -lrte_pmd_xenvirt
 endif
 
+ifeq ($(CONFIG_RTE_LIBRTE_PMD_SOFTNIC),y)
+LDLIBS += -lrte_pmd_softnic
+endif
+
 endif
 
 CFLAGS_cmdline.o := -D_GNU_SOURCE
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index e097ee0..d729267 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -167,6 +167,10 @@ struct fwd_engine * fwd_engines[] = {
 	&tx_only_engine,
 	&csum_fwd_engine,
 	&icmp_echo_engine,
+#if defined RTE_LIBRTE_PMD_SOFTNIC && defined RTE_LIBRTE_SCHED
+	&softnic_tm_engine,
+	&softnic_tm_bypass_engine,
+#endif
 #ifdef RTE_LIBRTE_IEEE1588
 	&ieee1588_fwd_engine,
 #endif
@@ -2085,6 +2089,17 @@ init_port_config(void)
 		    (rte_eth_devices[pid].data->dev_flags &
 		     RTE_ETH_DEV_INTR_RMV))
 			port->dev_conf.intr_conf.rmv = 1;
+
+#if defined RTE_LIBRTE_PMD_SOFTNIC && defined RTE_LIBRTE_SCHED
+		/* Detect softnic port */
+		if (!strcmp(port->dev_info.driver_name, "net_softnic")) {
+			port->softnic_enable = 1;
+			memset(&port->softport, 0, sizeof(struct softnic_port));
+
+			if (!strcmp(cur_fwd_eng->fwd_mode_name, "tm"))
+				port->softport.tm_flag = 1;
+		}
+#endif
 	}
 }
 
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 1d1ee75..973196d 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -84,6 +84,12 @@ typedef uint16_t streamid_t;
 
 #define MAX_QUEUE_ID ((1 << (sizeof(queueid_t) * 8)) - 1)
 
+#if defined RTE_LIBRTE_PMD_SOFTNIC && defined RTE_LIBRTE_SCHED
+#define TM_MODE			1
+#else
+#define TM_MODE			0
+#endif
+
 enum {
 	PORT_TOPOLOGY_PAIRED,
 	PORT_TOPOLOGY_CHAINED,
@@ -162,6 +168,37 @@ struct port_flow {
 	uint8_t data[]; /**< Storage for pattern/actions. */
 };
 
+#ifdef TM_MODE
+/**
+ * Soft port tm related parameters
+ */
+struct softnic_port_tm {
+	uint32_t hierarchy_frozen;  /**< flag for tm hierarchy status */
+
+	uint32_t n_subports_per_port;  /**< Num of subport nodes per port */
+	uint32_t n_pipes_per_subport;  /**< Num of pipe nodes per subport */
+
+	uint64_t tm_pktfield0_slabpos;	/**< Pkt field position for subport */
+	uint64_t tm_pktfield0_slabmask; /**< Pkt field mask for the subport */
+	uint64_t tm_pktfield0_slabshr;
+	uint64_t tm_pktfield1_slabpos; /**< Pkt field position for the pipe */
+	uint64_t tm_pktfield1_slabmask; /**< Pkt field mask for the pipe */
+	uint64_t tm_pktfield1_slabshr;
+	uint64_t tm_pktfield2_slabpos; /**< Pkt field position table index */
+	uint64_t tm_pktfield2_slabmask;	/**< Pkt field mask for tc table idx */
+	uint64_t tm_pktfield2_slabshr;
+	uint64_t tm_tc_table[64];  /**< TC translation table */
+};
+
+/**
+ * The data structure associate with softnic port
+ */
+struct softnic_port {
+	unsigned int tm_flag;	/**< set to 1 if tm feature is enabled */
+	struct softnic_port_tm tm;	/**< softnic port tm parameters */
+};
+#endif
+
 /**
  * The data structure associated with each port.
  */
@@ -195,6 +232,10 @@ struct rte_port {
 	uint32_t                mc_addr_nb; /**< nb. of addr. in mc_addr_pool */
 	uint8_t                 slave_flag; /**< bonding slave port */
 	struct port_flow        *flow_list; /**< Associated flows. */
+#ifdef TM_MODE
+	unsigned int			softnic_enable;	/**< set to 1 softnic detected */
+	struct softnic_port     softport;  /**< softnic port params */
+#endif
 };
 
 /**
@@ -253,6 +294,10 @@ extern struct fwd_engine rx_only_engine;
 extern struct fwd_engine tx_only_engine;
 extern struct fwd_engine csum_fwd_engine;
 extern struct fwd_engine icmp_echo_engine;
+#ifdef TM_MODE
+extern struct fwd_engine softnic_tm_engine;
+extern struct fwd_engine softnic_tm_bypass_engine;
+#endif
 #ifdef RTE_LIBRTE_IEEE1588
 extern struct fwd_engine ieee1588_fwd_engine;
 #endif
diff --git a/app/test-pmd/tm.c b/app/test-pmd/tm.c
new file mode 100644
index 0000000..772707e
--- /dev/null
+++ b/app/test-pmd/tm.c
@@ -0,0 +1,863 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <sys/stat.h>
+
+#include <rte_cycles.h>
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_flow.h>
+#include <rte_meter.h>
+#include <rte_eth_softnic.h>
+#include <rte_tm.h>
+
+#include "testpmd.h"
+
+#define SUBPORT_NODES_PER_PORT		1
+#define PIPE_NODES_PER_SUBPORT		4096
+#define TC_NODES_PER_PIPE			4
+#define QUEUE_NODES_PER_TC			4
+
+#define NUM_PIPE_NODES						\
+	(SUBPORT_NODES_PER_PORT * PIPE_NODES_PER_SUBPORT)
+
+#define NUM_TC_NODES						\
+	(NUM_PIPE_NODES * TC_NODES_PER_PIPE)
+
+#define ROOT_NODE_ID				1000000
+#define SUBPORT_NODES_START_ID		900000
+#define PIPE_NODES_START_ID			800000
+#define TC_NODES_START_ID			700000
+
+#define STATS_MASK_DEFAULT					\
+	(RTE_TM_STATS_N_PKTS |					\
+	RTE_TM_STATS_N_BYTES |					\
+	RTE_TM_STATS_N_PKTS_GREEN_DROPPED |			\
+	RTE_TM_STATS_N_BYTES_GREEN_DROPPED)
+
+#define STATS_MASK_QUEUE					\
+	(STATS_MASK_DEFAULT |					\
+	RTE_TM_STATS_N_PKTS_QUEUED)
+
+#define BYTES_IN_MBPS				(1000 * 1000 / 8)
+#define TOKEN_BUCKET_SIZE			1000000
+
+/* TM Hierarchy Levels */
+enum tm_hierarchy_level {
+	TM_NODE_LEVEL_PORT = 0,
+	TM_NODE_LEVEL_SUBPORT,
+	TM_NODE_LEVEL_PIPE,
+	TM_NODE_LEVEL_TC,
+	TM_NODE_LEVEL_QUEUE,
+	TM_NODE_LEVEL_MAX,
+};
+
+struct tm_hierarchy {
+	/* TM Nodes */
+	uint32_t root_node_id;
+	uint32_t subport_node_id[SUBPORT_NODES_PER_PORT];
+	uint32_t pipe_node_id[SUBPORT_NODES_PER_PORT][PIPE_NODES_PER_SUBPORT];
+	uint32_t tc_node_id[NUM_PIPE_NODES][TC_NODES_PER_PIPE];
+	uint32_t queue_node_id[NUM_TC_NODES][QUEUE_NODES_PER_TC];
+
+	/* TM Hierarchy Nodes Shaper Rates */
+	uint32_t root_node_shaper_rate;
+	uint32_t subport_node_shaper_rate;
+	uint32_t pipe_node_shaper_rate;
+	uint32_t tc_node_shaper_rate;
+	uint32_t tc_node_shared_shaper_rate;
+
+	uint32_t n_shapers;
+};
+
+#define BITFIELD(byte_array, slab_pos, slab_mask, slab_shr)	\
+({								\
+	uint64_t slab = *((uint64_t *) &byte_array[slab_pos]);	\
+	uint64_t val =				\
+		(rte_be_to_cpu_64(slab) & slab_mask) >> slab_shr;	\
+	val;						\
+})
+
+#define RTE_SCHED_PORT_HIERARCHY(subport, pipe,           \
+	traffic_class, queue, color)                          \
+	((((uint64_t) (queue)) & 0x3) |                       \
+	((((uint64_t) (traffic_class)) & 0x3) << 2) |         \
+	((((uint64_t) (color)) & 0x3) << 4) |                 \
+	((((uint64_t) (subport)) & 0xFFFF) << 16) |           \
+	((((uint64_t) (pipe)) & 0xFFFFFFFF) << 32))
+
+
+static void
+pkt_metadata_set(struct rte_port *p, struct rte_mbuf **pkts,
+	uint32_t n_pkts)
+{
+	struct softnic_port_tm *tm = &p->softport.tm;
+	uint32_t i;
+
+	for (i = 0; i < (n_pkts & (~0x3)); i += 4) {
+		struct rte_mbuf *pkt0 = pkts[i];
+		struct rte_mbuf *pkt1 = pkts[i + 1];
+		struct rte_mbuf *pkt2 = pkts[i + 2];
+		struct rte_mbuf *pkt3 = pkts[i + 3];
+
+		uint8_t *pkt0_data = rte_pktmbuf_mtod(pkt0, uint8_t *);
+		uint8_t *pkt1_data = rte_pktmbuf_mtod(pkt1, uint8_t *);
+		uint8_t *pkt2_data = rte_pktmbuf_mtod(pkt2, uint8_t *);
+		uint8_t *pkt3_data = rte_pktmbuf_mtod(pkt3, uint8_t *);
+
+		uint64_t pkt0_subport = BITFIELD(pkt0_data,
+					tm->tm_pktfield0_slabpos,
+					tm->tm_pktfield0_slabmask,
+					tm->tm_pktfield0_slabshr);
+		uint64_t pkt0_pipe = BITFIELD(pkt0_data,
+					tm->tm_pktfield1_slabpos,
+					tm->tm_pktfield1_slabmask,
+					tm->tm_pktfield1_slabshr);
+		uint64_t pkt0_dscp = BITFIELD(pkt0_data,
+					tm->tm_pktfield2_slabpos,
+					tm->tm_pktfield2_slabmask,
+					tm->tm_pktfield2_slabshr);
+		uint32_t pkt0_tc = tm->tm_tc_table[pkt0_dscp & 0x3F] >> 2;
+		uint32_t pkt0_tc_q = tm->tm_tc_table[pkt0_dscp & 0x3F] & 0x3;
+		uint64_t pkt1_subport = BITFIELD(pkt1_data,
+					tm->tm_pktfield0_slabpos,
+					tm->tm_pktfield0_slabmask,
+					tm->tm_pktfield0_slabshr);
+		uint64_t pkt1_pipe = BITFIELD(pkt1_data,
+					tm->tm_pktfield1_slabpos,
+					tm->tm_pktfield1_slabmask,
+					tm->tm_pktfield1_slabshr);
+		uint64_t pkt1_dscp = BITFIELD(pkt1_data,
+					tm->tm_pktfield2_slabpos,
+					tm->tm_pktfield2_slabmask,
+					tm->tm_pktfield2_slabshr);
+		uint32_t pkt1_tc = tm->tm_tc_table[pkt1_dscp & 0x3F] >> 2;
+		uint32_t pkt1_tc_q = tm->tm_tc_table[pkt1_dscp & 0x3F] & 0x3;
+
+		uint64_t pkt2_subport = BITFIELD(pkt2_data,
+					tm->tm_pktfield0_slabpos,
+					tm->tm_pktfield0_slabmask,
+					tm->tm_pktfield0_slabshr);
+		uint64_t pkt2_pipe = BITFIELD(pkt2_data,
+					tm->tm_pktfield1_slabpos,
+					tm->tm_pktfield1_slabmask,
+					tm->tm_pktfield1_slabshr);
+		uint64_t pkt2_dscp = BITFIELD(pkt2_data,
+					tm->tm_pktfield2_slabpos,
+					tm->tm_pktfield2_slabmask,
+					tm->tm_pktfield2_slabshr);
+		uint32_t pkt2_tc = tm->tm_tc_table[pkt2_dscp & 0x3F] >> 2;
+		uint32_t pkt2_tc_q = tm->tm_tc_table[pkt2_dscp & 0x3F] & 0x3;
+
+		uint64_t pkt3_subport = BITFIELD(pkt3_data,
+					tm->tm_pktfield0_slabpos,
+					tm->tm_pktfield0_slabmask,
+					tm->tm_pktfield0_slabshr);
+		uint64_t pkt3_pipe = BITFIELD(pkt3_data,
+					tm->tm_pktfield1_slabpos,
+					tm->tm_pktfield1_slabmask,
+					tm->tm_pktfield1_slabshr);
+		uint64_t pkt3_dscp = BITFIELD(pkt3_data,
+					tm->tm_pktfield2_slabpos,
+					tm->tm_pktfield2_slabmask,
+					tm->tm_pktfield2_slabshr);
+		uint32_t pkt3_tc = tm->tm_tc_table[pkt3_dscp & 0x3F] >> 2;
+		uint32_t pkt3_tc_q = tm->tm_tc_table[pkt3_dscp & 0x3F] & 0x3;
+
+		uint64_t pkt0_sched = RTE_SCHED_PORT_HIERARCHY(pkt0_subport,
+						pkt0_pipe,
+						pkt0_tc,
+						pkt0_tc_q,
+						0);
+		uint64_t pkt1_sched = RTE_SCHED_PORT_HIERARCHY(pkt1_subport,
+						pkt1_pipe,
+						pkt1_tc,
+						pkt1_tc_q,
+						0);
+		uint64_t pkt2_sched = RTE_SCHED_PORT_HIERARCHY(pkt2_subport,
+						pkt2_pipe,
+						pkt2_tc,
+						pkt2_tc_q,
+						0);
+		uint64_t pkt3_sched = RTE_SCHED_PORT_HIERARCHY(pkt3_subport,
+						pkt3_pipe,
+						pkt3_tc,
+						pkt3_tc_q,
+						0);
+
+		pkt0->hash.sched.lo = pkt0_sched & 0xFFFFFFFF;
+		pkt0->hash.sched.hi = pkt0_sched >> 32;
+		pkt1->hash.sched.lo = pkt1_sched & 0xFFFFFFFF;
+		pkt1->hash.sched.hi = pkt1_sched >> 32;
+		pkt2->hash.sched.lo = pkt2_sched & 0xFFFFFFFF;
+		pkt2->hash.sched.hi = pkt2_sched >> 32;
+		pkt3->hash.sched.lo = pkt3_sched & 0xFFFFFFFF;
+		pkt3->hash.sched.hi = pkt3_sched >> 32;
+	}
+
+	for (; i < n_pkts; i++)	{
+		struct rte_mbuf *pkt = pkts[i];
+
+		uint8_t *pkt_data = rte_pktmbuf_mtod(pkt, uint8_t *);
+
+		uint64_t pkt_subport = BITFIELD(pkt_data,
+					tm->tm_pktfield0_slabpos,
+					tm->tm_pktfield0_slabmask,
+					tm->tm_pktfield0_slabshr);
+		uint64_t pkt_pipe = BITFIELD(pkt_data,
+					tm->tm_pktfield1_slabpos,
+					tm->tm_pktfield1_slabmask,
+					tm->tm_pktfield1_slabshr);
+		uint64_t pkt_dscp = BITFIELD(pkt_data,
+					tm->tm_pktfield2_slabpos,
+					tm->tm_pktfield2_slabmask,
+					tm->tm_pktfield2_slabshr);
+		uint32_t pkt_tc = tm->tm_tc_table[pkt_dscp & 0x3F] >> 2;
+		uint32_t pkt_tc_q = tm->tm_tc_table[pkt_dscp & 0x3F] & 0x3;
+
+		uint64_t pkt_sched = RTE_SCHED_PORT_HIERARCHY(pkt_subport,
+						pkt_pipe,
+						pkt_tc,
+						pkt_tc_q,
+						0);
+
+		pkt->hash.sched.lo = pkt_sched & 0xFFFFFFFF;
+		pkt->hash.sched.hi = pkt_sched >> 32;
+	}
+}
+
+/*
+ * Soft port packet forward
+ */
+static void
+softport_packet_fwd(struct fwd_stream *fs)
+{
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	struct rte_port *rte_tx_port = &ports[fs->tx_port];
+	uint16_t nb_rx;
+	uint16_t nb_tx;
+	uint32_t retry;
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+	uint64_t start_tsc;
+	uint64_t end_tsc;
+	uint64_t core_cycles;
+#endif
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+	start_tsc = rte_rdtsc();
+#endif
+
+	/*  Packets Receive */
+	nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue,
+			pkts_burst, nb_pkt_per_burst);
+	fs->rx_packets += nb_rx;
+
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+	fs->rx_burst_stats.pkt_burst_spread[nb_rx]++;
+#endif
+
+	if (rte_tx_port->softnic_enable) {
+		/* Set packet metadata if tm flag enabled */
+		if (rte_tx_port->softport.tm_flag)
+			pkt_metadata_set(rte_tx_port, pkts_burst, nb_rx);
+
+		/* Softport run */
+		rte_pmd_softnic_run(fs->tx_port);
+	}
+	nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
+			pkts_burst, nb_rx);
+
+	/* Retry if necessary */
+	if (unlikely(nb_tx < nb_rx) && fs->retry_enabled) {
+		retry = 0;
+		while (nb_tx < nb_rx && retry++ < burst_tx_retry_num) {
+			rte_delay_us(burst_tx_delay_time);
+			nb_tx += rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
+					&pkts_burst[nb_tx], nb_rx - nb_tx);
+		}
+	}
+	fs->tx_packets += nb_tx;
+
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+	fs->tx_burst_stats.pkt_burst_spread[nb_tx]++;
+#endif
+
+	if (unlikely(nb_tx < nb_rx)) {
+		fs->fwd_dropped += (nb_rx - nb_tx);
+		do {
+			rte_pktmbuf_free(pkts_burst[nb_tx]);
+		} while (++nb_tx < nb_rx);
+	}
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+	end_tsc = rte_rdtsc();
+	core_cycles = (end_tsc - start_tsc);
+	fs->core_cycles = (uint64_t) (fs->core_cycles + core_cycles);
+#endif
+}
+
+static void
+set_tm_hiearchy_nodes_shaper_rate(portid_t port_id, struct tm_hierarchy *h)
+{
+	struct rte_eth_link link_params;
+	uint64_t tm_port_rate;
+
+	memset(&link_params, 0, sizeof(link_params));
+
+	rte_eth_link_get(port_id, &link_params);
+	tm_port_rate = link_params.link_speed * BYTES_IN_MBPS;
+
+	if (tm_port_rate > UINT32_MAX)
+		tm_port_rate = UINT32_MAX;
+
+	/* Set tm hierarchy shapers rate */
+	h->root_node_shaper_rate = tm_port_rate;
+	h->subport_node_shaper_rate =
+		tm_port_rate / SUBPORT_NODES_PER_PORT;
+	h->pipe_node_shaper_rate
+		= h->subport_node_shaper_rate / PIPE_NODES_PER_SUBPORT;
+	h->tc_node_shaper_rate = h->pipe_node_shaper_rate;
+	h->tc_node_shared_shaper_rate = h->subport_node_shaper_rate;
+}
+
+static int
+softport_tm_root_node_add(portid_t port_id, struct tm_hierarchy *h,
+	struct rte_tm_error *error)
+{
+	struct rte_tm_node_params rnp;
+	struct rte_tm_shaper_params rsp;
+	uint32_t priority, weight, level_id, shaper_profile_id;
+
+	memset(&rsp, 0, sizeof(struct rte_tm_shaper_params));
+	memset(&rnp, 0, sizeof(struct rte_tm_node_params));
+
+	/* Shaper profile Parameters */
+	rsp.peak.rate = h->root_node_shaper_rate;
+	rsp.peak.size = TOKEN_BUCKET_SIZE;
+	rsp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+	shaper_profile_id = 0;
+
+	if (rte_tm_shaper_profile_add(port_id, shaper_profile_id,
+		&rsp, error)) {
+		printf("%s ERROR(%d)-%s!(shaper_id %u)\n ",
+			__func__, error->type, error->message,
+			shaper_profile_id);
+		return -1;
+	}
+
+	/* Root Node Parameters */
+	h->root_node_id = ROOT_NODE_ID;
+	weight = 1;
+	priority = 0;
+	level_id = TM_NODE_LEVEL_PORT;
+	rnp.shaper_profile_id = shaper_profile_id;
+	rnp.nonleaf.n_sp_priorities = 1;
+	rnp.stats_mask = STATS_MASK_DEFAULT;
+
+	/* Add Node to TM Hierarchy */
+	if (rte_tm_node_add(port_id, h->root_node_id, RTE_TM_NODE_ID_NULL,
+		priority, weight, level_id, &rnp, error)) {
+		printf("%s ERROR(%d)-%s!(node_id %u, parent_id %u, level %u)\n",
+			__func__, error->type, error->message,
+			h->root_node_id, RTE_TM_NODE_ID_NULL,
+			level_id);
+		return -1;
+	}
+	/* Update */
+	h->n_shapers++;
+
+	printf("  Root node added (Start id %u, Count %u, level %u)\n",
+		h->root_node_id, 1, level_id);
+
+	return 0;
+}
+
+static int
+softport_tm_subport_node_add(portid_t port_id, struct tm_hierarchy *h,
+	struct rte_tm_error *error)
+{
+	uint32_t subport_parent_node_id, subport_node_id;
+	struct rte_tm_node_params snp;
+	struct rte_tm_shaper_params ssp;
+	uint32_t priority, weight, level_id, shaper_profile_id;
+	uint32_t i;
+
+	memset(&ssp, 0, sizeof(struct rte_tm_shaper_params));
+	memset(&snp, 0, sizeof(struct rte_tm_node_params));
+
+	shaper_profile_id = h->n_shapers;
+
+	/* Add Shaper Profile to TM Hierarchy */
+	for (i = 0; i < SUBPORT_NODES_PER_PORT; i++) {
+		ssp.peak.rate = h->subport_node_shaper_rate;
+		ssp.peak.size = TOKEN_BUCKET_SIZE;
+		ssp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+		if (rte_tm_shaper_profile_add(port_id, shaper_profile_id,
+			&ssp, error)) {
+			printf("%s ERROR(%d)-%s!(shaper_id %u)\n ",
+				__func__, error->type, error->message,
+				shaper_profile_id);
+			return -1;
+		}
+
+		/* Node Parameters */
+		h->subport_node_id[i] = SUBPORT_NODES_START_ID + i;
+		subport_parent_node_id = h->root_node_id;
+		weight = 1;
+		priority = 0;
+		level_id = TM_NODE_LEVEL_SUBPORT;
+		snp.shaper_profile_id = shaper_profile_id;
+		snp.nonleaf.n_sp_priorities = 1;
+		snp.stats_mask = STATS_MASK_DEFAULT;
+
+		/* Add Node to TM Hiearchy */
+		if (rte_tm_node_add(port_id,
+				h->subport_node_id[i],
+				subport_parent_node_id,
+				priority, weight,
+				level_id,
+				&snp,
+				error)) {
+			printf("%s ERROR(%d)-%s!(node %u,parent %u,level %u)\n",
+					__func__,
+					error->type,
+					error->message,
+					h->subport_node_id[i],
+					subport_parent_node_id,
+					level_id);
+			return -1;
+		}
+		shaper_profile_id++;
+		subport_node_id++;
+	}
+	/* Update */
+	h->n_shapers = shaper_profile_id;
+
+	printf("  Subport nodes added (Start id %u, Count %u, level %u)\n",
+		h->subport_node_id[0], SUBPORT_NODES_PER_PORT, level_id);
+
+	return 0;
+}
+
+static int
+softport_tm_pipe_node_add(portid_t port_id, struct tm_hierarchy *h,
+	struct rte_tm_error *error)
+{
+	uint32_t pipe_parent_node_id;
+	struct rte_tm_node_params pnp;
+	struct rte_tm_shaper_params psp;
+	uint32_t priority, weight, level_id, shaper_profile_id;
+	uint32_t i, j;
+
+	memset(&psp, 0, sizeof(struct rte_tm_shaper_params));
+	memset(&pnp, 0, sizeof(struct rte_tm_node_params));
+
+	shaper_profile_id = h->n_shapers;
+
+	/* Shaper Profile Parameters */
+	psp.peak.rate = h->pipe_node_shaper_rate;
+	psp.peak.size = TOKEN_BUCKET_SIZE;
+	psp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+	/* Pipe Node Parameters */
+	weight = 1;
+	priority = 0;
+	level_id = TM_NODE_LEVEL_PIPE;
+	pnp.nonleaf.n_sp_priorities = 4;
+	pnp.stats_mask = STATS_MASK_DEFAULT;
+
+	/* Add Shaper Profiles and Nodes to TM Hierarchy */
+	for (i = 0; i < SUBPORT_NODES_PER_PORT; i++) {
+		for (j = 0; j < PIPE_NODES_PER_SUBPORT; j++) {
+			if (rte_tm_shaper_profile_add(port_id,
+				shaper_profile_id, &psp, error)) {
+				printf("%s ERROR(%d)-%s!(shaper_id %u)\n ",
+					__func__, error->type, error->message,
+					shaper_profile_id);
+				return -1;
+			}
+			pnp.shaper_profile_id = shaper_profile_id;
+			pipe_parent_node_id = h->subport_node_id[i];
+			h->pipe_node_id[i][j] = PIPE_NODES_START_ID +
+				(i * PIPE_NODES_PER_SUBPORT) + j;
+
+			if (rte_tm_node_add(port_id,
+					h->pipe_node_id[i][j],
+					pipe_parent_node_id,
+					priority, weight, level_id,
+					&pnp,
+					error)) {
+				printf("%s ERROR(%d)-%s!(node %u,parent %u )\n",
+					__func__,
+					error->type,
+					error->message,
+					h->pipe_node_id[i][j],
+					pipe_parent_node_id);
+
+				return -1;
+			}
+			shaper_profile_id++;
+		}
+	}
+	/* Update */
+	h->n_shapers = shaper_profile_id;
+
+	printf("  Pipe nodes added (Start id %u, Count %u, level %u)\n",
+		h->pipe_node_id[0][0], NUM_PIPE_NODES, level_id);
+
+	return 0;
+}
+
+static int
+softport_tm_tc_node_add(portid_t port_id, struct tm_hierarchy *h,
+	struct rte_tm_error *error)
+{
+	uint32_t tc_parent_node_id;
+	struct rte_tm_node_params tnp;
+	struct rte_tm_shaper_params tsp, tssp;
+	uint32_t shared_shaper_profile_id[TC_NODES_PER_PIPE];
+	uint32_t priority, weight, level_id, shaper_profile_id;
+	uint32_t pos, n_tc_nodes, i, j, k;
+
+	memset(&tsp, 0, sizeof(struct rte_tm_shaper_params));
+	memset(&tssp, 0, sizeof(struct rte_tm_shaper_params));
+	memset(&tnp, 0, sizeof(struct rte_tm_node_params));
+
+	shaper_profile_id = h->n_shapers;
+
+	/* Private Shaper Profile (TC) Parameters */
+	tsp.peak.rate = h->tc_node_shaper_rate;
+	tsp.peak.size = TOKEN_BUCKET_SIZE;
+	tsp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+	/* Shared Shaper Profile (TC) Parameters */
+	tssp.peak.rate = h->tc_node_shared_shaper_rate;
+	tssp.peak.size = TOKEN_BUCKET_SIZE;
+	tssp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+	/* TC Node Parameters */
+	weight = 1;
+	level_id = TM_NODE_LEVEL_TC;
+	tnp.n_shared_shapers = 1;
+	tnp.nonleaf.n_sp_priorities = 1;
+	tnp.stats_mask = STATS_MASK_DEFAULT;
+
+	/* Add Shared Shaper Profiles to TM Hierarchy */
+	for (i = 0; i < TC_NODES_PER_PIPE; i++) {
+		shared_shaper_profile_id[i] = shaper_profile_id;
+
+		if (rte_tm_shaper_profile_add(port_id,
+			shared_shaper_profile_id[i], &tssp, error)) {
+			printf("%s ERROR(%d)-%s!(Shared shaper profileid %u)\n",
+				__func__, error->type, error->message,
+				shared_shaper_profile_id[i]);
+
+			return -1;
+		}
+		if (rte_tm_shared_shaper_add_update(port_id,  i,
+			shared_shaper_profile_id[i], error)) {
+			printf("%s ERROR(%d)-%s!(Shared shaper id %u)\n",
+				__func__, error->type, error->message, i);
+
+			return -1;
+		}
+		shaper_profile_id++;
+	}
+
+	/* Add Shaper Profiles and Nodes to TM Hierarchy */
+	n_tc_nodes = 0;
+	for (i = 0; i < SUBPORT_NODES_PER_PORT; i++) {
+		for (j = 0; j < PIPE_NODES_PER_SUBPORT; j++) {
+			for (k = 0; k < TC_NODES_PER_PIPE ; k++) {
+				priority = k;
+				tc_parent_node_id = h->pipe_node_id[i][j];
+				tnp.shared_shaper_id =
+					(uint32_t *)calloc(1, sizeof(uint32_t));
+				tnp.shared_shaper_id[0] = k;
+				pos = j + (i * PIPE_NODES_PER_SUBPORT);
+				h->tc_node_id[pos][k] = TC_NODES_START_ID + n_tc_nodes;
+
+				if (rte_tm_shaper_profile_add(port_id,
+					shaper_profile_id, &tsp, error)) {
+					printf("%s ERROR(%d)-%s!(shaper %u)\n",
+						__func__, error->type,
+						error->message,
+						shaper_profile_id);
+
+					return -1;
+				}
+				tnp.shaper_profile_id = shaper_profile_id;
+				if (rte_tm_node_add(port_id,
+						h->tc_node_id[pos][k],
+						tc_parent_node_id,
+						priority, weight,
+						level_id,
+						&tnp, error)) {
+					printf("%s ERROR(%d)-%s!(node id %u)\n",
+						__func__,
+						error->type,
+						error->message,
+						h->tc_node_id[pos][k]);
+
+					return -1;
+				}
+				shaper_profile_id++;
+				n_tc_nodes++;
+			}
+		}
+	}
+	/* Update */
+	h->n_shapers = shaper_profile_id;
+
+	printf("  TC nodes added (Start id %u, Count %u, level %u)\n",
+		h->tc_node_id[0][0], n_tc_nodes, level_id);
+
+	return 0;
+}
+
+static int
+softport_tm_queue_node_add(portid_t port_id, struct tm_hierarchy *h,
+	struct rte_tm_error *error)
+{
+	uint32_t queue_parent_node_id;
+	struct rte_tm_node_params qnp;
+	uint32_t priority, weight, level_id, pos;
+	uint32_t n_queue_nodes, i, j, k;
+
+	memset(&qnp, 0, sizeof(struct rte_tm_node_params));
+
+	/* Queue Node Parameters */
+	priority = 0;
+	weight = 1;
+	level_id = TM_NODE_LEVEL_QUEUE;
+	qnp.shaper_profile_id = RTE_TM_SHAPER_PROFILE_ID_NONE;
+	qnp.leaf.cman = RTE_TM_CMAN_TAIL_DROP;
+	qnp.stats_mask = STATS_MASK_QUEUE;
+
+	/* Add Queue Nodes to TM Hierarchy */
+	n_queue_nodes = 0;
+	for (i = 0; i < NUM_PIPE_NODES; i++) {
+		for (j = 0; j < TC_NODES_PER_PIPE; j++) {
+			queue_parent_node_id = h->tc_node_id[i][j];
+			for (k = 0; k < QUEUE_NODES_PER_TC; k++) {
+				pos = j + (i * TC_NODES_PER_PIPE);
+				h->queue_node_id[pos][k] = n_queue_nodes;
+				if (rte_tm_node_add(port_id,
+						h->queue_node_id[pos][k],
+						queue_parent_node_id,
+						priority,
+						weight,
+						level_id,
+						&qnp, error)) {
+					printf("%s ERROR(%d)-%s!(node %u)\n",
+						__func__,
+						error->type,
+						error->message,
+						h->queue_node_id[pos][k]);
+
+					return -1;
+				}
+				n_queue_nodes++;
+			}
+		}
+	}
+	printf("  Queue nodes added (Start id %u, Count %u, level %u)\n",
+		h->queue_node_id[0][0], n_queue_nodes, level_id);
+
+	return 0;
+}
+
+/*
+ * TM Packet Field Setup
+ */
+static void
+softport_tm_pktfield_setup(portid_t port_id)
+{
+	struct rte_port *p = &ports[port_id];
+	uint64_t pktfield0_mask = 0;
+	uint64_t pktfield1_mask = 0x0000000FFF000000LLU;
+	uint64_t pktfield2_mask = 0x00000000000000FCLLU;
+
+	p->softport.tm = (struct softnic_port_tm) {
+		.n_subports_per_port = SUBPORT_NODES_PER_PORT,
+		.n_pipes_per_subport = PIPE_NODES_PER_SUBPORT,
+
+		/* Packet field to identify subport
+		 *
+		 * Default configuration assumes only one subport, thus
+		 * the subport ID is hardcoded to 0
+		 */
+		.tm_pktfield0_slabpos = 0,
+		.tm_pktfield0_slabmask = pktfield0_mask,
+		.tm_pktfield0_slabshr =
+			__builtin_ctzll(pktfield0_mask),
+
+		/* Packet field to identify pipe.
+		 *
+		 * Default value assumes Ethernet/IPv4/UDP packets,
+		 * UDP payload bits 12 .. 23
+		 */
+		.tm_pktfield1_slabpos = 40,
+		.tm_pktfield1_slabmask = pktfield1_mask,
+		.tm_pktfield1_slabshr =
+			__builtin_ctzll(pktfield1_mask),
+
+		/* Packet field used as index into TC translation table
+		 * to identify the traffic class and queue.
+		 *
+		 * Default value assumes Ethernet/IPv4 packets, IPv4
+		 * DSCP field
+		 */
+		.tm_pktfield2_slabpos = 8,
+		.tm_pktfield2_slabmask = pktfield2_mask,
+		.tm_pktfield2_slabshr =
+			__builtin_ctzll(pktfield2_mask),
+
+		.tm_tc_table = {
+			0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+			0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+			0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+			0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+		}, /**< TC translation table */
+	};
+}
+
+static int
+softport_tm_hierarchy_specify(portid_t port_id, struct rte_tm_error *error)
+{
+
+	struct tm_hierarchy h;
+	int status;
+
+	memset(&h, 0, sizeof(struct tm_hierarchy));
+
+	/* TM hierarchy shapers rate */
+	set_tm_hiearchy_nodes_shaper_rate(port_id, &h);
+
+	/* Add root node (level 0) */
+	status = softport_tm_root_node_add(port_id, &h, error);
+	if (status)
+		return status;
+
+	/* Add subport node (level 1) */
+	status = softport_tm_subport_node_add(port_id, &h, error);
+	if (status)
+		return status;
+
+	/* Add pipe nodes (level 2) */
+	status = softport_tm_pipe_node_add(port_id, &h, error);
+	if (status)
+		return status;
+
+	/* Add traffic class nodes (level 3) */
+	status = softport_tm_tc_node_add(port_id, &h, error);
+	if (status)
+		return status;
+
+	/* Add queue nodes (level 4) */
+	status = softport_tm_queue_node_add(port_id, &h, error);
+	if (status)
+		return status;
+
+	/* TM packet fields setup */
+	softport_tm_pktfield_setup(port_id);
+
+	return 0;
+}
+
+/*
+ * Soft port Init
+ */
+static void
+softport_tm_begin(portid_t pi)
+{
+	struct rte_port *port = &ports[pi];
+
+	/* Soft port TM flag */
+	if (port->softport.tm_flag == 1) {
+		printf("\n\n  TM feature available on port %u\n", pi);
+
+		/* Soft port TM hierarchy frozen */
+		if (port->softport.tm.hierarchy_frozen == 0) {
+			struct rte_tm_error error;
+			int status;
+
+			/* Stop port */
+			rte_eth_dev_stop(pi);
+
+			/* TM hierarchy specification */
+			status = softport_tm_hierarchy_specify(pi, &error);
+			if (status) {
+				printf("  TM Hierarchy built error(%d) - %s\n",
+					error.type, error.message);
+				return;
+			}
+			printf("\n  TM Hierarchy Specified!\n\v");
+
+			/* TM hierarchy commit */
+			status = rte_tm_hierarchy_commit(pi, 0, &error);
+			if (status) {
+				printf("  Hierarchy commit error(%d) - %s\n",
+					error.type, error.message);
+				return;
+			}
+			printf("  Hierarchy Committed (port %u)!", pi);
+			port->softport.tm.hierarchy_frozen = 1;
+
+			/* Start port */
+			status = rte_eth_dev_start(pi);
+			if (status) {
+				printf("\n  Port %u start error!\n", pi);
+				return;
+			}
+			printf("\n  Port %u started!\n", pi);
+			return;
+		}
+	}
+	printf("\n  TM feature not available on port %u", pi);
+}
+
+struct fwd_engine softnic_tm_engine = {
+	.fwd_mode_name  = "tm",
+	.port_fwd_begin = softport_tm_begin,
+	.port_fwd_end   = NULL,
+	.packet_fwd     = softport_packet_fwd,
+};
+
+struct fwd_engine softnic_tm_bypass_engine = {
+	.fwd_mode_name  = "tm-bypass",
+	.port_fwd_begin = NULL,
+	.port_fwd_end   = NULL,
+	.packet_fwd     = softport_packet_fwd,
+};
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v3 2/5] app/test-pmd: add CLI for TM capability and stats
  2017-09-20  9:56   ` [PATCH v3 1/5] " Jasvinder Singh
@ 2017-09-20  9:56     ` Jasvinder Singh
  2017-09-20  9:56     ` [PATCH v3 3/5] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
                       ` (3 subsequent siblings)
  4 siblings, 0 replies; 49+ messages in thread
From: Jasvinder Singh @ 2017-09-20  9:56 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu, pablo.de.lara.guarch

Add following CLIs to testpmd application;
- commands to display TM capability information.
  (per port, per hierarchy level and per hierarchy node)
- command to display hiearchy node type
- stats collection

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
v3 change:
- Implements feedback from Pablo[1]
 - move TM API related CLIs into cmdline_tm.c 
 - split patch into small patches
 - replace link status check with testpmd fn port_is_started()

[1]http://dpdk.org/ml/archives/dev/2017-September/075748.html

 app/test-pmd/Makefile     |   1 +
 app/test-pmd/cmdline.c    |  34 ++-
 app/test-pmd/cmdline_tm.c | 739 ++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 773 insertions(+), 1 deletion(-)
 create mode 100644 app/test-pmd/cmdline_tm.c

diff --git a/app/test-pmd/Makefile b/app/test-pmd/Makefile
index 2c50f68..d1252bc 100644
--- a/app/test-pmd/Makefile
+++ b/app/test-pmd/Makefile
@@ -61,6 +61,7 @@ SRCS-$(CONFIG_RTE_LIBRTE_IEEE1588) += ieee1588fwd.c
 
 ifeq ($(CONFIG_RTE_LIBRTE_PMD_SOFTNIC)$(CONFIG_RTE_LIBRTE_SCHED),yy)
 SRCS-y += tm.c
+SRCS-y += cmdline_tm.c
 endif
 
 ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index ccdf239..6012c3a 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -230,6 +230,23 @@ static void cmd_help_long_parsed(void *parsed_result,
 
 			"clear vf stats (port_id) (vf_id)\n"
 			"    Reset a VF's statistics.\n\n"
+
+#ifdef TM_MODE
+			"show port tm cap (port_id)\n"
+			"	Display the port TM capability.\n\n"
+
+			"show port tm level cap (port_id) (level_id)\n"
+			"	Display the port TM hierarchical level capability.\n\n"
+
+			"show port tm node cap (port_id) (node_id)\n"
+			"	Display the port TM node capability.\n\n"
+
+			"show port tm node type (port_id) (node_id)\n"
+			"	Display the port TM node type.\n\n"
+
+			"show port tm node stats (port_id) (node_id) (clear)\n"
+			"	Display the port TM node stats.\n\n"
+#endif
 		);
 	}
 
@@ -14189,7 +14206,15 @@ cmdline_parse_inst_t cmd_load_from_file = {
 	},
 };
 
-/* ******************************************************************************** */
+#ifdef TM_MODE
+extern cmdline_parse_inst_t cmd_show_port_tm_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_level_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_type;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_stats;
+#endif
+
+/* *********************************************************************** */
 
 /* list of instructions */
 cmdline_parse_ctx_t main_ctx[] = {
@@ -14380,6 +14405,13 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_ptype_mapping_replace,
 	(cmdline_parse_inst_t *)&cmd_ptype_mapping_reset,
 	(cmdline_parse_inst_t *)&cmd_ptype_mapping_update,
+#ifdef TM_MODE
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_level_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_type,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_stats,
+#endif
 	NULL,
 };
 
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
new file mode 100644
index 0000000..a20942e
--- /dev/null
+++ b/app/test-pmd/cmdline_tm.c
@@ -0,0 +1,739 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+
+#include <rte_ethdev.h>
+#include <rte_flow.h>
+#include <rte_sched.h>
+#include <rte_eth_softnic.h>
+#include <rte_tm.h>
+
+#include "testpmd.h"
+
+/** Display TM Error Message */
+static void
+print_err_msg(struct rte_tm_error *error)
+{
+	static const char *const errstrlist[] = {
+		[RTE_TM_ERROR_TYPE_NONE] = "no error",
+		[RTE_TM_ERROR_TYPE_UNSPECIFIED] = "cause unspecified",
+		[RTE_TM_ERROR_TYPE_CAPABILITIES]
+			= "capability parameter null",
+		[RTE_TM_ERROR_TYPE_LEVEL_ID] = "level id",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE]
+			= "wred profile null",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_GREEN] = "wred profile(green)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_YELLOW]
+			= "wred profile(yellow)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_RED] = "wred profile(red)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_ID] = "wred profile id",
+		[RTE_TM_ERROR_TYPE_SHARED_WRED_CONTEXT_ID]
+			= "shared wred context id",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE] = "shaper profile null",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE]
+			= "committed rate field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE]
+			= "committed size field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE]
+			= "peak rate field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE]
+			= "peak size field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN]
+			= "packet adjust length field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID] = "shaper profile id",
+		[RTE_TM_ERROR_TYPE_SHARED_SHAPER_ID] = "shared shaper id",
+		[RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID] = "parent node id",
+		[RTE_TM_ERROR_TYPE_NODE_PRIORITY] = "node priority",
+		[RTE_TM_ERROR_TYPE_NODE_WEIGHT] = "node weight",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS] = "node parameter null",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID]
+			= "shaper profile id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID]
+			= "shared shaper id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS]
+			= "num shared shapers field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE]
+			= "wfq weght mode field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES]
+			= "num strict priorities field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN]
+			= "congestion management mode field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID] =
+			"wred profile id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID]
+			= "shared wred context id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS]
+			= "num shared wred contexts field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS]
+			= "stats field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_ID] = "node id",
+	};
+
+	const char *errstr;
+	char buf[64];
+
+	if ((unsigned int)error->type >= RTE_DIM(errstrlist) ||
+		!errstrlist[error->type])
+		errstr = "unknown type";
+	else
+		errstr = errstrlist[error->type];
+
+	if (error->cause)
+		snprintf(buf, sizeof(buf), "cause: %p, ", error->cause);
+
+	printf("%s: %s%s (error %d)\n", errstr, error->cause ? buf : "",
+		error->message ? error->message : "(no stated reason)",
+		error->type);
+}
+
+/* *** Port TM Capability *** */
+struct cmd_show_port_tm_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t cap;
+	uint8_t port_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		 port_id, UINT8);
+
+static void cmd_show_port_tm_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_cap_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_capabilities cap;
+	struct rte_tm_error error;
+	uint8_t port_id = res->port_id;
+	uint32_t i;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	memset(&cap, 0, sizeof(struct rte_tm_capabilities));
+	ret = rte_tm_capabilities_get(port_id, &cap, &error);
+	if (ret) {
+		print_err_msg(&error);
+		return;
+	}
+
+	printf("\n****   Port TM Capabilities ****\n\n");
+	printf("cap.n_nodes_max %u\n", cap.n_nodes_max);
+	printf("cap.n_levels_max %u\n", cap.n_levels_max);
+	printf("cap.non_leaf_nodes_identical %d\n",
+		cap.non_leaf_nodes_identical);
+	printf("cap.leaf_nodes_identical %d\n", cap.leaf_nodes_identical);
+	printf("cap.shaper_n_max %u\n", cap.shaper_n_max);
+	printf("cap.shaper_private_n_max %u\n", cap.shaper_private_n_max);
+	printf("cap.shaper_private_dual_rate_n_max %d\n",
+		cap.shaper_private_dual_rate_n_max);
+	printf("cap.shaper_private_rate_min %lu\n",
+		cap.shaper_private_rate_min);
+	printf("cap.shaper_private_rate_max %lu\n",
+		cap.shaper_private_rate_max);
+	printf("cap.shaper_shared_n_max %u\n", cap.shaper_shared_n_max);
+	printf("cap.shaper_shared_n_nodes_per_shaper_max %u\n",
+		cap.shaper_shared_n_nodes_per_shaper_max);
+	printf("cap.shaper_shared_n_shapers_per_node_max %u\n",
+		cap.shaper_shared_n_shapers_per_node_max);
+	printf("cap.shaper_shared_dual_rate_n_max %u\n",
+		cap.shaper_shared_dual_rate_n_max);
+	printf("cap.shaper_shared_rate_min %lu\n",
+		cap.shaper_shared_rate_min);
+	printf("cap.shaper_shared_rate_max %lu\n",
+		cap.shaper_shared_rate_max);
+	printf("cap.shaper_pkt_length_adjust_min %d\n",
+		cap.shaper_pkt_length_adjust_min);
+	printf("cap.shaper_pkt_length_adjust_max %d\n",
+		cap.shaper_pkt_length_adjust_max);
+	printf("cap.sched_n_children_max %u\n", cap.sched_n_children_max);
+	printf("cap.sched_sp_n_priorities_max %u\n",
+		cap.sched_sp_n_priorities_max);
+	printf("cap.sched_wfq_n_children_per_group_max %u\n",
+		cap.sched_wfq_n_children_per_group_max);
+	printf("cap.sched_wfq_n_groups_max %u\n", cap.sched_wfq_n_groups_max);
+	printf("cap.sched_wfq_weight_max %u\n", cap.sched_wfq_weight_max);
+	printf("cap.cman_head_drop_supported %d\n",
+		cap.cman_head_drop_supported);
+	printf("cap.cman_wred_context_n_max %u\n", cap.cman_wred_context_n_max);
+	printf("cap.cman_wred_context_private_n_max %u\n",
+		cap.cman_wred_context_private_n_max);
+	printf("cap.cman_wred_context_shared_n_max %u\n",
+		cap.cman_wred_context_shared_n_max);
+	printf("cap.cman_wred_context_shared_n_nodes_per_context_max %u\n",
+		cap.cman_wred_context_shared_n_nodes_per_context_max);
+	printf("cap.cman_wred_context_shared_n_contexts_per_node_max %u\n",
+		cap.cman_wred_context_shared_n_contexts_per_node_max);
+
+	for (i = 0; i < RTE_TM_COLORS; i++) {
+		printf("cap.mark_vlan_dei_supported %d\n",
+			cap.mark_vlan_dei_supported[i]);
+		printf("cap.mark_ip_ecn_tcp_supported %d\n",
+			cap.mark_ip_ecn_tcp_supported[i]);
+		printf("cap.mark_ip_ecn_sctp_supported %d\n",
+			cap.mark_ip_ecn_sctp_supported[i]);
+		printf("cap.mark_ip_dscp_supported %d\n",
+			cap.mark_ip_dscp_supported[i]);
+	}
+
+	printf("cap.dynamic_update_mask %lu\n", cap.dynamic_update_mask);
+	printf("cap.stats_mask %lu\n", cap.stats_mask);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_cap = {
+	.f = cmd_show_port_tm_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_cap_show,
+		(void *)&cmd_show_port_tm_cap_port,
+		(void *)&cmd_show_port_tm_cap_tm,
+		(void *)&cmd_show_port_tm_cap_cap,
+		(void *)&cmd_show_port_tm_cap_port_id,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchical Level Capability *** */
+struct cmd_show_port_tm_level_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t level;
+	cmdline_fixed_string_t cap;
+	uint8_t port_id;
+	uint32_t level_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_level =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		level, "level");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_level_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		 port_id, UINT8);
+cmdline_parse_token_num_t cmd_show_port_tm_level_cap_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		 level_id, UINT32);
+
+
+static void cmd_show_port_tm_level_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_level_cap_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_level_capabilities lcap;
+	struct rte_tm_error error;
+	uint8_t port_id = res->port_id;
+	int ret, level_id = res->level_id;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	if ((level_id > 4) || (level_id < 0)) {
+		printf("  TM hierarchical level invalid !! ");
+		return;
+	}
+
+	memset(&lcap, 0, sizeof(struct rte_tm_level_capabilities));
+	ret = rte_tm_level_capabilities_get(port_id, level_id, &lcap, &error);
+	if (ret) {
+		print_err_msg(&error);
+		return;
+	}
+	printf("\n****   Port TM Hierarchy level %u Capability ****\n\n",
+		level_id);
+
+	printf("cap.n_nodes_max %u\n", lcap.n_nodes_max);
+	printf("cap.n_nodes_nonleaf_max %u\n", lcap.n_nodes_nonleaf_max);
+	printf("cap.n_nodes_leaf_max %u\n", lcap.n_nodes_leaf_max);
+	printf("cap.non_leaf_nodes_identical %d\n",
+		lcap.non_leaf_nodes_identical);
+	printf("cap.leaf_nodes_identical %d\n", lcap.leaf_nodes_identical);
+	if (level_id <= 3) {
+		printf("cap.nonleaf.shaper_private_supported %d\n",
+			lcap.nonleaf.shaper_private_supported);
+		printf("cap.nonleaf.shaper_private_dual_rate_supported %d\n",
+			lcap.nonleaf.shaper_private_dual_rate_supported);
+		printf("cap.nonleaf.shaper_private_rate_min %lu\n",
+			lcap.nonleaf.shaper_private_rate_min);
+		printf("cap.nonleaf.shaper_private_rate_max %lu\n",
+			lcap.nonleaf.shaper_private_rate_max);
+		printf("cap.nonleaf.shaper_shared_n_max %u\n",
+			lcap.nonleaf.shaper_shared_n_max);
+		printf("cap.nonleaf.sched_n_children_max %u\n",
+			lcap.nonleaf.sched_n_children_max);
+		printf("cap.nonleaf.sched_sp_n_priorities_max %u\n",
+			lcap.nonleaf.sched_sp_n_priorities_max);
+		printf("cap.nonleaf.sched_wfq_n_children_per_group_max %u\n",
+			lcap.nonleaf.sched_wfq_n_children_per_group_max);
+		printf("cap.nonleaf.sched_wfq_n_groups_max %u\n",
+			lcap.nonleaf.sched_wfq_n_groups_max);
+		printf("cap.nonleaf.sched_wfq_weight_max %u\n",
+			lcap.nonleaf.sched_wfq_weight_max);
+		printf("cap.nonleaf.stats_mask %lu\n", lcap.nonleaf.stats_mask);
+	} else {
+		printf("cap.leaf.shaper_private_supported %d\n",
+			lcap.leaf.shaper_private_supported);
+		printf("cap.leaf.shaper_private_dual_rate_supported %d\n",
+			lcap.leaf.shaper_private_dual_rate_supported);
+		printf("cap.leaf.shaper_private_rate_min %lu\n",
+			lcap.leaf.shaper_private_rate_min);
+		printf("cap.leaf.shaper_private_rate_max %lu\n",
+			lcap.leaf.shaper_private_rate_max);
+		printf("cap.leaf.shaper_shared_n_max %u\n",
+			lcap.leaf.shaper_shared_n_max);
+		printf("cap.leaf.cman_head_drop_supported %d\n",
+			lcap.leaf.cman_head_drop_supported);
+		printf("cap.leaf.cman_wred_context_private_supported %d\n",
+			lcap.leaf.cman_wred_context_private_supported);
+		printf("cap.leaf.cman_wred_context_shared_n_max %u\n",
+			lcap.leaf.cman_wred_context_shared_n_max);
+		printf("cap.leaf.stats_mask %lu\n",
+			lcap.leaf.stats_mask);
+	}
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_level_cap = {
+	.f = cmd_show_port_tm_level_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Hierarhical level Capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_level_cap_show,
+		(void *)&cmd_show_port_tm_level_cap_port,
+		(void *)&cmd_show_port_tm_level_cap_tm,
+		(void *)&cmd_show_port_tm_level_cap_level,
+		(void *)&cmd_show_port_tm_level_cap_cap,
+		(void *)&cmd_show_port_tm_level_cap_port_id,
+		(void *)&cmd_show_port_tm_level_cap_level_id,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchy Node Capability *** */
+struct cmd_show_port_tm_node_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t cap;
+	uint8_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_node =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_node_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		 port_id, UINT8);
+cmdline_parse_token_num_t cmd_show_port_tm_node_cap_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		 node_id, UINT32);
+
+static void cmd_show_port_tm_node_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_cap_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_node_capabilities ncap;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint8_t port_id = res->port_id;
+	int ret, is_leaf = 0;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Node id must be valid */
+	ret = rte_tm_node_type_get(port_id, node_id, &is_leaf, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	memset(&ncap, 0, sizeof(struct rte_tm_node_capabilities));
+	ret = rte_tm_node_capabilities_get(port_id, node_id, &ncap, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+	printf("\n****   Port TM Hierarchy node %u Capability ****\n\n",
+		node_id);
+	printf("cap.shaper_private_supported %d\n",
+		ncap.shaper_private_supported);
+	printf("cap.shaper_private_dual_rate_supported %d\n",
+		ncap.shaper_private_dual_rate_supported);
+	printf("cap.shaper_private_rate_min %lu\n",
+		ncap.shaper_private_rate_min);
+	printf("cap.shaper_private_rate_max %lu\n",
+		ncap.shaper_private_rate_max);
+	printf("cap.shaper_shared_n_max %u\n",
+		ncap.shaper_shared_n_max);
+	if (!is_leaf) {
+		printf("cap.nonleaf.sched_n_children_max %u\n",
+			ncap.nonleaf.sched_n_children_max);
+		printf("cap.nonleaf.sched_sp_n_priorities_max %u\n",
+			ncap.nonleaf.sched_sp_n_priorities_max);
+		printf("cap.nonleaf.sched_wfq_n_children_per_group_max %u\n",
+			ncap.nonleaf.sched_wfq_n_children_per_group_max);
+		printf("cap.nonleaf.sched_wfq_n_groups_max %u\n",
+			ncap.nonleaf.sched_wfq_n_groups_max);
+		printf("cap.nonleaf.sched_wfq_weight_max %u\n",
+			ncap.nonleaf.sched_wfq_weight_max);
+	} else {
+		printf("cap.leaf.cman_head_drop_supported %d\n",
+			ncap.leaf.cman_head_drop_supported);
+		printf("cap.leaf.cman_wred_context_private_supported %d\n",
+			ncap.leaf.cman_wred_context_private_supported);
+		printf("cap.leaf.cman_wred_context_shared_n_max %u\n",
+			ncap.leaf.cman_wred_context_shared_n_max);
+	}
+	printf("cap.stats_mask %lu\n", ncap.stats_mask);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_cap = {
+	.f = cmd_show_port_tm_node_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Hierarchy node capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_cap_show,
+		(void *)&cmd_show_port_tm_node_cap_port,
+		(void *)&cmd_show_port_tm_node_cap_tm,
+		(void *)&cmd_show_port_tm_node_cap_node,
+		(void *)&cmd_show_port_tm_node_cap_cap,
+		(void *)&cmd_show_port_tm_node_cap_port_id,
+		(void *)&cmd_show_port_tm_node_cap_node_id,
+		NULL,
+	},
+};
+
+/* *** Show Port TM Node Statistics *** */
+struct cmd_show_port_tm_node_stats_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t stats;
+	uint8_t port_id;
+	uint32_t node_id;
+	uint32_t clear;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_show =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_stats =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, stats, "stats");
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_stats_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result,
+			node_id, UINT32);
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_clear =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, clear, UINT32);
+
+static void cmd_show_port_tm_node_stats_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_stats_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_node_stats stats;
+	struct rte_tm_error error;
+	uint64_t stats_mask = 0, leaf_stats_mask;
+	uint32_t node_id = res->node_id;
+	uint32_t clear = res->clear;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	/* TM hierarchy status */
+	if (port->softport.tm.hierarchy_frozen == 0) {
+		printf(" hierarchy not frozen(error)\n");
+		return;
+	}
+
+	/* Port status */
+	if (!port_is_started(port_id)) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	memset(&stats, 0, sizeof(struct rte_tm_node_stats));
+	ret = rte_tm_node_stats_read(port_id, node_id, &stats,
+			&stats_mask, clear, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	leaf_stats_mask = RTE_TM_STATS_N_PKTS |
+		RTE_TM_STATS_N_BYTES |
+		RTE_TM_STATS_N_PKTS_GREEN_DROPPED |
+		RTE_TM_STATS_N_BYTES_GREEN_DROPPED |
+		RTE_TM_STATS_N_PKTS_QUEUED;
+
+	printf("pkts scheduled from node %lu\n", stats.n_pkts);
+	printf("bytes scheduled from node %lu\n", stats.n_bytes);
+	printf("pkts dropped %lu\n ", stats.leaf.n_pkts_dropped[RTE_TM_GREEN]);
+	printf("bytes dropped %lu\n ",
+		stats.leaf.n_bytes_dropped[RTE_TM_GREEN]);
+
+	if (stats_mask == leaf_stats_mask)
+		printf("packets enqueued %lu\n", stats.leaf.n_pkts_queued);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_stats = {
+	.f = cmd_show_port_tm_node_stats_parsed,
+	.data = NULL,
+	.help_str = "Show port tm node stats",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_stats_show,
+		(void *)&cmd_show_port_tm_node_stats_port,
+		(void *)&cmd_show_port_tm_node_stats_tm,
+		(void *)&cmd_show_port_tm_node_stats_node,
+		(void *)&cmd_show_port_tm_node_stats_stats,
+		(void *)&cmd_show_port_tm_node_stats_port_id,
+		(void *)&cmd_show_port_tm_node_stats_node_id,
+		(void *)&cmd_show_port_tm_node_stats_clear,
+		NULL,
+	},
+};
+
+/* *** Show Port TM Node Type *** */
+struct cmd_show_port_tm_node_type_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t type;
+	uint8_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_show =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, type, "type");
+cmdline_parse_token_num_t cmd_show_port_tm_node_type_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_show_port_tm_node_type_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result,
+			node_id, UINT32);
+
+static void cmd_show_port_tm_node_type_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_type_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint8_t port_id = res->port_id;
+	int ret, is_leaf = 0;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	ret = rte_tm_node_type_get(port_id, node_id, &is_leaf, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	if (is_leaf == 1)
+		printf("leaf node\n");
+	else
+		printf("nonleaf node\n");
+
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_type = {
+	.f = cmd_show_port_tm_node_type_parsed,
+	.data = NULL,
+	.help_str = "Show port tm node type",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_type_show,
+		(void *)&cmd_show_port_tm_node_type_port,
+		(void *)&cmd_show_port_tm_node_type_tm,
+		(void *)&cmd_show_port_tm_node_type_node,
+		(void *)&cmd_show_port_tm_node_type_type,
+		(void *)&cmd_show_port_tm_node_type_port_id,
+		(void *)&cmd_show_port_tm_node_type_node_id,
+		NULL,
+	},
+};
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v3 3/5] app/test-pmd: add CLI for shaper and wred profiles
  2017-09-20  9:56   ` [PATCH v3 1/5] " Jasvinder Singh
  2017-09-20  9:56     ` [PATCH v3 2/5] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
@ 2017-09-20  9:56     ` Jasvinder Singh
  2017-09-20  9:56     ` [PATCH v3 4/5] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
                       ` (2 subsequent siblings)
  4 siblings, 0 replies; 49+ messages in thread
From: Jasvinder Singh @ 2017-09-20  9:56 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu, pablo.de.lara.guarch

Add following CLIs in testpmd application;
- commands to add/del shaper profile for TM hieraqrchy nodes.
- commands to add/update shared shapers
- commands to add/del WRED profiles for TM hiearchy leaf nodes.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 app/test-pmd/cmdline.c    |  41 +++
 app/test-pmd/cmdline_tm.c | 866 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 907 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 6012c3a..c41974b 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -653,7 +653,34 @@ static void cmd_help_long_parsed(void *parsed_result,
 
 			"ptype mapping update (port_id) (hw_ptype) (sw_ptype)\n"
 			"    Update a ptype mapping item on a port\n\n"
+#ifdef TM_MODE
+			"add port tm node shaper profile (port_id) (shaper_profile_id)"
+			" (tb_rate) (tb_size)\n"
+			"	Add port tm node private shaper profile.\n\n"
+
+			"del port tm node shaper profile (port_id) (shaper_profile_id)\n"
+			"	Delete port tm node private shaper profile.\n\n"
+
+			"add port tm node shared shaper (port_id) (shared_shaper_id)"
+			" (shaper_profile_id)\n"
+			"	Add/update port tm node shared shaper.\n\n"
+
+			"del port tm node shared shaper (port_id) (shared_shaper_id)\n"
+			"	Delete port tm node shared shaper.\n\n"
 
+			"set port tm node shaper profile (port_id) (node_id)"
+			" (shaper_profile_id)\n"
+			"	Set port tm node shaper profile.\n\n"
+
+			"add port tm node wred profile (port_id) (wred_profile_id)"
+			" (color_g) (min_th_g) (max_th_g) (maxp_inv_g) (wq_log2_g)"
+			" (color_y) (min_th_y) (max_th_y) (maxp_inv_y) (wq_log2_y)"
+			" (color_r) (min_th_r) (max_th_r) (maxp_inv_r) (wq_log2_r)\n"
+			"	Add port tm node wred profile.\n\n"
+
+			"del port tm node wred profile (port_id) (wred_profile_id)\n"
+			"	Delete port tm node wred profile.\n\n"
+#endif
 			, list_pkt_forwarding_modes()
 		);
 	}
@@ -14212,6 +14239,13 @@ extern cmdline_parse_inst_t cmd_show_port_tm_level_cap;
 extern cmdline_parse_inst_t cmd_show_port_tm_node_cap;
 extern cmdline_parse_inst_t cmd_show_port_tm_node_type;
 extern cmdline_parse_inst_t cmd_show_port_tm_node_stats;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_shared_shaper;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile;
+extern cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile;
 #endif
 
 /* *********************************************************************** */
@@ -14411,6 +14445,13 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_cap,
 	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_type,
 	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_stats,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_shared_shaper,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_shared_shaper,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_wred_profile,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_wred_profile,
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_shaper_profile,
 #endif
 	NULL,
 };
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
index a20942e..7d78549 100644
--- a/app/test-pmd/cmdline_tm.c
+++ b/app/test-pmd/cmdline_tm.c
@@ -737,3 +737,869 @@ cmdline_parse_inst_t cmd_show_port_tm_node_type = {
 		NULL,
 	},
 };
+
+/* *** Add Port TM Private Shaper Profile *** */
+struct cmd_add_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint8_t port_id;
+	uint32_t shaper_id;
+	uint64_t tb_rate;
+	uint64_t tb_size;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_tb_rate =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tb_rate, UINT64);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_tb_size =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tb_size, UINT64);
+
+static void cmd_add_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_shaper_params sp;
+	struct rte_tm_error error;
+	uint32_t shaper_id = res->shaper_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Private shaper profile params */
+	memset(&sp, 0, sizeof(struct rte_tm_shaper_params));
+	sp.peak.rate = res->tb_rate;
+	sp.peak.size = res->tb_size;
+	sp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+	ret = rte_tm_shaper_profile_add(port_id, shaper_id, &sp, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_shaper_profile = {
+	.f = cmd_add_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Add port tm node private shaper profile",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_shaper_profile_add,
+		(void *)&cmd_add_port_tm_node_shaper_profile_port,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_add_port_tm_node_shaper_profile_node,
+		(void *)&cmd_add_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_add_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_add_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_add_port_tm_node_shaper_profile_shaper_id,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tb_rate,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tb_size,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM Private Shaper Profile *** */
+struct cmd_del_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint8_t port_id;
+	uint32_t shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_del_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_del_port_tm_node_shaper_profile_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			shaper_id, UINT32);
+
+static void cmd_del_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_error error;
+	uint32_t shaper_id = res->shaper_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	ret = rte_tm_shaper_profile_delete(port_id, shaper_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_shaper_profile = {
+	.f = cmd_del_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node private shaper profile",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_shaper_profile_del,
+		(void *)&cmd_del_port_tm_node_shaper_profile_port,
+		(void *)&cmd_del_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_del_port_tm_node_shaper_profile_node,
+		(void *)&cmd_del_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_del_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_del_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_del_port_tm_node_shaper_profile_shaper_id,
+		NULL,
+	},
+};
+
+/* *** Add/Update Port TM shared Shaper *** */
+struct cmd_add_port_tm_node_shared_shaper_result {
+	cmdline_fixed_string_t cmd_type;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shared;
+	cmdline_fixed_string_t shaper;
+	uint8_t port_id;
+	uint32_t shared_shaper_id;
+	uint32_t shaper_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_cmd_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			cmd_type, "add#set");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_shared =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shared, "shared");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shaper, "shaper");
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shared_shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shaper_profile_id, UINT32);
+
+static void cmd_add_port_tm_node_shared_shaper_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_shared_shaper_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_error error;
+	uint32_t shared_shaper_id = res->shared_shaper_id;
+	uint32_t shaper_profile_id = res->shaper_profile_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Command type: add */
+	if (strcmp(res->cmd_type, "add") == 0) {
+		/* Port status */
+		if (port_is_started(port_id)) {
+			printf(" Port %u not stopped (error)\n", port_id);
+			return;
+		}
+
+		/* TM hierarchy status */
+		if (port->softport.tm.hierarchy_frozen == 1)
+			port->softport.tm.hierarchy_frozen = 0;
+	}
+
+	/* Command type: set (update) */
+	if (strcmp(res->cmd_type, "set") == 0) {
+		/* TM hierarchy status */
+		if (port->softport.tm.hierarchy_frozen == 0) {
+			printf(" hierarchy not frozen (error)\n");
+			return;
+		}
+
+		/* Port status */
+		if (!port_is_started(port_id)) {
+			printf(" Port %u not started (error)\n", port_id);
+			return;
+		}
+	}
+
+	ret = rte_tm_shared_shaper_add_update(port_id, shared_shaper_id,
+		shaper_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_shared_shaper = {
+	.f = cmd_add_port_tm_node_shared_shaper_parsed,
+	.data = NULL,
+	.help_str = "add/update port tm node shared shaper",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_shared_shaper_cmd_type,
+		(void *)&cmd_add_port_tm_node_shared_shaper_port,
+		(void *)&cmd_add_port_tm_node_shared_shaper_tm,
+		(void *)&cmd_add_port_tm_node_shared_shaper_node,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shared,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shaper,
+		(void *)&cmd_add_port_tm_node_shared_shaper_port_id,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shared_shaper_id,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shaper_profile_id,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM shared Shaper *** */
+struct cmd_del_port_tm_node_shared_shaper_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shared;
+	cmdline_fixed_string_t shaper;
+	uint8_t port_id;
+	uint32_t shared_shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_shared =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shared, "shared");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shaper, "shaper");
+cmdline_parse_token_num_t cmd_del_port_tm_node_shared_shaper_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_del_port_tm_node_shared_shaper_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shared_shaper_id, UINT32);
+
+static void cmd_del_port_tm_node_shared_shaper_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_shared_shaper_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_error error;
+	uint32_t shared_shaper_id = res->shared_shaper_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	ret = rte_tm_shared_shaper_delete(port_id, shared_shaper_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper = {
+	.f = cmd_del_port_tm_node_shared_shaper_parsed,
+	.data = NULL,
+	.help_str = "delete port tm node shared shaper",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_shared_shaper_del,
+		(void *)&cmd_del_port_tm_node_shared_shaper_port,
+		(void *)&cmd_del_port_tm_node_shared_shaper_tm,
+		(void *)&cmd_del_port_tm_node_shared_shaper_node,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shared,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shaper,
+		(void *)&cmd_del_port_tm_node_shared_shaper_port_id,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shared_shaper_id,
+		NULL,
+	},
+};
+
+/* *** Add Port TM Node WRED Profile *** */
+struct cmd_add_port_tm_node_wred_profile_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t wred;
+	cmdline_fixed_string_t profile;
+	uint8_t port_id;
+	uint32_t wred_profile_id;
+	cmdline_fixed_string_t color_g;
+	uint16_t min_th_g;
+	uint16_t max_th_g;
+	uint16_t maxp_inv_g;
+	uint16_t wq_log2_g;
+	cmdline_fixed_string_t color_y;
+	uint16_t min_th_y;
+	uint16_t max_th_y;
+	uint16_t maxp_inv_y;
+	uint16_t wq_log2_y;
+	cmdline_fixed_string_t color_r;
+	uint16_t min_th_r;
+	uint16_t max_th_r;
+	uint16_t maxp_inv_r;
+	uint16_t wq_log2_r;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_wred =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, wred, "wred");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wred_profile_id, UINT32);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_g =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_g, "G#g");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_g, UINT16);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_y =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_y, "Y#y");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_y, UINT16);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_r =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_r, "R#r");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_r, UINT16);
+
+
+static void cmd_add_port_tm_node_wred_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_wred_profile_result *res = parsed_result;
+	struct rte_tm_wred_params wp;
+	enum rte_tm_color color;
+	struct rte_port *port;
+	struct rte_tm_error error;
+	uint32_t wred_profile_id = res->wred_profile_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	memset(&wp, 0, sizeof(struct rte_tm_wred_params));
+
+	/* WRED Params  (Green Color)*/
+	if ((strcmp(res->color_g, "G") == 0) ||
+		(strcmp(res->color_g, "g") == 0)) {
+		color = RTE_TM_GREEN;
+		wp.red_params[color].min_th = res->min_th_g;
+		wp.red_params[color].max_th = res->max_th_g;
+		wp.red_params[color].maxp_inv = res->maxp_inv_g;
+		wp.red_params[color].wq_log2 = res->wq_log2_g;
+	} else {
+		printf("WRED profile error(G or g for green color)!\n");
+		return;
+	}
+
+	/* WRED Params  (Yellow Color)*/
+	if ((strcmp(res->color_y, "Y") == 0) ||
+		(strcmp(res->color_y, "y") == 0)) {
+		color = RTE_TM_YELLOW;
+		wp.red_params[color].min_th = res->min_th_y;
+		wp.red_params[color].max_th = res->max_th_y;
+		wp.red_params[color].maxp_inv = res->maxp_inv_y;
+		wp.red_params[color].wq_log2 = res->wq_log2_y;
+	} else {
+		printf("WRED profile error(Y or y for yellow color)!\n");
+		return;
+	}
+
+	/* WRED Params  (Red Color)*/
+	if ((strcmp(res->color_r, "R") == 0) ||
+		(strcmp(res->color_r, "r") == 0)) {
+		color = RTE_TM_RED;
+		wp.red_params[color].min_th = res->min_th_r;
+		wp.red_params[color].max_th = res->max_th_r;
+		wp.red_params[color].maxp_inv = res->maxp_inv_r;
+		wp.red_params[color].wq_log2 = res->wq_log2_r;
+	} else {
+		printf("WRED profile error(R or r for red color)!\n");
+		return;
+	}
+
+	ret = rte_tm_wred_profile_add(port_id, wred_profile_id, &wp, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile = {
+	.f = cmd_add_port_tm_node_wred_profile_parsed,
+	.data = NULL,
+	.help_str = "Add port tm node wred profile",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_wred_profile_add,
+		(void *)&cmd_add_port_tm_node_wred_profile_port,
+		(void *)&cmd_add_port_tm_node_wred_profile_tm,
+		(void *)&cmd_add_port_tm_node_wred_profile_node,
+		(void *)&cmd_add_port_tm_node_wred_profile_wred,
+		(void *)&cmd_add_port_tm_node_wred_profile_profile,
+		(void *)&cmd_add_port_tm_node_wred_profile_port_id,
+		(void *)&cmd_add_port_tm_node_wred_profile_wred_profile_id,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_r,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM node WRED Profile *** */
+struct cmd_del_port_tm_node_wred_profile_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t wred;
+	cmdline_fixed_string_t profile;
+	uint8_t port_id;
+	uint32_t wred_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_wred =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, wred, "wred");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_del_port_tm_node_wred_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_del_port_tm_node_wred_profile_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			wred_profile_id, UINT32);
+
+static void cmd_del_port_tm_node_wred_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_wred_profile_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_error error;
+	uint32_t wred_profile_id = res->wred_profile_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	ret = rte_tm_wred_profile_delete(port_id, wred_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile = {
+	.f = cmd_del_port_tm_node_wred_profile_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node wred profile",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_wred_profile_del,
+		(void *)&cmd_del_port_tm_node_wred_profile_port,
+		(void *)&cmd_del_port_tm_node_wred_profile_tm,
+		(void *)&cmd_del_port_tm_node_wred_profile_node,
+		(void *)&cmd_del_port_tm_node_wred_profile_wred,
+		(void *)&cmd_del_port_tm_node_wred_profile_profile,
+		(void *)&cmd_del_port_tm_node_wred_profile_port_id,
+		(void *)&cmd_del_port_tm_node_wred_profile_wred_profile_id,
+		NULL,
+	},
+};
+
+/* *** Update Port TM Node Shaper profile *** */
+struct cmd_set_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint8_t port_id;
+	uint32_t node_id;
+	uint32_t shaper_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_set_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_set_port_tm_node_shaper_profile_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_shaper_profile_result,
+		node_id, UINT32);
+cmdline_parse_token_num_t
+	cmd_set_port_tm_node_shaper_shaper_profile_profile_id =
+		TOKEN_NUM_INITIALIZER(
+			struct cmd_set_port_tm_node_shaper_profile_result,
+			shaper_profile_id, UINT32);
+
+static void cmd_set_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint32_t shaper_profile_id = res->shaper_profile_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	/* TM hierarchy status */
+	if (port->softport.tm.hierarchy_frozen == 0) {
+		printf(" hierarchy not frozen(error)\n");
+		return;
+	}
+
+	/* Port status */
+	if (!port_is_started(port_id)) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_shaper_update(port_id, node_id,
+		shaper_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile = {
+	.f = cmd_set_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node shaper profile",
+	.tokens = {
+		(void *)&cmd_set_port_tm_node_shaper_profile_set,
+		(void *)&cmd_set_port_tm_node_shaper_profile_port,
+		(void *)&cmd_set_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_set_port_tm_node_shaper_profile_node,
+		(void *)&cmd_set_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_set_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_set_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_set_port_tm_node_shaper_profile_node_id,
+		(void *)&cmd_set_port_tm_node_shaper_shaper_profile_profile_id,
+		NULL,
+	},
+};
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v3 4/5] app/test-pmd: add CLI for TM nodes and hierarchy commit
  2017-09-20  9:56   ` [PATCH v3 1/5] " Jasvinder Singh
  2017-09-20  9:56     ` [PATCH v3 2/5] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
  2017-09-20  9:56     ` [PATCH v3 3/5] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
@ 2017-09-20  9:56     ` Jasvinder Singh
  2017-09-20  9:56     ` [PATCH v3 5/5] app/test-pmd: add CLI for TM packet classification Jasvinder Singh
  2017-09-22 16:35     ` [PATCH v4 1/5] app/testpmd: add traffic management forwarding mode Jasvinder Singh
  4 siblings, 0 replies; 49+ messages in thread
From: Jasvinder Singh @ 2017-09-20  9:56 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu, pablo.de.lara.guarch

Add following CLIs in testpmd application;
- commands to add TM hierarchy nodes (leaf and nonleaf).
- command for runtime update of node weight.
- command to commit the TM hierarchy

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 app/test-pmd/cmdline.c    |  36 +++
 app/test-pmd/cmdline_tm.c | 594 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 630 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index c41974b..70a376a 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -680,6 +680,28 @@ static void cmd_help_long_parsed(void *parsed_result,
 
 			"del port tm node wred profile (port_id) (wred_profile_id)\n"
 			"	Delete port tm node wred profile.\n\n"
+
+			"add port tm nonleaf node (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight) (level_id) (shaper_profile_id)"
+			" (shared_shaper_id) (n_shared_shapers) (n_sp_priorities)\n"
+			"	Add port tm nonleaf node.\n\n"
+
+			"add port tm leaf node (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight) (level_id) (cman_mode)"
+			" (wred_profile_id)\n"
+			"	Add port tm leaf node.\n\n"
+
+			"del port tm node (port_id) (node_id)\n"
+			"	Delete port tm node.\n\n"
+
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+			"set port tm node parent (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight)\n"
+			"	Set port tm node parent.\n\n"
+#endif
+			"port tm hierarchy commit (port_id) (clean_on_fail)\n"
+			"	Commit tm hierarchy.\n\n"
+
 #endif
 			, list_pkt_forwarding_modes()
 		);
@@ -14246,6 +14268,13 @@ extern cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper;
 extern cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile;
 extern cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile;
 extern cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_add_port_tm_nonleaf_node;
+extern cmdline_parse_inst_t cmd_add_port_tm_leaf_node;
+extern cmdline_parse_inst_t cmd_del_port_tm_node;
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+extern cmdline_parse_inst_t cmd_set_port_tm_node_parent;
+#endif
+extern cmdline_parse_inst_t cmd_port_tm_hierarchy_commit;
 #endif
 
 /* *********************************************************************** */
@@ -14452,6 +14481,13 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_wred_profile,
 	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_wred_profile,
 	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_nonleaf_node,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_leaf_node,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node,
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_parent,
+#endif
+	(cmdline_parse_inst_t *)&cmd_port_tm_hierarchy_commit,
 #endif
 	NULL,
 };
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
index 7d78549..b36326d 100644
--- a/app/test-pmd/cmdline_tm.c
+++ b/app/test-pmd/cmdline_tm.c
@@ -1603,3 +1603,597 @@ cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile = {
 		NULL,
 	},
 };
+
+/* *** Add Port TM nonleaf node *** */
+struct cmd_add_port_tm_nonleaf_node_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t nonleaf;
+	cmdline_fixed_string_t node;
+	uint8_t port_id;
+	uint32_t node_id;
+	int32_t parent_node_id;
+	uint32_t priority;
+	uint32_t weight;
+	uint32_t level_id;
+	uint32_t shaper_profile_id;
+	uint32_t shared_shaper_id;
+	uint32_t n_shared_shapers;
+	uint32_t n_sp_priorities;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_nonleaf =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, nonleaf, "nonleaf");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, node, "node");
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result,
+		 port_id, UINT8);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 node_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 parent_node_id, INT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 priority, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 weight, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 level_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 shaper_profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 shared_shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_n_shared_shapers =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 n_shared_shapers, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_n_sp_priorities =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 n_sp_priorities, UINT32);
+
+static void cmd_add_port_tm_nonleaf_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_nonleaf_node_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_error error;
+	struct rte_tm_node_params np;
+	uint32_t parent_node_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	/* TM hierarchy status */
+	if (port->softport.tm.hierarchy_frozen == 1)
+		port->softport.tm.hierarchy_frozen = 0;
+
+	/* Node parameters */
+	if (res->parent_node_id < 0)
+		parent_node_id = UINT32_MAX;
+	else
+		parent_node_id = res->parent_node_id;
+
+	memset(&np, 0, sizeof(struct rte_tm_node_params));
+	np.shaper_profile_id = res->shaper_profile_id;
+	np.n_shared_shapers = res->n_shared_shapers;
+	np.shared_shaper_id = &res->shared_shaper_id;
+	np.nonleaf.n_sp_priorities = res->n_sp_priorities;
+	np.nonleaf.wfq_weight_mode = NULL;
+	np.stats_mask = RTE_TM_STATS_N_PKTS |
+		RTE_TM_STATS_N_BYTES |
+		RTE_TM_STATS_N_PKTS_GREEN_DROPPED |
+		RTE_TM_STATS_N_BYTES_GREEN_DROPPED;
+
+	ret = rte_tm_node_add(port_id, res->node_id, parent_node_id,
+				res->priority, res->weight, res->level_id,
+				&np, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_nonleaf_node = {
+	.f = cmd_add_port_tm_nonleaf_node_parsed,
+	.data = NULL,
+	.help_str = "Add port tm nonleaf node",
+	.tokens = {
+		(void *)&cmd_add_port_tm_nonleaf_node_add,
+		(void *)&cmd_add_port_tm_nonleaf_node_port,
+		(void *)&cmd_add_port_tm_nonleaf_node_tm,
+		(void *)&cmd_add_port_tm_nonleaf_node_nonleaf,
+		(void *)&cmd_add_port_tm_nonleaf_node_node,
+		(void *)&cmd_add_port_tm_nonleaf_node_port_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_node_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_parent_node_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_priority,
+		(void *)&cmd_add_port_tm_nonleaf_node_weight,
+		(void *)&cmd_add_port_tm_nonleaf_node_level_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_shaper_profile_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_shared_shaper_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_n_shared_shapers,
+		(void *)&cmd_add_port_tm_nonleaf_node_n_sp_priorities,
+		NULL,
+	},
+};
+
+/* *** Add Port TM leaf node *** */
+struct cmd_add_port_tm_leaf_node_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t leaf;
+	cmdline_fixed_string_t node;
+	uint8_t port_id;
+	uint32_t node_id;
+	int32_t parent_node_id;
+	uint32_t priority;
+	uint32_t weight;
+	uint32_t level_id;
+	uint32_t cman_mode;
+	uint32_t wred_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_nonleaf =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, leaf, "leaf");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, node, "node");
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 port_id, UINT8);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 node_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 parent_node_id, INT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 priority, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 weight, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 level_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_cman_mode =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 cman_mode, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 wred_profile_id, UINT32);
+
+static void cmd_add_port_tm_leaf_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_leaf_node_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_error error;
+	struct rte_tm_node_params np;
+	uint32_t parent_node_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	/* TM hierarchy status */
+	if (port->softport.tm.hierarchy_frozen == 1)
+		port->softport.tm.hierarchy_frozen = 0;
+
+	/* Node parameters */
+	if (res->parent_node_id < 0)
+		parent_node_id = UINT32_MAX;
+	else
+		parent_node_id = res->parent_node_id;
+
+	memset(&np, 0, sizeof(struct rte_tm_node_params));
+	np.shaper_profile_id = RTE_TM_SHAPER_PROFILE_ID_NONE;
+	np.n_shared_shapers = 0;
+	np.leaf.cman = res->cman_mode;
+	np.leaf.wred.wred_profile_id = res->wred_profile_id;
+	np.stats_mask = RTE_TM_STATS_N_PKTS |
+		RTE_TM_STATS_N_BYTES |
+		RTE_TM_STATS_N_PKTS_GREEN_DROPPED |
+		RTE_TM_STATS_N_BYTES_GREEN_DROPPED |
+		RTE_TM_STATS_N_PKTS_QUEUED;
+
+	ret = rte_tm_node_add(port_id, res->node_id, parent_node_id,
+				res->priority, res->weight, res->level_id,
+				&np, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_leaf_node = {
+	.f = cmd_add_port_tm_leaf_node_parsed,
+	.data = NULL,
+	.help_str = "Add port tm leaf node",
+	.tokens = {
+		(void *)&cmd_add_port_tm_leaf_node_add,
+		(void *)&cmd_add_port_tm_leaf_node_port,
+		(void *)&cmd_add_port_tm_leaf_node_tm,
+		(void *)&cmd_add_port_tm_leaf_node_nonleaf,
+		(void *)&cmd_add_port_tm_leaf_node_node,
+		(void *)&cmd_add_port_tm_leaf_node_port_id,
+		(void *)&cmd_add_port_tm_leaf_node_node_id,
+		(void *)&cmd_add_port_tm_leaf_node_parent_node_id,
+		(void *)&cmd_add_port_tm_leaf_node_priority,
+		(void *)&cmd_add_port_tm_leaf_node_weight,
+		(void *)&cmd_add_port_tm_leaf_node_level_id,
+		(void *)&cmd_add_port_tm_leaf_node_cman_mode,
+		(void *)&cmd_add_port_tm_leaf_node_wred_profile_id,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM Node *** */
+struct cmd_del_port_tm_node_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	uint8_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, node, "node");
+cmdline_parse_token_num_t cmd_del_port_tm_node_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_del_port_tm_node_result,
+		 port_id, UINT8);
+cmdline_parse_token_num_t cmd_del_port_tm_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_del_port_tm_node_result,
+		node_id, UINT32);
+
+static void cmd_del_port_tm_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	/* TM hierarchy status */
+	if (port->softport.tm.hierarchy_frozen == 1)
+		port->softport.tm.hierarchy_frozen = 0;
+
+	ret = rte_tm_node_delete(port_id, node_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node = {
+	.f = cmd_del_port_tm_node_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_del,
+		(void *)&cmd_del_port_tm_node_port,
+		(void *)&cmd_del_port_tm_node_tm,
+		(void *)&cmd_del_port_tm_node_node,
+		(void *)&cmd_del_port_tm_node_port_id,
+		(void *)&cmd_del_port_tm_node_node_id,
+		NULL,
+	},
+};
+
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+/* *** Update Port TM Node Parent *** */
+struct cmd_set_port_tm_node_parent_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t parent;
+	uint8_t port_id;
+	uint32_t node_id;
+	uint32_t parent_id;
+	uint32_t priority;
+	uint32_t weight;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, node, "node");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_parent =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, parent, "parent");
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, port_id, UINT8);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, node_id, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_parent_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		parent_id, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		priority, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		weight, UINT32);
+
+static void cmd_set_port_tm_node_parent_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_node_parent_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint32_t parent_id = res->parent_id;
+	uint32_t priority = res->priority;
+	uint32_t weight = res->weight;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	/* TM hierarchy status */
+	if (port->softport.tm.hierarchy_frozen == 0) {
+		printf(" hierarchy not frozen(error)\n");
+		return;
+	}
+
+	/* Port status */
+	if (!port_is_started(port_id)) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_parent_update(port_id, node_id,
+		parent_id, priority, weight, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_node_parent = {
+	.f = cmd_set_port_tm_node_parent_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node parent",
+	.tokens = {
+		(void *)&cmd_set_port_tm_node_parent_set,
+		(void *)&cmd_set_port_tm_node_parent_port,
+		(void *)&cmd_set_port_tm_node_parent_tm,
+		(void *)&cmd_set_port_tm_node_parent_node,
+		(void *)&cmd_set_port_tm_node_parent_parent,
+		(void *)&cmd_set_port_tm_node_parent_port_id,
+		(void *)&cmd_set_port_tm_node_parent_node_id,
+		(void *)&cmd_set_port_tm_node_parent_parent_id,
+		(void *)&cmd_set_port_tm_node_parent_priority,
+		(void *)&cmd_set_port_tm_node_parent_weight,
+		NULL,
+	},
+};
+#endif
+
+/* *** Port TM Hierarchy Commit *** */
+struct cmd_port_tm_hierarchy_commit_result {
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t hierarchy;
+	cmdline_fixed_string_t commit;
+	uint8_t port_id;
+	uint32_t clean_on_fail;
+};
+
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, port, "port");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, tm, "tm");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_hierarchy =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result,
+			hierarchy, "hierarchy");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_commit =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, commit, "commit");
+cmdline_parse_token_num_t cmd_port_tm_hierarchy_commit_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_port_tm_hierarchy_commit_clean_on_fail =
+	TOKEN_NUM_INITIALIZER(struct cmd_port_tm_hierarchy_commit_result,
+		 clean_on_fail, UINT32);
+
+static void cmd_port_tm_hierarchy_commit_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_port_tm_hierarchy_commit_result *res = parsed_result;
+	struct rte_port *port;
+	struct rte_tm_error error;
+	uint32_t clean_on_fail = res->clean_on_fail;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	port = &ports[port_id];
+
+	/* Port tm flag */
+	if (port->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_hierarchy_commit(port_id, clean_on_fail, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+	/* Set TM hierarchy commit flag */
+	port->softport.tm.hierarchy_frozen = 1;
+}
+
+cmdline_parse_inst_t cmd_port_tm_hierarchy_commit = {
+	.f = cmd_port_tm_hierarchy_commit_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node shaper profile",
+	.tokens = {
+		(void *)&cmd_port_tm_hierarchy_commit_port,
+		(void *)&cmd_port_tm_hierarchy_commit_tm,
+		(void *)&cmd_port_tm_hierarchy_commit_hierarchy,
+		(void *)&cmd_port_tm_hierarchy_commit_commit,
+		(void *)&cmd_port_tm_hierarchy_commit_port_id,
+		(void *)&cmd_port_tm_hierarchy_commit_clean_on_fail,
+		NULL,
+	},
+};
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v3 5/5] app/test-pmd: add CLI for TM packet classification
  2017-09-20  9:56   ` [PATCH v3 1/5] " Jasvinder Singh
                       ` (2 preceding siblings ...)
  2017-09-20  9:56     ` [PATCH v3 4/5] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
@ 2017-09-20  9:56     ` Jasvinder Singh
  2017-09-22 16:35     ` [PATCH v4 1/5] app/testpmd: add traffic management forwarding mode Jasvinder Singh
  4 siblings, 0 replies; 49+ messages in thread
From: Jasvinder Singh @ 2017-09-20  9:56 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu, pablo.de.lara.guarch

Add following CLIs in testpmd application;
- command to set the packet field mask and offset value for
  classification.
- command to set traffic class translation table entry

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 app/test-pmd/cmdline.c    |  11 ++
 app/test-pmd/cmdline_tm.c | 305 ++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 316 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 70a376a..480fe4b 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -702,6 +702,13 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"port tm hierarchy commit (port_id) (clean_on_fail)\n"
 			"	Commit tm hierarchy.\n\n"
 
+			"set port tm pktfield (subport|pipe|tc) (port_id) offset"
+			" (offset) mask (mask)\n"
+			"	Set port tm packet field.\n\n"
+
+			"set port tm tc table (port_id) index (tb_index) tc (tc_id)"
+			" queue (queue id)\n"
+			"	Set port tm traffic class table entry.\n\n"
 #endif
 			, list_pkt_forwarding_modes()
 		);
@@ -14275,6 +14282,8 @@ extern cmdline_parse_inst_t cmd_del_port_tm_node;
 extern cmdline_parse_inst_t cmd_set_port_tm_node_parent;
 #endif
 extern cmdline_parse_inst_t cmd_port_tm_hierarchy_commit;
+extern cmdline_parse_inst_t cmd_set_port_tm_pktfield;
+extern cmdline_parse_inst_t cmd_set_port_tm_tc_table;
 #endif
 
 /* *********************************************************************** */
@@ -14488,6 +14497,8 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_parent,
 #endif
 	(cmdline_parse_inst_t *)&cmd_port_tm_hierarchy_commit,
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_pktfield,
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_tc_table,
 #endif
 	NULL,
 };
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
index b36326d..829442f 100644
--- a/app/test-pmd/cmdline_tm.c
+++ b/app/test-pmd/cmdline_tm.c
@@ -2197,3 +2197,308 @@ cmdline_parse_inst_t cmd_port_tm_hierarchy_commit = {
 		NULL,
 	},
 };
+
+static int
+port_tm_pktfield_validate_mask(uint64_t mask, uint64_t n)
+{
+	int count = __builtin_popcountll(mask);
+	int pos_lead = sizeof(uint64_t) * 8 - __builtin_clzll(mask);
+	int pos_trail = __builtin_ctzll(mask);
+	int count_expected = __builtin_popcount(n - 1);
+
+	/* Handle the exceptions */
+	if (n == 0)
+		return -1;			/* Error */
+
+	if ((mask == 0) && (n == 1))
+		return 0;			/* OK */
+
+	if (((mask == 0) && (n != 1)) || ((mask != 0) && (n == 1)))
+		return -2;			/* Error */
+
+	/* Check that mask is contiguous */
+	if ((pos_lead - pos_trail) != count)
+		return -3;			/* Error */
+
+	/* Check that mask contains the expected number of bits set */
+	if (count != count_expected)
+		return -4;			/* Error */
+
+	return 0;			/* OK */
+	}
+
+/* *** Set Port TM Packet Fields *** */
+struct cmd_set_port_tm_pktfield_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t pktfield;
+	cmdline_fixed_string_t type;
+	uint8_t port_id;
+	cmdline_fixed_string_t offset_string;
+	uint32_t offset;
+	cmdline_fixed_string_t mask_string;
+	uint64_t mask;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result, port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,	tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_pktfield =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			pktfield, "pktfield");
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			type, "subport#pipe#tc");
+cmdline_parse_token_num_t cmd_set_port_tm_pktfield_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_offset_string =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			offset_string, "offset");
+cmdline_parse_token_num_t cmd_set_port_tm_pktfield_offset =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			offset, UINT32);
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_mask_string =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			mask_string, "mask");
+cmdline_parse_token_num_t cmd_set_port_tm_pktfield_mask =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			mask, UINT64);
+
+static void cmd_set_port_tm_pktfield_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_pktfield_result *res = parsed_result;
+	struct rte_port *p;
+	uint32_t offset = res->offset;
+	uint64_t mask = res->mask;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	p = &ports[port_id];
+
+	/* Port tm flag */
+	if (p->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Subport */
+	if (strcmp(res->type, "subport") == 0) {
+		uint32_t n = p->softport.tm.n_subports_per_port;
+
+		ret = port_tm_pktfield_validate_mask(mask, n);
+		if (ret) {
+			printf(" invalid subport mask(error %d)", ret);
+			return;
+		}
+		/* Set packet field */
+		p->softport.tm.tm_pktfield0_slabpos = offset;
+		p->softport.tm.tm_pktfield0_slabmask = mask;
+		p->softport.tm.tm_pktfield0_slabshr = __builtin_ctzll(mask);
+		return;
+	}
+
+	/* Pipe */
+	if (strcmp(res->type, "pipe") == 0) {
+		uint32_t n = p->softport.tm.n_pipes_per_subport;
+
+		ret = port_tm_pktfield_validate_mask(mask, n);
+		if (ret) {
+			printf(" invalid pipe mask(error %d)", ret);
+			return;
+		}
+		/* Set packet field */
+		p->softport.tm.tm_pktfield1_slabpos = offset;
+		p->softport.tm.tm_pktfield1_slabmask = mask;
+		p->softport.tm.tm_pktfield1_slabshr = __builtin_ctzll(mask);
+		return;
+	}
+
+	/* Traffic class */
+	if (strcmp(res->type, "tc") == 0) {
+		uint32_t n = RTE_DIM(p->softport.tm.tm_tc_table);
+
+		ret = port_tm_pktfield_validate_mask(mask, n);
+		if (ret) {
+			printf(" invalid tc mask(error %d)", ret);
+			return;
+		}
+		/* Set packet field */
+		p->softport.tm.tm_pktfield1_slabpos = offset;
+		p->softport.tm.tm_pktfield1_slabmask = mask;
+		p->softport.tm.tm_pktfield1_slabshr = __builtin_ctzll(mask);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_pktfield = {
+	.f = cmd_set_port_tm_pktfield_parsed,
+	.data = NULL,
+	.help_str = "Set port tm pktfield",
+	.tokens = {
+		(void *)&cmd_set_port_tm_pktfield_set,
+		(void *)&cmd_set_port_tm_pktfield_port,
+		(void *)&cmd_set_port_tm_pktfield_tm,
+		(void *)&cmd_set_port_tm_pktfield_pktfield,
+		(void *)&cmd_set_port_tm_pktfield_type,
+		(void *)&cmd_set_port_tm_pktfield_port_id,
+		(void *)&cmd_set_port_tm_pktfield_offset_string,
+		(void *)&cmd_set_port_tm_pktfield_offset,
+		(void *)&cmd_set_port_tm_pktfield_mask_string,
+		(void *)&cmd_set_port_tm_pktfield_mask,
+		NULL,
+	},
+};
+
+/* *** Set Port TM Traffic Class Table Entry *** */
+struct cmd_set_port_tm_tc_table_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t tc_table;
+	uint8_t port_id;
+	cmdline_fixed_string_t index_string;
+	uint32_t index;
+	cmdline_fixed_string_t tc_string;
+	uint32_t tc;
+	cmdline_fixed_string_t queue_string;
+	uint32_t queue;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result, port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,	tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_tc_table =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			tc_table, "tc table");
+cmdline_parse_token_num_t cmd_set_port_tm_tc_table_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_index_string =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			index_string, "index");
+cmdline_parse_token_num_t cmd_set_port_tm_tc_table_index =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			index, UINT32);
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_tc_string =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			tc_string, "tc");
+cmdline_parse_token_num_t cmd_set_port_tm_tc_table_tc =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			tc, UINT32);
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_queue_string =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			queue_string, "queue");
+cmdline_parse_token_num_t cmd_set_port_tm_tc_table_queue =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			queue, UINT32);
+
+static void cmd_set_port_tm_tc_table_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_tc_table_result *res = parsed_result;
+	struct rte_port *p;
+	uint32_t tc = res->tc;
+	uint32_t index = res->index;
+	uint32_t queue = res->queue;
+	uint32_t val;
+	uint8_t port_id = res->port_id;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	p = &ports[port_id];
+
+	/* Port tm flag */
+	if (p->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Traffic class table index */
+	if (tc >= RTE_DIM(p->softport.tm.tm_tc_table)) {
+		printf("  invalid traffic class table index(error)\n");
+		return;
+	}
+
+	/* Traffic class id */
+	if (tc >= RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE) {
+		printf("  invalid traffic class id(error)\n");
+		return;
+	}
+
+	/* Traffic class queue */
+	if (queue >= RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS) {
+		printf("  invalid traffic class queue(error)\n");
+		return;
+	}
+
+	val = tc * RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS + queue;
+	p->softport.tm.tm_tc_table[index] = val;
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_tc_table = {
+	.f = cmd_set_port_tm_tc_table_parsed,
+	.data = NULL,
+	.help_str = "Set port tm TC table entry",
+	.tokens = {
+		(void *)&cmd_set_port_tm_tc_table_set,
+		(void *)&cmd_set_port_tm_tc_table_port,
+		(void *)&cmd_set_port_tm_tc_table_tm,
+		(void *)&cmd_set_port_tm_tc_table_tc_table,
+		(void *)&cmd_set_port_tm_tc_table_port_id,
+		(void *)&cmd_set_port_tm_tc_table_index_string,
+		(void *)&cmd_set_port_tm_tc_table_index,
+		(void *)&cmd_set_port_tm_tc_table_tc_string,
+		(void *)&cmd_set_port_tm_tc_table_tc,
+		(void *)&cmd_set_port_tm_tc_table_queue_string,
+		(void *)&cmd_set_port_tm_tc_table_queue,
+		NULL,
+	},
+};
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v4 1/5] app/testpmd: add traffic management forwarding mode
  2017-09-20  9:56   ` [PATCH v3 1/5] " Jasvinder Singh
                       ` (3 preceding siblings ...)
  2017-09-20  9:56     ` [PATCH v3 5/5] app/test-pmd: add CLI for TM packet classification Jasvinder Singh
@ 2017-09-22 16:35     ` Jasvinder Singh
  2017-09-22 16:35       ` [PATCH v4 2/5] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
                         ` (3 more replies)
  4 siblings, 4 replies; 49+ messages in thread
From: Jasvinder Singh @ 2017-09-22 16:35 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu, pablo.de.lara.guarch

This commit extends the testpmd application with new forwarding engine
that demonstrates the use of ethdev traffic management APIs and softnic
PMD for QoS traffic management.

In this mode, 5-level hierarchical tree of the QoS scheduler is built
with the help of ethdev TM APIs such as shaper profile add/delete,
shared shaper add/update, node add/delete, hierarchy commit, etc.
The hierarchical tree has following nodes; root node(x1, level 0),
subport node(x1, level 1), pipe node(x4096, level 2),
tc node(x16348, level 3), queue node(x65536, level 4).

During runtime, each received packet is first classified by mapping the
packet fields information to 5-tuples (HQoS subport, pipe, traffic class,
queue within traffic class, and color) and storing it in the packet mbuf
sched field. After classification, each packet is sent to softnic port
which prioritizes the transmission of the received packets, and
accordingly sends them on to the output interface.

To enable traffic management mode, following testpmd command is used;

$ ./testpmd -c c -n 4 --vdev
	'net_softnic0,hard_name=0000:06:00.1,soft_tm=on' -- -i
	--forward-mode=tm

This patchset has dependency on following patch series;
http://dpdk.org/ml/archives/dev/2017-September/075655.html
http://dpdk.org/ml/archives/dev/2017-September/075656.html
http://dpdk.org/ml/archives/dev/2017-September/075657.html
http://dpdk.org/ml/archives/dev/2017-September/075658.html


Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
v3 change:
- Implements feedback from Pablo[1]
  - add flag to check required librte_sched lib and softnic pmd
  - code cleanup

v2 change:
- change file name softnictm.c to tm.c
- change forward mode name to "tm"
- code clean up

[1] http://dpdk.org/ml/archives/dev/2017-September/075744.html

 app/test-pmd/Makefile  |   8 +
 app/test-pmd/testpmd.c |  15 +
 app/test-pmd/testpmd.h |  45 +++
 app/test-pmd/tm.c      | 863 +++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 931 insertions(+)
 create mode 100644 app/test-pmd/tm.c

diff --git a/app/test-pmd/Makefile b/app/test-pmd/Makefile
index c36be19..2c50f68 100644
--- a/app/test-pmd/Makefile
+++ b/app/test-pmd/Makefile
@@ -59,6 +59,10 @@ SRCS-y += csumonly.c
 SRCS-y += icmpecho.c
 SRCS-$(CONFIG_RTE_LIBRTE_IEEE1588) += ieee1588fwd.c
 
+ifeq ($(CONFIG_RTE_LIBRTE_PMD_SOFTNIC)$(CONFIG_RTE_LIBRTE_SCHED),yy)
+SRCS-y += tm.c
+endif
+
 ifeq ($(CONFIG_RTE_BUILD_SHARED_LIB),y)
 
 ifeq ($(CONFIG_RTE_LIBRTE_PMD_BOND),y)
@@ -81,6 +85,10 @@ ifeq ($(CONFIG_RTE_LIBRTE_PMD_XENVIRT),y)
 LDLIBS += -lrte_pmd_xenvirt
 endif
 
+ifeq ($(CONFIG_RTE_LIBRTE_PMD_SOFTNIC),y)
+LDLIBS += -lrte_pmd_softnic
+endif
+
 endif
 
 CFLAGS_cmdline.o := -D_GNU_SOURCE
diff --git a/app/test-pmd/testpmd.c b/app/test-pmd/testpmd.c
index e097ee0..d729267 100644
--- a/app/test-pmd/testpmd.c
+++ b/app/test-pmd/testpmd.c
@@ -167,6 +167,10 @@ struct fwd_engine * fwd_engines[] = {
 	&tx_only_engine,
 	&csum_fwd_engine,
 	&icmp_echo_engine,
+#if defined RTE_LIBRTE_PMD_SOFTNIC && defined RTE_LIBRTE_SCHED
+	&softnic_tm_engine,
+	&softnic_tm_bypass_engine,
+#endif
 #ifdef RTE_LIBRTE_IEEE1588
 	&ieee1588_fwd_engine,
 #endif
@@ -2085,6 +2089,17 @@ init_port_config(void)
 		    (rte_eth_devices[pid].data->dev_flags &
 		     RTE_ETH_DEV_INTR_RMV))
 			port->dev_conf.intr_conf.rmv = 1;
+
+#if defined RTE_LIBRTE_PMD_SOFTNIC && defined RTE_LIBRTE_SCHED
+		/* Detect softnic port */
+		if (!strcmp(port->dev_info.driver_name, "net_softnic")) {
+			port->softnic_enable = 1;
+			memset(&port->softport, 0, sizeof(struct softnic_port));
+
+			if (!strcmp(cur_fwd_eng->fwd_mode_name, "tm"))
+				port->softport.tm_flag = 1;
+		}
+#endif
 	}
 }
 
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index 1d1ee75..d8cb679 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -84,6 +84,12 @@ typedef uint16_t streamid_t;
 
 #define MAX_QUEUE_ID ((1 << (sizeof(queueid_t) * 8)) - 1)
 
+#if defined RTE_LIBRTE_PMD_SOFTNIC && defined RTE_LIBRTE_SCHED
+#define TM_MODE			1
+#else
+#define TM_MODE			0
+#endif
+
 enum {
 	PORT_TOPOLOGY_PAIRED,
 	PORT_TOPOLOGY_CHAINED,
@@ -162,6 +168,37 @@ struct port_flow {
 	uint8_t data[]; /**< Storage for pattern/actions. */
 };
 
+#ifdef TM_MODE
+/**
+ * Soft port tm related parameters
+ */
+struct softnic_port_tm {
+	uint32_t hierarchy_config;  /**< flag for tm hierarchy config */
+
+	uint32_t n_subports_per_port;  /**< Num of subport nodes per port */
+	uint32_t n_pipes_per_subport;  /**< Num of pipe nodes per subport */
+
+	uint64_t tm_pktfield0_slabpos;	/**< Pkt field position for subport */
+	uint64_t tm_pktfield0_slabmask; /**< Pkt field mask for the subport */
+	uint64_t tm_pktfield0_slabshr;
+	uint64_t tm_pktfield1_slabpos; /**< Pkt field position for the pipe */
+	uint64_t tm_pktfield1_slabmask; /**< Pkt field mask for the pipe */
+	uint64_t tm_pktfield1_slabshr;
+	uint64_t tm_pktfield2_slabpos; /**< Pkt field position table index */
+	uint64_t tm_pktfield2_slabmask;	/**< Pkt field mask for tc table idx */
+	uint64_t tm_pktfield2_slabshr;
+	uint64_t tm_tc_table[64];  /**< TC translation table */
+};
+
+/**
+ * The data structure associate with softnic port
+ */
+struct softnic_port {
+	unsigned int tm_flag;	/**< set to 1 if tm feature is enabled */
+	struct softnic_port_tm tm;	/**< softnic port tm parameters */
+};
+#endif
+
 /**
  * The data structure associated with each port.
  */
@@ -195,6 +232,10 @@ struct rte_port {
 	uint32_t                mc_addr_nb; /**< nb. of addr. in mc_addr_pool */
 	uint8_t                 slave_flag; /**< bonding slave port */
 	struct port_flow        *flow_list; /**< Associated flows. */
+#ifdef TM_MODE
+	unsigned int			softnic_enable;	/**< set to 1 softnic detected */
+	struct softnic_port     softport;  /**< softnic port params */
+#endif
 };
 
 /**
@@ -253,6 +294,10 @@ extern struct fwd_engine rx_only_engine;
 extern struct fwd_engine tx_only_engine;
 extern struct fwd_engine csum_fwd_engine;
 extern struct fwd_engine icmp_echo_engine;
+#ifdef TM_MODE
+extern struct fwd_engine softnic_tm_engine;
+extern struct fwd_engine softnic_tm_bypass_engine;
+#endif
 #ifdef RTE_LIBRTE_IEEE1588
 extern struct fwd_engine ieee1588_fwd_engine;
 #endif
diff --git a/app/test-pmd/tm.c b/app/test-pmd/tm.c
new file mode 100644
index 0000000..a079f93
--- /dev/null
+++ b/app/test-pmd/tm.c
@@ -0,0 +1,863 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <stdio.h>
+#include <sys/stat.h>
+
+#include <rte_cycles.h>
+#include <rte_mbuf.h>
+#include <rte_ethdev.h>
+#include <rte_flow.h>
+#include <rte_meter.h>
+#include <rte_eth_softnic.h>
+#include <rte_tm.h>
+
+#include "testpmd.h"
+
+#define SUBPORT_NODES_PER_PORT		1
+#define PIPE_NODES_PER_SUBPORT		4096
+#define TC_NODES_PER_PIPE			4
+#define QUEUE_NODES_PER_TC			4
+
+#define NUM_PIPE_NODES						\
+	(SUBPORT_NODES_PER_PORT * PIPE_NODES_PER_SUBPORT)
+
+#define NUM_TC_NODES						\
+	(NUM_PIPE_NODES * TC_NODES_PER_PIPE)
+
+#define ROOT_NODE_ID				1000000
+#define SUBPORT_NODES_START_ID		900000
+#define PIPE_NODES_START_ID			800000
+#define TC_NODES_START_ID			700000
+
+#define STATS_MASK_DEFAULT					\
+	(RTE_TM_STATS_N_PKTS |					\
+	RTE_TM_STATS_N_BYTES |					\
+	RTE_TM_STATS_N_PKTS_GREEN_DROPPED |			\
+	RTE_TM_STATS_N_BYTES_GREEN_DROPPED)
+
+#define STATS_MASK_QUEUE					\
+	(STATS_MASK_DEFAULT |					\
+	RTE_TM_STATS_N_PKTS_QUEUED)
+
+#define BYTES_IN_MBPS				(1000 * 1000 / 8)
+#define TOKEN_BUCKET_SIZE			1000000
+
+/* TM Hierarchy Levels */
+enum tm_hierarchy_level {
+	TM_NODE_LEVEL_PORT = 0,
+	TM_NODE_LEVEL_SUBPORT,
+	TM_NODE_LEVEL_PIPE,
+	TM_NODE_LEVEL_TC,
+	TM_NODE_LEVEL_QUEUE,
+	TM_NODE_LEVEL_MAX,
+};
+
+struct tm_hierarchy {
+	/* TM Nodes */
+	uint32_t root_node_id;
+	uint32_t subport_node_id[SUBPORT_NODES_PER_PORT];
+	uint32_t pipe_node_id[SUBPORT_NODES_PER_PORT][PIPE_NODES_PER_SUBPORT];
+	uint32_t tc_node_id[NUM_PIPE_NODES][TC_NODES_PER_PIPE];
+	uint32_t queue_node_id[NUM_TC_NODES][QUEUE_NODES_PER_TC];
+
+	/* TM Hierarchy Nodes Shaper Rates */
+	uint32_t root_node_shaper_rate;
+	uint32_t subport_node_shaper_rate;
+	uint32_t pipe_node_shaper_rate;
+	uint32_t tc_node_shaper_rate;
+	uint32_t tc_node_shared_shaper_rate;
+
+	uint32_t n_shapers;
+};
+
+#define BITFIELD(byte_array, slab_pos, slab_mask, slab_shr)	\
+({								\
+	uint64_t slab = *((uint64_t *) &byte_array[slab_pos]);	\
+	uint64_t val =				\
+		(rte_be_to_cpu_64(slab) & slab_mask) >> slab_shr;	\
+	val;						\
+})
+
+#define RTE_SCHED_PORT_HIERARCHY(subport, pipe,           \
+	traffic_class, queue, color)                          \
+	((((uint64_t) (queue)) & 0x3) |                       \
+	((((uint64_t) (traffic_class)) & 0x3) << 2) |         \
+	((((uint64_t) (color)) & 0x3) << 4) |                 \
+	((((uint64_t) (subport)) & 0xFFFF) << 16) |           \
+	((((uint64_t) (pipe)) & 0xFFFFFFFF) << 32))
+
+
+static void
+pkt_metadata_set(struct rte_port *p, struct rte_mbuf **pkts,
+	uint32_t n_pkts)
+{
+	struct softnic_port_tm *tm = &p->softport.tm;
+	uint32_t i;
+
+	for (i = 0; i < (n_pkts & (~0x3)); i += 4) {
+		struct rte_mbuf *pkt0 = pkts[i];
+		struct rte_mbuf *pkt1 = pkts[i + 1];
+		struct rte_mbuf *pkt2 = pkts[i + 2];
+		struct rte_mbuf *pkt3 = pkts[i + 3];
+
+		uint8_t *pkt0_data = rte_pktmbuf_mtod(pkt0, uint8_t *);
+		uint8_t *pkt1_data = rte_pktmbuf_mtod(pkt1, uint8_t *);
+		uint8_t *pkt2_data = rte_pktmbuf_mtod(pkt2, uint8_t *);
+		uint8_t *pkt3_data = rte_pktmbuf_mtod(pkt3, uint8_t *);
+
+		uint64_t pkt0_subport = BITFIELD(pkt0_data,
+					tm->tm_pktfield0_slabpos,
+					tm->tm_pktfield0_slabmask,
+					tm->tm_pktfield0_slabshr);
+		uint64_t pkt0_pipe = BITFIELD(pkt0_data,
+					tm->tm_pktfield1_slabpos,
+					tm->tm_pktfield1_slabmask,
+					tm->tm_pktfield1_slabshr);
+		uint64_t pkt0_dscp = BITFIELD(pkt0_data,
+					tm->tm_pktfield2_slabpos,
+					tm->tm_pktfield2_slabmask,
+					tm->tm_pktfield2_slabshr);
+		uint32_t pkt0_tc = tm->tm_tc_table[pkt0_dscp & 0x3F] >> 2;
+		uint32_t pkt0_tc_q = tm->tm_tc_table[pkt0_dscp & 0x3F] & 0x3;
+		uint64_t pkt1_subport = BITFIELD(pkt1_data,
+					tm->tm_pktfield0_slabpos,
+					tm->tm_pktfield0_slabmask,
+					tm->tm_pktfield0_slabshr);
+		uint64_t pkt1_pipe = BITFIELD(pkt1_data,
+					tm->tm_pktfield1_slabpos,
+					tm->tm_pktfield1_slabmask,
+					tm->tm_pktfield1_slabshr);
+		uint64_t pkt1_dscp = BITFIELD(pkt1_data,
+					tm->tm_pktfield2_slabpos,
+					tm->tm_pktfield2_slabmask,
+					tm->tm_pktfield2_slabshr);
+		uint32_t pkt1_tc = tm->tm_tc_table[pkt1_dscp & 0x3F] >> 2;
+		uint32_t pkt1_tc_q = tm->tm_tc_table[pkt1_dscp & 0x3F] & 0x3;
+
+		uint64_t pkt2_subport = BITFIELD(pkt2_data,
+					tm->tm_pktfield0_slabpos,
+					tm->tm_pktfield0_slabmask,
+					tm->tm_pktfield0_slabshr);
+		uint64_t pkt2_pipe = BITFIELD(pkt2_data,
+					tm->tm_pktfield1_slabpos,
+					tm->tm_pktfield1_slabmask,
+					tm->tm_pktfield1_slabshr);
+		uint64_t pkt2_dscp = BITFIELD(pkt2_data,
+					tm->tm_pktfield2_slabpos,
+					tm->tm_pktfield2_slabmask,
+					tm->tm_pktfield2_slabshr);
+		uint32_t pkt2_tc = tm->tm_tc_table[pkt2_dscp & 0x3F] >> 2;
+		uint32_t pkt2_tc_q = tm->tm_tc_table[pkt2_dscp & 0x3F] & 0x3;
+
+		uint64_t pkt3_subport = BITFIELD(pkt3_data,
+					tm->tm_pktfield0_slabpos,
+					tm->tm_pktfield0_slabmask,
+					tm->tm_pktfield0_slabshr);
+		uint64_t pkt3_pipe = BITFIELD(pkt3_data,
+					tm->tm_pktfield1_slabpos,
+					tm->tm_pktfield1_slabmask,
+					tm->tm_pktfield1_slabshr);
+		uint64_t pkt3_dscp = BITFIELD(pkt3_data,
+					tm->tm_pktfield2_slabpos,
+					tm->tm_pktfield2_slabmask,
+					tm->tm_pktfield2_slabshr);
+		uint32_t pkt3_tc = tm->tm_tc_table[pkt3_dscp & 0x3F] >> 2;
+		uint32_t pkt3_tc_q = tm->tm_tc_table[pkt3_dscp & 0x3F] & 0x3;
+
+		uint64_t pkt0_sched = RTE_SCHED_PORT_HIERARCHY(pkt0_subport,
+						pkt0_pipe,
+						pkt0_tc,
+						pkt0_tc_q,
+						0);
+		uint64_t pkt1_sched = RTE_SCHED_PORT_HIERARCHY(pkt1_subport,
+						pkt1_pipe,
+						pkt1_tc,
+						pkt1_tc_q,
+						0);
+		uint64_t pkt2_sched = RTE_SCHED_PORT_HIERARCHY(pkt2_subport,
+						pkt2_pipe,
+						pkt2_tc,
+						pkt2_tc_q,
+						0);
+		uint64_t pkt3_sched = RTE_SCHED_PORT_HIERARCHY(pkt3_subport,
+						pkt3_pipe,
+						pkt3_tc,
+						pkt3_tc_q,
+						0);
+
+		pkt0->hash.sched.lo = pkt0_sched & 0xFFFFFFFF;
+		pkt0->hash.sched.hi = pkt0_sched >> 32;
+		pkt1->hash.sched.lo = pkt1_sched & 0xFFFFFFFF;
+		pkt1->hash.sched.hi = pkt1_sched >> 32;
+		pkt2->hash.sched.lo = pkt2_sched & 0xFFFFFFFF;
+		pkt2->hash.sched.hi = pkt2_sched >> 32;
+		pkt3->hash.sched.lo = pkt3_sched & 0xFFFFFFFF;
+		pkt3->hash.sched.hi = pkt3_sched >> 32;
+	}
+
+	for (; i < n_pkts; i++)	{
+		struct rte_mbuf *pkt = pkts[i];
+
+		uint8_t *pkt_data = rte_pktmbuf_mtod(pkt, uint8_t *);
+
+		uint64_t pkt_subport = BITFIELD(pkt_data,
+					tm->tm_pktfield0_slabpos,
+					tm->tm_pktfield0_slabmask,
+					tm->tm_pktfield0_slabshr);
+		uint64_t pkt_pipe = BITFIELD(pkt_data,
+					tm->tm_pktfield1_slabpos,
+					tm->tm_pktfield1_slabmask,
+					tm->tm_pktfield1_slabshr);
+		uint64_t pkt_dscp = BITFIELD(pkt_data,
+					tm->tm_pktfield2_slabpos,
+					tm->tm_pktfield2_slabmask,
+					tm->tm_pktfield2_slabshr);
+		uint32_t pkt_tc = tm->tm_tc_table[pkt_dscp & 0x3F] >> 2;
+		uint32_t pkt_tc_q = tm->tm_tc_table[pkt_dscp & 0x3F] & 0x3;
+
+		uint64_t pkt_sched = RTE_SCHED_PORT_HIERARCHY(pkt_subport,
+						pkt_pipe,
+						pkt_tc,
+						pkt_tc_q,
+						0);
+
+		pkt->hash.sched.lo = pkt_sched & 0xFFFFFFFF;
+		pkt->hash.sched.hi = pkt_sched >> 32;
+	}
+}
+
+/*
+ * Soft port packet forward
+ */
+static void
+softport_packet_fwd(struct fwd_stream *fs)
+{
+	struct rte_mbuf *pkts_burst[MAX_PKT_BURST];
+	struct rte_port *rte_tx_port = &ports[fs->tx_port];
+	uint16_t nb_rx;
+	uint16_t nb_tx;
+	uint32_t retry;
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+	uint64_t start_tsc;
+	uint64_t end_tsc;
+	uint64_t core_cycles;
+#endif
+
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+	start_tsc = rte_rdtsc();
+#endif
+
+	/*  Packets Receive */
+	nb_rx = rte_eth_rx_burst(fs->rx_port, fs->rx_queue,
+			pkts_burst, nb_pkt_per_burst);
+	fs->rx_packets += nb_rx;
+
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+	fs->rx_burst_stats.pkt_burst_spread[nb_rx]++;
+#endif
+
+	if (rte_tx_port->softnic_enable) {
+		/* Set packet metadata if tm flag enabled */
+		if (rte_tx_port->softport.tm_flag)
+			pkt_metadata_set(rte_tx_port, pkts_burst, nb_rx);
+
+		/* Softport run */
+		rte_pmd_softnic_run(fs->tx_port);
+	}
+	nb_tx = rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
+			pkts_burst, nb_rx);
+
+	/* Retry if necessary */
+	if (unlikely(nb_tx < nb_rx) && fs->retry_enabled) {
+		retry = 0;
+		while (nb_tx < nb_rx && retry++ < burst_tx_retry_num) {
+			rte_delay_us(burst_tx_delay_time);
+			nb_tx += rte_eth_tx_burst(fs->tx_port, fs->tx_queue,
+					&pkts_burst[nb_tx], nb_rx - nb_tx);
+		}
+	}
+	fs->tx_packets += nb_tx;
+
+#ifdef RTE_TEST_PMD_RECORD_BURST_STATS
+	fs->tx_burst_stats.pkt_burst_spread[nb_tx]++;
+#endif
+
+	if (unlikely(nb_tx < nb_rx)) {
+		fs->fwd_dropped += (nb_rx - nb_tx);
+		do {
+			rte_pktmbuf_free(pkts_burst[nb_tx]);
+		} while (++nb_tx < nb_rx);
+	}
+#ifdef RTE_TEST_PMD_RECORD_CORE_CYCLES
+	end_tsc = rte_rdtsc();
+	core_cycles = (end_tsc - start_tsc);
+	fs->core_cycles = (uint64_t) (fs->core_cycles + core_cycles);
+#endif
+}
+
+static void
+set_tm_hiearchy_nodes_shaper_rate(portid_t port_id, struct tm_hierarchy *h)
+{
+	struct rte_eth_link link_params;
+	uint64_t tm_port_rate;
+
+	memset(&link_params, 0, sizeof(link_params));
+
+	rte_eth_link_get(port_id, &link_params);
+	tm_port_rate = link_params.link_speed * BYTES_IN_MBPS;
+
+	if (tm_port_rate > UINT32_MAX)
+		tm_port_rate = UINT32_MAX;
+
+	/* Set tm hierarchy shapers rate */
+	h->root_node_shaper_rate = tm_port_rate;
+	h->subport_node_shaper_rate =
+		tm_port_rate / SUBPORT_NODES_PER_PORT;
+	h->pipe_node_shaper_rate
+		= h->subport_node_shaper_rate / PIPE_NODES_PER_SUBPORT;
+	h->tc_node_shaper_rate = h->pipe_node_shaper_rate;
+	h->tc_node_shared_shaper_rate = h->subport_node_shaper_rate;
+}
+
+static int
+softport_tm_root_node_add(portid_t port_id, struct tm_hierarchy *h,
+	struct rte_tm_error *error)
+{
+	struct rte_tm_node_params rnp;
+	struct rte_tm_shaper_params rsp;
+	uint32_t priority, weight, level_id, shaper_profile_id;
+
+	memset(&rsp, 0, sizeof(struct rte_tm_shaper_params));
+	memset(&rnp, 0, sizeof(struct rte_tm_node_params));
+
+	/* Shaper profile Parameters */
+	rsp.peak.rate = h->root_node_shaper_rate;
+	rsp.peak.size = TOKEN_BUCKET_SIZE;
+	rsp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+	shaper_profile_id = 0;
+
+	if (rte_tm_shaper_profile_add(port_id, shaper_profile_id,
+		&rsp, error)) {
+		printf("%s ERROR(%d)-%s!(shaper_id %u)\n ",
+			__func__, error->type, error->message,
+			shaper_profile_id);
+		return -1;
+	}
+
+	/* Root Node Parameters */
+	h->root_node_id = ROOT_NODE_ID;
+	weight = 1;
+	priority = 0;
+	level_id = TM_NODE_LEVEL_PORT;
+	rnp.shaper_profile_id = shaper_profile_id;
+	rnp.nonleaf.n_sp_priorities = 1;
+	rnp.stats_mask = STATS_MASK_DEFAULT;
+
+	/* Add Node to TM Hierarchy */
+	if (rte_tm_node_add(port_id, h->root_node_id, RTE_TM_NODE_ID_NULL,
+		priority, weight, level_id, &rnp, error)) {
+		printf("%s ERROR(%d)-%s!(node_id %u, parent_id %u, level %u)\n",
+			__func__, error->type, error->message,
+			h->root_node_id, RTE_TM_NODE_ID_NULL,
+			level_id);
+		return -1;
+	}
+	/* Update */
+	h->n_shapers++;
+
+	printf("  Root node added (Start id %u, Count %u, level %u)\n",
+		h->root_node_id, 1, level_id);
+
+	return 0;
+}
+
+static int
+softport_tm_subport_node_add(portid_t port_id, struct tm_hierarchy *h,
+	struct rte_tm_error *error)
+{
+	uint32_t subport_parent_node_id, subport_node_id;
+	struct rte_tm_node_params snp;
+	struct rte_tm_shaper_params ssp;
+	uint32_t priority, weight, level_id, shaper_profile_id;
+	uint32_t i;
+
+	memset(&ssp, 0, sizeof(struct rte_tm_shaper_params));
+	memset(&snp, 0, sizeof(struct rte_tm_node_params));
+
+	shaper_profile_id = h->n_shapers;
+
+	/* Add Shaper Profile to TM Hierarchy */
+	for (i = 0; i < SUBPORT_NODES_PER_PORT; i++) {
+		ssp.peak.rate = h->subport_node_shaper_rate;
+		ssp.peak.size = TOKEN_BUCKET_SIZE;
+		ssp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+		if (rte_tm_shaper_profile_add(port_id, shaper_profile_id,
+			&ssp, error)) {
+			printf("%s ERROR(%d)-%s!(shaper_id %u)\n ",
+				__func__, error->type, error->message,
+				shaper_profile_id);
+			return -1;
+		}
+
+		/* Node Parameters */
+		h->subport_node_id[i] = SUBPORT_NODES_START_ID + i;
+		subport_parent_node_id = h->root_node_id;
+		weight = 1;
+		priority = 0;
+		level_id = TM_NODE_LEVEL_SUBPORT;
+		snp.shaper_profile_id = shaper_profile_id;
+		snp.nonleaf.n_sp_priorities = 1;
+		snp.stats_mask = STATS_MASK_DEFAULT;
+
+		/* Add Node to TM Hiearchy */
+		if (rte_tm_node_add(port_id,
+				h->subport_node_id[i],
+				subport_parent_node_id,
+				priority, weight,
+				level_id,
+				&snp,
+				error)) {
+			printf("%s ERROR(%d)-%s!(node %u,parent %u,level %u)\n",
+					__func__,
+					error->type,
+					error->message,
+					h->subport_node_id[i],
+					subport_parent_node_id,
+					level_id);
+			return -1;
+		}
+		shaper_profile_id++;
+		subport_node_id++;
+	}
+	/* Update */
+	h->n_shapers = shaper_profile_id;
+
+	printf("  Subport nodes added (Start id %u, Count %u, level %u)\n",
+		h->subport_node_id[0], SUBPORT_NODES_PER_PORT, level_id);
+
+	return 0;
+}
+
+static int
+softport_tm_pipe_node_add(portid_t port_id, struct tm_hierarchy *h,
+	struct rte_tm_error *error)
+{
+	uint32_t pipe_parent_node_id;
+	struct rte_tm_node_params pnp;
+	struct rte_tm_shaper_params psp;
+	uint32_t priority, weight, level_id, shaper_profile_id;
+	uint32_t i, j;
+
+	memset(&psp, 0, sizeof(struct rte_tm_shaper_params));
+	memset(&pnp, 0, sizeof(struct rte_tm_node_params));
+
+	shaper_profile_id = h->n_shapers;
+
+	/* Shaper Profile Parameters */
+	psp.peak.rate = h->pipe_node_shaper_rate;
+	psp.peak.size = TOKEN_BUCKET_SIZE;
+	psp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+	/* Pipe Node Parameters */
+	weight = 1;
+	priority = 0;
+	level_id = TM_NODE_LEVEL_PIPE;
+	pnp.nonleaf.n_sp_priorities = 4;
+	pnp.stats_mask = STATS_MASK_DEFAULT;
+
+	/* Add Shaper Profiles and Nodes to TM Hierarchy */
+	for (i = 0; i < SUBPORT_NODES_PER_PORT; i++) {
+		for (j = 0; j < PIPE_NODES_PER_SUBPORT; j++) {
+			if (rte_tm_shaper_profile_add(port_id,
+				shaper_profile_id, &psp, error)) {
+				printf("%s ERROR(%d)-%s!(shaper_id %u)\n ",
+					__func__, error->type, error->message,
+					shaper_profile_id);
+				return -1;
+			}
+			pnp.shaper_profile_id = shaper_profile_id;
+			pipe_parent_node_id = h->subport_node_id[i];
+			h->pipe_node_id[i][j] = PIPE_NODES_START_ID +
+				(i * PIPE_NODES_PER_SUBPORT) + j;
+
+			if (rte_tm_node_add(port_id,
+					h->pipe_node_id[i][j],
+					pipe_parent_node_id,
+					priority, weight, level_id,
+					&pnp,
+					error)) {
+				printf("%s ERROR(%d)-%s!(node %u,parent %u )\n",
+					__func__,
+					error->type,
+					error->message,
+					h->pipe_node_id[i][j],
+					pipe_parent_node_id);
+
+				return -1;
+			}
+			shaper_profile_id++;
+		}
+	}
+	/* Update */
+	h->n_shapers = shaper_profile_id;
+
+	printf("  Pipe nodes added (Start id %u, Count %u, level %u)\n",
+		h->pipe_node_id[0][0], NUM_PIPE_NODES, level_id);
+
+	return 0;
+}
+
+static int
+softport_tm_tc_node_add(portid_t port_id, struct tm_hierarchy *h,
+	struct rte_tm_error *error)
+{
+	uint32_t tc_parent_node_id;
+	struct rte_tm_node_params tnp;
+	struct rte_tm_shaper_params tsp, tssp;
+	uint32_t shared_shaper_profile_id[TC_NODES_PER_PIPE];
+	uint32_t priority, weight, level_id, shaper_profile_id;
+	uint32_t pos, n_tc_nodes, i, j, k;
+
+	memset(&tsp, 0, sizeof(struct rte_tm_shaper_params));
+	memset(&tssp, 0, sizeof(struct rte_tm_shaper_params));
+	memset(&tnp, 0, sizeof(struct rte_tm_node_params));
+
+	shaper_profile_id = h->n_shapers;
+
+	/* Private Shaper Profile (TC) Parameters */
+	tsp.peak.rate = h->tc_node_shaper_rate;
+	tsp.peak.size = TOKEN_BUCKET_SIZE;
+	tsp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+	/* Shared Shaper Profile (TC) Parameters */
+	tssp.peak.rate = h->tc_node_shared_shaper_rate;
+	tssp.peak.size = TOKEN_BUCKET_SIZE;
+	tssp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+	/* TC Node Parameters */
+	weight = 1;
+	level_id = TM_NODE_LEVEL_TC;
+	tnp.n_shared_shapers = 1;
+	tnp.nonleaf.n_sp_priorities = 1;
+	tnp.stats_mask = STATS_MASK_DEFAULT;
+
+	/* Add Shared Shaper Profiles to TM Hierarchy */
+	for (i = 0; i < TC_NODES_PER_PIPE; i++) {
+		shared_shaper_profile_id[i] = shaper_profile_id;
+
+		if (rte_tm_shaper_profile_add(port_id,
+			shared_shaper_profile_id[i], &tssp, error)) {
+			printf("%s ERROR(%d)-%s!(Shared shaper profileid %u)\n",
+				__func__, error->type, error->message,
+				shared_shaper_profile_id[i]);
+
+			return -1;
+		}
+		if (rte_tm_shared_shaper_add_update(port_id,  i,
+			shared_shaper_profile_id[i], error)) {
+			printf("%s ERROR(%d)-%s!(Shared shaper id %u)\n",
+				__func__, error->type, error->message, i);
+
+			return -1;
+		}
+		shaper_profile_id++;
+	}
+
+	/* Add Shaper Profiles and Nodes to TM Hierarchy */
+	n_tc_nodes = 0;
+	for (i = 0; i < SUBPORT_NODES_PER_PORT; i++) {
+		for (j = 0; j < PIPE_NODES_PER_SUBPORT; j++) {
+			for (k = 0; k < TC_NODES_PER_PIPE ; k++) {
+				priority = k;
+				tc_parent_node_id = h->pipe_node_id[i][j];
+				tnp.shared_shaper_id =
+					(uint32_t *)calloc(1, sizeof(uint32_t));
+				tnp.shared_shaper_id[0] = k;
+				pos = j + (i * PIPE_NODES_PER_SUBPORT);
+				h->tc_node_id[pos][k] = TC_NODES_START_ID + n_tc_nodes;
+
+				if (rte_tm_shaper_profile_add(port_id,
+					shaper_profile_id, &tsp, error)) {
+					printf("%s ERROR(%d)-%s!(shaper %u)\n",
+						__func__, error->type,
+						error->message,
+						shaper_profile_id);
+
+					return -1;
+				}
+				tnp.shaper_profile_id = shaper_profile_id;
+				if (rte_tm_node_add(port_id,
+						h->tc_node_id[pos][k],
+						tc_parent_node_id,
+						priority, weight,
+						level_id,
+						&tnp, error)) {
+					printf("%s ERROR(%d)-%s!(node id %u)\n",
+						__func__,
+						error->type,
+						error->message,
+						h->tc_node_id[pos][k]);
+
+					return -1;
+				}
+				shaper_profile_id++;
+				n_tc_nodes++;
+			}
+		}
+	}
+	/* Update */
+	h->n_shapers = shaper_profile_id;
+
+	printf("  TC nodes added (Start id %u, Count %u, level %u)\n",
+		h->tc_node_id[0][0], n_tc_nodes, level_id);
+
+	return 0;
+}
+
+static int
+softport_tm_queue_node_add(portid_t port_id, struct tm_hierarchy *h,
+	struct rte_tm_error *error)
+{
+	uint32_t queue_parent_node_id;
+	struct rte_tm_node_params qnp;
+	uint32_t priority, weight, level_id, pos;
+	uint32_t n_queue_nodes, i, j, k;
+
+	memset(&qnp, 0, sizeof(struct rte_tm_node_params));
+
+	/* Queue Node Parameters */
+	priority = 0;
+	weight = 1;
+	level_id = TM_NODE_LEVEL_QUEUE;
+	qnp.shaper_profile_id = RTE_TM_SHAPER_PROFILE_ID_NONE;
+	qnp.leaf.cman = RTE_TM_CMAN_TAIL_DROP;
+	qnp.stats_mask = STATS_MASK_QUEUE;
+
+	/* Add Queue Nodes to TM Hierarchy */
+	n_queue_nodes = 0;
+	for (i = 0; i < NUM_PIPE_NODES; i++) {
+		for (j = 0; j < TC_NODES_PER_PIPE; j++) {
+			queue_parent_node_id = h->tc_node_id[i][j];
+			for (k = 0; k < QUEUE_NODES_PER_TC; k++) {
+				pos = j + (i * TC_NODES_PER_PIPE);
+				h->queue_node_id[pos][k] = n_queue_nodes;
+				if (rte_tm_node_add(port_id,
+						h->queue_node_id[pos][k],
+						queue_parent_node_id,
+						priority,
+						weight,
+						level_id,
+						&qnp, error)) {
+					printf("%s ERROR(%d)-%s!(node %u)\n",
+						__func__,
+						error->type,
+						error->message,
+						h->queue_node_id[pos][k]);
+
+					return -1;
+				}
+				n_queue_nodes++;
+			}
+		}
+	}
+	printf("  Queue nodes added (Start id %u, Count %u, level %u)\n",
+		h->queue_node_id[0][0], n_queue_nodes, level_id);
+
+	return 0;
+}
+
+/*
+ * TM Packet Field Setup
+ */
+static void
+softport_tm_pktfield_setup(portid_t port_id)
+{
+	struct rte_port *p = &ports[port_id];
+	uint64_t pktfield0_mask = 0;
+	uint64_t pktfield1_mask = 0x0000000FFF000000LLU;
+	uint64_t pktfield2_mask = 0x00000000000000FCLLU;
+
+	p->softport.tm = (struct softnic_port_tm) {
+		.n_subports_per_port = SUBPORT_NODES_PER_PORT,
+		.n_pipes_per_subport = PIPE_NODES_PER_SUBPORT,
+
+		/* Packet field to identify subport
+		 *
+		 * Default configuration assumes only one subport, thus
+		 * the subport ID is hardcoded to 0
+		 */
+		.tm_pktfield0_slabpos = 0,
+		.tm_pktfield0_slabmask = pktfield0_mask,
+		.tm_pktfield0_slabshr =
+			__builtin_ctzll(pktfield0_mask),
+
+		/* Packet field to identify pipe.
+		 *
+		 * Default value assumes Ethernet/IPv4/UDP packets,
+		 * UDP payload bits 12 .. 23
+		 */
+		.tm_pktfield1_slabpos = 40,
+		.tm_pktfield1_slabmask = pktfield1_mask,
+		.tm_pktfield1_slabshr =
+			__builtin_ctzll(pktfield1_mask),
+
+		/* Packet field used as index into TC translation table
+		 * to identify the traffic class and queue.
+		 *
+		 * Default value assumes Ethernet/IPv4 packets, IPv4
+		 * DSCP field
+		 */
+		.tm_pktfield2_slabpos = 8,
+		.tm_pktfield2_slabmask = pktfield2_mask,
+		.tm_pktfield2_slabshr =
+			__builtin_ctzll(pktfield2_mask),
+
+		.tm_tc_table = {
+			0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+			0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+			0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+			0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+		}, /**< TC translation table */
+	};
+}
+
+static int
+softport_tm_hierarchy_specify(portid_t port_id, struct rte_tm_error *error)
+{
+
+	struct tm_hierarchy h;
+	int status;
+
+	memset(&h, 0, sizeof(struct tm_hierarchy));
+
+	/* TM hierarchy shapers rate */
+	set_tm_hiearchy_nodes_shaper_rate(port_id, &h);
+
+	/* Add root node (level 0) */
+	status = softport_tm_root_node_add(port_id, &h, error);
+	if (status)
+		return status;
+
+	/* Add subport node (level 1) */
+	status = softport_tm_subport_node_add(port_id, &h, error);
+	if (status)
+		return status;
+
+	/* Add pipe nodes (level 2) */
+	status = softport_tm_pipe_node_add(port_id, &h, error);
+	if (status)
+		return status;
+
+	/* Add traffic class nodes (level 3) */
+	status = softport_tm_tc_node_add(port_id, &h, error);
+	if (status)
+		return status;
+
+	/* Add queue nodes (level 4) */
+	status = softport_tm_queue_node_add(port_id, &h, error);
+	if (status)
+		return status;
+
+	/* TM packet fields setup */
+	softport_tm_pktfield_setup(port_id);
+
+	return 0;
+}
+
+/*
+ * Soft port Init
+ */
+static void
+softport_tm_begin(portid_t pi)
+{
+	struct rte_port *port = &ports[pi];
+
+	/* Soft port TM flag */
+	if (port->softport.tm_flag == 1) {
+		printf("\n\n  TM feature available on port %u\n", pi);
+
+		/* Soft port TM hierarchy frozen */
+		if (port->softport.tm.hierarchy_config == 0) {
+			struct rte_tm_error error;
+			int status;
+
+			/* Stop port */
+			rte_eth_dev_stop(pi);
+
+			/* TM hierarchy specification */
+			status = softport_tm_hierarchy_specify(pi, &error);
+			if (status) {
+				printf("  TM Hierarchy built error(%d) - %s\n",
+					error.type, error.message);
+				return;
+			}
+			printf("\n  TM Hierarchy Specified!\n\v");
+
+			/* TM hierarchy commit */
+			status = rte_tm_hierarchy_commit(pi, 0, &error);
+			if (status) {
+				printf("  Hierarchy commit error(%d) - %s\n",
+					error.type, error.message);
+				return;
+			}
+			printf("  Hierarchy Committed (port %u)!", pi);
+			port->softport.tm.hierarchy_config = 1;
+
+			/* Start port */
+			status = rte_eth_dev_start(pi);
+			if (status) {
+				printf("\n  Port %u start error!\n", pi);
+				return;
+			}
+			printf("\n  Port %u started!\n", pi);
+			return;
+		}
+	}
+	printf("\n  TM feature not available on port %u", pi);
+}
+
+struct fwd_engine softnic_tm_engine = {
+	.fwd_mode_name  = "tm",
+	.port_fwd_begin = softport_tm_begin,
+	.port_fwd_end   = NULL,
+	.packet_fwd     = softport_packet_fwd,
+};
+
+struct fwd_engine softnic_tm_bypass_engine = {
+	.fwd_mode_name  = "tm-bypass",
+	.port_fwd_begin = NULL,
+	.port_fwd_end   = NULL,
+	.packet_fwd     = softport_packet_fwd,
+};
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v4 2/5] app/test-pmd: add CLI for TM capability and stats
  2017-09-22 16:35     ` [PATCH v4 1/5] app/testpmd: add traffic management forwarding mode Jasvinder Singh
@ 2017-09-22 16:35       ` Jasvinder Singh
  2017-09-29 12:38         ` [PATCH v5 1/3] " Jasvinder Singh
  2017-09-22 16:35       ` [PATCH v4 3/5] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
                         ` (2 subsequent siblings)
  3 siblings, 1 reply; 49+ messages in thread
From: Jasvinder Singh @ 2017-09-22 16:35 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu, pablo.de.lara.guarch

Add following CLIs to testpmd application;
- commands to display TM capability information.
  (per port, per hierarchy level and per hierarchy node)
- command to display hiearchy node type
- stats collection

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
v4 change:
 - remove softnic specific checkes to make it generic

v3 change:
- Implements feedback from Pablo[1]
 - move TM API related CLIs into cmdline_tm.c 
 - split patch into small patches
 - replace link status check with testpmd fn port_is_started()

[1]http://dpdk.org/ml/archives/dev/2017-September/075748.html

 app/test-pmd/Makefile          |   1 +
 app/test-pmd/cmdline.c         |  23 +-
 app/test-pmd/cmdline_tm.c      | 654 +++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/testpmd_cmdline.h |  44 +++
 4 files changed, 721 insertions(+), 1 deletion(-)
 create mode 100644 app/test-pmd/cmdline_tm.c
 create mode 100755 app/test-pmd/testpmd_cmdline.h

diff --git a/app/test-pmd/Makefile b/app/test-pmd/Makefile
index 2c50f68..99dbe4d 100644
--- a/app/test-pmd/Makefile
+++ b/app/test-pmd/Makefile
@@ -59,6 +59,7 @@ SRCS-y += csumonly.c
 SRCS-y += icmpecho.c
 SRCS-$(CONFIG_RTE_LIBRTE_IEEE1588) += ieee1588fwd.c
 
+SRCS-y += cmdline_tm.c
 ifeq ($(CONFIG_RTE_LIBRTE_PMD_SOFTNIC)$(CONFIG_RTE_LIBRTE_SCHED),yy)
 SRCS-y += tm.c
 endif
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index ccdf239..769afe8 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -99,6 +99,7 @@
 #include <rte_pmd_bnxt.h>
 #endif
 #include "testpmd.h"
+#include "testpmd_cmdline.h"
 
 static struct cmdline *testpmd_cl;
 
@@ -230,6 +231,21 @@ static void cmd_help_long_parsed(void *parsed_result,
 
 			"clear vf stats (port_id) (vf_id)\n"
 			"    Reset a VF's statistics.\n\n"
+
+			"show port tm cap (port_id)\n"
+			"	Display the port TM capability.\n\n"
+
+			"show port tm level cap (port_id) (level_id)\n"
+			"	Display the port TM hierarchical level capability.\n\n"
+
+			"show port tm node cap (port_id) (node_id)\n"
+			"	Display the port TM node capability.\n\n"
+
+			"show port tm node type (port_id) (node_id)\n"
+			"	Display the port TM node type.\n\n"
+
+			"show port tm node stats (port_id) (node_id) (clear)\n"
+			"	Display the port TM node stats.\n\n"
 		);
 	}
 
@@ -14189,7 +14205,7 @@ cmdline_parse_inst_t cmd_load_from_file = {
 	},
 };
 
-/* ******************************************************************************** */
+/* *********************************************************************** */
 
 /* list of instructions */
 cmdline_parse_ctx_t main_ctx[] = {
@@ -14380,6 +14396,11 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_ptype_mapping_replace,
 	(cmdline_parse_inst_t *)&cmd_ptype_mapping_reset,
 	(cmdline_parse_inst_t *)&cmd_ptype_mapping_update,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_level_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_type,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_stats,
 	NULL,
 };
 
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
new file mode 100644
index 0000000..8139908
--- /dev/null
+++ b/app/test-pmd/cmdline_tm.c
@@ -0,0 +1,654 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+
+#include <rte_ethdev.h>
+#include <rte_flow.h>
+#include <rte_sched.h>
+#include <rte_eth_softnic.h>
+#include <rte_tm.h>
+
+#include "testpmd.h"
+#include "testpmd_cmdline.h"
+
+/** Display TM Error Message */
+static void
+print_err_msg(struct rte_tm_error *error)
+{
+	static const char *const errstrlist[] = {
+		[RTE_TM_ERROR_TYPE_NONE] = "no error",
+		[RTE_TM_ERROR_TYPE_UNSPECIFIED] = "cause unspecified",
+		[RTE_TM_ERROR_TYPE_CAPABILITIES]
+			= "capability parameter null",
+		[RTE_TM_ERROR_TYPE_LEVEL_ID] = "level id",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE]
+			= "wred profile null",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_GREEN] = "wred profile(green)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_YELLOW]
+			= "wred profile(yellow)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_RED] = "wred profile(red)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_ID] = "wred profile id",
+		[RTE_TM_ERROR_TYPE_SHARED_WRED_CONTEXT_ID]
+			= "shared wred context id",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE] = "shaper profile null",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE]
+			= "committed rate field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE]
+			= "committed size field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE]
+			= "peak rate field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE]
+			= "peak size field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN]
+			= "packet adjust length field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID] = "shaper profile id",
+		[RTE_TM_ERROR_TYPE_SHARED_SHAPER_ID] = "shared shaper id",
+		[RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID] = "parent node id",
+		[RTE_TM_ERROR_TYPE_NODE_PRIORITY] = "node priority",
+		[RTE_TM_ERROR_TYPE_NODE_WEIGHT] = "node weight",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS] = "node parameter null",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID]
+			= "shaper profile id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID]
+			= "shared shaper id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS]
+			= "num shared shapers field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE]
+			= "wfq weght mode field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES]
+			= "num strict priorities field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN]
+			= "congestion management mode field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID] =
+			"wred profile id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID]
+			= "shared wred context id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS]
+			= "num shared wred contexts field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS]
+			= "stats field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_ID] = "node id",
+	};
+
+	const char *errstr;
+	char buf[64];
+
+	if ((unsigned int)error->type >= RTE_DIM(errstrlist) ||
+		!errstrlist[error->type])
+		errstr = "unknown type";
+	else
+		errstr = errstrlist[error->type];
+
+	if (error->cause)
+		snprintf(buf, sizeof(buf), "cause: %p, ", error->cause);
+
+	printf("%s: %s%s (error %d)\n", errstr, error->cause ? buf : "",
+		error->message ? error->message : "(no stated reason)",
+		error->type);
+}
+
+/* *** Port TM Capability *** */
+struct cmd_show_port_tm_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t cap;
+	uint8_t port_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		 port_id, UINT8);
+
+static void cmd_show_port_tm_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_cap_result *res = parsed_result;
+	struct rte_tm_capabilities cap;
+	struct rte_tm_error error;
+	uint8_t port_id = res->port_id;
+	uint32_t i;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	memset(&cap, 0, sizeof(struct rte_tm_capabilities));
+	ret = rte_tm_capabilities_get(port_id, &cap, &error);
+	if (ret) {
+		print_err_msg(&error);
+		return;
+	}
+
+	printf("\n****   Port TM Capabilities ****\n\n");
+	printf("cap.n_nodes_max %u\n", cap.n_nodes_max);
+	printf("cap.n_levels_max %u\n", cap.n_levels_max);
+	printf("cap.non_leaf_nodes_identical %d\n",
+		cap.non_leaf_nodes_identical);
+	printf("cap.leaf_nodes_identical %d\n", cap.leaf_nodes_identical);
+	printf("cap.shaper_n_max %u\n", cap.shaper_n_max);
+	printf("cap.shaper_private_n_max %u\n", cap.shaper_private_n_max);
+	printf("cap.shaper_private_dual_rate_n_max %d\n",
+		cap.shaper_private_dual_rate_n_max);
+	printf("cap.shaper_private_rate_min %lu\n",
+		cap.shaper_private_rate_min);
+	printf("cap.shaper_private_rate_max %lu\n",
+		cap.shaper_private_rate_max);
+	printf("cap.shaper_shared_n_max %u\n", cap.shaper_shared_n_max);
+	printf("cap.shaper_shared_n_nodes_per_shaper_max %u\n",
+		cap.shaper_shared_n_nodes_per_shaper_max);
+	printf("cap.shaper_shared_n_shapers_per_node_max %u\n",
+		cap.shaper_shared_n_shapers_per_node_max);
+	printf("cap.shaper_shared_dual_rate_n_max %u\n",
+		cap.shaper_shared_dual_rate_n_max);
+	printf("cap.shaper_shared_rate_min %lu\n",
+		cap.shaper_shared_rate_min);
+	printf("cap.shaper_shared_rate_max %lu\n",
+		cap.shaper_shared_rate_max);
+	printf("cap.shaper_pkt_length_adjust_min %d\n",
+		cap.shaper_pkt_length_adjust_min);
+	printf("cap.shaper_pkt_length_adjust_max %d\n",
+		cap.shaper_pkt_length_adjust_max);
+	printf("cap.sched_n_children_max %u\n", cap.sched_n_children_max);
+	printf("cap.sched_sp_n_priorities_max %u\n",
+		cap.sched_sp_n_priorities_max);
+	printf("cap.sched_wfq_n_children_per_group_max %u\n",
+		cap.sched_wfq_n_children_per_group_max);
+	printf("cap.sched_wfq_n_groups_max %u\n", cap.sched_wfq_n_groups_max);
+	printf("cap.sched_wfq_weight_max %u\n", cap.sched_wfq_weight_max);
+	printf("cap.cman_head_drop_supported %d\n",
+		cap.cman_head_drop_supported);
+	printf("cap.cman_wred_context_n_max %u\n", cap.cman_wred_context_n_max);
+	printf("cap.cman_wred_context_private_n_max %u\n",
+		cap.cman_wred_context_private_n_max);
+	printf("cap.cman_wred_context_shared_n_max %u\n",
+		cap.cman_wred_context_shared_n_max);
+	printf("cap.cman_wred_context_shared_n_nodes_per_context_max %u\n",
+		cap.cman_wred_context_shared_n_nodes_per_context_max);
+	printf("cap.cman_wred_context_shared_n_contexts_per_node_max %u\n",
+		cap.cman_wred_context_shared_n_contexts_per_node_max);
+
+	for (i = 0; i < RTE_TM_COLORS; i++) {
+		printf("cap.mark_vlan_dei_supported %d\n",
+			cap.mark_vlan_dei_supported[i]);
+		printf("cap.mark_ip_ecn_tcp_supported %d\n",
+			cap.mark_ip_ecn_tcp_supported[i]);
+		printf("cap.mark_ip_ecn_sctp_supported %d\n",
+			cap.mark_ip_ecn_sctp_supported[i]);
+		printf("cap.mark_ip_dscp_supported %d\n",
+			cap.mark_ip_dscp_supported[i]);
+	}
+
+	printf("cap.dynamic_update_mask %lu\n", cap.dynamic_update_mask);
+	printf("cap.stats_mask %lu\n", cap.stats_mask);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_cap = {
+	.f = cmd_show_port_tm_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_cap_show,
+		(void *)&cmd_show_port_tm_cap_port,
+		(void *)&cmd_show_port_tm_cap_tm,
+		(void *)&cmd_show_port_tm_cap_cap,
+		(void *)&cmd_show_port_tm_cap_port_id,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchical Level Capability *** */
+struct cmd_show_port_tm_level_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t level;
+	cmdline_fixed_string_t cap;
+	uint8_t port_id;
+	uint32_t level_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_level =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		level, "level");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_level_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		 port_id, UINT8);
+cmdline_parse_token_num_t cmd_show_port_tm_level_cap_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		 level_id, UINT32);
+
+
+static void cmd_show_port_tm_level_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_level_cap_result *res = parsed_result;
+	struct rte_tm_level_capabilities lcap;
+	struct rte_tm_error error;
+	uint8_t port_id = res->port_id;
+	int ret, level_id = res->level_id;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	memset(&lcap, 0, sizeof(struct rte_tm_level_capabilities));
+	ret = rte_tm_level_capabilities_get(port_id, level_id, &lcap, &error);
+	if (ret) {
+		print_err_msg(&error);
+		return;
+	}
+	printf("\n****   Port TM Hierarchy level %u Capability ****\n\n",
+		level_id);
+
+	printf("cap.n_nodes_max %u\n", lcap.n_nodes_max);
+	printf("cap.n_nodes_nonleaf_max %u\n", lcap.n_nodes_nonleaf_max);
+	printf("cap.n_nodes_leaf_max %u\n", lcap.n_nodes_leaf_max);
+	printf("cap.non_leaf_nodes_identical %d\n",
+		lcap.non_leaf_nodes_identical);
+	printf("cap.leaf_nodes_identical %d\n", lcap.leaf_nodes_identical);
+	if (level_id <= 3) {
+		printf("cap.nonleaf.shaper_private_supported %d\n",
+			lcap.nonleaf.shaper_private_supported);
+		printf("cap.nonleaf.shaper_private_dual_rate_supported %d\n",
+			lcap.nonleaf.shaper_private_dual_rate_supported);
+		printf("cap.nonleaf.shaper_private_rate_min %lu\n",
+			lcap.nonleaf.shaper_private_rate_min);
+		printf("cap.nonleaf.shaper_private_rate_max %lu\n",
+			lcap.nonleaf.shaper_private_rate_max);
+		printf("cap.nonleaf.shaper_shared_n_max %u\n",
+			lcap.nonleaf.shaper_shared_n_max);
+		printf("cap.nonleaf.sched_n_children_max %u\n",
+			lcap.nonleaf.sched_n_children_max);
+		printf("cap.nonleaf.sched_sp_n_priorities_max %u\n",
+			lcap.nonleaf.sched_sp_n_priorities_max);
+		printf("cap.nonleaf.sched_wfq_n_children_per_group_max %u\n",
+			lcap.nonleaf.sched_wfq_n_children_per_group_max);
+		printf("cap.nonleaf.sched_wfq_n_groups_max %u\n",
+			lcap.nonleaf.sched_wfq_n_groups_max);
+		printf("cap.nonleaf.sched_wfq_weight_max %u\n",
+			lcap.nonleaf.sched_wfq_weight_max);
+		printf("cap.nonleaf.stats_mask %lu\n", lcap.nonleaf.stats_mask);
+	} else {
+		printf("cap.leaf.shaper_private_supported %d\n",
+			lcap.leaf.shaper_private_supported);
+		printf("cap.leaf.shaper_private_dual_rate_supported %d\n",
+			lcap.leaf.shaper_private_dual_rate_supported);
+		printf("cap.leaf.shaper_private_rate_min %lu\n",
+			lcap.leaf.shaper_private_rate_min);
+		printf("cap.leaf.shaper_private_rate_max %lu\n",
+			lcap.leaf.shaper_private_rate_max);
+		printf("cap.leaf.shaper_shared_n_max %u\n",
+			lcap.leaf.shaper_shared_n_max);
+		printf("cap.leaf.cman_head_drop_supported %d\n",
+			lcap.leaf.cman_head_drop_supported);
+		printf("cap.leaf.cman_wred_context_private_supported %d\n",
+			lcap.leaf.cman_wred_context_private_supported);
+		printf("cap.leaf.cman_wred_context_shared_n_max %u\n",
+			lcap.leaf.cman_wred_context_shared_n_max);
+		printf("cap.leaf.stats_mask %lu\n",
+			lcap.leaf.stats_mask);
+	}
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_level_cap = {
+	.f = cmd_show_port_tm_level_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Hierarhical level Capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_level_cap_show,
+		(void *)&cmd_show_port_tm_level_cap_port,
+		(void *)&cmd_show_port_tm_level_cap_tm,
+		(void *)&cmd_show_port_tm_level_cap_level,
+		(void *)&cmd_show_port_tm_level_cap_cap,
+		(void *)&cmd_show_port_tm_level_cap_port_id,
+		(void *)&cmd_show_port_tm_level_cap_level_id,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchy Node Capability *** */
+struct cmd_show_port_tm_node_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t cap;
+	uint8_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_node =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_node_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		 port_id, UINT8);
+cmdline_parse_token_num_t cmd_show_port_tm_node_cap_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		 node_id, UINT32);
+
+static void cmd_show_port_tm_node_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_cap_result *res = parsed_result;
+	struct rte_tm_node_capabilities ncap;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint8_t port_id = res->port_id;
+	int ret, is_leaf = 0;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Node id must be valid */
+	ret = rte_tm_node_type_get(port_id, node_id, &is_leaf, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	memset(&ncap, 0, sizeof(struct rte_tm_node_capabilities));
+	ret = rte_tm_node_capabilities_get(port_id, node_id, &ncap, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+	printf("\n****   Port TM Hierarchy node %u Capability ****\n\n",
+		node_id);
+	printf("cap.shaper_private_supported %d\n",
+		ncap.shaper_private_supported);
+	printf("cap.shaper_private_dual_rate_supported %d\n",
+		ncap.shaper_private_dual_rate_supported);
+	printf("cap.shaper_private_rate_min %lu\n",
+		ncap.shaper_private_rate_min);
+	printf("cap.shaper_private_rate_max %lu\n",
+		ncap.shaper_private_rate_max);
+	printf("cap.shaper_shared_n_max %u\n",
+		ncap.shaper_shared_n_max);
+	if (!is_leaf) {
+		printf("cap.nonleaf.sched_n_children_max %u\n",
+			ncap.nonleaf.sched_n_children_max);
+		printf("cap.nonleaf.sched_sp_n_priorities_max %u\n",
+			ncap.nonleaf.sched_sp_n_priorities_max);
+		printf("cap.nonleaf.sched_wfq_n_children_per_group_max %u\n",
+			ncap.nonleaf.sched_wfq_n_children_per_group_max);
+		printf("cap.nonleaf.sched_wfq_n_groups_max %u\n",
+			ncap.nonleaf.sched_wfq_n_groups_max);
+		printf("cap.nonleaf.sched_wfq_weight_max %u\n",
+			ncap.nonleaf.sched_wfq_weight_max);
+	} else {
+		printf("cap.leaf.cman_head_drop_supported %d\n",
+			ncap.leaf.cman_head_drop_supported);
+		printf("cap.leaf.cman_wred_context_private_supported %d\n",
+			ncap.leaf.cman_wred_context_private_supported);
+		printf("cap.leaf.cman_wred_context_shared_n_max %u\n",
+			ncap.leaf.cman_wred_context_shared_n_max);
+	}
+	printf("cap.stats_mask %lu\n", ncap.stats_mask);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_cap = {
+	.f = cmd_show_port_tm_node_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Hierarchy node capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_cap_show,
+		(void *)&cmd_show_port_tm_node_cap_port,
+		(void *)&cmd_show_port_tm_node_cap_tm,
+		(void *)&cmd_show_port_tm_node_cap_node,
+		(void *)&cmd_show_port_tm_node_cap_cap,
+		(void *)&cmd_show_port_tm_node_cap_port_id,
+		(void *)&cmd_show_port_tm_node_cap_node_id,
+		NULL,
+	},
+};
+
+/* *** Show Port TM Node Statistics *** */
+struct cmd_show_port_tm_node_stats_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t stats;
+	uint8_t port_id;
+	uint32_t node_id;
+	uint32_t clear;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_show =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_stats =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, stats, "stats");
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_stats_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result,
+			node_id, UINT32);
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_clear =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, clear, UINT32);
+
+static void cmd_show_port_tm_node_stats_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_stats_result *res = parsed_result;
+	struct rte_tm_node_stats stats;
+	struct rte_tm_error error;
+	uint64_t stats_mask = 0, leaf_stats_mask;
+	uint32_t node_id = res->node_id;
+	uint32_t clear = res->clear;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (!port_is_started(port_id)) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	memset(&stats, 0, sizeof(struct rte_tm_node_stats));
+	ret = rte_tm_node_stats_read(port_id, node_id, &stats,
+			&stats_mask, clear, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	leaf_stats_mask = RTE_TM_STATS_N_PKTS |
+		RTE_TM_STATS_N_BYTES |
+		RTE_TM_STATS_N_PKTS_GREEN_DROPPED |
+		RTE_TM_STATS_N_BYTES_GREEN_DROPPED |
+		RTE_TM_STATS_N_PKTS_QUEUED;
+
+	printf("pkts scheduled from node %lu\n", stats.n_pkts);
+	printf("bytes scheduled from node %lu\n", stats.n_bytes);
+	printf("pkts dropped %lu\n ", stats.leaf.n_pkts_dropped[RTE_TM_GREEN]);
+	printf("bytes dropped %lu\n ",
+		stats.leaf.n_bytes_dropped[RTE_TM_GREEN]);
+
+	if (stats_mask == leaf_stats_mask)
+		printf("packets enqueued %lu\n", stats.leaf.n_pkts_queued);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_stats = {
+	.f = cmd_show_port_tm_node_stats_parsed,
+	.data = NULL,
+	.help_str = "Show port tm node stats",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_stats_show,
+		(void *)&cmd_show_port_tm_node_stats_port,
+		(void *)&cmd_show_port_tm_node_stats_tm,
+		(void *)&cmd_show_port_tm_node_stats_node,
+		(void *)&cmd_show_port_tm_node_stats_stats,
+		(void *)&cmd_show_port_tm_node_stats_port_id,
+		(void *)&cmd_show_port_tm_node_stats_node_id,
+		(void *)&cmd_show_port_tm_node_stats_clear,
+		NULL,
+	},
+};
+
+/* *** Show Port TM Node Type *** */
+struct cmd_show_port_tm_node_type_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t type;
+	uint8_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_show =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, type, "type");
+cmdline_parse_token_num_t cmd_show_port_tm_node_type_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_show_port_tm_node_type_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result,
+			node_id, UINT32);
+
+static void cmd_show_port_tm_node_type_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_type_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint8_t port_id = res->port_id;
+	int ret, is_leaf = 0;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_node_type_get(port_id, node_id, &is_leaf, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	if (is_leaf == 1)
+		printf("leaf node\n");
+	else
+		printf("nonleaf node\n");
+
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_type = {
+	.f = cmd_show_port_tm_node_type_parsed,
+	.data = NULL,
+	.help_str = "Show port tm node type",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_type_show,
+		(void *)&cmd_show_port_tm_node_type_port,
+		(void *)&cmd_show_port_tm_node_type_tm,
+		(void *)&cmd_show_port_tm_node_type_node,
+		(void *)&cmd_show_port_tm_node_type_type,
+		(void *)&cmd_show_port_tm_node_type_port_id,
+		(void *)&cmd_show_port_tm_node_type_node_id,
+		NULL,
+	},
+};
diff --git a/app/test-pmd/testpmd_cmdline.h b/app/test-pmd/testpmd_cmdline.h
new file mode 100755
index 0000000..36fc498
--- /dev/null
+++ b/app/test-pmd/testpmd_cmdline.h
@@ -0,0 +1,44 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _TESTPMD_CMDLINE_H_
+#define _TESTPMD_CMDLINE_H_
+
+ /* Traffic Management CLI */
+extern cmdline_parse_inst_t cmd_show_port_tm_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_level_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_type;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_stats;
+
+#endif /* _TESTPMD_CMDLINE_H_ */
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v4 3/5] app/test-pmd: add CLI for shaper and wred profiles
  2017-09-22 16:35     ` [PATCH v4 1/5] app/testpmd: add traffic management forwarding mode Jasvinder Singh
  2017-09-22 16:35       ` [PATCH v4 2/5] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
@ 2017-09-22 16:35       ` Jasvinder Singh
  2017-09-22 16:35       ` [PATCH v4 4/5] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
  2017-09-22 16:35       ` [PATCH v4 5/5] app/test-pmd: add CLI for TM packet classification Jasvinder Singh
  3 siblings, 0 replies; 49+ messages in thread
From: Jasvinder Singh @ 2017-09-22 16:35 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu, pablo.de.lara.guarch

Add following CLIs in testpmd application;
- commands to add/del shaper profile for TM hieraqrchy nodes.
- commands to add/update shared shapers
- commands to add/del WRED profiles for TM hiearchy leaf nodes.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
v4 change:
 - remove softnic specific checkes to make it generic

 app/test-pmd/cmdline.c         |  34 ++
 app/test-pmd/cmdline_tm.c      | 741 +++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/testpmd_cmdline.h |   7 +
 3 files changed, 782 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 769afe8..36a29ba 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -653,6 +653,33 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"ptype mapping update (port_id) (hw_ptype) (sw_ptype)\n"
 			"    Update a ptype mapping item on a port\n\n"
 
+			"add port tm node shaper profile (port_id) (shaper_profile_id)"
+			" (tb_rate) (tb_size)\n"
+			"	Add port tm node private shaper profile.\n\n"
+
+			"del port tm node shaper profile (port_id) (shaper_profile_id)\n"
+			"	Delete port tm node private shaper profile.\n\n"
+
+			"add port tm node shared shaper (port_id) (shared_shaper_id)"
+			" (shaper_profile_id)\n"
+			"	Add/update port tm node shared shaper.\n\n"
+
+			"del port tm node shared shaper (port_id) (shared_shaper_id)\n"
+			"	Delete port tm node shared shaper.\n\n"
+
+			"set port tm node shaper profile (port_id) (node_id)"
+			" (shaper_profile_id)\n"
+			"	Set port tm node shaper profile.\n\n"
+
+			"add port tm node wred profile (port_id) (wred_profile_id)"
+			" (color_g) (min_th_g) (max_th_g) (maxp_inv_g) (wq_log2_g)"
+			" (color_y) (min_th_y) (max_th_y) (maxp_inv_y) (wq_log2_y)"
+			" (color_r) (min_th_r) (max_th_r) (maxp_inv_r) (wq_log2_r)\n"
+			"	Add port tm node wred profile.\n\n"
+
+			"del port tm node wred profile (port_id) (wred_profile_id)\n"
+			"	Delete port tm node wred profile.\n\n"
+
 			, list_pkt_forwarding_modes()
 		);
 	}
@@ -14401,6 +14428,13 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_cap,
 	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_type,
 	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_stats,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_shared_shaper,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_shared_shaper,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_wred_profile,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_wred_profile,
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_shaper_profile,
 	NULL,
 };
 
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
index 8139908..b875e75 100644
--- a/app/test-pmd/cmdline_tm.c
+++ b/app/test-pmd/cmdline_tm.c
@@ -652,3 +652,744 @@ cmdline_parse_inst_t cmd_show_port_tm_node_type = {
 		NULL,
 	},
 };
+
+/* *** Add Port TM Private Shaper Profile *** */
+struct cmd_add_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint8_t port_id;
+	uint32_t shaper_id;
+	uint64_t tb_rate;
+	uint64_t tb_size;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_tb_rate =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tb_rate, UINT64);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_tb_size =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tb_size, UINT64);
+
+static void cmd_add_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_tm_shaper_params sp;
+	struct rte_tm_error error;
+	uint32_t shaper_id = res->shaper_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Private shaper profile params */
+	memset(&sp, 0, sizeof(struct rte_tm_shaper_params));
+	sp.peak.rate = res->tb_rate;
+	sp.peak.size = res->tb_size;
+	sp.pkt_length_adjust = RTE_TM_ETH_FRAMING_OVERHEAD_FCS;
+
+	ret = rte_tm_shaper_profile_add(port_id, shaper_id, &sp, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_shaper_profile = {
+	.f = cmd_add_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Add port tm node private shaper profile",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_shaper_profile_add,
+		(void *)&cmd_add_port_tm_node_shaper_profile_port,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_add_port_tm_node_shaper_profile_node,
+		(void *)&cmd_add_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_add_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_add_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_add_port_tm_node_shaper_profile_shaper_id,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tb_rate,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tb_size,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM Private Shaper Profile *** */
+struct cmd_del_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint8_t port_id;
+	uint32_t shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_del_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_del_port_tm_node_shaper_profile_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			shaper_id, UINT32);
+
+static void cmd_del_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t shaper_id = res->shaper_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_shaper_profile_delete(port_id, shaper_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_shaper_profile = {
+	.f = cmd_del_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node private shaper profile",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_shaper_profile_del,
+		(void *)&cmd_del_port_tm_node_shaper_profile_port,
+		(void *)&cmd_del_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_del_port_tm_node_shaper_profile_node,
+		(void *)&cmd_del_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_del_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_del_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_del_port_tm_node_shaper_profile_shaper_id,
+		NULL,
+	},
+};
+
+/* *** Add/Update Port TM shared Shaper *** */
+struct cmd_add_port_tm_node_shared_shaper_result {
+	cmdline_fixed_string_t cmd_type;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shared;
+	cmdline_fixed_string_t shaper;
+	uint8_t port_id;
+	uint32_t shared_shaper_id;
+	uint32_t shaper_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_cmd_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			cmd_type, "add#set");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_shared =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shared, "shared");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shaper, "shaper");
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shared_shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shaper_profile_id, UINT32);
+
+static void cmd_add_port_tm_node_shared_shaper_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_shared_shaper_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t shared_shaper_id = res->shared_shaper_id;
+	uint32_t shaper_profile_id = res->shaper_profile_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Command type: add */
+	if ((strcmp(res->cmd_type, "add") == 0) &&
+		(port_is_started(port_id))) {
+			printf(" Port %u not stopped (error)\n", port_id);
+			return;
+	}
+
+	/* Command type: set (update) */
+	if ((strcmp(res->cmd_type, "set") == 0) &&
+		(!port_is_started(port_id))) {
+			printf(" Port %u not started (error)\n", port_id);
+			return;
+	}
+
+	ret = rte_tm_shared_shaper_add_update(port_id, shared_shaper_id,
+		shaper_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_shared_shaper = {
+	.f = cmd_add_port_tm_node_shared_shaper_parsed,
+	.data = NULL,
+	.help_str = "add/update port tm node shared shaper",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_shared_shaper_cmd_type,
+		(void *)&cmd_add_port_tm_node_shared_shaper_port,
+		(void *)&cmd_add_port_tm_node_shared_shaper_tm,
+		(void *)&cmd_add_port_tm_node_shared_shaper_node,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shared,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shaper,
+		(void *)&cmd_add_port_tm_node_shared_shaper_port_id,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shared_shaper_id,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shaper_profile_id,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM shared Shaper *** */
+struct cmd_del_port_tm_node_shared_shaper_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shared;
+	cmdline_fixed_string_t shaper;
+	uint8_t port_id;
+	uint32_t shared_shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_shared =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shared, "shared");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shaper, "shaper");
+cmdline_parse_token_num_t cmd_del_port_tm_node_shared_shaper_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_del_port_tm_node_shared_shaper_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shared_shaper_id, UINT32);
+
+static void cmd_del_port_tm_node_shared_shaper_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_shared_shaper_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t shared_shaper_id = res->shared_shaper_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_shared_shaper_delete(port_id, shared_shaper_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper = {
+	.f = cmd_del_port_tm_node_shared_shaper_parsed,
+	.data = NULL,
+	.help_str = "delete port tm node shared shaper",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_shared_shaper_del,
+		(void *)&cmd_del_port_tm_node_shared_shaper_port,
+		(void *)&cmd_del_port_tm_node_shared_shaper_tm,
+		(void *)&cmd_del_port_tm_node_shared_shaper_node,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shared,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shaper,
+		(void *)&cmd_del_port_tm_node_shared_shaper_port_id,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shared_shaper_id,
+		NULL,
+	},
+};
+
+/* *** Add Port TM Node WRED Profile *** */
+struct cmd_add_port_tm_node_wred_profile_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t wred;
+	cmdline_fixed_string_t profile;
+	uint8_t port_id;
+	uint32_t wred_profile_id;
+	cmdline_fixed_string_t color_g;
+	uint16_t min_th_g;
+	uint16_t max_th_g;
+	uint16_t maxp_inv_g;
+	uint16_t wq_log2_g;
+	cmdline_fixed_string_t color_y;
+	uint16_t min_th_y;
+	uint16_t max_th_y;
+	uint16_t maxp_inv_y;
+	uint16_t wq_log2_y;
+	cmdline_fixed_string_t color_r;
+	uint16_t min_th_r;
+	uint16_t max_th_r;
+	uint16_t maxp_inv_r;
+	uint16_t wq_log2_r;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_wred =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, wred, "wred");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wred_profile_id, UINT32);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_g =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_g, "G#g");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_g, UINT16);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_y =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_y, "Y#y");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_y, UINT16);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_r =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_r, "R#r");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_r, UINT16);
+
+
+static void cmd_add_port_tm_node_wred_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_wred_profile_result *res = parsed_result;
+	struct rte_tm_wred_params wp;
+	enum rte_tm_color color;
+	struct rte_tm_error error;
+	uint32_t wred_profile_id = res->wred_profile_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	memset(&wp, 0, sizeof(struct rte_tm_wred_params));
+
+	/* WRED Params  (Green Color)*/
+	if ((strcmp(res->color_g, "G") == 0) ||
+		(strcmp(res->color_g, "g") == 0)) {
+		color = RTE_TM_GREEN;
+		wp.red_params[color].min_th = res->min_th_g;
+		wp.red_params[color].max_th = res->max_th_g;
+		wp.red_params[color].maxp_inv = res->maxp_inv_g;
+		wp.red_params[color].wq_log2 = res->wq_log2_g;
+	} else {
+		printf("WRED profile error(G or g for green color)!\n");
+		return;
+	}
+
+	/* WRED Params  (Yellow Color)*/
+	if ((strcmp(res->color_y, "Y") == 0) ||
+		(strcmp(res->color_y, "y") == 0)) {
+		color = RTE_TM_YELLOW;
+		wp.red_params[color].min_th = res->min_th_y;
+		wp.red_params[color].max_th = res->max_th_y;
+		wp.red_params[color].maxp_inv = res->maxp_inv_y;
+		wp.red_params[color].wq_log2 = res->wq_log2_y;
+	} else {
+		printf("WRED profile error(Y or y for yellow color)!\n");
+		return;
+	}
+
+	/* WRED Params  (Red Color)*/
+	if ((strcmp(res->color_r, "R") == 0) ||
+		(strcmp(res->color_r, "r") == 0)) {
+		color = RTE_TM_RED;
+		wp.red_params[color].min_th = res->min_th_r;
+		wp.red_params[color].max_th = res->max_th_r;
+		wp.red_params[color].maxp_inv = res->maxp_inv_r;
+		wp.red_params[color].wq_log2 = res->wq_log2_r;
+	} else {
+		printf("WRED profile error(R or r for red color)!\n");
+		return;
+	}
+
+	ret = rte_tm_wred_profile_add(port_id, wred_profile_id, &wp, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile = {
+	.f = cmd_add_port_tm_node_wred_profile_parsed,
+	.data = NULL,
+	.help_str = "Add port tm node wred profile",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_wred_profile_add,
+		(void *)&cmd_add_port_tm_node_wred_profile_port,
+		(void *)&cmd_add_port_tm_node_wred_profile_tm,
+		(void *)&cmd_add_port_tm_node_wred_profile_node,
+		(void *)&cmd_add_port_tm_node_wred_profile_wred,
+		(void *)&cmd_add_port_tm_node_wred_profile_profile,
+		(void *)&cmd_add_port_tm_node_wred_profile_port_id,
+		(void *)&cmd_add_port_tm_node_wred_profile_wred_profile_id,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_r,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM node WRED Profile *** */
+struct cmd_del_port_tm_node_wred_profile_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t wred;
+	cmdline_fixed_string_t profile;
+	uint8_t port_id;
+	uint32_t wred_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_wred =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, wred, "wred");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_del_port_tm_node_wred_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_del_port_tm_node_wred_profile_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			wred_profile_id, UINT32);
+
+static void cmd_del_port_tm_node_wred_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_wred_profile_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t wred_profile_id = res->wred_profile_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_wred_profile_delete(port_id, wred_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile = {
+	.f = cmd_del_port_tm_node_wred_profile_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node wred profile",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_wred_profile_del,
+		(void *)&cmd_del_port_tm_node_wred_profile_port,
+		(void *)&cmd_del_port_tm_node_wred_profile_tm,
+		(void *)&cmd_del_port_tm_node_wred_profile_node,
+		(void *)&cmd_del_port_tm_node_wred_profile_wred,
+		(void *)&cmd_del_port_tm_node_wred_profile_profile,
+		(void *)&cmd_del_port_tm_node_wred_profile_port_id,
+		(void *)&cmd_del_port_tm_node_wred_profile_wred_profile_id,
+		NULL,
+	},
+};
+
+/* *** Update Port TM Node Shaper profile *** */
+struct cmd_set_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint8_t port_id;
+	uint32_t node_id;
+	uint32_t shaper_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_set_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_set_port_tm_node_shaper_profile_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_shaper_profile_result,
+		node_id, UINT32);
+cmdline_parse_token_num_t
+	cmd_set_port_tm_node_shaper_shaper_profile_profile_id =
+		TOKEN_NUM_INITIALIZER(
+			struct cmd_set_port_tm_node_shaper_profile_result,
+			shaper_profile_id, UINT32);
+
+static void cmd_set_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint32_t shaper_profile_id = res->shaper_profile_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (!port_is_started(port_id)) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_shaper_update(port_id, node_id,
+		shaper_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile = {
+	.f = cmd_set_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node shaper profile",
+	.tokens = {
+		(void *)&cmd_set_port_tm_node_shaper_profile_set,
+		(void *)&cmd_set_port_tm_node_shaper_profile_port,
+		(void *)&cmd_set_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_set_port_tm_node_shaper_profile_node,
+		(void *)&cmd_set_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_set_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_set_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_set_port_tm_node_shaper_profile_node_id,
+		(void *)&cmd_set_port_tm_node_shaper_shaper_profile_profile_id,
+		NULL,
+	},
+};
diff --git a/app/test-pmd/testpmd_cmdline.h b/app/test-pmd/testpmd_cmdline.h
index 36fc498..0aa0aa6 100755
--- a/app/test-pmd/testpmd_cmdline.h
+++ b/app/test-pmd/testpmd_cmdline.h
@@ -40,5 +40,12 @@ extern cmdline_parse_inst_t cmd_show_port_tm_level_cap;
 extern cmdline_parse_inst_t cmd_show_port_tm_node_cap;
 extern cmdline_parse_inst_t cmd_show_port_tm_node_type;
 extern cmdline_parse_inst_t cmd_show_port_tm_node_stats;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_shared_shaper;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile;
+extern cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile;
 
 #endif /* _TESTPMD_CMDLINE_H_ */
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v4 4/5] app/test-pmd: add CLI for TM nodes and hierarchy commit
  2017-09-22 16:35     ` [PATCH v4 1/5] app/testpmd: add traffic management forwarding mode Jasvinder Singh
  2017-09-22 16:35       ` [PATCH v4 2/5] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
  2017-09-22 16:35       ` [PATCH v4 3/5] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
@ 2017-09-22 16:35       ` Jasvinder Singh
  2017-09-22 16:35       ` [PATCH v4 5/5] app/test-pmd: add CLI for TM packet classification Jasvinder Singh
  3 siblings, 0 replies; 49+ messages in thread
From: Jasvinder Singh @ 2017-09-22 16:35 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu, pablo.de.lara.guarch

Add following CLIs in testpmd application;
- commands to add TM hierarchy nodes (leaf and nonleaf).
- command for runtime update of node weight.
- command to commit the TM hierarchy

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
v4 change:
 - remove softnic specific checkes to make it generic

 app/test-pmd/cmdline.c         |  25 +++
 app/test-pmd/cmdline_tm.c      | 497 +++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/testpmd_cmdline.h |   5 +
 3 files changed, 527 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 36a29ba..de7f487 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -680,6 +680,26 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"del port tm node wred profile (port_id) (wred_profile_id)\n"
 			"	Delete port tm node wred profile.\n\n"
 
+			"add port tm nonleaf node (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight) (level_id) (shaper_profile_id)"
+			" (shared_shaper_id) (n_shared_shapers) (n_sp_priorities)\n"
+			"	Add port tm nonleaf node.\n\n"
+
+			"add port tm leaf node (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight) (level_id) (cman_mode)"
+			" (wred_profile_id)\n"
+			"	Add port tm leaf node.\n\n"
+
+			"del port tm node (port_id) (node_id)\n"
+			"	Delete port tm node.\n\n"
+
+			"set port tm node parent (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight)\n"
+			"	Set port tm node parent.\n\n"
+
+			"port tm hierarchy commit (port_id) (clean_on_fail)\n"
+			"	Commit tm hierarchy.\n\n"
+
 			, list_pkt_forwarding_modes()
 		);
 	}
@@ -14435,6 +14455,11 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_wred_profile,
 	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_wred_profile,
 	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_nonleaf_node,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_leaf_node,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node,
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_parent,
+	(cmdline_parse_inst_t *)&cmd_port_tm_hierarchy_commit,
 	NULL,
 };
 
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
index b875e75..5fc946d 100644
--- a/app/test-pmd/cmdline_tm.c
+++ b/app/test-pmd/cmdline_tm.c
@@ -1393,3 +1393,500 @@ cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile = {
 		NULL,
 	},
 };
+
+/* *** Add Port TM nonleaf node *** */
+struct cmd_add_port_tm_nonleaf_node_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t nonleaf;
+	cmdline_fixed_string_t node;
+	uint8_t port_id;
+	uint32_t node_id;
+	int32_t parent_node_id;
+	uint32_t priority;
+	uint32_t weight;
+	uint32_t level_id;
+	uint32_t shaper_profile_id;
+	uint32_t shared_shaper_id;
+	uint32_t n_shared_shapers;
+	uint32_t n_sp_priorities;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_nonleaf =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, nonleaf, "nonleaf");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, node, "node");
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result,
+		 port_id, UINT8);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 node_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 parent_node_id, INT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 priority, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 weight, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 level_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 shaper_profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 shared_shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_n_shared_shapers =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 n_shared_shapers, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_n_sp_priorities =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 n_sp_priorities, UINT32);
+
+static void cmd_add_port_tm_nonleaf_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_nonleaf_node_result *res = parsed_result;
+	struct rte_tm_error error;
+	struct rte_tm_node_params np;
+	uint32_t parent_node_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	/* Node parameters */
+	if (res->parent_node_id < 0)
+		parent_node_id = UINT32_MAX;
+	else
+		parent_node_id = res->parent_node_id;
+
+	memset(&np, 0, sizeof(struct rte_tm_node_params));
+	np.shaper_profile_id = res->shaper_profile_id;
+	np.n_shared_shapers = res->n_shared_shapers;
+	np.shared_shaper_id = &res->shared_shaper_id;
+	np.nonleaf.n_sp_priorities = res->n_sp_priorities;
+	np.nonleaf.wfq_weight_mode = NULL;
+	np.stats_mask = RTE_TM_STATS_N_PKTS |
+		RTE_TM_STATS_N_BYTES |
+		RTE_TM_STATS_N_PKTS_GREEN_DROPPED |
+		RTE_TM_STATS_N_BYTES_GREEN_DROPPED;
+
+	ret = rte_tm_node_add(port_id, res->node_id, parent_node_id,
+				res->priority, res->weight, res->level_id,
+				&np, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_nonleaf_node = {
+	.f = cmd_add_port_tm_nonleaf_node_parsed,
+	.data = NULL,
+	.help_str = "Add port tm nonleaf node",
+	.tokens = {
+		(void *)&cmd_add_port_tm_nonleaf_node_add,
+		(void *)&cmd_add_port_tm_nonleaf_node_port,
+		(void *)&cmd_add_port_tm_nonleaf_node_tm,
+		(void *)&cmd_add_port_tm_nonleaf_node_nonleaf,
+		(void *)&cmd_add_port_tm_nonleaf_node_node,
+		(void *)&cmd_add_port_tm_nonleaf_node_port_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_node_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_parent_node_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_priority,
+		(void *)&cmd_add_port_tm_nonleaf_node_weight,
+		(void *)&cmd_add_port_tm_nonleaf_node_level_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_shaper_profile_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_shared_shaper_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_n_shared_shapers,
+		(void *)&cmd_add_port_tm_nonleaf_node_n_sp_priorities,
+		NULL,
+	},
+};
+
+/* *** Add Port TM leaf node *** */
+struct cmd_add_port_tm_leaf_node_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t leaf;
+	cmdline_fixed_string_t node;
+	uint8_t port_id;
+	uint32_t node_id;
+	int32_t parent_node_id;
+	uint32_t priority;
+	uint32_t weight;
+	uint32_t level_id;
+	uint32_t cman_mode;
+	uint32_t wred_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_nonleaf =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, leaf, "leaf");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, node, "node");
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 port_id, UINT8);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 node_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 parent_node_id, INT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 priority, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 weight, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 level_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_cman_mode =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 cman_mode, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 wred_profile_id, UINT32);
+
+static void cmd_add_port_tm_leaf_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_leaf_node_result *res = parsed_result;
+	struct rte_tm_error error;
+	struct rte_tm_node_params np;
+	uint32_t parent_node_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	/* Node parameters */
+	if (res->parent_node_id < 0)
+		parent_node_id = UINT32_MAX;
+	else
+		parent_node_id = res->parent_node_id;
+
+	memset(&np, 0, sizeof(struct rte_tm_node_params));
+	np.shaper_profile_id = RTE_TM_SHAPER_PROFILE_ID_NONE;
+	np.n_shared_shapers = 0;
+	np.leaf.cman = res->cman_mode;
+	np.leaf.wred.wred_profile_id = res->wred_profile_id;
+	np.stats_mask = RTE_TM_STATS_N_PKTS |
+		RTE_TM_STATS_N_BYTES |
+		RTE_TM_STATS_N_PKTS_GREEN_DROPPED |
+		RTE_TM_STATS_N_BYTES_GREEN_DROPPED |
+		RTE_TM_STATS_N_PKTS_QUEUED;
+
+	ret = rte_tm_node_add(port_id, res->node_id, parent_node_id,
+				res->priority, res->weight, res->level_id,
+				&np, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_leaf_node = {
+	.f = cmd_add_port_tm_leaf_node_parsed,
+	.data = NULL,
+	.help_str = "Add port tm leaf node",
+	.tokens = {
+		(void *)&cmd_add_port_tm_leaf_node_add,
+		(void *)&cmd_add_port_tm_leaf_node_port,
+		(void *)&cmd_add_port_tm_leaf_node_tm,
+		(void *)&cmd_add_port_tm_leaf_node_nonleaf,
+		(void *)&cmd_add_port_tm_leaf_node_node,
+		(void *)&cmd_add_port_tm_leaf_node_port_id,
+		(void *)&cmd_add_port_tm_leaf_node_node_id,
+		(void *)&cmd_add_port_tm_leaf_node_parent_node_id,
+		(void *)&cmd_add_port_tm_leaf_node_priority,
+		(void *)&cmd_add_port_tm_leaf_node_weight,
+		(void *)&cmd_add_port_tm_leaf_node_level_id,
+		(void *)&cmd_add_port_tm_leaf_node_cman_mode,
+		(void *)&cmd_add_port_tm_leaf_node_wred_profile_id,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM Node *** */
+struct cmd_del_port_tm_node_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	uint8_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, node, "node");
+cmdline_parse_token_num_t cmd_del_port_tm_node_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_del_port_tm_node_result,
+		 port_id, UINT8);
+cmdline_parse_token_num_t cmd_del_port_tm_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_del_port_tm_node_result,
+		node_id, UINT32);
+
+static void cmd_del_port_tm_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_delete(port_id, node_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node = {
+	.f = cmd_del_port_tm_node_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_del,
+		(void *)&cmd_del_port_tm_node_port,
+		(void *)&cmd_del_port_tm_node_tm,
+		(void *)&cmd_del_port_tm_node_node,
+		(void *)&cmd_del_port_tm_node_port_id,
+		(void *)&cmd_del_port_tm_node_node_id,
+		NULL,
+	},
+};
+
+/* *** Update Port TM Node Parent *** */
+struct cmd_set_port_tm_node_parent_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t parent;
+	uint8_t port_id;
+	uint32_t node_id;
+	uint32_t parent_id;
+	uint32_t priority;
+	uint32_t weight;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, node, "node");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_parent =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, parent, "parent");
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, port_id, UINT8);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, node_id, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_parent_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		parent_id, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		priority, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		weight, UINT32);
+
+static void cmd_set_port_tm_node_parent_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_node_parent_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint32_t parent_id = res->parent_id;
+	uint32_t priority = res->priority;
+	uint32_t weight = res->weight;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (!port_is_started(port_id)) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_parent_update(port_id, node_id,
+		parent_id, priority, weight, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_node_parent = {
+	.f = cmd_set_port_tm_node_parent_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node parent",
+	.tokens = {
+		(void *)&cmd_set_port_tm_node_parent_set,
+		(void *)&cmd_set_port_tm_node_parent_port,
+		(void *)&cmd_set_port_tm_node_parent_tm,
+		(void *)&cmd_set_port_tm_node_parent_node,
+		(void *)&cmd_set_port_tm_node_parent_parent,
+		(void *)&cmd_set_port_tm_node_parent_port_id,
+		(void *)&cmd_set_port_tm_node_parent_node_id,
+		(void *)&cmd_set_port_tm_node_parent_parent_id,
+		(void *)&cmd_set_port_tm_node_parent_priority,
+		(void *)&cmd_set_port_tm_node_parent_weight,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchy Commit *** */
+struct cmd_port_tm_hierarchy_commit_result {
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t hierarchy;
+	cmdline_fixed_string_t commit;
+	uint8_t port_id;
+	uint32_t clean_on_fail;
+};
+
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, port, "port");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, tm, "tm");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_hierarchy =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result,
+			hierarchy, "hierarchy");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_commit =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, commit, "commit");
+cmdline_parse_token_num_t cmd_port_tm_hierarchy_commit_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_port_tm_hierarchy_commit_clean_on_fail =
+	TOKEN_NUM_INITIALIZER(struct cmd_port_tm_hierarchy_commit_result,
+		 clean_on_fail, UINT32);
+
+static void cmd_port_tm_hierarchy_commit_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_port_tm_hierarchy_commit_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t clean_on_fail = res->clean_on_fail;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_hierarchy_commit(port_id, clean_on_fail, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_port_tm_hierarchy_commit = {
+	.f = cmd_port_tm_hierarchy_commit_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node shaper profile",
+	.tokens = {
+		(void *)&cmd_port_tm_hierarchy_commit_port,
+		(void *)&cmd_port_tm_hierarchy_commit_tm,
+		(void *)&cmd_port_tm_hierarchy_commit_hierarchy,
+		(void *)&cmd_port_tm_hierarchy_commit_commit,
+		(void *)&cmd_port_tm_hierarchy_commit_port_id,
+		(void *)&cmd_port_tm_hierarchy_commit_clean_on_fail,
+		NULL,
+	},
+};
diff --git a/app/test-pmd/testpmd_cmdline.h b/app/test-pmd/testpmd_cmdline.h
index 0aa0aa6..4fa7cc4 100755
--- a/app/test-pmd/testpmd_cmdline.h
+++ b/app/test-pmd/testpmd_cmdline.h
@@ -47,5 +47,10 @@ extern cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper;
 extern cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile;
 extern cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile;
 extern cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_add_port_tm_nonleaf_node;
+extern cmdline_parse_inst_t cmd_add_port_tm_leaf_node;
+extern cmdline_parse_inst_t cmd_del_port_tm_node;
+extern cmdline_parse_inst_t cmd_set_port_tm_node_parent;
+extern cmdline_parse_inst_t cmd_port_tm_hierarchy_commit;
 
 #endif /* _TESTPMD_CMDLINE_H_ */
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v4 5/5] app/test-pmd: add CLI for TM packet classification
  2017-09-22 16:35     ` [PATCH v4 1/5] app/testpmd: add traffic management forwarding mode Jasvinder Singh
                         ` (2 preceding siblings ...)
  2017-09-22 16:35       ` [PATCH v4 4/5] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
@ 2017-09-22 16:35       ` Jasvinder Singh
  3 siblings, 0 replies; 49+ messages in thread
From: Jasvinder Singh @ 2017-09-22 16:35 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu, pablo.de.lara.guarch

Add following CLIs in testpmd application;
- command to set the packet field mask and offset value for
  classification.
- command to set traffic class translation table entry

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 app/test-pmd/cmdline.c         |  13 ++
 app/test-pmd/cmdline_tm.c      | 309 +++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/testpmd_cmdline.h |   4 +
 3 files changed, 326 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index de7f487..cc0a505 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -700,6 +700,15 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"port tm hierarchy commit (port_id) (clean_on_fail)\n"
 			"	Commit tm hierarchy.\n\n"
 
+#if defined RTE_LIBRTE_PMD_SOFTNIC && defined RTE_LIBRTE_SCHED
+			"set port tm pktfield (subport|pipe|tc) (port_id) offset"
+			" (offset) mask (mask)\n"
+			"	Set port tm packet field.\n\n"
+
+			"set port tm tc table (port_id) index (tb_index) tc (tc_id)"
+			" queue (queue id)\n"
+			"	Set port tm traffic class table entry.\n\n"
+#endif
 			, list_pkt_forwarding_modes()
 		);
 	}
@@ -14460,6 +14469,10 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_del_port_tm_node,
 	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_parent,
 	(cmdline_parse_inst_t *)&cmd_port_tm_hierarchy_commit,
+#if defined RTE_LIBRTE_PMD_SOFTNIC && defined RTE_LIBRTE_SCHED
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_pktfield,
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_tc_table,
+#endif
 	NULL,
 };
 
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
index 5fc946d..ddeb45b 100644
--- a/app/test-pmd/cmdline_tm.c
+++ b/app/test-pmd/cmdline_tm.c
@@ -1890,3 +1890,312 @@ cmdline_parse_inst_t cmd_port_tm_hierarchy_commit = {
 		NULL,
 	},
 };
+
+#if defined RTE_LIBRTE_PMD_SOFTNIC && defined RTE_LIBRTE_SCHED
+
+static int
+port_tm_pktfield_validate_mask(uint64_t mask, uint64_t n)
+{
+	int count = __builtin_popcountll(mask);
+	int pos_lead = sizeof(uint64_t) * 8 - __builtin_clzll(mask);
+	int pos_trail = __builtin_ctzll(mask);
+	int count_expected = __builtin_popcount(n - 1);
+
+	/* Handle the exceptions */
+	if (n == 0)
+		return -1;			/* Error */
+
+	if ((mask == 0) && (n == 1))
+		return 0;			/* OK */
+
+	if (((mask == 0) && (n != 1)) || ((mask != 0) && (n == 1)))
+		return -2;			/* Error */
+
+	/* Check that mask is contiguous */
+	if ((pos_lead - pos_trail) != count)
+		return -3;			/* Error */
+
+	/* Check that mask contains the expected number of bits set */
+	if (count != count_expected)
+		return -4;			/* Error */
+
+	return 0;			/* OK */
+	}
+
+/* *** Set Port TM Packet Fields *** */
+struct cmd_set_port_tm_pktfield_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t pktfield;
+	cmdline_fixed_string_t type;
+	uint8_t port_id;
+	cmdline_fixed_string_t offset_string;
+	uint32_t offset;
+	cmdline_fixed_string_t mask_string;
+	uint64_t mask;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result, port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,	tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_pktfield =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			pktfield, "pktfield");
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			type, "subport#pipe#tc");
+cmdline_parse_token_num_t cmd_set_port_tm_pktfield_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_offset_string =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			offset_string, "offset");
+cmdline_parse_token_num_t cmd_set_port_tm_pktfield_offset =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			offset, UINT32);
+cmdline_parse_token_string_t cmd_set_port_tm_pktfield_mask_string =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			mask_string, "mask");
+cmdline_parse_token_num_t cmd_set_port_tm_pktfield_mask =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_pktfield_result,
+			mask, UINT64);
+
+static void cmd_set_port_tm_pktfield_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_pktfield_result *res = parsed_result;
+	struct rte_port *p;
+	uint32_t offset = res->offset;
+	uint64_t mask = res->mask;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	p = &ports[port_id];
+
+	/* Port tm flag */
+	if (p->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Subport */
+	if (strcmp(res->type, "subport") == 0) {
+		uint32_t n = p->softport.tm.n_subports_per_port;
+
+		ret = port_tm_pktfield_validate_mask(mask, n);
+		if (ret) {
+			printf(" invalid subport mask(error %d)", ret);
+			return;
+		}
+		/* Set packet field */
+		p->softport.tm.tm_pktfield0_slabpos = offset;
+		p->softport.tm.tm_pktfield0_slabmask = mask;
+		p->softport.tm.tm_pktfield0_slabshr = __builtin_ctzll(mask);
+		return;
+	}
+
+	/* Pipe */
+	if (strcmp(res->type, "pipe") == 0) {
+		uint32_t n = p->softport.tm.n_pipes_per_subport;
+
+		ret = port_tm_pktfield_validate_mask(mask, n);
+		if (ret) {
+			printf(" invalid pipe mask(error %d)", ret);
+			return;
+		}
+		/* Set packet field */
+		p->softport.tm.tm_pktfield1_slabpos = offset;
+		p->softport.tm.tm_pktfield1_slabmask = mask;
+		p->softport.tm.tm_pktfield1_slabshr = __builtin_ctzll(mask);
+		return;
+	}
+
+	/* Traffic class */
+	if (strcmp(res->type, "tc") == 0) {
+		uint32_t n = RTE_DIM(p->softport.tm.tm_tc_table);
+
+		ret = port_tm_pktfield_validate_mask(mask, n);
+		if (ret) {
+			printf(" invalid tc mask(error %d)", ret);
+			return;
+		}
+		/* Set packet field */
+		p->softport.tm.tm_pktfield1_slabpos = offset;
+		p->softport.tm.tm_pktfield1_slabmask = mask;
+		p->softport.tm.tm_pktfield1_slabshr = __builtin_ctzll(mask);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_pktfield = {
+	.f = cmd_set_port_tm_pktfield_parsed,
+	.data = NULL,
+	.help_str = "Set port tm pktfield",
+	.tokens = {
+		(void *)&cmd_set_port_tm_pktfield_set,
+		(void *)&cmd_set_port_tm_pktfield_port,
+		(void *)&cmd_set_port_tm_pktfield_tm,
+		(void *)&cmd_set_port_tm_pktfield_pktfield,
+		(void *)&cmd_set_port_tm_pktfield_type,
+		(void *)&cmd_set_port_tm_pktfield_port_id,
+		(void *)&cmd_set_port_tm_pktfield_offset_string,
+		(void *)&cmd_set_port_tm_pktfield_offset,
+		(void *)&cmd_set_port_tm_pktfield_mask_string,
+		(void *)&cmd_set_port_tm_pktfield_mask,
+		NULL,
+	},
+};
+
+/* *** Set Port TM Traffic Class Table Entry *** */
+struct cmd_set_port_tm_tc_table_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t tc_table;
+	uint8_t port_id;
+	cmdline_fixed_string_t index_string;
+	uint32_t index;
+	cmdline_fixed_string_t tc_string;
+	uint32_t tc;
+	cmdline_fixed_string_t queue_string;
+	uint32_t queue;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result, port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,	tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_tc_table =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			tc_table, "tc table");
+cmdline_parse_token_num_t cmd_set_port_tm_tc_table_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			port_id, UINT8);
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_index_string =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			index_string, "index");
+cmdline_parse_token_num_t cmd_set_port_tm_tc_table_index =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			index, UINT32);
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_tc_string =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			tc_string, "tc");
+cmdline_parse_token_num_t cmd_set_port_tm_tc_table_tc =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			tc, UINT32);
+cmdline_parse_token_string_t cmd_set_port_tm_tc_table_queue_string =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			queue_string, "queue");
+cmdline_parse_token_num_t cmd_set_port_tm_tc_table_queue =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_tc_table_result,
+			queue, UINT32);
+
+static void cmd_set_port_tm_tc_table_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_tc_table_result *res = parsed_result;
+	struct rte_port *p;
+	uint32_t tc = res->tc;
+	uint32_t index = res->index;
+	uint32_t queue = res->queue;
+	uint32_t val;
+	uint8_t port_id = res->port_id;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	p = &ports[port_id];
+
+	/* Port tm flag */
+	if (p->softport.tm_flag == 0) {
+		printf("  tm not enabled on port %u (error)\n", port_id);
+		return;
+	}
+
+	/* Forward mode: tm */
+	if (strcmp(cur_fwd_config.fwd_eng->fwd_mode_name, "tm")) {
+		printf("  tm mode not enabled(error)\n");
+		return;
+	}
+
+	/* Traffic class table index */
+	if (tc >= RTE_DIM(p->softport.tm.tm_tc_table)) {
+		printf("  invalid traffic class table index(error)\n");
+		return;
+	}
+
+	/* Traffic class id */
+	if (tc >= RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE) {
+		printf("  invalid traffic class id(error)\n");
+		return;
+	}
+
+	/* Traffic class queue */
+	if (queue >= RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS) {
+		printf("  invalid traffic class queue(error)\n");
+		return;
+	}
+
+	val = tc * RTE_SCHED_QUEUES_PER_TRAFFIC_CLASS + queue;
+	p->softport.tm.tm_tc_table[index] = val;
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_tc_table = {
+	.f = cmd_set_port_tm_tc_table_parsed,
+	.data = NULL,
+	.help_str = "Set port tm TC table entry",
+	.tokens = {
+		(void *)&cmd_set_port_tm_tc_table_set,
+		(void *)&cmd_set_port_tm_tc_table_port,
+		(void *)&cmd_set_port_tm_tc_table_tm,
+		(void *)&cmd_set_port_tm_tc_table_tc_table,
+		(void *)&cmd_set_port_tm_tc_table_port_id,
+		(void *)&cmd_set_port_tm_tc_table_index_string,
+		(void *)&cmd_set_port_tm_tc_table_index,
+		(void *)&cmd_set_port_tm_tc_table_tc_string,
+		(void *)&cmd_set_port_tm_tc_table_tc,
+		(void *)&cmd_set_port_tm_tc_table_queue_string,
+		(void *)&cmd_set_port_tm_tc_table_queue,
+		NULL,
+	},
+};
+
+#endif
diff --git a/app/test-pmd/testpmd_cmdline.h b/app/test-pmd/testpmd_cmdline.h
index 4fa7cc4..b6ca8c4 100755
--- a/app/test-pmd/testpmd_cmdline.h
+++ b/app/test-pmd/testpmd_cmdline.h
@@ -52,5 +52,9 @@ extern cmdline_parse_inst_t cmd_add_port_tm_leaf_node;
 extern cmdline_parse_inst_t cmd_del_port_tm_node;
 extern cmdline_parse_inst_t cmd_set_port_tm_node_parent;
 extern cmdline_parse_inst_t cmd_port_tm_hierarchy_commit;
+#if defined RTE_LIBRTE_PMD_SOFTNIC && defined RTE_LIBRTE_SCHED
+extern cmdline_parse_inst_t cmd_set_port_tm_pktfield;
+extern cmdline_parse_inst_t cmd_set_port_tm_tc_table;
+#endif
 
 #endif /* _TESTPMD_CMDLINE_H_ */
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v5 1/3] app/test-pmd: add CLI for TM capability and stats
  2017-09-22 16:35       ` [PATCH v4 2/5] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
@ 2017-09-29 12:38         ` Jasvinder Singh
  2017-09-29 12:38           ` [PATCH v5 2/3] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
                             ` (2 more replies)
  0 siblings, 3 replies; 49+ messages in thread
From: Jasvinder Singh @ 2017-09-29 12:38 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu, pablo.de.lara.guarch

Add following CLIs to testpmd application for device traffic management;
- commands to display TM capability information.
  (per port, per hierarchy level and per hierarchy node)
- command to display hiearchy node type
- stats collection

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
v4 change:
 - remove softnic specific checks to make it generic for the devices

v3 change:
- Implements feedback from Pablo[1]
 - move TM API related CLIs into cmdline_tm.c 
 - split patch into small patches
 - replace link status check with testpmd fn port_is_started()

[1]http://dpdk.org/ml/archives/dev/2017-September/075748.html

 app/test-pmd/Makefile          |   1 +
 app/test-pmd/cmdline.c         |  23 +-
 app/test-pmd/cmdline_tm.c      | 654 +++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/testpmd_cmdline.h |  44 +++
 4 files changed, 721 insertions(+), 1 deletion(-)
 create mode 100644 app/test-pmd/cmdline_tm.c
 create mode 100644 app/test-pmd/cmdline_tm.h

diff --git a/app/test-pmd/Makefile b/app/test-pmd/Makefile
index 2c50f68..e4a6352 100644
--- a/app/test-pmd/Makefile
+++ b/app/test-pmd/Makefile
@@ -48,6 +48,7 @@ SRCS-y := testpmd.c
 SRCS-y += parameters.c
 SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline.c
 SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline_flow.c
+SRCS-y += cmdline_tm.c
 SRCS-y += config.c
 SRCS-y += iofwd.c
 SRCS-y += macfwd.c
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 435ee0d..6874d8a 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -99,6 +99,7 @@
 #include <rte_pmd_bnxt.h>
 #endif
 #include "testpmd.h"
+#include "cmdline_tm.h"
 
 static struct cmdline *testpmd_cl;
 
@@ -230,6 +231,21 @@ static void cmd_help_long_parsed(void *parsed_result,
 
 			"clear vf stats (port_id) (vf_id)\n"
 			"    Reset a VF's statistics.\n\n"
+
+			"show port tm cap (port_id)\n"
+			"	Display the port TM capability.\n\n"
+
+			"show port tm level cap (port_id) (level_id)\n"
+			"	Display the port TM hierarchical level capability.\n\n"
+
+			"show port tm node cap (port_id) (node_id)\n"
+			"	Display the port TM node capability.\n\n"
+
+			"show port tm node type (port_id) (node_id)\n"
+			"	Display the port TM node type.\n\n"
+
+			"show port tm node stats (port_id) (node_id) (clear)\n"
+			"	Display the port TM node stats.\n\n"
 		);
 	}
 
@@ -14274,7 +14290,7 @@ cmdline_parse_inst_t cmd_load_from_file = {
 	},
 };
 
-/* ******************************************************************************** */
+/* *********************************************************************** */
 
 /* list of instructions */
 cmdline_parse_ctx_t main_ctx[] = {
@@ -14468,6 +14484,11 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_ptype_mapping_replace,
 	(cmdline_parse_inst_t *)&cmd_ptype_mapping_reset,
 	(cmdline_parse_inst_t *)&cmd_ptype_mapping_update,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_level_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_type,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_stats,
 	NULL,
 };
 
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
new file mode 100644
index 0000000..97582fe
--- /dev/null
+++ b/app/test-pmd/cmdline_tm.c
@@ -0,0 +1,669 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+
+#include <rte_ethdev.h>
+#include <rte_flow.h>
+#include <rte_tm.h>
+
+#include "testpmd.h"
+#include "cmdline_tm.h"
+
+/** Display TM Error Message */
+static void
+print_err_msg(struct rte_tm_error *error)
+{
+	static const char *const errstrlist[] = {
+		[RTE_TM_ERROR_TYPE_NONE] = "no error",
+		[RTE_TM_ERROR_TYPE_UNSPECIFIED] = "cause unspecified",
+		[RTE_TM_ERROR_TYPE_CAPABILITIES]
+			= "capability parameter null",
+		[RTE_TM_ERROR_TYPE_LEVEL_ID] = "level id",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE]
+			= "wred profile null",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_GREEN] = "wred profile(green)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_YELLOW]
+			= "wred profile(yellow)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_RED] = "wred profile(red)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_ID] = "wred profile id",
+		[RTE_TM_ERROR_TYPE_SHARED_WRED_CONTEXT_ID]
+			= "shared wred context id",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE] = "shaper profile null",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE]
+			= "committed rate field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE]
+			= "committed size field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE]
+			= "peak rate field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE]
+			= "peak size field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN]
+			= "packet adjust length field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID] = "shaper profile id",
+		[RTE_TM_ERROR_TYPE_SHARED_SHAPER_ID] = "shared shaper id",
+		[RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID] = "parent node id",
+		[RTE_TM_ERROR_TYPE_NODE_PRIORITY] = "node priority",
+		[RTE_TM_ERROR_TYPE_NODE_WEIGHT] = "node weight",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS] = "node parameter null",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID]
+			= "shaper profile id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID]
+			= "shared shaper id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS]
+			= "num shared shapers field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE]
+			= "wfq weght mode field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES]
+			= "num strict priorities field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN]
+			= "congestion management mode field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID] =
+			"wred profile id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID]
+			= "shared wred context id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS]
+			= "num shared wred contexts field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS]
+			= "stats field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_ID] = "node id",
+	};
+
+	const char *errstr;
+	char buf[64];
+
+	if ((unsigned int)error->type >= RTE_DIM(errstrlist) ||
+		!errstrlist[error->type])
+		errstr = "unknown type";
+	else
+		errstr = errstrlist[error->type];
+
+	if (error->cause)
+		snprintf(buf, sizeof(buf), "cause: %p, ", error->cause);
+
+	printf("%s: %s%s (error %d)\n", errstr, error->cause ? buf : "",
+		error->message ? error->message : "(no stated reason)",
+		error->type);
+}
+
+/* *** Port TM Capability *** */
+struct cmd_show_port_tm_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t cap;
+	uint8_t port_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		 port_id, UINT8);
+
+static void cmd_show_port_tm_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_cap_result *res = parsed_result;
+	struct rte_tm_capabilities cap;
+	struct rte_tm_error error;
+	uint8_t port_id = res->port_id;
+	uint32_t i;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	memset(&cap, 0, sizeof(struct rte_tm_capabilities));
+	ret = rte_tm_capabilities_get(port_id, &cap, &error);
+	if (ret) {
+		print_err_msg(&error);
+		return;
+	}
+
+	printf("\n****   Port TM Capabilities ****\n\n");
+	printf("cap.n_nodes_max %u\n", cap.n_nodes_max);
+	printf("cap.n_levels_max %u\n", cap.n_levels_max);
+	printf("cap.non_leaf_nodes_identical %d\n",
+		cap.non_leaf_nodes_identical);
+	printf("cap.leaf_nodes_identical %d\n", cap.leaf_nodes_identical);
+	printf("cap.shaper_n_max %u\n", cap.shaper_n_max);
+	printf("cap.shaper_private_n_max %u\n", cap.shaper_private_n_max);
+	printf("cap.shaper_private_dual_rate_n_max %d\n",
+		cap.shaper_private_dual_rate_n_max);
+	printf("cap.shaper_private_rate_min %lu\n",
+		cap.shaper_private_rate_min);
+	printf("cap.shaper_private_rate_max %lu\n",
+		cap.shaper_private_rate_max);
+	printf("cap.shaper_shared_n_max %u\n", cap.shaper_shared_n_max);
+	printf("cap.shaper_shared_n_nodes_per_shaper_max %u\n",
+		cap.shaper_shared_n_nodes_per_shaper_max);
+	printf("cap.shaper_shared_n_shapers_per_node_max %u\n",
+		cap.shaper_shared_n_shapers_per_node_max);
+	printf("cap.shaper_shared_dual_rate_n_max %u\n",
+		cap.shaper_shared_dual_rate_n_max);
+	printf("cap.shaper_shared_rate_min %lu\n",
+		cap.shaper_shared_rate_min);
+	printf("cap.shaper_shared_rate_max %lu\n",
+		cap.shaper_shared_rate_max);
+	printf("cap.shaper_pkt_length_adjust_min %d\n",
+		cap.shaper_pkt_length_adjust_min);
+	printf("cap.shaper_pkt_length_adjust_max %d\n",
+		cap.shaper_pkt_length_adjust_max);
+	printf("cap.sched_n_children_max %u\n", cap.sched_n_children_max);
+	printf("cap.sched_sp_n_priorities_max %u\n",
+		cap.sched_sp_n_priorities_max);
+	printf("cap.sched_wfq_n_children_per_group_max %u\n",
+		cap.sched_wfq_n_children_per_group_max);
+	printf("cap.sched_wfq_n_groups_max %u\n", cap.sched_wfq_n_groups_max);
+	printf("cap.sched_wfq_weight_max %u\n", cap.sched_wfq_weight_max);
+	printf("cap.cman_head_drop_supported %d\n",
+		cap.cman_head_drop_supported);
+	printf("cap.cman_wred_context_n_max %u\n", cap.cman_wred_context_n_max);
+	printf("cap.cman_wred_context_private_n_max %u\n",
+		cap.cman_wred_context_private_n_max);
+	printf("cap.cman_wred_context_shared_n_max %u\n",
+		cap.cman_wred_context_shared_n_max);
+	printf("cap.cman_wred_context_shared_n_nodes_per_context_max %u\n",
+		cap.cman_wred_context_shared_n_nodes_per_context_max);
+	printf("cap.cman_wred_context_shared_n_contexts_per_node_max %u\n",
+		cap.cman_wred_context_shared_n_contexts_per_node_max);
+
+	for (i = 0; i < RTE_TM_COLORS; i++) {
+		printf("cap.mark_vlan_dei_supported %d\n",
+			cap.mark_vlan_dei_supported[i]);
+		printf("cap.mark_ip_ecn_tcp_supported %d\n",
+			cap.mark_ip_ecn_tcp_supported[i]);
+		printf("cap.mark_ip_ecn_sctp_supported %d\n",
+			cap.mark_ip_ecn_sctp_supported[i]);
+		printf("cap.mark_ip_dscp_supported %d\n",
+			cap.mark_ip_dscp_supported[i]);
+	}
+
+	printf("cap.dynamic_update_mask %lx\n", cap.dynamic_update_mask);
+	printf("cap.stats_mask %lx\n", cap.stats_mask);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_cap = {
+	.f = cmd_show_port_tm_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_cap_show,
+		(void *)&cmd_show_port_tm_cap_port,
+		(void *)&cmd_show_port_tm_cap_tm,
+		(void *)&cmd_show_port_tm_cap_cap,
+		(void *)&cmd_show_port_tm_cap_port_id,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchical Level Capability *** */
+struct cmd_show_port_tm_level_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t level;
+	cmdline_fixed_string_t cap;
+	uint8_t port_id;
+	uint32_t level_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_level =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		level, "level");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_level_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		 port_id, UINT8);
+cmdline_parse_token_num_t cmd_show_port_tm_level_cap_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		 level_id, UINT32);
+
+
+static void cmd_show_port_tm_level_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_level_cap_result *res = parsed_result;
+	struct rte_tm_level_capabilities lcap;
+	struct rte_tm_error error;
+	uint8_t port_id = res->port_id;
+	int ret, level_id = res->level_id;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	memset(&lcap, 0, sizeof(struct rte_tm_level_capabilities));
+	ret = rte_tm_level_capabilities_get(port_id, level_id, &lcap, &error);
+	if (ret) {
+		print_err_msg(&error);
+		return;
+	}
+	printf("\n****   Port TM Hierarchy level %u Capability ****\n\n",
+		level_id);
+
+	printf("cap.n_nodes_max %u\n", lcap.n_nodes_max);
+	printf("cap.n_nodes_nonleaf_max %u\n", lcap.n_nodes_nonleaf_max);
+	printf("cap.n_nodes_leaf_max %u\n", lcap.n_nodes_leaf_max);
+	printf("cap.non_leaf_nodes_identical %d\n",
+		lcap.non_leaf_nodes_identical);
+	printf("cap.leaf_nodes_identical %d\n", lcap.leaf_nodes_identical);
+	if (level_id <= 3) {
+		printf("cap.nonleaf.shaper_private_supported %d\n",
+			lcap.nonleaf.shaper_private_supported);
+		printf("cap.nonleaf.shaper_private_dual_rate_supported %d\n",
+			lcap.nonleaf.shaper_private_dual_rate_supported);
+		printf("cap.nonleaf.shaper_private_rate_min %lu\n",
+			lcap.nonleaf.shaper_private_rate_min);
+		printf("cap.nonleaf.shaper_private_rate_max %lu\n",
+			lcap.nonleaf.shaper_private_rate_max);
+		printf("cap.nonleaf.shaper_shared_n_max %u\n",
+			lcap.nonleaf.shaper_shared_n_max);
+		printf("cap.nonleaf.sched_n_children_max %u\n",
+			lcap.nonleaf.sched_n_children_max);
+		printf("cap.nonleaf.sched_sp_n_priorities_max %u\n",
+			lcap.nonleaf.sched_sp_n_priorities_max);
+		printf("cap.nonleaf.sched_wfq_n_children_per_group_max %u\n",
+			lcap.nonleaf.sched_wfq_n_children_per_group_max);
+		printf("cap.nonleaf.sched_wfq_n_groups_max %u\n",
+			lcap.nonleaf.sched_wfq_n_groups_max);
+		printf("cap.nonleaf.sched_wfq_weight_max %u\n",
+			lcap.nonleaf.sched_wfq_weight_max);
+		printf("cap.nonleaf.stats_mask %lx\n", lcap.nonleaf.stats_mask);
+	} else {
+		printf("cap.leaf.shaper_private_supported %d\n",
+			lcap.leaf.shaper_private_supported);
+		printf("cap.leaf.shaper_private_dual_rate_supported %d\n",
+			lcap.leaf.shaper_private_dual_rate_supported);
+		printf("cap.leaf.shaper_private_rate_min %lu\n",
+			lcap.leaf.shaper_private_rate_min);
+		printf("cap.leaf.shaper_private_rate_max %lu\n",
+			lcap.leaf.shaper_private_rate_max);
+		printf("cap.leaf.shaper_shared_n_max %u\n",
+			lcap.leaf.shaper_shared_n_max);
+		printf("cap.leaf.cman_head_drop_supported %d\n",
+			lcap.leaf.cman_head_drop_supported);
+		printf("cap.leaf.cman_wred_context_private_supported %d\n",
+			lcap.leaf.cman_wred_context_private_supported);
+		printf("cap.leaf.cman_wred_context_shared_n_max %u\n",
+			lcap.leaf.cman_wred_context_shared_n_max);
+		printf("cap.leaf.stats_mask %lx\n",
+			lcap.leaf.stats_mask);
+	}
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_level_cap = {
+	.f = cmd_show_port_tm_level_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Hierarhical level Capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_level_cap_show,
+		(void *)&cmd_show_port_tm_level_cap_port,
+		(void *)&cmd_show_port_tm_level_cap_tm,
+		(void *)&cmd_show_port_tm_level_cap_level,
+		(void *)&cmd_show_port_tm_level_cap_cap,
+		(void *)&cmd_show_port_tm_level_cap_port_id,
+		(void *)&cmd_show_port_tm_level_cap_level_id,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchy Node Capability *** */
+struct cmd_show_port_tm_node_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t cap;
+	uint8_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_node =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_node_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		 port_id, UINT8);
+cmdline_parse_token_num_t cmd_show_port_tm_node_cap_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		 node_id, UINT32);
+
+static void cmd_show_port_tm_node_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_cap_result *res = parsed_result;
+	struct rte_tm_node_capabilities ncap;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint8_t port_id = res->port_id;
+	int ret, is_leaf = 0;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Node id must be valid */
+	ret = rte_tm_node_type_get(port_id, node_id, &is_leaf, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	memset(&ncap, 0, sizeof(struct rte_tm_node_capabilities));
+	ret = rte_tm_node_capabilities_get(port_id, node_id, &ncap, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+	printf("\n****   Port TM Hierarchy node %u Capability ****\n\n",
+		node_id);
+	printf("cap.shaper_private_supported %d\n",
+		ncap.shaper_private_supported);
+	printf("cap.shaper_private_dual_rate_supported %d\n",
+		ncap.shaper_private_dual_rate_supported);
+	printf("cap.shaper_private_rate_min %lu\n",
+		ncap.shaper_private_rate_min);
+	printf("cap.shaper_private_rate_max %lu\n",
+		ncap.shaper_private_rate_max);
+	printf("cap.shaper_shared_n_max %u\n",
+		ncap.shaper_shared_n_max);
+	if (!is_leaf) {
+		printf("cap.nonleaf.sched_n_children_max %u\n",
+			ncap.nonleaf.sched_n_children_max);
+		printf("cap.nonleaf.sched_sp_n_priorities_max %u\n",
+			ncap.nonleaf.sched_sp_n_priorities_max);
+		printf("cap.nonleaf.sched_wfq_n_children_per_group_max %u\n",
+			ncap.nonleaf.sched_wfq_n_children_per_group_max);
+		printf("cap.nonleaf.sched_wfq_n_groups_max %u\n",
+			ncap.nonleaf.sched_wfq_n_groups_max);
+		printf("cap.nonleaf.sched_wfq_weight_max %u\n",
+			ncap.nonleaf.sched_wfq_weight_max);
+	} else {
+		printf("cap.leaf.cman_head_drop_supported %d\n",
+			ncap.leaf.cman_head_drop_supported);
+		printf("cap.leaf.cman_wred_context_private_supported %d\n",
+			ncap.leaf.cman_wred_context_private_supported);
+		printf("cap.leaf.cman_wred_context_shared_n_max %u\n",
+			ncap.leaf.cman_wred_context_shared_n_max);
+	}
+	printf("cap.stats_mask %lx\n", ncap.stats_mask);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_cap = {
+	.f = cmd_show_port_tm_node_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Hierarchy node capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_cap_show,
+		(void *)&cmd_show_port_tm_node_cap_port,
+		(void *)&cmd_show_port_tm_node_cap_tm,
+		(void *)&cmd_show_port_tm_node_cap_node,
+		(void *)&cmd_show_port_tm_node_cap_cap,
+		(void *)&cmd_show_port_tm_node_cap_port_id,
+		(void *)&cmd_show_port_tm_node_cap_node_id,
+		NULL,
+	},
+};
+
+/* *** Show Port TM Node Statistics *** */
+struct cmd_show_port_tm_node_stats_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t stats;
+	uint8_t port_id;
+	uint32_t node_id;
+	uint32_t clear;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_show =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_stats =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, stats, "stats");
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_stats_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result,
+			node_id, UINT32);
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_clear =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, clear, UINT32);
+
+static void cmd_show_port_tm_node_stats_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_stats_result *res = parsed_result;
+	struct rte_tm_node_stats stats;
+	struct rte_tm_error error;
+	uint64_t stats_mask = 0;
+	uint32_t node_id = res->node_id;
+	uint32_t clear = res->clear;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (!port_is_started(port_id)) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	memset(&stats, 0, sizeof(struct rte_tm_node_stats));
+	ret = rte_tm_node_stats_read(port_id, node_id, &stats,
+			&stats_mask, clear, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	/* Display stats */
+	if (stats_mask & RTE_TM_STATS_N_PKTS)
+		printf("\tPkts scheduled from node: %" PRIu64 "\n",
+			stats.n_pkts);
+	if (stats_mask & RTE_TM_STATS_N_BYTES)
+		printf("\tBytes scheduled from node: %" PRIu64 "\n",
+			stats.n_bytes);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_GREEN_DROPPED)
+		printf("\tPkts dropped (green): %" PRIu64 "\n",
+			stats.leaf.n_pkts_dropped[RTE_TM_GREEN]);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_YELLOW_DROPPED)
+		printf("\tPkts dropped (yellow): %" PRIu64 "\n",
+			stats.leaf.n_pkts_dropped[RTE_TM_YELLOW]);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_RED_DROPPED)
+		printf("\tPkts dropped (red): %" PRIu64 "\n",
+			stats.leaf.n_pkts_dropped[RTE_TM_RED]);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_GREEN_DROPPED)
+		printf("\tBytes dropped (green): %" PRIu64 "\n",
+			stats.leaf.n_bytes_dropped[RTE_TM_GREEN]);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_YELLOW_DROPPED)
+		printf("\tBytes dropped (yellow): %" PRIu64 "\n",
+			stats.leaf.n_bytes_dropped[RTE_TM_YELLOW]);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_RED_DROPPED)
+		printf("\tBytes dropped (red): %" PRIu64 "\n",
+			stats.leaf.n_bytes_dropped[RTE_TM_RED]);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_QUEUED)
+		printf("\tPkts queued: %" PRIu64 "\n",
+			stats.leaf.n_pkts_queued);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_QUEUED)
+		printf("\tBytes queued: %" PRIu64 "\n",
+			stats.leaf.n_bytes_queued);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_stats = {
+	.f = cmd_show_port_tm_node_stats_parsed,
+	.data = NULL,
+	.help_str = "Show port tm node stats",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_stats_show,
+		(void *)&cmd_show_port_tm_node_stats_port,
+		(void *)&cmd_show_port_tm_node_stats_tm,
+		(void *)&cmd_show_port_tm_node_stats_node,
+		(void *)&cmd_show_port_tm_node_stats_stats,
+		(void *)&cmd_show_port_tm_node_stats_port_id,
+		(void *)&cmd_show_port_tm_node_stats_node_id,
+		(void *)&cmd_show_port_tm_node_stats_clear,
+		NULL,
+	},
+};
+
+/* *** Show Port TM Node Type *** */
+struct cmd_show_port_tm_node_type_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t type;
+	uint8_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_show =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, type, "type");
+cmdline_parse_token_num_t cmd_show_port_tm_node_type_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_show_port_tm_node_type_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result,
+			node_id, UINT32);
+
+static void cmd_show_port_tm_node_type_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_type_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint8_t port_id = res->port_id;
+	int ret, is_leaf = 0;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_node_type_get(port_id, node_id, &is_leaf, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	if (is_leaf == 1)
+		printf("leaf node\n");
+	else
+		printf("nonleaf node\n");
+
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_type = {
+	.f = cmd_show_port_tm_node_type_parsed,
+	.data = NULL,
+	.help_str = "Show port tm node type",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_type_show,
+		(void *)&cmd_show_port_tm_node_type_port,
+		(void *)&cmd_show_port_tm_node_type_tm,
+		(void *)&cmd_show_port_tm_node_type_node,
+		(void *)&cmd_show_port_tm_node_type_type,
+		(void *)&cmd_show_port_tm_node_type_port_id,
+		(void *)&cmd_show_port_tm_node_type_node_id,
+		NULL,
+	},
+};
diff --git a/app/test-pmd/cmdline_tm.h b/app/test-pmd/cmdline_tm.h
new file mode 100644
index 0000000..945af89
--- /dev/null
+++ b/app/test-pmd/cmdline_tm.h
@@ -0,0 +1,44 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CMDLINE_TM_H_
+#define _CMDLINE_TM_H_
+
+ /* Traffic Management CLI */
+extern cmdline_parse_inst_t cmd_show_port_tm_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_level_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_type;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_stats;
+
+#endif /* _CMDLINE_TM_H_ */
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v5 2/3] app/test-pmd: add CLI for shaper and wred profiles
  2017-09-29 12:38         ` [PATCH v5 1/3] " Jasvinder Singh
@ 2017-09-29 12:38           ` Jasvinder Singh
  2017-09-29 12:38           ` [PATCH v5 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
  2017-10-09 19:07           ` [PATCH v6 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
  2 siblings, 0 replies; 49+ messages in thread
From: Jasvinder Singh @ 2017-09-29 12:38 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu, pablo.de.lara.guarch

Add following CLIs in testpmd application for device traffic management;
- commands to add/del shaper profile for TM hieraqrchy nodes.
- commands to add/update shared shapers
- commands to add/del WRED profiles for TM hiearchy leaf nodes.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
v5 change:
 - add packet length adjust parameter to add shaper profile command

v4 change:
 - remove softnic specific checks to make it generic for the devices

 app/test-pmd/cmdline.c    |  34 +++
 app/test-pmd/cmdline_tm.c | 748 ++++++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/cmdline_tm.h |   7 +
 3 files changed, 789 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 6874d8a..fe0aefe 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -658,6 +658,33 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"ptype mapping update (port_id) (hw_ptype) (sw_ptype)\n"
 			"    Update a ptype mapping item on a port\n\n"
 
+			"add port tm node shaper profile (port_id) (shaper_profile_id)"
+			" (tb_rate) (tb_size) (packet_length_adjust)\n"
+			"	Add port tm node private shaper profile.\n\n"
+
+			"del port tm node shaper profile (port_id) (shaper_profile_id)\n"
+			"	Delete port tm node private shaper profile.\n\n"
+
+			"add port tm node shared shaper (port_id) (shared_shaper_id)"
+			" (shaper_profile_id)\n"
+			"	Add/update port tm node shared shaper.\n\n"
+
+			"del port tm node shared shaper (port_id) (shared_shaper_id)\n"
+			"	Delete port tm node shared shaper.\n\n"
+
+			"set port tm node shaper profile (port_id) (node_id)"
+			" (shaper_profile_id)\n"
+			"	Set port tm node shaper profile.\n\n"
+
+			"add port tm node wred profile (port_id) (wred_profile_id)"
+			" (color_g) (min_th_g) (max_th_g) (maxp_inv_g) (wq_log2_g)"
+			" (color_y) (min_th_y) (max_th_y) (maxp_inv_y) (wq_log2_y)"
+			" (color_r) (min_th_r) (max_th_r) (maxp_inv_r) (wq_log2_r)\n"
+			"	Add port tm node wred profile.\n\n"
+
+			"del port tm node wred profile (port_id) (wred_profile_id)\n"
+			"	Delete port tm node wred profile.\n\n"
+
 			, list_pkt_forwarding_modes()
 		);
 	}
@@ -14489,6 +14516,13 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_cap,
 	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_type,
 	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_stats,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_shared_shaper,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_shared_shaper,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_wred_profile,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_wred_profile,
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_shaper_profile,
 	NULL,
 };
 
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
index 97582fe..9ca22f0 100644
--- a/app/test-pmd/cmdline_tm.c
+++ b/app/test-pmd/cmdline_tm.c
@@ -667,3 +667,751 @@ cmdline_parse_inst_t cmd_show_port_tm_node_type = {
 		NULL,
 	},
 };
+
+/* *** Add Port TM Private Shaper Profile *** */
+struct cmd_add_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint8_t port_id;
+	uint32_t shaper_id;
+	uint64_t tb_rate;
+	uint64_t tb_size;
+	uint32_t pktlen_adjust;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_tb_rate =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tb_rate, UINT64);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_tb_size =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tb_size, UINT64);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_pktlen_adjust =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			pktlen_adjust, UINT32);
+
+static void cmd_add_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_tm_shaper_params sp;
+	struct rte_tm_error error;
+	uint32_t shaper_id = res->shaper_id;
+	uint32_t pkt_len_adjust = res->pktlen_adjust;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Private shaper profile params */
+	memset(&sp, 0, sizeof(struct rte_tm_shaper_params));
+	sp.peak.rate = res->tb_rate;
+	sp.peak.size = res->tb_size;
+	sp.pkt_length_adjust = pkt_len_adjust;
+
+	ret = rte_tm_shaper_profile_add(port_id, shaper_id, &sp, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_shaper_profile = {
+	.f = cmd_add_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Add port tm node private shaper profile",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_shaper_profile_add,
+		(void *)&cmd_add_port_tm_node_shaper_profile_port,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_add_port_tm_node_shaper_profile_node,
+		(void *)&cmd_add_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_add_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_add_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_add_port_tm_node_shaper_profile_shaper_id,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tb_rate,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tb_size,
+		(void *)&cmd_add_port_tm_node_shaper_profile_pktlen_adjust,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM Private Shaper Profile *** */
+struct cmd_del_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint8_t port_id;
+	uint32_t shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_del_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_del_port_tm_node_shaper_profile_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			shaper_id, UINT32);
+
+static void cmd_del_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t shaper_id = res->shaper_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_shaper_profile_delete(port_id, shaper_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_shaper_profile = {
+	.f = cmd_del_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node private shaper profile",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_shaper_profile_del,
+		(void *)&cmd_del_port_tm_node_shaper_profile_port,
+		(void *)&cmd_del_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_del_port_tm_node_shaper_profile_node,
+		(void *)&cmd_del_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_del_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_del_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_del_port_tm_node_shaper_profile_shaper_id,
+		NULL,
+	},
+};
+
+/* *** Add/Update Port TM shared Shaper *** */
+struct cmd_add_port_tm_node_shared_shaper_result {
+	cmdline_fixed_string_t cmd_type;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shared;
+	cmdline_fixed_string_t shaper;
+	uint8_t port_id;
+	uint32_t shared_shaper_id;
+	uint32_t shaper_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_cmd_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			cmd_type, "add#set");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_shared =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shared, "shared");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shaper, "shaper");
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shared_shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shaper_profile_id, UINT32);
+
+static void cmd_add_port_tm_node_shared_shaper_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_shared_shaper_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t shared_shaper_id = res->shared_shaper_id;
+	uint32_t shaper_profile_id = res->shaper_profile_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Command type: add */
+	if ((strcmp(res->cmd_type, "add") == 0) &&
+		(port_is_started(port_id))) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	/* Command type: set (update) */
+	if ((strcmp(res->cmd_type, "set") == 0) &&
+		(!port_is_started(port_id))) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_shared_shaper_add_update(port_id, shared_shaper_id,
+		shaper_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_shared_shaper = {
+	.f = cmd_add_port_tm_node_shared_shaper_parsed,
+	.data = NULL,
+	.help_str = "add/update port tm node shared shaper",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_shared_shaper_cmd_type,
+		(void *)&cmd_add_port_tm_node_shared_shaper_port,
+		(void *)&cmd_add_port_tm_node_shared_shaper_tm,
+		(void *)&cmd_add_port_tm_node_shared_shaper_node,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shared,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shaper,
+		(void *)&cmd_add_port_tm_node_shared_shaper_port_id,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shared_shaper_id,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shaper_profile_id,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM shared Shaper *** */
+struct cmd_del_port_tm_node_shared_shaper_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shared;
+	cmdline_fixed_string_t shaper;
+	uint8_t port_id;
+	uint32_t shared_shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_shared =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shared, "shared");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shaper, "shaper");
+cmdline_parse_token_num_t cmd_del_port_tm_node_shared_shaper_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_del_port_tm_node_shared_shaper_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shared_shaper_id, UINT32);
+
+static void cmd_del_port_tm_node_shared_shaper_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_shared_shaper_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t shared_shaper_id = res->shared_shaper_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_shared_shaper_delete(port_id, shared_shaper_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper = {
+	.f = cmd_del_port_tm_node_shared_shaper_parsed,
+	.data = NULL,
+	.help_str = "delete port tm node shared shaper",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_shared_shaper_del,
+		(void *)&cmd_del_port_tm_node_shared_shaper_port,
+		(void *)&cmd_del_port_tm_node_shared_shaper_tm,
+		(void *)&cmd_del_port_tm_node_shared_shaper_node,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shared,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shaper,
+		(void *)&cmd_del_port_tm_node_shared_shaper_port_id,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shared_shaper_id,
+		NULL,
+	},
+};
+
+/* *** Add Port TM Node WRED Profile *** */
+struct cmd_add_port_tm_node_wred_profile_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t wred;
+	cmdline_fixed_string_t profile;
+	uint8_t port_id;
+	uint32_t wred_profile_id;
+	cmdline_fixed_string_t color_g;
+	uint16_t min_th_g;
+	uint16_t max_th_g;
+	uint16_t maxp_inv_g;
+	uint16_t wq_log2_g;
+	cmdline_fixed_string_t color_y;
+	uint16_t min_th_y;
+	uint16_t max_th_y;
+	uint16_t maxp_inv_y;
+	uint16_t wq_log2_y;
+	cmdline_fixed_string_t color_r;
+	uint16_t min_th_r;
+	uint16_t max_th_r;
+	uint16_t maxp_inv_r;
+	uint16_t wq_log2_r;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_wred =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, wred, "wred");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wred_profile_id, UINT32);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_g =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_g, "G#g");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_g, UINT16);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_y =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_y, "Y#y");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_y, UINT16);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_r =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_r, "R#r");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_r, UINT16);
+
+
+static void cmd_add_port_tm_node_wred_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_wred_profile_result *res = parsed_result;
+	struct rte_tm_wred_params wp;
+	enum rte_tm_color color;
+	struct rte_tm_error error;
+	uint32_t wred_profile_id = res->wred_profile_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	memset(&wp, 0, sizeof(struct rte_tm_wred_params));
+
+	/* WRED Params  (Green Color)*/
+	if ((strcmp(res->color_g, "G") == 0) ||
+		(strcmp(res->color_g, "g") == 0)) {
+		color = RTE_TM_GREEN;
+		wp.red_params[color].min_th = res->min_th_g;
+		wp.red_params[color].max_th = res->max_th_g;
+		wp.red_params[color].maxp_inv = res->maxp_inv_g;
+		wp.red_params[color].wq_log2 = res->wq_log2_g;
+	} else {
+		printf("WRED profile error(G or g for green color)!\n");
+		return;
+	}
+
+	/* WRED Params  (Yellow Color)*/
+	if ((strcmp(res->color_y, "Y") == 0) ||
+		(strcmp(res->color_y, "y") == 0)) {
+		color = RTE_TM_YELLOW;
+		wp.red_params[color].min_th = res->min_th_y;
+		wp.red_params[color].max_th = res->max_th_y;
+		wp.red_params[color].maxp_inv = res->maxp_inv_y;
+		wp.red_params[color].wq_log2 = res->wq_log2_y;
+	} else {
+		printf("WRED profile error(Y or y for yellow color)!\n");
+		return;
+	}
+
+	/* WRED Params  (Red Color)*/
+	if ((strcmp(res->color_r, "R") == 0) ||
+		(strcmp(res->color_r, "r") == 0)) {
+		color = RTE_TM_RED;
+		wp.red_params[color].min_th = res->min_th_r;
+		wp.red_params[color].max_th = res->max_th_r;
+		wp.red_params[color].maxp_inv = res->maxp_inv_r;
+		wp.red_params[color].wq_log2 = res->wq_log2_r;
+	} else {
+		printf("WRED profile error(R or r for red color)!\n");
+		return;
+	}
+
+	ret = rte_tm_wred_profile_add(port_id, wred_profile_id, &wp, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile = {
+	.f = cmd_add_port_tm_node_wred_profile_parsed,
+	.data = NULL,
+	.help_str = "Add port tm node wred profile",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_wred_profile_add,
+		(void *)&cmd_add_port_tm_node_wred_profile_port,
+		(void *)&cmd_add_port_tm_node_wred_profile_tm,
+		(void *)&cmd_add_port_tm_node_wred_profile_node,
+		(void *)&cmd_add_port_tm_node_wred_profile_wred,
+		(void *)&cmd_add_port_tm_node_wred_profile_profile,
+		(void *)&cmd_add_port_tm_node_wred_profile_port_id,
+		(void *)&cmd_add_port_tm_node_wred_profile_wred_profile_id,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_r,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM node WRED Profile *** */
+struct cmd_del_port_tm_node_wred_profile_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t wred;
+	cmdline_fixed_string_t profile;
+	uint8_t port_id;
+	uint32_t wred_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_wred =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, wred, "wred");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_del_port_tm_node_wred_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_del_port_tm_node_wred_profile_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			wred_profile_id, UINT32);
+
+static void cmd_del_port_tm_node_wred_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_wred_profile_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t wred_profile_id = res->wred_profile_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_wred_profile_delete(port_id, wred_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile = {
+	.f = cmd_del_port_tm_node_wred_profile_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node wred profile",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_wred_profile_del,
+		(void *)&cmd_del_port_tm_node_wred_profile_port,
+		(void *)&cmd_del_port_tm_node_wred_profile_tm,
+		(void *)&cmd_del_port_tm_node_wred_profile_node,
+		(void *)&cmd_del_port_tm_node_wred_profile_wred,
+		(void *)&cmd_del_port_tm_node_wred_profile_profile,
+		(void *)&cmd_del_port_tm_node_wred_profile_port_id,
+		(void *)&cmd_del_port_tm_node_wred_profile_wred_profile_id,
+		NULL,
+	},
+};
+
+/* *** Update Port TM Node Shaper profile *** */
+struct cmd_set_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint8_t port_id;
+	uint32_t node_id;
+	uint32_t shaper_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_set_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_set_port_tm_node_shaper_profile_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_shaper_profile_result,
+		node_id, UINT32);
+cmdline_parse_token_num_t
+	cmd_set_port_tm_node_shaper_shaper_profile_profile_id =
+		TOKEN_NUM_INITIALIZER(
+			struct cmd_set_port_tm_node_shaper_profile_result,
+			shaper_profile_id, UINT32);
+
+static void cmd_set_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint32_t shaper_profile_id = res->shaper_profile_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (!port_is_started(port_id)) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_shaper_update(port_id, node_id,
+		shaper_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile = {
+	.f = cmd_set_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node shaper profile",
+	.tokens = {
+		(void *)&cmd_set_port_tm_node_shaper_profile_set,
+		(void *)&cmd_set_port_tm_node_shaper_profile_port,
+		(void *)&cmd_set_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_set_port_tm_node_shaper_profile_node,
+		(void *)&cmd_set_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_set_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_set_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_set_port_tm_node_shaper_profile_node_id,
+		(void *)&cmd_set_port_tm_node_shaper_shaper_profile_profile_id,
+		NULL,
+	},
+};
diff --git a/app/test-pmd/cmdline_tm.h b/app/test-pmd/cmdline_tm.h
index 945af89..5ed9de0 100644
--- a/app/test-pmd/cmdline_tm.h
+++ b/app/test-pmd/cmdline_tm.h
@@ -40,5 +40,12 @@ extern cmdline_parse_inst_t cmd_show_port_tm_level_cap;
 extern cmdline_parse_inst_t cmd_show_port_tm_node_cap;
 extern cmdline_parse_inst_t cmd_show_port_tm_node_type;
 extern cmdline_parse_inst_t cmd_show_port_tm_node_stats;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_shared_shaper;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile;
+extern cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile;
 
 #endif /* _CMDLINE_TM_H_ */
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v5 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit
  2017-09-29 12:38         ` [PATCH v5 1/3] " Jasvinder Singh
  2017-09-29 12:38           ` [PATCH v5 2/3] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
@ 2017-09-29 12:38           ` Jasvinder Singh
  2017-10-09 19:07           ` [PATCH v6 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
  2 siblings, 0 replies; 49+ messages in thread
From: Jasvinder Singh @ 2017-09-29 12:38 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu, pablo.de.lara.guarch

Add following CLIs in testpmd application for device traffic management;
- commands to add TM hierarchy nodes (leaf and nonleaf).
- command for runtime update of node weight.
- command to commit the TM hierarchy

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
v5 change:
 - add shaper related parameters to leaf node add command

v4 change:
 - remove softnic specific checks to make it generic for the devices

 app/test-pmd/cmdline.c    |  27 +++
 app/test-pmd/cmdline_tm.c | 526 ++++++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/cmdline_tm.h |   5 +
 3 files changed, 558 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index fe0aefe..1ead407 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -685,6 +685,28 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"del port tm node wred profile (port_id) (wred_profile_id)\n"
 			"	Delete port tm node wred profile.\n\n"
 
+			"add port tm nonleaf node (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight) (level_id) (shaper_profile_id)"
+			" (shared_shaper_id) (n_shared_shapers) (n_sp_priorities)"
+			" (stats_mask)\n"
+			"	Add port tm nonleaf node.\n\n"
+
+			"add port tm leaf node (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight) (level_id) (shaper_profile_id)"
+			" (shared_shaper_id) (n_shared_shapers) (n_sp_priorities)"
+			" (cman_mode) (wred_profile_id) (stats_mask)\n"
+			"	Add port tm leaf node.\n\n"
+
+			"del port tm node (port_id) (node_id)\n"
+			"	Delete port tm node.\n\n"
+
+			"set port tm node parent (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight)\n"
+			"	Set port tm node parent.\n\n"
+
+			"port tm hierarchy commit (port_id) (clean_on_fail)\n"
+			"	Commit tm hierarchy.\n\n"
+
 			, list_pkt_forwarding_modes()
 		);
 	}
@@ -14523,6 +14545,11 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_wred_profile,
 	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_wred_profile,
 	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_nonleaf_node,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_leaf_node,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node,
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_parent,
+	(cmdline_parse_inst_t *)&cmd_port_tm_hierarchy_commit,
 	NULL,
 };
 
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
index 9ca22f0..5b569b5 100644
--- a/app/test-pmd/cmdline_tm.c
+++ b/app/test-pmd/cmdline_tm.c
@@ -1415,3 +1415,529 @@ cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile = {
 		NULL,
 	},
 };
+
+/* *** Add Port TM nonleaf node *** */
+struct cmd_add_port_tm_nonleaf_node_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t nonleaf;
+	cmdline_fixed_string_t node;
+	uint8_t port_id;
+	uint32_t node_id;
+	int32_t parent_node_id;
+	uint32_t priority;
+	uint32_t weight;
+	uint32_t level_id;
+	uint32_t shaper_profile_id;
+	uint32_t shared_shaper_id;
+	uint32_t n_shared_shapers;
+	uint32_t n_sp_priorities;
+	uint64_t stats_mask;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_nonleaf =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, nonleaf, "nonleaf");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, node, "node");
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result,
+		 port_id, UINT8);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 node_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 parent_node_id, INT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 priority, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 weight, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 level_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 shaper_profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 shared_shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_n_shared_shapers =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 n_shared_shapers, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_n_sp_priorities =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 n_sp_priorities, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_stats_mask =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 stats_mask, UINT64);
+
+static void cmd_add_port_tm_nonleaf_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_nonleaf_node_result *res = parsed_result;
+	struct rte_tm_error error;
+	struct rte_tm_node_params np;
+	uint32_t parent_node_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	/* Node parameters */
+	if (res->parent_node_id < 0)
+		parent_node_id = UINT32_MAX;
+	else
+		parent_node_id = res->parent_node_id;
+
+	memset(&np, 0, sizeof(struct rte_tm_node_params));
+	np.shaper_profile_id = res->shaper_profile_id;
+	np.n_shared_shapers = res->n_shared_shapers;
+
+	if (np.n_shared_shapers == 1)
+		np.shared_shaper_id[0] = res->shared_shaper_id;
+	else
+		np.shared_shaper_id = NULL;
+
+	np.nonleaf.n_sp_priorities = res->n_sp_priorities;
+	np.stats_mask = res->stats_mask;
+	np.nonleaf.wfq_weight_mode = NULL;
+
+	ret = rte_tm_node_add(port_id, res->node_id, parent_node_id,
+				res->priority, res->weight, res->level_id,
+				&np, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_nonleaf_node = {
+	.f = cmd_add_port_tm_nonleaf_node_parsed,
+	.data = NULL,
+	.help_str = "Add port tm nonleaf node",
+	.tokens = {
+		(void *)&cmd_add_port_tm_nonleaf_node_add,
+		(void *)&cmd_add_port_tm_nonleaf_node_port,
+		(void *)&cmd_add_port_tm_nonleaf_node_tm,
+		(void *)&cmd_add_port_tm_nonleaf_node_nonleaf,
+		(void *)&cmd_add_port_tm_nonleaf_node_node,
+		(void *)&cmd_add_port_tm_nonleaf_node_port_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_node_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_parent_node_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_priority,
+		(void *)&cmd_add_port_tm_nonleaf_node_weight,
+		(void *)&cmd_add_port_tm_nonleaf_node_level_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_shaper_profile_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_shared_shaper_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_n_shared_shapers,
+		(void *)&cmd_add_port_tm_nonleaf_node_n_sp_priorities,
+		(void *)&cmd_add_port_tm_nonleaf_node_stats_mask,
+		NULL,
+	},
+};
+
+/* *** Add Port TM leaf node *** */
+struct cmd_add_port_tm_leaf_node_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t leaf;
+	cmdline_fixed_string_t node;
+	uint8_t port_id;
+	uint32_t node_id;
+	int32_t parent_node_id;
+	uint32_t priority;
+	uint32_t weight;
+	uint32_t level_id;
+	uint32_t shaper_profile_id;
+	uint32_t shared_shaper_id;
+	uint32_t n_shared_shapers;
+	uint32_t cman_mode;
+	uint32_t wred_profile_id;
+	uint64_t stats_mask;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_nonleaf =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, leaf, "leaf");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, node, "node");
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 port_id, UINT8);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 node_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 parent_node_id, INT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 priority, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 weight, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 level_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 shaper_profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 shared_shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_n_shared_shapers =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 n_shared_shapers, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_cman_mode =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 cman_mode, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 wred_profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_stats_mask =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 stats_mask, UINT64);
+
+static void cmd_add_port_tm_leaf_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_leaf_node_result *res = parsed_result;
+	struct rte_tm_error error;
+	struct rte_tm_node_params np;
+	uint32_t parent_node_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	/* Node parameters */
+	if (res->parent_node_id < 0)
+		parent_node_id = UINT32_MAX;
+	else
+		parent_node_id = res->parent_node_id;
+
+	memset(&np, 0, sizeof(struct rte_tm_node_params));
+	np.shaper_profile_id = res->shaper_profile_id;
+	np.n_shared_shapers = res->n_shared_shapers;
+
+	if (np.n_shared_shapers == 1)
+		np.shared_shaper_id[0] = res->shared_shaper_id;
+	else
+		np.shared_shaper_id = NULL;
+
+	np.leaf.cman = res->cman_mode;
+	np.leaf.wred.wred_profile_id = res->wred_profile_id;
+	np.stats_mask = res->stats_mask;
+
+	ret = rte_tm_node_add(port_id, res->node_id, parent_node_id,
+				res->priority, res->weight, res->level_id,
+				&np, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_leaf_node = {
+	.f = cmd_add_port_tm_leaf_node_parsed,
+	.data = NULL,
+	.help_str = "Add port tm leaf node",
+	.tokens = {
+		(void *)&cmd_add_port_tm_leaf_node_add,
+		(void *)&cmd_add_port_tm_leaf_node_port,
+		(void *)&cmd_add_port_tm_leaf_node_tm,
+		(void *)&cmd_add_port_tm_leaf_node_nonleaf,
+		(void *)&cmd_add_port_tm_leaf_node_node,
+		(void *)&cmd_add_port_tm_leaf_node_port_id,
+		(void *)&cmd_add_port_tm_leaf_node_node_id,
+		(void *)&cmd_add_port_tm_leaf_node_parent_node_id,
+		(void *)&cmd_add_port_tm_leaf_node_priority,
+		(void *)&cmd_add_port_tm_leaf_node_weight,
+		(void *)&cmd_add_port_tm_leaf_node_level_id,
+		(void *)&cmd_add_port_tm_leaf_node_shaper_profile_id,
+		(void *)&cmd_add_port_tm_leaf_node_shared_shaper_id,
+		(void *)&cmd_add_port_tm_leaf_node_n_shared_shapers,
+		(void *)&cmd_add_port_tm_leaf_node_cman_mode,
+		(void *)&cmd_add_port_tm_leaf_node_wred_profile_id,
+		(void *)&cmd_add_port_tm_leaf_node_stats_mask,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM Node *** */
+struct cmd_del_port_tm_node_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	uint8_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, node, "node");
+cmdline_parse_token_num_t cmd_del_port_tm_node_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_del_port_tm_node_result,
+		 port_id, UINT8);
+cmdline_parse_token_num_t cmd_del_port_tm_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_del_port_tm_node_result,
+		node_id, UINT32);
+
+static void cmd_del_port_tm_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_delete(port_id, node_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node = {
+	.f = cmd_del_port_tm_node_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_del,
+		(void *)&cmd_del_port_tm_node_port,
+		(void *)&cmd_del_port_tm_node_tm,
+		(void *)&cmd_del_port_tm_node_node,
+		(void *)&cmd_del_port_tm_node_port_id,
+		(void *)&cmd_del_port_tm_node_node_id,
+		NULL,
+	},
+};
+
+/* *** Update Port TM Node Parent *** */
+struct cmd_set_port_tm_node_parent_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t parent;
+	uint8_t port_id;
+	uint32_t node_id;
+	uint32_t parent_id;
+	uint32_t priority;
+	uint32_t weight;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, node, "node");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_parent =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, parent, "parent");
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, port_id, UINT8);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, node_id, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_parent_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		parent_id, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		priority, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		weight, UINT32);
+
+static void cmd_set_port_tm_node_parent_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_node_parent_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint32_t parent_id = res->parent_id;
+	uint32_t priority = res->priority;
+	uint32_t weight = res->weight;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (!port_is_started(port_id)) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_parent_update(port_id, node_id,
+		parent_id, priority, weight, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_node_parent = {
+	.f = cmd_set_port_tm_node_parent_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node parent",
+	.tokens = {
+		(void *)&cmd_set_port_tm_node_parent_set,
+		(void *)&cmd_set_port_tm_node_parent_port,
+		(void *)&cmd_set_port_tm_node_parent_tm,
+		(void *)&cmd_set_port_tm_node_parent_node,
+		(void *)&cmd_set_port_tm_node_parent_parent,
+		(void *)&cmd_set_port_tm_node_parent_port_id,
+		(void *)&cmd_set_port_tm_node_parent_node_id,
+		(void *)&cmd_set_port_tm_node_parent_parent_id,
+		(void *)&cmd_set_port_tm_node_parent_priority,
+		(void *)&cmd_set_port_tm_node_parent_weight,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchy Commit *** */
+struct cmd_port_tm_hierarchy_commit_result {
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t hierarchy;
+	cmdline_fixed_string_t commit;
+	uint8_t port_id;
+	uint32_t clean_on_fail;
+};
+
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, port, "port");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, tm, "tm");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_hierarchy =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result,
+			hierarchy, "hierarchy");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_commit =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, commit, "commit");
+cmdline_parse_token_num_t cmd_port_tm_hierarchy_commit_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result,
+			port_id, UINT8);
+cmdline_parse_token_num_t cmd_port_tm_hierarchy_commit_clean_on_fail =
+	TOKEN_NUM_INITIALIZER(struct cmd_port_tm_hierarchy_commit_result,
+		 clean_on_fail, UINT32);
+
+static void cmd_port_tm_hierarchy_commit_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_port_tm_hierarchy_commit_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t clean_on_fail = res->clean_on_fail;
+	uint8_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_hierarchy_commit(port_id, clean_on_fail, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_port_tm_hierarchy_commit = {
+	.f = cmd_port_tm_hierarchy_commit_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node shaper profile",
+	.tokens = {
+		(void *)&cmd_port_tm_hierarchy_commit_port,
+		(void *)&cmd_port_tm_hierarchy_commit_tm,
+		(void *)&cmd_port_tm_hierarchy_commit_hierarchy,
+		(void *)&cmd_port_tm_hierarchy_commit_commit,
+		(void *)&cmd_port_tm_hierarchy_commit_port_id,
+		(void *)&cmd_port_tm_hierarchy_commit_clean_on_fail,
+		NULL,
+	},
+};
diff --git a/app/test-pmd/cmdline_tm.h b/app/test-pmd/cmdline_tm.h
index 5ed9de0..9d5fdf0 100644
--- a/app/test-pmd/cmdline_tm.h
+++ b/app/test-pmd/cmdline_tm.h
@@ -47,5 +47,10 @@ extern cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper;
 extern cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile;
 extern cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile;
 extern cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_add_port_tm_nonleaf_node;
+extern cmdline_parse_inst_t cmd_add_port_tm_leaf_node;
+extern cmdline_parse_inst_t cmd_del_port_tm_node;
+extern cmdline_parse_inst_t cmd_set_port_tm_node_parent;
+extern cmdline_parse_inst_t cmd_port_tm_hierarchy_commit;
 
 #endif /* _CMDLINE_TM_H_ */
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v6 1/3] app/test-pmd: add CLI for TM capability and stats
  2017-09-29 12:38         ` [PATCH v5 1/3] " Jasvinder Singh
  2017-09-29 12:38           ` [PATCH v5 2/3] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
  2017-09-29 12:38           ` [PATCH v5 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
@ 2017-10-09 19:07           ` Jasvinder Singh
  2017-10-09 19:07             ` [PATCH v6 2/3] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
                               ` (2 more replies)
  2 siblings, 3 replies; 49+ messages in thread
From: Jasvinder Singh @ 2017-10-09 19:07 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu, pablo.de.lara.guarch

Add following CLIs to testpmd application for device traffic management;
- commands to display TM capability information.
  (per port, per hierarchy level and per hierarchy node)
- command to display hiearchy node type
- stats collection

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
v6 change:
- fix compilation warning
- change port_id type to uint16_t

v4 change:
 - remove softnic specific checks to make it generic for the devices

v3 change:
- Implements feedback from Pablo[1]
 - move TM API related CLIs into cmdline_tm.c
 - split patch into small patches
 - replace link status check with testpmd fn port_is_started()

[1]http://dpdk.org/ml/archives/dev/2017-September/075748.html
---
 app/test-pmd/Makefile     |   1 +
 app/test-pmd/cmdline.c    |  20 ++
 app/test-pmd/cmdline_tm.c | 681 ++++++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/cmdline_tm.h |  44 +++
 4 files changed, 746 insertions(+)
 create mode 100644 app/test-pmd/cmdline_tm.c
 create mode 100644 app/test-pmd/cmdline_tm.h

diff --git a/app/test-pmd/Makefile b/app/test-pmd/Makefile
index b6e80dd..b78c73a 100644
--- a/app/test-pmd/Makefile
+++ b/app/test-pmd/Makefile
@@ -48,6 +48,7 @@ SRCS-y := testpmd.c
 SRCS-y += parameters.c
 SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline.c
 SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline_flow.c
+SRCS-y += cmdline_tm.c
 SRCS-y += config.c
 SRCS-y += iofwd.c
 SRCS-y += macfwd.c
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 91766bc..2376f23 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -99,6 +99,7 @@
 #include <rte_pmd_bnxt.h>
 #endif
 #include "testpmd.h"
+#include "cmdline_tm.h"
 
 static struct cmdline *testpmd_cl;
 
@@ -234,6 +235,20 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"show port (port_id) pctype mapping\n"
 			"    Get flow ptype to pctype mapping on a port\n\n"
 
+			"show port tm cap (port_id)\n"
+			"	Display the port TM capability.\n\n"
+
+			"show port tm level cap (port_id) (level_id)\n"
+			"	Display the port TM hierarchical level capability.\n\n"
+
+			"show port tm node cap (port_id) (node_id)\n"
+			"	Display the port TM node capability.\n\n"
+
+			"show port tm node type (port_id) (node_id)\n"
+			"	Display the port TM node type.\n\n"
+
+			"show port tm node stats (port_id) (node_id) (clear)\n"
+			"	Display the port TM node stats.\n\n"
 		);
 	}
 
@@ -14818,6 +14833,11 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_pctype_mapping_get,
 	(cmdline_parse_inst_t *)&cmd_pctype_mapping_reset,
 	(cmdline_parse_inst_t *)&cmd_pctype_mapping_update,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_level_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_type,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_stats,
 	NULL,
 };
 
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
new file mode 100644
index 0000000..f024372
--- /dev/null
+++ b/app/test-pmd/cmdline_tm.c
@@ -0,0 +1,681 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+
+#include <rte_ethdev.h>
+#include <rte_flow.h>
+#include <rte_tm.h>
+
+#include "testpmd.h"
+#include "cmdline_tm.h"
+
+/** Display TM Error Message */
+static void
+print_err_msg(struct rte_tm_error *error)
+{
+	static const char *const errstrlist[] = {
+		[RTE_TM_ERROR_TYPE_NONE] = "no error",
+		[RTE_TM_ERROR_TYPE_UNSPECIFIED] = "cause unspecified",
+		[RTE_TM_ERROR_TYPE_CAPABILITIES]
+			= "capability parameter null",
+		[RTE_TM_ERROR_TYPE_LEVEL_ID] = "level id",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE]
+			= "wred profile null",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_GREEN] = "wred profile(green)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_YELLOW]
+			= "wred profile(yellow)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_RED] = "wred profile(red)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_ID] = "wred profile id",
+		[RTE_TM_ERROR_TYPE_SHARED_WRED_CONTEXT_ID]
+			= "shared wred context id",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE] = "shaper profile null",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE]
+			= "committed rate field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE]
+			= "committed size field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE]
+			= "peak rate field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE]
+			= "peak size field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN]
+			= "packet adjust length field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID] = "shaper profile id",
+		[RTE_TM_ERROR_TYPE_SHARED_SHAPER_ID] = "shared shaper id",
+		[RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID] = "parent node id",
+		[RTE_TM_ERROR_TYPE_NODE_PRIORITY] = "node priority",
+		[RTE_TM_ERROR_TYPE_NODE_WEIGHT] = "node weight",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS] = "node parameter null",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID]
+			= "shaper profile id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID]
+			= "shared shaper id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS]
+			= "num shared shapers field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE]
+			= "wfq weght mode field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES]
+			= "num strict priorities field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN]
+			= "congestion management mode field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID] =
+			"wred profile id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID]
+			= "shared wred context id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS]
+			= "num shared wred contexts field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS]
+			= "stats field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_ID] = "node id",
+	};
+
+	const char *errstr;
+	char buf[64];
+
+	if ((unsigned int)error->type >= RTE_DIM(errstrlist) ||
+		!errstrlist[error->type])
+		errstr = "unknown type";
+	else
+		errstr = errstrlist[error->type];
+
+	if (error->cause)
+		snprintf(buf, sizeof(buf), "cause: %p, ", error->cause);
+
+	printf("%s: %s%s (error %d)\n", errstr, error->cause ? buf : "",
+		error->message ? error->message : "(no stated reason)",
+		error->type);
+}
+
+/* *** Port TM Capability *** */
+struct cmd_show_port_tm_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t cap;
+	uint16_t port_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		 port_id, UINT16);
+
+static void cmd_show_port_tm_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_cap_result *res = parsed_result;
+	struct rte_tm_capabilities cap;
+	struct rte_tm_error error;
+	portid_t port_id = res->port_id;
+	uint32_t i;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	memset(&cap, 0, sizeof(struct rte_tm_capabilities));
+	ret = rte_tm_capabilities_get(port_id, &cap, &error);
+	if (ret) {
+		print_err_msg(&error);
+		return;
+	}
+
+	printf("\n****   Port TM Capabilities ****\n\n");
+	printf("cap.n_nodes_max %" PRIu32 "\n", cap.n_nodes_max);
+	printf("cap.n_levels_max %" PRIu32 "\n", cap.n_levels_max);
+	printf("cap.non_leaf_nodes_identical %" PRId32 "\n",
+		cap.non_leaf_nodes_identical);
+	printf("cap.leaf_nodes_identical %" PRId32 "\n",
+		cap.leaf_nodes_identical);
+	printf("cap.shaper_n_max %u\n", cap.shaper_n_max);
+	printf("cap.shaper_private_n_max %" PRIu32 "\n",
+		cap.shaper_private_n_max);
+	printf("cap.shaper_private_dual_rate_n_max %" PRId32 "\n",
+		cap.shaper_private_dual_rate_n_max);
+	printf("cap.shaper_private_rate_min %" PRIu64 "\n",
+		cap.shaper_private_rate_min);
+	printf("cap.shaper_private_rate_max %" PRIu64 "\n",
+		cap.shaper_private_rate_max);
+	printf("cap.shaper_shared_n_max %" PRIu32 "\n",
+		cap.shaper_shared_n_max);
+	printf("cap.shaper_shared_n_nodes_per_shaper_max %" PRIu32 "\n",
+		cap.shaper_shared_n_nodes_per_shaper_max);
+	printf("cap.shaper_shared_n_shapers_per_node_max %" PRIu32 "\n",
+		cap.shaper_shared_n_shapers_per_node_max);
+	printf("cap.shaper_shared_dual_rate_n_max %" PRIu32 "\n",
+		cap.shaper_shared_dual_rate_n_max);
+	printf("cap.shaper_shared_rate_min %" PRIu64 "\n",
+		cap.shaper_shared_rate_min);
+	printf("cap.shaper_shared_rate_max %" PRIu64 "\n",
+		cap.shaper_shared_rate_max);
+	printf("cap.shaper_pkt_length_adjust_min %" PRId32 "\n",
+		cap.shaper_pkt_length_adjust_min);
+	printf("cap.shaper_pkt_length_adjust_max %" PRId32 "\n",
+		cap.shaper_pkt_length_adjust_max);
+	printf("cap.sched_n_children_max %" PRIu32 "\n",
+		cap.sched_n_children_max);
+	printf("cap.sched_sp_n_priorities_max %" PRIu32 "\n",
+		cap.sched_sp_n_priorities_max);
+	printf("cap.sched_wfq_n_children_per_group_max %" PRIu32 "\n",
+		cap.sched_wfq_n_children_per_group_max);
+	printf("cap.sched_wfq_n_groups_max %" PRIu32 "\n",
+		cap.sched_wfq_n_groups_max);
+	printf("cap.sched_wfq_weight_max %" PRIu32 "\n",
+		cap.sched_wfq_weight_max);
+	printf("cap.cman_head_drop_supported %" PRId32 "\n",
+		cap.cman_head_drop_supported);
+	printf("cap.cman_wred_context_n_max %" PRIu32 "\n",
+		cap.cman_wred_context_n_max);
+	printf("cap.cman_wred_context_private_n_max %" PRIu32 "\n",
+		cap.cman_wred_context_private_n_max);
+	printf("cap.cman_wred_context_shared_n_max %" PRIu32 "\n",
+		cap.cman_wred_context_shared_n_max);
+	printf("cap.cman_wred_context_shared_n_nodes_per_context_max %" PRIu32
+		"\n", cap.cman_wred_context_shared_n_nodes_per_context_max);
+	printf("cap.cman_wred_context_shared_n_contexts_per_node_max %" PRIu32
+		"\n", cap.cman_wred_context_shared_n_contexts_per_node_max);
+
+	for (i = 0; i < RTE_TM_COLORS; i++) {
+		printf("cap.mark_vlan_dei_supported %" PRId32 "\n",
+			cap.mark_vlan_dei_supported[i]);
+		printf("cap.mark_ip_ecn_tcp_supported %" PRId32 "\n",
+			cap.mark_ip_ecn_tcp_supported[i]);
+		printf("cap.mark_ip_ecn_sctp_supported %" PRId32 "\n",
+			cap.mark_ip_ecn_sctp_supported[i]);
+		printf("cap.mark_ip_dscp_supported %" PRId32 "\n",
+			cap.mark_ip_dscp_supported[i]);
+	}
+
+	printf("cap.dynamic_update_mask %" PRIx64 "\n",
+		cap.dynamic_update_mask);
+	printf("cap.stats_mask %" PRIx64 "\n", cap.stats_mask);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_cap = {
+	.f = cmd_show_port_tm_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_cap_show,
+		(void *)&cmd_show_port_tm_cap_port,
+		(void *)&cmd_show_port_tm_cap_tm,
+		(void *)&cmd_show_port_tm_cap_cap,
+		(void *)&cmd_show_port_tm_cap_port_id,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchical Level Capability *** */
+struct cmd_show_port_tm_level_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t level;
+	cmdline_fixed_string_t cap;
+	uint16_t port_id;
+	uint32_t level_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_level =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		level, "level");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_level_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_level_cap_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		 level_id, UINT32);
+
+
+static void cmd_show_port_tm_level_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_level_cap_result *res = parsed_result;
+	struct rte_tm_level_capabilities lcap;
+	struct rte_tm_error error;
+	portid_t port_id = res->port_id;
+	uint32_t level_id = res->level_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	memset(&lcap, 0, sizeof(struct rte_tm_level_capabilities));
+	ret = rte_tm_level_capabilities_get(port_id, level_id, &lcap, &error);
+	if (ret) {
+		print_err_msg(&error);
+		return;
+	}
+	printf("\n**   Port TM Hierarchy level %" PRIu32 " Capability **\n\n",
+		level_id);
+
+	printf("cap.n_nodes_max %" PRIu32 "\n", lcap.n_nodes_max);
+	printf("cap.n_nodes_nonleaf_max %" PRIu32 "\n",
+		lcap.n_nodes_nonleaf_max);
+	printf("cap.n_nodes_leaf_max %" PRIu32 "\n", lcap.n_nodes_leaf_max);
+	printf("cap.non_leaf_nodes_identical %" PRId32 "\n",
+		lcap.non_leaf_nodes_identical);
+	printf("cap.leaf_nodes_identical %" PRId32 "\n",
+		lcap.leaf_nodes_identical);
+	if (level_id <= 3) {
+		printf("cap.nonleaf.shaper_private_supported %" PRId32 "\n",
+			lcap.nonleaf.shaper_private_supported);
+		printf("cap.nonleaf.shaper_private_dual_rate_supported %" PRId32
+			"\n", lcap.nonleaf.shaper_private_dual_rate_supported);
+		printf("cap.nonleaf.shaper_private_rate_min %" PRIu64 "\n",
+			lcap.nonleaf.shaper_private_rate_min);
+		printf("cap.nonleaf.shaper_private_rate_max %" PRIu64 "\n",
+			lcap.nonleaf.shaper_private_rate_max);
+		printf("cap.nonleaf.shaper_shared_n_max %" PRIu32 "\n",
+			lcap.nonleaf.shaper_shared_n_max);
+		printf("cap.nonleaf.sched_n_children_max %" PRIu32 "\n",
+			lcap.nonleaf.sched_n_children_max);
+		printf("cap.nonleaf.sched_sp_n_priorities_max %" PRIu32 "\n",
+			lcap.nonleaf.sched_sp_n_priorities_max);
+		printf("cap.nonleaf.sched_wfq_n_children_per_group_max %" PRIu32
+			"\n", lcap.nonleaf.sched_wfq_n_children_per_group_max);
+		printf("cap.nonleaf.sched_wfq_n_groups_max %" PRIu32 "\n",
+			lcap.nonleaf.sched_wfq_n_groups_max);
+		printf("cap.nonleaf.sched_wfq_weight_max %" PRIu32 "\n",
+			lcap.nonleaf.sched_wfq_weight_max);
+		printf("cap.nonleaf.stats_mask %" PRIx64 "\n",
+			lcap.nonleaf.stats_mask);
+	} else {
+		printf("cap.leaf.shaper_private_supported %" PRId32 "\n",
+			lcap.leaf.shaper_private_supported);
+		printf("cap.leaf.shaper_private_dual_rate_supported %" PRId32
+			"\n", lcap.leaf.shaper_private_dual_rate_supported);
+		printf("cap.leaf.shaper_private_rate_min %" PRIu64 "\n",
+			lcap.leaf.shaper_private_rate_min);
+		printf("cap.leaf.shaper_private_rate_max %" PRIu64 "\n",
+			lcap.leaf.shaper_private_rate_max);
+		printf("cap.leaf.shaper_shared_n_max %" PRIu32 "\n",
+			lcap.leaf.shaper_shared_n_max);
+		printf("cap.leaf.cman_head_drop_supported %" PRId32 "\n",
+			lcap.leaf.cman_head_drop_supported);
+		printf("cap.leaf.cman_wred_context_private_supported %"	PRId32
+			"\n", lcap.leaf.cman_wred_context_private_supported);
+		printf("cap.leaf.cman_wred_context_shared_n_max %" PRIu32 "\n",
+			lcap.leaf.cman_wred_context_shared_n_max);
+		printf("cap.leaf.stats_mask %" PRIx64 "\n",
+			lcap.leaf.stats_mask);
+	}
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_level_cap = {
+	.f = cmd_show_port_tm_level_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Hierarhical level Capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_level_cap_show,
+		(void *)&cmd_show_port_tm_level_cap_port,
+		(void *)&cmd_show_port_tm_level_cap_tm,
+		(void *)&cmd_show_port_tm_level_cap_level,
+		(void *)&cmd_show_port_tm_level_cap_cap,
+		(void *)&cmd_show_port_tm_level_cap_port_id,
+		(void *)&cmd_show_port_tm_level_cap_level_id,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchy Node Capability *** */
+struct cmd_show_port_tm_node_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t cap;
+	uint16_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_node =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_node_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_node_cap_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		 node_id, UINT32);
+
+static void cmd_show_port_tm_node_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_cap_result *res = parsed_result;
+	struct rte_tm_node_capabilities ncap;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	portid_t port_id = res->port_id;
+	int ret, is_leaf = 0;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Node id must be valid */
+	ret = rte_tm_node_type_get(port_id, node_id, &is_leaf, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	memset(&ncap, 0, sizeof(struct rte_tm_node_capabilities));
+	ret = rte_tm_node_capabilities_get(port_id, node_id, &ncap, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+	printf("\n**   Port TM Hierarchy node %" PRIu32 " Capability **\n\n",
+		node_id);
+	printf("cap.shaper_private_supported %" PRId32 "\n",
+		ncap.shaper_private_supported);
+	printf("cap.shaper_private_dual_rate_supported %" PRId32 "\n",
+		ncap.shaper_private_dual_rate_supported);
+	printf("cap.shaper_private_rate_min %" PRIu64 "\n",
+		ncap.shaper_private_rate_min);
+	printf("cap.shaper_private_rate_max %" PRIu64 "\n",
+		ncap.shaper_private_rate_max);
+	printf("cap.shaper_shared_n_max %" PRIu32 "\n",
+		ncap.shaper_shared_n_max);
+	if (!is_leaf) {
+		printf("cap.nonleaf.sched_n_children_max %" PRIu32 "\n",
+			ncap.nonleaf.sched_n_children_max);
+		printf("cap.nonleaf.sched_sp_n_priorities_max %" PRIu32 "\n",
+			ncap.nonleaf.sched_sp_n_priorities_max);
+		printf("cap.nonleaf.sched_wfq_n_children_per_group_max %" PRIu32
+			"\n", ncap.nonleaf.sched_wfq_n_children_per_group_max);
+		printf("cap.nonleaf.sched_wfq_n_groups_max %" PRIu32 "\n",
+			ncap.nonleaf.sched_wfq_n_groups_max);
+		printf("cap.nonleaf.sched_wfq_weight_max %" PRIu32 "\n",
+			ncap.nonleaf.sched_wfq_weight_max);
+	} else {
+		printf("cap.leaf.cman_head_drop_supported %" PRId32 "\n",
+			ncap.leaf.cman_head_drop_supported);
+		printf("cap.leaf.cman_wred_context_private_supported %" PRId32
+			"\n", ncap.leaf.cman_wred_context_private_supported);
+		printf("cap.leaf.cman_wred_context_shared_n_max %" PRIu32 "\n",
+			ncap.leaf.cman_wred_context_shared_n_max);
+	}
+	printf("cap.stats_mask %" PRIx64 "\n", ncap.stats_mask);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_cap = {
+	.f = cmd_show_port_tm_node_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Hierarchy node capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_cap_show,
+		(void *)&cmd_show_port_tm_node_cap_port,
+		(void *)&cmd_show_port_tm_node_cap_tm,
+		(void *)&cmd_show_port_tm_node_cap_node,
+		(void *)&cmd_show_port_tm_node_cap_cap,
+		(void *)&cmd_show_port_tm_node_cap_port_id,
+		(void *)&cmd_show_port_tm_node_cap_node_id,
+		NULL,
+	},
+};
+
+/* *** Show Port TM Node Statistics *** */
+struct cmd_show_port_tm_node_stats_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t stats;
+	uint16_t port_id;
+	uint32_t node_id;
+	uint32_t clear;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_show =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_stats =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, stats, "stats");
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_stats_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result,
+			node_id, UINT32);
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_clear =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, clear, UINT32);
+
+static void cmd_show_port_tm_node_stats_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_stats_result *res = parsed_result;
+	struct rte_tm_node_stats stats;
+	struct rte_tm_error error;
+	uint64_t stats_mask = 0;
+	uint32_t node_id = res->node_id;
+	uint32_t clear = res->clear;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (!port_is_started(port_id)) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	memset(&stats, 0, sizeof(struct rte_tm_node_stats));
+	ret = rte_tm_node_stats_read(port_id, node_id, &stats,
+			&stats_mask, clear, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	/* Display stats */
+	if (stats_mask & RTE_TM_STATS_N_PKTS)
+		printf("\tPkts scheduled from node: %" PRIu64 "\n",
+			stats.n_pkts);
+	if (stats_mask & RTE_TM_STATS_N_BYTES)
+		printf("\tBytes scheduled from node: %" PRIu64 "\n",
+			stats.n_bytes);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_GREEN_DROPPED)
+		printf("\tPkts dropped (green): %" PRIu64 "\n",
+			stats.leaf.n_pkts_dropped[RTE_TM_GREEN]);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_YELLOW_DROPPED)
+		printf("\tPkts dropped (yellow): %" PRIu64 "\n",
+			stats.leaf.n_pkts_dropped[RTE_TM_YELLOW]);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_RED_DROPPED)
+		printf("\tPkts dropped (red): %" PRIu64 "\n",
+			stats.leaf.n_pkts_dropped[RTE_TM_RED]);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_GREEN_DROPPED)
+		printf("\tBytes dropped (green): %" PRIu64 "\n",
+			stats.leaf.n_bytes_dropped[RTE_TM_GREEN]);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_YELLOW_DROPPED)
+		printf("\tBytes dropped (yellow): %" PRIu64 "\n",
+			stats.leaf.n_bytes_dropped[RTE_TM_YELLOW]);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_RED_DROPPED)
+		printf("\tBytes dropped (red): %" PRIu64 "\n",
+			stats.leaf.n_bytes_dropped[RTE_TM_RED]);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_QUEUED)
+		printf("\tPkts queued: %" PRIu64 "\n",
+			stats.leaf.n_pkts_queued);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_QUEUED)
+		printf("\tBytes queued: %" PRIu64 "\n",
+			stats.leaf.n_bytes_queued);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_stats = {
+	.f = cmd_show_port_tm_node_stats_parsed,
+	.data = NULL,
+	.help_str = "Show port tm node stats",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_stats_show,
+		(void *)&cmd_show_port_tm_node_stats_port,
+		(void *)&cmd_show_port_tm_node_stats_tm,
+		(void *)&cmd_show_port_tm_node_stats_node,
+		(void *)&cmd_show_port_tm_node_stats_stats,
+		(void *)&cmd_show_port_tm_node_stats_port_id,
+		(void *)&cmd_show_port_tm_node_stats_node_id,
+		(void *)&cmd_show_port_tm_node_stats_clear,
+		NULL,
+	},
+};
+
+/* *** Show Port TM Node Type *** */
+struct cmd_show_port_tm_node_type_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t type;
+	uint16_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_show =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, type, "type");
+cmdline_parse_token_num_t cmd_show_port_tm_node_type_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_node_type_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result,
+			node_id, UINT32);
+
+static void cmd_show_port_tm_node_type_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_type_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	portid_t port_id = res->port_id;
+	int ret, is_leaf = 0;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_node_type_get(port_id, node_id, &is_leaf, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	if (is_leaf == 1)
+		printf("leaf node\n");
+	else
+		printf("nonleaf node\n");
+
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_type = {
+	.f = cmd_show_port_tm_node_type_parsed,
+	.data = NULL,
+	.help_str = "Show port tm node type",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_type_show,
+		(void *)&cmd_show_port_tm_node_type_port,
+		(void *)&cmd_show_port_tm_node_type_tm,
+		(void *)&cmd_show_port_tm_node_type_node,
+		(void *)&cmd_show_port_tm_node_type_type,
+		(void *)&cmd_show_port_tm_node_type_port_id,
+		(void *)&cmd_show_port_tm_node_type_node_id,
+		NULL,
+	},
+};
diff --git a/app/test-pmd/cmdline_tm.h b/app/test-pmd/cmdline_tm.h
new file mode 100644
index 0000000..945af89
--- /dev/null
+++ b/app/test-pmd/cmdline_tm.h
@@ -0,0 +1,44 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CMDLINE_TM_H_
+#define _CMDLINE_TM_H_
+
+ /* Traffic Management CLI */
+extern cmdline_parse_inst_t cmd_show_port_tm_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_level_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_type;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_stats;
+
+#endif /* _CMDLINE_TM_H_ */
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v6 2/3] app/test-pmd: add CLI for shaper and wred profiles
  2017-10-09 19:07           ` [PATCH v6 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
@ 2017-10-09 19:07             ` Jasvinder Singh
  2017-10-09 19:07             ` [PATCH v6 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
  2017-10-11  9:26             ` [PATCH v7 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
  2 siblings, 0 replies; 49+ messages in thread
From: Jasvinder Singh @ 2017-10-09 19:07 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu, pablo.de.lara.guarch

Add following CLIs in testpmd application for device traffic management;
- commands to add/del shaper profile for TM hieraqrchy nodes.
- commands to add/update shared shapers
- commands to add/del WRED profiles for TM hiearchy leaf nodes.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
v6 change:
- change port id type to uint16_t
 
v5 change:
- add packet length adjust parameter to add shaper profile command

v4 change:
- remove softnic specific checks to make it generic for the devices

 app/test-pmd/cmdline.c    |  34 +++
 app/test-pmd/cmdline_tm.c | 748 ++++++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/cmdline_tm.h |   7 +
 3 files changed, 789 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 2376f23..d89583c 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -656,6 +656,33 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"ptype mapping update (port_id) (hw_ptype) (sw_ptype)\n"
 			"    Update a ptype mapping item on a port\n\n"
 
+			"add port tm node shaper profile (port_id) (shaper_profile_id)"
+			" (tb_rate) (tb_size) (packet_length_adjust)\n"
+			"	Add port tm node private shaper profile.\n\n"
+
+			"del port tm node shaper profile (port_id) (shaper_profile_id)\n"
+			"	Delete port tm node private shaper profile.\n\n"
+
+			"add port tm node shared shaper (port_id) (shared_shaper_id)"
+			" (shaper_profile_id)\n"
+			"	Add/update port tm node shared shaper.\n\n"
+
+			"del port tm node shared shaper (port_id) (shared_shaper_id)\n"
+			"	Delete port tm node shared shaper.\n\n"
+
+			"set port tm node shaper profile (port_id) (node_id)"
+			" (shaper_profile_id)\n"
+			"	Set port tm node shaper profile.\n\n"
+
+			"add port tm node wred profile (port_id) (wred_profile_id)"
+			" (color_g) (min_th_g) (max_th_g) (maxp_inv_g) (wq_log2_g)"
+			" (color_y) (min_th_y) (max_th_y) (maxp_inv_y) (wq_log2_y)"
+			" (color_r) (min_th_r) (max_th_r) (maxp_inv_r) (wq_log2_r)\n"
+			"	Add port tm node wred profile.\n\n"
+
+			"del port tm node wred profile (port_id) (wred_profile_id)\n"
+			"	Delete port tm node wred profile.\n\n"
+
 			, list_pkt_forwarding_modes()
 		);
 	}
@@ -14838,6 +14865,13 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_cap,
 	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_type,
 	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_stats,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_shared_shaper,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_shared_shaper,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_wred_profile,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_wred_profile,
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_shaper_profile,
 	NULL,
 };
 
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
index f024372..f1cd810 100644
--- a/app/test-pmd/cmdline_tm.c
+++ b/app/test-pmd/cmdline_tm.c
@@ -679,3 +679,751 @@ cmdline_parse_inst_t cmd_show_port_tm_node_type = {
 		NULL,
 	},
 };
+
+/* *** Add Port TM Private Shaper Profile *** */
+struct cmd_add_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint16_t port_id;
+	uint32_t shaper_id;
+	uint64_t tb_rate;
+	uint64_t tb_size;
+	uint32_t pktlen_adjust;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_tb_rate =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tb_rate, UINT64);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_tb_size =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tb_size, UINT64);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_pktlen_adjust =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			pktlen_adjust, UINT32);
+
+static void cmd_add_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_tm_shaper_params sp;
+	struct rte_tm_error error;
+	uint32_t shaper_id = res->shaper_id;
+	uint32_t pkt_len_adjust = res->pktlen_adjust;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Private shaper profile params */
+	memset(&sp, 0, sizeof(struct rte_tm_shaper_params));
+	sp.peak.rate = res->tb_rate;
+	sp.peak.size = res->tb_size;
+	sp.pkt_length_adjust = pkt_len_adjust;
+
+	ret = rte_tm_shaper_profile_add(port_id, shaper_id, &sp, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_shaper_profile = {
+	.f = cmd_add_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Add port tm node private shaper profile",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_shaper_profile_add,
+		(void *)&cmd_add_port_tm_node_shaper_profile_port,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_add_port_tm_node_shaper_profile_node,
+		(void *)&cmd_add_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_add_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_add_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_add_port_tm_node_shaper_profile_shaper_id,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tb_rate,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tb_size,
+		(void *)&cmd_add_port_tm_node_shaper_profile_pktlen_adjust,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM Private Shaper Profile *** */
+struct cmd_del_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint16_t port_id;
+	uint32_t shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_del_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_tm_node_shaper_profile_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			shaper_id, UINT32);
+
+static void cmd_del_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t shaper_id = res->shaper_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_shaper_profile_delete(port_id, shaper_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_shaper_profile = {
+	.f = cmd_del_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node private shaper profile",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_shaper_profile_del,
+		(void *)&cmd_del_port_tm_node_shaper_profile_port,
+		(void *)&cmd_del_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_del_port_tm_node_shaper_profile_node,
+		(void *)&cmd_del_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_del_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_del_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_del_port_tm_node_shaper_profile_shaper_id,
+		NULL,
+	},
+};
+
+/* *** Add/Update Port TM shared Shaper *** */
+struct cmd_add_port_tm_node_shared_shaper_result {
+	cmdline_fixed_string_t cmd_type;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shared;
+	cmdline_fixed_string_t shaper;
+	uint16_t port_id;
+	uint32_t shared_shaper_id;
+	uint32_t shaper_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_cmd_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			cmd_type, "add#set");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_shared =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shared, "shared");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shaper, "shaper");
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shared_shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shaper_profile_id, UINT32);
+
+static void cmd_add_port_tm_node_shared_shaper_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_shared_shaper_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t shared_shaper_id = res->shared_shaper_id;
+	uint32_t shaper_profile_id = res->shaper_profile_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Command type: add */
+	if ((strcmp(res->cmd_type, "add") == 0) &&
+		(port_is_started(port_id))) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	/* Command type: set (update) */
+	if ((strcmp(res->cmd_type, "set") == 0) &&
+		(!port_is_started(port_id))) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_shared_shaper_add_update(port_id, shared_shaper_id,
+		shaper_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_shared_shaper = {
+	.f = cmd_add_port_tm_node_shared_shaper_parsed,
+	.data = NULL,
+	.help_str = "add/update port tm node shared shaper",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_shared_shaper_cmd_type,
+		(void *)&cmd_add_port_tm_node_shared_shaper_port,
+		(void *)&cmd_add_port_tm_node_shared_shaper_tm,
+		(void *)&cmd_add_port_tm_node_shared_shaper_node,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shared,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shaper,
+		(void *)&cmd_add_port_tm_node_shared_shaper_port_id,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shared_shaper_id,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shaper_profile_id,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM shared Shaper *** */
+struct cmd_del_port_tm_node_shared_shaper_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shared;
+	cmdline_fixed_string_t shaper;
+	uint16_t port_id;
+	uint32_t shared_shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_shared =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shared, "shared");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shaper, "shaper");
+cmdline_parse_token_num_t cmd_del_port_tm_node_shared_shaper_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_tm_node_shared_shaper_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shared_shaper_id, UINT32);
+
+static void cmd_del_port_tm_node_shared_shaper_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_shared_shaper_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t shared_shaper_id = res->shared_shaper_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_shared_shaper_delete(port_id, shared_shaper_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper = {
+	.f = cmd_del_port_tm_node_shared_shaper_parsed,
+	.data = NULL,
+	.help_str = "delete port tm node shared shaper",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_shared_shaper_del,
+		(void *)&cmd_del_port_tm_node_shared_shaper_port,
+		(void *)&cmd_del_port_tm_node_shared_shaper_tm,
+		(void *)&cmd_del_port_tm_node_shared_shaper_node,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shared,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shaper,
+		(void *)&cmd_del_port_tm_node_shared_shaper_port_id,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shared_shaper_id,
+		NULL,
+	},
+};
+
+/* *** Add Port TM Node WRED Profile *** */
+struct cmd_add_port_tm_node_wred_profile_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t wred;
+	cmdline_fixed_string_t profile;
+	uint16_t port_id;
+	uint32_t wred_profile_id;
+	cmdline_fixed_string_t color_g;
+	uint16_t min_th_g;
+	uint16_t max_th_g;
+	uint16_t maxp_inv_g;
+	uint16_t wq_log2_g;
+	cmdline_fixed_string_t color_y;
+	uint16_t min_th_y;
+	uint16_t max_th_y;
+	uint16_t maxp_inv_y;
+	uint16_t wq_log2_y;
+	cmdline_fixed_string_t color_r;
+	uint16_t min_th_r;
+	uint16_t max_th_r;
+	uint16_t maxp_inv_r;
+	uint16_t wq_log2_r;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_wred =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, wred, "wred");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wred_profile_id, UINT32);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_g =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_g, "G#g");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_g, UINT16);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_y =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_y, "Y#y");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_y, UINT16);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_r =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_r, "R#r");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_r, UINT16);
+
+
+static void cmd_add_port_tm_node_wred_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_wred_profile_result *res = parsed_result;
+	struct rte_tm_wred_params wp;
+	enum rte_tm_color color;
+	struct rte_tm_error error;
+	uint32_t wred_profile_id = res->wred_profile_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	memset(&wp, 0, sizeof(struct rte_tm_wred_params));
+
+	/* WRED Params  (Green Color)*/
+	if ((strcmp(res->color_g, "G") == 0) ||
+		(strcmp(res->color_g, "g") == 0)) {
+		color = RTE_TM_GREEN;
+		wp.red_params[color].min_th = res->min_th_g;
+		wp.red_params[color].max_th = res->max_th_g;
+		wp.red_params[color].maxp_inv = res->maxp_inv_g;
+		wp.red_params[color].wq_log2 = res->wq_log2_g;
+	} else {
+		printf("WRED profile error(G or g for green color)!\n");
+		return;
+	}
+
+	/* WRED Params  (Yellow Color)*/
+	if ((strcmp(res->color_y, "Y") == 0) ||
+		(strcmp(res->color_y, "y") == 0)) {
+		color = RTE_TM_YELLOW;
+		wp.red_params[color].min_th = res->min_th_y;
+		wp.red_params[color].max_th = res->max_th_y;
+		wp.red_params[color].maxp_inv = res->maxp_inv_y;
+		wp.red_params[color].wq_log2 = res->wq_log2_y;
+	} else {
+		printf("WRED profile error(Y or y for yellow color)!\n");
+		return;
+	}
+
+	/* WRED Params  (Red Color)*/
+	if ((strcmp(res->color_r, "R") == 0) ||
+		(strcmp(res->color_r, "r") == 0)) {
+		color = RTE_TM_RED;
+		wp.red_params[color].min_th = res->min_th_r;
+		wp.red_params[color].max_th = res->max_th_r;
+		wp.red_params[color].maxp_inv = res->maxp_inv_r;
+		wp.red_params[color].wq_log2 = res->wq_log2_r;
+	} else {
+		printf("WRED profile error(R or r for red color)!\n");
+		return;
+	}
+
+	ret = rte_tm_wred_profile_add(port_id, wred_profile_id, &wp, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile = {
+	.f = cmd_add_port_tm_node_wred_profile_parsed,
+	.data = NULL,
+	.help_str = "Add port tm node wred profile",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_wred_profile_add,
+		(void *)&cmd_add_port_tm_node_wred_profile_port,
+		(void *)&cmd_add_port_tm_node_wred_profile_tm,
+		(void *)&cmd_add_port_tm_node_wred_profile_node,
+		(void *)&cmd_add_port_tm_node_wred_profile_wred,
+		(void *)&cmd_add_port_tm_node_wred_profile_profile,
+		(void *)&cmd_add_port_tm_node_wred_profile_port_id,
+		(void *)&cmd_add_port_tm_node_wred_profile_wred_profile_id,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_r,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM node WRED Profile *** */
+struct cmd_del_port_tm_node_wred_profile_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t wred;
+	cmdline_fixed_string_t profile;
+	uint16_t port_id;
+	uint32_t wred_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_wred =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, wred, "wred");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_del_port_tm_node_wred_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_tm_node_wred_profile_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			wred_profile_id, UINT32);
+
+static void cmd_del_port_tm_node_wred_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_wred_profile_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t wred_profile_id = res->wred_profile_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_wred_profile_delete(port_id, wred_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile = {
+	.f = cmd_del_port_tm_node_wred_profile_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node wred profile",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_wred_profile_del,
+		(void *)&cmd_del_port_tm_node_wred_profile_port,
+		(void *)&cmd_del_port_tm_node_wred_profile_tm,
+		(void *)&cmd_del_port_tm_node_wred_profile_node,
+		(void *)&cmd_del_port_tm_node_wred_profile_wred,
+		(void *)&cmd_del_port_tm_node_wred_profile_profile,
+		(void *)&cmd_del_port_tm_node_wred_profile_port_id,
+		(void *)&cmd_del_port_tm_node_wred_profile_wred_profile_id,
+		NULL,
+	},
+};
+
+/* *** Update Port TM Node Shaper profile *** */
+struct cmd_set_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint16_t port_id;
+	uint32_t node_id;
+	uint32_t shaper_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_set_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_set_port_tm_node_shaper_profile_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_shaper_profile_result,
+		node_id, UINT32);
+cmdline_parse_token_num_t
+	cmd_set_port_tm_node_shaper_shaper_profile_profile_id =
+		TOKEN_NUM_INITIALIZER(
+			struct cmd_set_port_tm_node_shaper_profile_result,
+			shaper_profile_id, UINT32);
+
+static void cmd_set_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint32_t shaper_profile_id = res->shaper_profile_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (!port_is_started(port_id)) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_shaper_update(port_id, node_id,
+		shaper_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile = {
+	.f = cmd_set_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node shaper profile",
+	.tokens = {
+		(void *)&cmd_set_port_tm_node_shaper_profile_set,
+		(void *)&cmd_set_port_tm_node_shaper_profile_port,
+		(void *)&cmd_set_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_set_port_tm_node_shaper_profile_node,
+		(void *)&cmd_set_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_set_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_set_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_set_port_tm_node_shaper_profile_node_id,
+		(void *)&cmd_set_port_tm_node_shaper_shaper_profile_profile_id,
+		NULL,
+	},
+};
diff --git a/app/test-pmd/cmdline_tm.h b/app/test-pmd/cmdline_tm.h
index 945af89..5ed9de0 100644
--- a/app/test-pmd/cmdline_tm.h
+++ b/app/test-pmd/cmdline_tm.h
@@ -40,5 +40,12 @@ extern cmdline_parse_inst_t cmd_show_port_tm_level_cap;
 extern cmdline_parse_inst_t cmd_show_port_tm_node_cap;
 extern cmdline_parse_inst_t cmd_show_port_tm_node_type;
 extern cmdline_parse_inst_t cmd_show_port_tm_node_stats;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_shared_shaper;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile;
+extern cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile;
 
 #endif /* _CMDLINE_TM_H_ */
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v6 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit
  2017-10-09 19:07           ` [PATCH v6 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
  2017-10-09 19:07             ` [PATCH v6 2/3] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
@ 2017-10-09 19:07             ` Jasvinder Singh
  2017-10-11  8:40               ` Pei, Yulong
  2017-10-11  9:26             ` [PATCH v7 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
  2 siblings, 1 reply; 49+ messages in thread
From: Jasvinder Singh @ 2017-10-09 19:07 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu, pablo.de.lara.guarch

Add following CLIs in testpmd application for device traffic management;
- commands to add TM hierarchy nodes (leaf and nonleaf).
- command for runtime update of node weight.
- command to commit the TM hierarchy

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
v5 change:
- add shaper related parameters to leaf node add command

v4 change:
- remove softnic specific checks to make it generic for the devices

 app/test-pmd/cmdline.c    |  27 +++
 app/test-pmd/cmdline_tm.c | 526 ++++++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/cmdline_tm.h |   5 +
 3 files changed, 558 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index d89583c..c6b35ba 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -683,6 +683,28 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"del port tm node wred profile (port_id) (wred_profile_id)\n"
 			"	Delete port tm node wred profile.\n\n"
 
+			"add port tm nonleaf node (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight) (level_id) (shaper_profile_id)"
+			" (shared_shaper_id) (n_shared_shapers) (n_sp_priorities)"
+			" (stats_mask)\n"
+			"	Add port tm nonleaf node.\n\n"
+
+			"add port tm leaf node (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight) (level_id) (shaper_profile_id)"
+			" (shared_shaper_id) (n_shared_shapers) (n_sp_priorities)"
+			" (cman_mode) (wred_profile_id) (stats_mask)\n"
+			"	Add port tm leaf node.\n\n"
+
+			"del port tm node (port_id) (node_id)\n"
+			"	Delete port tm node.\n\n"
+
+			"set port tm node parent (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight)\n"
+			"	Set port tm node parent.\n\n"
+
+			"port tm hierarchy commit (port_id) (clean_on_fail)\n"
+			"	Commit tm hierarchy.\n\n"
+
 			, list_pkt_forwarding_modes()
 		);
 	}
@@ -14872,6 +14894,11 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_wred_profile,
 	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_wred_profile,
 	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_nonleaf_node,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_leaf_node,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node,
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_parent,
+	(cmdline_parse_inst_t *)&cmd_port_tm_hierarchy_commit,
 	NULL,
 };
 
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
index f1cd810..a8b7c20 100644
--- a/app/test-pmd/cmdline_tm.c
+++ b/app/test-pmd/cmdline_tm.c
@@ -1427,3 +1427,529 @@ cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile = {
 		NULL,
 	},
 };
+
+/* *** Add Port TM nonleaf node *** */
+struct cmd_add_port_tm_nonleaf_node_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t nonleaf;
+	cmdline_fixed_string_t node;
+	uint16_t port_id;
+	uint32_t node_id;
+	int32_t parent_node_id;
+	uint32_t priority;
+	uint32_t weight;
+	uint32_t level_id;
+	uint32_t shaper_profile_id;
+	uint32_t shared_shaper_id;
+	uint32_t n_shared_shapers;
+	uint32_t n_sp_priorities;
+	uint64_t stats_mask;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_nonleaf =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, nonleaf, "nonleaf");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, node, "node");
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 node_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 parent_node_id, INT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 priority, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 weight, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 level_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 shaper_profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 shared_shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_n_shared_shapers =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 n_shared_shapers, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_n_sp_priorities =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 n_sp_priorities, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_stats_mask =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 stats_mask, UINT64);
+
+static void cmd_add_port_tm_nonleaf_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_nonleaf_node_result *res = parsed_result;
+	struct rte_tm_error error;
+	struct rte_tm_node_params np;
+	uint32_t parent_node_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	/* Node parameters */
+	if (res->parent_node_id < 0)
+		parent_node_id = UINT32_MAX;
+	else
+		parent_node_id = res->parent_node_id;
+
+	memset(&np, 0, sizeof(struct rte_tm_node_params));
+	np.shaper_profile_id = res->shaper_profile_id;
+	np.n_shared_shapers = res->n_shared_shapers;
+
+	if (np.n_shared_shapers == 1)
+		np.shared_shaper_id[0] = res->shared_shaper_id;
+	else
+		np.shared_shaper_id = NULL;
+
+	np.nonleaf.n_sp_priorities = res->n_sp_priorities;
+	np.stats_mask = res->stats_mask;
+	np.nonleaf.wfq_weight_mode = NULL;
+
+	ret = rte_tm_node_add(port_id, res->node_id, parent_node_id,
+				res->priority, res->weight, res->level_id,
+				&np, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_nonleaf_node = {
+	.f = cmd_add_port_tm_nonleaf_node_parsed,
+	.data = NULL,
+	.help_str = "Add port tm nonleaf node",
+	.tokens = {
+		(void *)&cmd_add_port_tm_nonleaf_node_add,
+		(void *)&cmd_add_port_tm_nonleaf_node_port,
+		(void *)&cmd_add_port_tm_nonleaf_node_tm,
+		(void *)&cmd_add_port_tm_nonleaf_node_nonleaf,
+		(void *)&cmd_add_port_tm_nonleaf_node_node,
+		(void *)&cmd_add_port_tm_nonleaf_node_port_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_node_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_parent_node_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_priority,
+		(void *)&cmd_add_port_tm_nonleaf_node_weight,
+		(void *)&cmd_add_port_tm_nonleaf_node_level_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_shaper_profile_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_shared_shaper_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_n_shared_shapers,
+		(void *)&cmd_add_port_tm_nonleaf_node_n_sp_priorities,
+		(void *)&cmd_add_port_tm_nonleaf_node_stats_mask,
+		NULL,
+	},
+};
+
+/* *** Add Port TM leaf node *** */
+struct cmd_add_port_tm_leaf_node_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t leaf;
+	cmdline_fixed_string_t node;
+	uint16_t port_id;
+	uint32_t node_id;
+	int32_t parent_node_id;
+	uint32_t priority;
+	uint32_t weight;
+	uint32_t level_id;
+	uint32_t shaper_profile_id;
+	uint32_t shared_shaper_id;
+	uint32_t n_shared_shapers;
+	uint32_t cman_mode;
+	uint32_t wred_profile_id;
+	uint64_t stats_mask;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_nonleaf =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, leaf, "leaf");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, node, "node");
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 node_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 parent_node_id, INT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 priority, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 weight, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 level_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 shaper_profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 shared_shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_n_shared_shapers =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 n_shared_shapers, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_cman_mode =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 cman_mode, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 wred_profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_stats_mask =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 stats_mask, UINT64);
+
+static void cmd_add_port_tm_leaf_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_leaf_node_result *res = parsed_result;
+	struct rte_tm_error error;
+	struct rte_tm_node_params np;
+	uint32_t parent_node_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	/* Node parameters */
+	if (res->parent_node_id < 0)
+		parent_node_id = UINT32_MAX;
+	else
+		parent_node_id = res->parent_node_id;
+
+	memset(&np, 0, sizeof(struct rte_tm_node_params));
+	np.shaper_profile_id = res->shaper_profile_id;
+	np.n_shared_shapers = res->n_shared_shapers;
+
+	if (np.n_shared_shapers == 1)
+		np.shared_shaper_id[0] = res->shared_shaper_id;
+	else
+		np.shared_shaper_id = NULL;
+
+	np.leaf.cman = res->cman_mode;
+	np.leaf.wred.wred_profile_id = res->wred_profile_id;
+	np.stats_mask = res->stats_mask;
+
+	ret = rte_tm_node_add(port_id, res->node_id, parent_node_id,
+				res->priority, res->weight, res->level_id,
+				&np, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_leaf_node = {
+	.f = cmd_add_port_tm_leaf_node_parsed,
+	.data = NULL,
+	.help_str = "Add port tm leaf node",
+	.tokens = {
+		(void *)&cmd_add_port_tm_leaf_node_add,
+		(void *)&cmd_add_port_tm_leaf_node_port,
+		(void *)&cmd_add_port_tm_leaf_node_tm,
+		(void *)&cmd_add_port_tm_leaf_node_nonleaf,
+		(void *)&cmd_add_port_tm_leaf_node_node,
+		(void *)&cmd_add_port_tm_leaf_node_port_id,
+		(void *)&cmd_add_port_tm_leaf_node_node_id,
+		(void *)&cmd_add_port_tm_leaf_node_parent_node_id,
+		(void *)&cmd_add_port_tm_leaf_node_priority,
+		(void *)&cmd_add_port_tm_leaf_node_weight,
+		(void *)&cmd_add_port_tm_leaf_node_level_id,
+		(void *)&cmd_add_port_tm_leaf_node_shaper_profile_id,
+		(void *)&cmd_add_port_tm_leaf_node_shared_shaper_id,
+		(void *)&cmd_add_port_tm_leaf_node_n_shared_shapers,
+		(void *)&cmd_add_port_tm_leaf_node_cman_mode,
+		(void *)&cmd_add_port_tm_leaf_node_wred_profile_id,
+		(void *)&cmd_add_port_tm_leaf_node_stats_mask,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM Node *** */
+struct cmd_del_port_tm_node_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	uint16_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, node, "node");
+cmdline_parse_token_num_t cmd_del_port_tm_node_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_del_port_tm_node_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_tm_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_del_port_tm_node_result,
+		node_id, UINT32);
+
+static void cmd_del_port_tm_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_delete(port_id, node_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node = {
+	.f = cmd_del_port_tm_node_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_del,
+		(void *)&cmd_del_port_tm_node_port,
+		(void *)&cmd_del_port_tm_node_tm,
+		(void *)&cmd_del_port_tm_node_node,
+		(void *)&cmd_del_port_tm_node_port_id,
+		(void *)&cmd_del_port_tm_node_node_id,
+		NULL,
+	},
+};
+
+/* *** Update Port TM Node Parent *** */
+struct cmd_set_port_tm_node_parent_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t parent;
+	uint16_t port_id;
+	uint32_t node_id;
+	uint32_t parent_id;
+	uint32_t priority;
+	uint32_t weight;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, node, "node");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_parent =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, parent, "parent");
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, port_id, UINT16);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, node_id, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_parent_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		parent_id, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		priority, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		weight, UINT32);
+
+static void cmd_set_port_tm_node_parent_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_node_parent_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint32_t parent_id = res->parent_id;
+	uint32_t priority = res->priority;
+	uint32_t weight = res->weight;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (!port_is_started(port_id)) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_parent_update(port_id, node_id,
+		parent_id, priority, weight, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_node_parent = {
+	.f = cmd_set_port_tm_node_parent_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node parent",
+	.tokens = {
+		(void *)&cmd_set_port_tm_node_parent_set,
+		(void *)&cmd_set_port_tm_node_parent_port,
+		(void *)&cmd_set_port_tm_node_parent_tm,
+		(void *)&cmd_set_port_tm_node_parent_node,
+		(void *)&cmd_set_port_tm_node_parent_parent,
+		(void *)&cmd_set_port_tm_node_parent_port_id,
+		(void *)&cmd_set_port_tm_node_parent_node_id,
+		(void *)&cmd_set_port_tm_node_parent_parent_id,
+		(void *)&cmd_set_port_tm_node_parent_priority,
+		(void *)&cmd_set_port_tm_node_parent_weight,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchy Commit *** */
+struct cmd_port_tm_hierarchy_commit_result {
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t hierarchy;
+	cmdline_fixed_string_t commit;
+	uint16_t port_id;
+	uint32_t clean_on_fail;
+};
+
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, port, "port");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, tm, "tm");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_hierarchy =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result,
+			hierarchy, "hierarchy");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_commit =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, commit, "commit");
+cmdline_parse_token_num_t cmd_port_tm_hierarchy_commit_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_port_tm_hierarchy_commit_clean_on_fail =
+	TOKEN_NUM_INITIALIZER(struct cmd_port_tm_hierarchy_commit_result,
+		 clean_on_fail, UINT32);
+
+static void cmd_port_tm_hierarchy_commit_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_port_tm_hierarchy_commit_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t clean_on_fail = res->clean_on_fail;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_hierarchy_commit(port_id, clean_on_fail, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_port_tm_hierarchy_commit = {
+	.f = cmd_port_tm_hierarchy_commit_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node shaper profile",
+	.tokens = {
+		(void *)&cmd_port_tm_hierarchy_commit_port,
+		(void *)&cmd_port_tm_hierarchy_commit_tm,
+		(void *)&cmd_port_tm_hierarchy_commit_hierarchy,
+		(void *)&cmd_port_tm_hierarchy_commit_commit,
+		(void *)&cmd_port_tm_hierarchy_commit_port_id,
+		(void *)&cmd_port_tm_hierarchy_commit_clean_on_fail,
+		NULL,
+	},
+};
diff --git a/app/test-pmd/cmdline_tm.h b/app/test-pmd/cmdline_tm.h
index 5ed9de0..9d5fdf0 100644
--- a/app/test-pmd/cmdline_tm.h
+++ b/app/test-pmd/cmdline_tm.h
@@ -47,5 +47,10 @@ extern cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper;
 extern cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile;
 extern cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile;
 extern cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_add_port_tm_nonleaf_node;
+extern cmdline_parse_inst_t cmd_add_port_tm_leaf_node;
+extern cmdline_parse_inst_t cmd_del_port_tm_node;
+extern cmdline_parse_inst_t cmd_set_port_tm_node_parent;
+extern cmdline_parse_inst_t cmd_port_tm_hierarchy_commit;
 
 #endif /* _CMDLINE_TM_H_ */
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* Re: [PATCH v6 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit
  2017-10-09 19:07             ` [PATCH v6 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
@ 2017-10-11  8:40               ` Pei, Yulong
  2017-10-11  8:51                 ` Singh, Jasvinder
  0 siblings, 1 reply; 49+ messages in thread
From: Pei, Yulong @ 2017-10-11  8:40 UTC (permalink / raw)
  To: Singh, Jasvinder, dev
  Cc: Dumitrescu, Cristian, Wu, Jingjing, De Lara Guarch, Pablo

Hi Jasvinder,


-----Original Message-----
From: dev [mailto:dev-bounces@dpdk.org] On Behalf Of Jasvinder Singh
Sent: Tuesday, October 10, 2017 3:08 AM
To: dev@dpdk.org
Cc: Dumitrescu, Cristian <cristian.dumitrescu@intel.com>; Wu, Jingjing <jingjing.wu@intel.com>; De Lara Guarch, Pablo <pablo.de.lara.guarch@intel.com>
Subject: [dpdk-dev] [PATCH v6 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit

Add following CLIs in testpmd application for device traffic management;
- commands to add TM hierarchy nodes (leaf and nonleaf).
- command for runtime update of node weight.
- command to commit the TM hierarchy

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
v5 change:
- add shaper related parameters to leaf node add command

v4 change:
- remove softnic specific checks to make it generic for the devices

 app/test-pmd/cmdline.c    |  27 +++
 app/test-pmd/cmdline_tm.c | 526 ++++++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/cmdline_tm.h |   5 +
 3 files changed, 558 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index d89583c..c6b35ba 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -683,6 +683,28 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"del port tm node wred profile (port_id) (wred_profile_id)\n"
 			"	Delete port tm node wred profile.\n\n"
 
+			"add port tm nonleaf node (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight) (level_id) (shaper_profile_id)"
+			" (shared_shaper_id) (n_shared_shapers) (n_sp_priorities)"
+			" (stats_mask)\n"
+			"	Add port tm nonleaf node.\n\n"
+
+			"add port tm leaf node (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight) (level_id) (shaper_profile_id)"
+			" (shared_shaper_id) (n_shared_shapers) (n_sp_priorities)"
+			" (cman_mode) (wred_profile_id) (stats_mask)\n"
+			"	Add port tm leaf node.\n\n"
+

For leaf node , it should not have "n_sp_priorities" parameter.

Best Regards
Yulong Pei

+			"del port tm node (port_id) (node_id)\n"
+			"	Delete port tm node.\n\n"
+
+			"set port tm node parent (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight)\n"
+			"	Set port tm node parent.\n\n"
+
+			"port tm hierarchy commit (port_id) (clean_on_fail)\n"
+			"	Commit tm hierarchy.\n\n"
+
 			, list_pkt_forwarding_modes()
 		);
 	}
@@ -14872,6 +14894,11 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_wred_profile,
 	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_wred_profile,
 	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_nonleaf_node,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_leaf_node,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node,
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_parent,
+	(cmdline_parse_inst_t *)&cmd_port_tm_hierarchy_commit,
 	NULL,
 };
 
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c index f1cd810..a8b7c20 100644
--- a/app/test-pmd/cmdline_tm.c
+++ b/app/test-pmd/cmdline_tm.c
@@ -1427,3 +1427,529 @@ cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile = {
 		NULL,
 	},
 };
+
+/* *** Add Port TM nonleaf node *** */
+struct cmd_add_port_tm_nonleaf_node_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t nonleaf;
+	cmdline_fixed_string_t node;
+	uint16_t port_id;
+	uint32_t node_id;
+	int32_t parent_node_id;
+	uint32_t priority;
+	uint32_t weight;
+	uint32_t level_id;
+	uint32_t shaper_profile_id;
+	uint32_t shared_shaper_id;
+	uint32_t n_shared_shapers;
+	uint32_t n_sp_priorities;
+	uint64_t stats_mask;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, add, "add"); 
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, port, "port"); 
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, tm, "tm"); 
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_nonleaf =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, nonleaf, "nonleaf"); 
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, node, "node"); 
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 node_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 parent_node_id, INT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 priority, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 weight, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 level_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 shaper_profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 shared_shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_n_shared_shapers =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 n_shared_shapers, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_n_sp_priorities =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 n_sp_priorities, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_stats_mask =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 stats_mask, UINT64);
+
+static void cmd_add_port_tm_nonleaf_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_nonleaf_node_result *res = parsed_result;
+	struct rte_tm_error error;
+	struct rte_tm_node_params np;
+	uint32_t parent_node_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	/* Node parameters */
+	if (res->parent_node_id < 0)
+		parent_node_id = UINT32_MAX;
+	else
+		parent_node_id = res->parent_node_id;
+
+	memset(&np, 0, sizeof(struct rte_tm_node_params));
+	np.shaper_profile_id = res->shaper_profile_id;
+	np.n_shared_shapers = res->n_shared_shapers;
+
+	if (np.n_shared_shapers == 1)
+		np.shared_shaper_id[0] = res->shared_shaper_id;
+	else
+		np.shared_shaper_id = NULL;
+
+	np.nonleaf.n_sp_priorities = res->n_sp_priorities;
+	np.stats_mask = res->stats_mask;
+	np.nonleaf.wfq_weight_mode = NULL;
+
+	ret = rte_tm_node_add(port_id, res->node_id, parent_node_id,
+				res->priority, res->weight, res->level_id,
+				&np, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_nonleaf_node = {
+	.f = cmd_add_port_tm_nonleaf_node_parsed,
+	.data = NULL,
+	.help_str = "Add port tm nonleaf node",
+	.tokens = {
+		(void *)&cmd_add_port_tm_nonleaf_node_add,
+		(void *)&cmd_add_port_tm_nonleaf_node_port,
+		(void *)&cmd_add_port_tm_nonleaf_node_tm,
+		(void *)&cmd_add_port_tm_nonleaf_node_nonleaf,
+		(void *)&cmd_add_port_tm_nonleaf_node_node,
+		(void *)&cmd_add_port_tm_nonleaf_node_port_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_node_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_parent_node_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_priority,
+		(void *)&cmd_add_port_tm_nonleaf_node_weight,
+		(void *)&cmd_add_port_tm_nonleaf_node_level_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_shaper_profile_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_shared_shaper_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_n_shared_shapers,
+		(void *)&cmd_add_port_tm_nonleaf_node_n_sp_priorities,
+		(void *)&cmd_add_port_tm_nonleaf_node_stats_mask,
+		NULL,
+	},
+};
+
+/* *** Add Port TM leaf node *** */
+struct cmd_add_port_tm_leaf_node_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t leaf;
+	cmdline_fixed_string_t node;
+	uint16_t port_id;
+	uint32_t node_id;
+	int32_t parent_node_id;
+	uint32_t priority;
+	uint32_t weight;
+	uint32_t level_id;
+	uint32_t shaper_profile_id;
+	uint32_t shared_shaper_id;
+	uint32_t n_shared_shapers;
+	uint32_t cman_mode;
+	uint32_t wred_profile_id;
+	uint64_t stats_mask;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, add, "add"); 
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, port, "port"); 
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, tm, "tm"); 
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_nonleaf =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, leaf, "leaf"); 
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, node, "node"); 
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 node_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 parent_node_id, INT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 priority, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 weight, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 level_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 shaper_profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 shared_shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_n_shared_shapers =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 n_shared_shapers, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_cman_mode =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 cman_mode, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 wred_profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_stats_mask =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 stats_mask, UINT64);
+
+static void cmd_add_port_tm_leaf_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_leaf_node_result *res = parsed_result;
+	struct rte_tm_error error;
+	struct rte_tm_node_params np;
+	uint32_t parent_node_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	/* Node parameters */
+	if (res->parent_node_id < 0)
+		parent_node_id = UINT32_MAX;
+	else
+		parent_node_id = res->parent_node_id;
+
+	memset(&np, 0, sizeof(struct rte_tm_node_params));
+	np.shaper_profile_id = res->shaper_profile_id;
+	np.n_shared_shapers = res->n_shared_shapers;
+
+	if (np.n_shared_shapers == 1)
+		np.shared_shaper_id[0] = res->shared_shaper_id;
+	else
+		np.shared_shaper_id = NULL;
+
+	np.leaf.cman = res->cman_mode;
+	np.leaf.wred.wred_profile_id = res->wred_profile_id;
+	np.stats_mask = res->stats_mask;
+
+	ret = rte_tm_node_add(port_id, res->node_id, parent_node_id,
+				res->priority, res->weight, res->level_id,
+				&np, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_leaf_node = {
+	.f = cmd_add_port_tm_leaf_node_parsed,
+	.data = NULL,
+	.help_str = "Add port tm leaf node",
+	.tokens = {
+		(void *)&cmd_add_port_tm_leaf_node_add,
+		(void *)&cmd_add_port_tm_leaf_node_port,
+		(void *)&cmd_add_port_tm_leaf_node_tm,
+		(void *)&cmd_add_port_tm_leaf_node_nonleaf,
+		(void *)&cmd_add_port_tm_leaf_node_node,
+		(void *)&cmd_add_port_tm_leaf_node_port_id,
+		(void *)&cmd_add_port_tm_leaf_node_node_id,
+		(void *)&cmd_add_port_tm_leaf_node_parent_node_id,
+		(void *)&cmd_add_port_tm_leaf_node_priority,
+		(void *)&cmd_add_port_tm_leaf_node_weight,
+		(void *)&cmd_add_port_tm_leaf_node_level_id,
+		(void *)&cmd_add_port_tm_leaf_node_shaper_profile_id,
+		(void *)&cmd_add_port_tm_leaf_node_shared_shaper_id,
+		(void *)&cmd_add_port_tm_leaf_node_n_shared_shapers,
+		(void *)&cmd_add_port_tm_leaf_node_cman_mode,
+		(void *)&cmd_add_port_tm_leaf_node_wred_profile_id,
+		(void *)&cmd_add_port_tm_leaf_node_stats_mask,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM Node *** */
+struct cmd_del_port_tm_node_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	uint16_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, del, "del"); 
+cmdline_parse_token_string_t cmd_del_port_tm_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, port, "port"); 
+cmdline_parse_token_string_t cmd_del_port_tm_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, tm, "tm"); 
+cmdline_parse_token_string_t cmd_del_port_tm_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, node, "node"); 
+cmdline_parse_token_num_t cmd_del_port_tm_node_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_del_port_tm_node_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_tm_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_del_port_tm_node_result,
+		node_id, UINT32);
+
+static void cmd_del_port_tm_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_delete(port_id, node_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node = {
+	.f = cmd_del_port_tm_node_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_del,
+		(void *)&cmd_del_port_tm_node_port,
+		(void *)&cmd_del_port_tm_node_tm,
+		(void *)&cmd_del_port_tm_node_node,
+		(void *)&cmd_del_port_tm_node_port_id,
+		(void *)&cmd_del_port_tm_node_node_id,
+		NULL,
+	},
+};
+
+/* *** Update Port TM Node Parent *** */ struct 
+cmd_set_port_tm_node_parent_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t parent;
+	uint16_t port_id;
+	uint32_t node_id;
+	uint32_t parent_id;
+	uint32_t priority;
+	uint32_t weight;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, set, "set"); 
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, port, "port"); 
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, tm, "tm"); 
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, node, "node"); 
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_parent =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, parent, "parent"); 
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, port_id, UINT16); 
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, node_id, UINT32); 
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_parent_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		parent_id, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		priority, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		weight, UINT32);
+
+static void cmd_set_port_tm_node_parent_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_node_parent_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint32_t parent_id = res->parent_id;
+	uint32_t priority = res->priority;
+	uint32_t weight = res->weight;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (!port_is_started(port_id)) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_parent_update(port_id, node_id,
+		parent_id, priority, weight, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_node_parent = {
+	.f = cmd_set_port_tm_node_parent_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node parent",
+	.tokens = {
+		(void *)&cmd_set_port_tm_node_parent_set,
+		(void *)&cmd_set_port_tm_node_parent_port,
+		(void *)&cmd_set_port_tm_node_parent_tm,
+		(void *)&cmd_set_port_tm_node_parent_node,
+		(void *)&cmd_set_port_tm_node_parent_parent,
+		(void *)&cmd_set_port_tm_node_parent_port_id,
+		(void *)&cmd_set_port_tm_node_parent_node_id,
+		(void *)&cmd_set_port_tm_node_parent_parent_id,
+		(void *)&cmd_set_port_tm_node_parent_priority,
+		(void *)&cmd_set_port_tm_node_parent_weight,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchy Commit *** */
+struct cmd_port_tm_hierarchy_commit_result {
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t hierarchy;
+	cmdline_fixed_string_t commit;
+	uint16_t port_id;
+	uint32_t clean_on_fail;
+};
+
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, port, "port"); 
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, tm, "tm"); 
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_hierarchy =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result,
+			hierarchy, "hierarchy");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_commit =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, commit, "commit"); 
+cmdline_parse_token_num_t cmd_port_tm_hierarchy_commit_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_port_tm_hierarchy_commit_clean_on_fail =
+	TOKEN_NUM_INITIALIZER(struct cmd_port_tm_hierarchy_commit_result,
+		 clean_on_fail, UINT32);
+
+static void cmd_port_tm_hierarchy_commit_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_port_tm_hierarchy_commit_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t clean_on_fail = res->clean_on_fail;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_hierarchy_commit(port_id, clean_on_fail, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_port_tm_hierarchy_commit = {
+	.f = cmd_port_tm_hierarchy_commit_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node shaper profile",
+	.tokens = {
+		(void *)&cmd_port_tm_hierarchy_commit_port,
+		(void *)&cmd_port_tm_hierarchy_commit_tm,
+		(void *)&cmd_port_tm_hierarchy_commit_hierarchy,
+		(void *)&cmd_port_tm_hierarchy_commit_commit,
+		(void *)&cmd_port_tm_hierarchy_commit_port_id,
+		(void *)&cmd_port_tm_hierarchy_commit_clean_on_fail,
+		NULL,
+	},
+};
diff --git a/app/test-pmd/cmdline_tm.h b/app/test-pmd/cmdline_tm.h index 5ed9de0..9d5fdf0 100644
--- a/app/test-pmd/cmdline_tm.h
+++ b/app/test-pmd/cmdline_tm.h
@@ -47,5 +47,10 @@ extern cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper;
 extern cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile;
 extern cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile;
 extern cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_add_port_tm_nonleaf_node; extern 
+cmdline_parse_inst_t cmd_add_port_tm_leaf_node; extern 
+cmdline_parse_inst_t cmd_del_port_tm_node; extern cmdline_parse_inst_t 
+cmd_set_port_tm_node_parent; extern cmdline_parse_inst_t 
+cmd_port_tm_hierarchy_commit;
 
 #endif /* _CMDLINE_TM_H_ */
--
2.9.3

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v6 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit
  2017-10-11  8:40               ` Pei, Yulong
@ 2017-10-11  8:51                 ` Singh, Jasvinder
  0 siblings, 0 replies; 49+ messages in thread
From: Singh, Jasvinder @ 2017-10-11  8:51 UTC (permalink / raw)
  To: Pei, Yulong, dev
  Cc: Dumitrescu, Cristian, Wu, Jingjing, De Lara Guarch, Pablo

<snip>

>  app/test-pmd/cmdline.c    |  27 +++
>  app/test-pmd/cmdline_tm.c | 526
> ++++++++++++++++++++++++++++++++++++++++++++++
>  app/test-pmd/cmdline_tm.h |   5 +
>  3 files changed, 558 insertions(+)
> 
> diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index
> d89583c..c6b35ba 100644
> --- a/app/test-pmd/cmdline.c
> +++ b/app/test-pmd/cmdline.c
> @@ -683,6 +683,28 @@ static void cmd_help_long_parsed(void
> *parsed_result,
>  			"del port tm node wred profile (port_id)
> (wred_profile_id)\n"
>  			"	Delete port tm node wred profile.\n\n"
> 
> +			"add port tm nonleaf node (port_id) (node_id)
> (parent_node_id)"
> +			" (priority) (weight) (level_id) (shaper_profile_id)"
> +			" (shared_shaper_id) (n_shared_shapers)
> (n_sp_priorities)"
> +			" (stats_mask)\n"
> +			"	Add port tm nonleaf node.\n\n"
> +
> +			"add port tm leaf node (port_id) (node_id)
> (parent_node_id)"
> +			" (priority) (weight) (level_id) (shaper_profile_id)"
> +			" (shared_shaper_id) (n_shared_shapers)
> (n_sp_priorities)"
> +			" (cman_mode) (wred_profile_id) (stats_mask)\n"
> +			"	Add port tm leaf node.\n\n"
> +
> 
> For leaf node , it should not have "n_sp_priorities" parameter.
> 
Forgot to edit here in help. Thanks. Will fix in the next version.

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [PATCH v7 1/3] app/test-pmd: add CLI for TM capability and stats
  2017-10-09 19:07           ` [PATCH v6 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
  2017-10-09 19:07             ` [PATCH v6 2/3] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
  2017-10-09 19:07             ` [PATCH v6 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
@ 2017-10-11  9:26             ` Jasvinder Singh
  2017-10-11  9:26               ` [PATCH v7 2/3] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
                                 ` (5 more replies)
  2 siblings, 6 replies; 49+ messages in thread
From: Jasvinder Singh @ 2017-10-11  9:26 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu, pablo.de.lara.guarch, yulong.pei

Add following CLIs to testpmd application for device traffic management;
- commands to display TM capability information.
  (per port, per hierarchy level and per hierarchy node)
- command to display hiearchy node type
- stats collection

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
v6 change:
- fix compilation warning
- change port_id type to uint16_t

v4 change:
 - remove softnic specific checks to make it generic for the devices

v3 change:
- Implements feedback from Pablo[1]
 - move TM API related CLIs into cmdline_tm.c
 - split patch into small patches
 - replace link status check with testpmd fn port_is_started()

[1]http://dpdk.org/ml/archives/dev/2017-September/075748.html
---
 app/test-pmd/Makefile     |   1 +
 app/test-pmd/cmdline.c    |  20 ++
 app/test-pmd/cmdline_tm.c | 681 ++++++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/cmdline_tm.h |  44 +++
 4 files changed, 746 insertions(+)
 create mode 100644 app/test-pmd/cmdline_tm.c
 create mode 100644 app/test-pmd/cmdline_tm.h

diff --git a/app/test-pmd/Makefile b/app/test-pmd/Makefile
index b6e80dd..b78c73a 100644
--- a/app/test-pmd/Makefile
+++ b/app/test-pmd/Makefile
@@ -48,6 +48,7 @@ SRCS-y := testpmd.c
 SRCS-y += parameters.c
 SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline.c
 SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline_flow.c
+SRCS-y += cmdline_tm.c
 SRCS-y += config.c
 SRCS-y += iofwd.c
 SRCS-y += macfwd.c
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 91766bc..2376f23 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -99,6 +99,7 @@
 #include <rte_pmd_bnxt.h>
 #endif
 #include "testpmd.h"
+#include "cmdline_tm.h"
 
 static struct cmdline *testpmd_cl;
 
@@ -234,6 +235,20 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"show port (port_id) pctype mapping\n"
 			"    Get flow ptype to pctype mapping on a port\n\n"
 
+			"show port tm cap (port_id)\n"
+			"	Display the port TM capability.\n\n"
+
+			"show port tm level cap (port_id) (level_id)\n"
+			"	Display the port TM hierarchical level capability.\n\n"
+
+			"show port tm node cap (port_id) (node_id)\n"
+			"	Display the port TM node capability.\n\n"
+
+			"show port tm node type (port_id) (node_id)\n"
+			"	Display the port TM node type.\n\n"
+
+			"show port tm node stats (port_id) (node_id) (clear)\n"
+			"	Display the port TM node stats.\n\n"
 		);
 	}
 
@@ -14818,6 +14833,11 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_pctype_mapping_get,
 	(cmdline_parse_inst_t *)&cmd_pctype_mapping_reset,
 	(cmdline_parse_inst_t *)&cmd_pctype_mapping_update,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_level_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_type,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_stats,
 	NULL,
 };
 
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
new file mode 100644
index 0000000..f024372
--- /dev/null
+++ b/app/test-pmd/cmdline_tm.c
@@ -0,0 +1,681 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+
+#include <rte_ethdev.h>
+#include <rte_flow.h>
+#include <rte_tm.h>
+
+#include "testpmd.h"
+#include "cmdline_tm.h"
+
+/** Display TM Error Message */
+static void
+print_err_msg(struct rte_tm_error *error)
+{
+	static const char *const errstrlist[] = {
+		[RTE_TM_ERROR_TYPE_NONE] = "no error",
+		[RTE_TM_ERROR_TYPE_UNSPECIFIED] = "cause unspecified",
+		[RTE_TM_ERROR_TYPE_CAPABILITIES]
+			= "capability parameter null",
+		[RTE_TM_ERROR_TYPE_LEVEL_ID] = "level id",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE]
+			= "wred profile null",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_GREEN] = "wred profile(green)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_YELLOW]
+			= "wred profile(yellow)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_RED] = "wred profile(red)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_ID] = "wred profile id",
+		[RTE_TM_ERROR_TYPE_SHARED_WRED_CONTEXT_ID]
+			= "shared wred context id",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE] = "shaper profile null",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE]
+			= "committed rate field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE]
+			= "committed size field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE]
+			= "peak rate field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE]
+			= "peak size field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN]
+			= "packet adjust length field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID] = "shaper profile id",
+		[RTE_TM_ERROR_TYPE_SHARED_SHAPER_ID] = "shared shaper id",
+		[RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID] = "parent node id",
+		[RTE_TM_ERROR_TYPE_NODE_PRIORITY] = "node priority",
+		[RTE_TM_ERROR_TYPE_NODE_WEIGHT] = "node weight",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS] = "node parameter null",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID]
+			= "shaper profile id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID]
+			= "shared shaper id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS]
+			= "num shared shapers field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE]
+			= "wfq weght mode field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES]
+			= "num strict priorities field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN]
+			= "congestion management mode field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID] =
+			"wred profile id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID]
+			= "shared wred context id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS]
+			= "num shared wred contexts field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS]
+			= "stats field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_ID] = "node id",
+	};
+
+	const char *errstr;
+	char buf[64];
+
+	if ((unsigned int)error->type >= RTE_DIM(errstrlist) ||
+		!errstrlist[error->type])
+		errstr = "unknown type";
+	else
+		errstr = errstrlist[error->type];
+
+	if (error->cause)
+		snprintf(buf, sizeof(buf), "cause: %p, ", error->cause);
+
+	printf("%s: %s%s (error %d)\n", errstr, error->cause ? buf : "",
+		error->message ? error->message : "(no stated reason)",
+		error->type);
+}
+
+/* *** Port TM Capability *** */
+struct cmd_show_port_tm_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t cap;
+	uint16_t port_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		 port_id, UINT16);
+
+static void cmd_show_port_tm_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_cap_result *res = parsed_result;
+	struct rte_tm_capabilities cap;
+	struct rte_tm_error error;
+	portid_t port_id = res->port_id;
+	uint32_t i;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	memset(&cap, 0, sizeof(struct rte_tm_capabilities));
+	ret = rte_tm_capabilities_get(port_id, &cap, &error);
+	if (ret) {
+		print_err_msg(&error);
+		return;
+	}
+
+	printf("\n****   Port TM Capabilities ****\n\n");
+	printf("cap.n_nodes_max %" PRIu32 "\n", cap.n_nodes_max);
+	printf("cap.n_levels_max %" PRIu32 "\n", cap.n_levels_max);
+	printf("cap.non_leaf_nodes_identical %" PRId32 "\n",
+		cap.non_leaf_nodes_identical);
+	printf("cap.leaf_nodes_identical %" PRId32 "\n",
+		cap.leaf_nodes_identical);
+	printf("cap.shaper_n_max %u\n", cap.shaper_n_max);
+	printf("cap.shaper_private_n_max %" PRIu32 "\n",
+		cap.shaper_private_n_max);
+	printf("cap.shaper_private_dual_rate_n_max %" PRId32 "\n",
+		cap.shaper_private_dual_rate_n_max);
+	printf("cap.shaper_private_rate_min %" PRIu64 "\n",
+		cap.shaper_private_rate_min);
+	printf("cap.shaper_private_rate_max %" PRIu64 "\n",
+		cap.shaper_private_rate_max);
+	printf("cap.shaper_shared_n_max %" PRIu32 "\n",
+		cap.shaper_shared_n_max);
+	printf("cap.shaper_shared_n_nodes_per_shaper_max %" PRIu32 "\n",
+		cap.shaper_shared_n_nodes_per_shaper_max);
+	printf("cap.shaper_shared_n_shapers_per_node_max %" PRIu32 "\n",
+		cap.shaper_shared_n_shapers_per_node_max);
+	printf("cap.shaper_shared_dual_rate_n_max %" PRIu32 "\n",
+		cap.shaper_shared_dual_rate_n_max);
+	printf("cap.shaper_shared_rate_min %" PRIu64 "\n",
+		cap.shaper_shared_rate_min);
+	printf("cap.shaper_shared_rate_max %" PRIu64 "\n",
+		cap.shaper_shared_rate_max);
+	printf("cap.shaper_pkt_length_adjust_min %" PRId32 "\n",
+		cap.shaper_pkt_length_adjust_min);
+	printf("cap.shaper_pkt_length_adjust_max %" PRId32 "\n",
+		cap.shaper_pkt_length_adjust_max);
+	printf("cap.sched_n_children_max %" PRIu32 "\n",
+		cap.sched_n_children_max);
+	printf("cap.sched_sp_n_priorities_max %" PRIu32 "\n",
+		cap.sched_sp_n_priorities_max);
+	printf("cap.sched_wfq_n_children_per_group_max %" PRIu32 "\n",
+		cap.sched_wfq_n_children_per_group_max);
+	printf("cap.sched_wfq_n_groups_max %" PRIu32 "\n",
+		cap.sched_wfq_n_groups_max);
+	printf("cap.sched_wfq_weight_max %" PRIu32 "\n",
+		cap.sched_wfq_weight_max);
+	printf("cap.cman_head_drop_supported %" PRId32 "\n",
+		cap.cman_head_drop_supported);
+	printf("cap.cman_wred_context_n_max %" PRIu32 "\n",
+		cap.cman_wred_context_n_max);
+	printf("cap.cman_wred_context_private_n_max %" PRIu32 "\n",
+		cap.cman_wred_context_private_n_max);
+	printf("cap.cman_wred_context_shared_n_max %" PRIu32 "\n",
+		cap.cman_wred_context_shared_n_max);
+	printf("cap.cman_wred_context_shared_n_nodes_per_context_max %" PRIu32
+		"\n", cap.cman_wred_context_shared_n_nodes_per_context_max);
+	printf("cap.cman_wred_context_shared_n_contexts_per_node_max %" PRIu32
+		"\n", cap.cman_wred_context_shared_n_contexts_per_node_max);
+
+	for (i = 0; i < RTE_TM_COLORS; i++) {
+		printf("cap.mark_vlan_dei_supported %" PRId32 "\n",
+			cap.mark_vlan_dei_supported[i]);
+		printf("cap.mark_ip_ecn_tcp_supported %" PRId32 "\n",
+			cap.mark_ip_ecn_tcp_supported[i]);
+		printf("cap.mark_ip_ecn_sctp_supported %" PRId32 "\n",
+			cap.mark_ip_ecn_sctp_supported[i]);
+		printf("cap.mark_ip_dscp_supported %" PRId32 "\n",
+			cap.mark_ip_dscp_supported[i]);
+	}
+
+	printf("cap.dynamic_update_mask %" PRIx64 "\n",
+		cap.dynamic_update_mask);
+	printf("cap.stats_mask %" PRIx64 "\n", cap.stats_mask);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_cap = {
+	.f = cmd_show_port_tm_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_cap_show,
+		(void *)&cmd_show_port_tm_cap_port,
+		(void *)&cmd_show_port_tm_cap_tm,
+		(void *)&cmd_show_port_tm_cap_cap,
+		(void *)&cmd_show_port_tm_cap_port_id,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchical Level Capability *** */
+struct cmd_show_port_tm_level_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t level;
+	cmdline_fixed_string_t cap;
+	uint16_t port_id;
+	uint32_t level_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_level =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		level, "level");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_level_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_level_cap_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		 level_id, UINT32);
+
+
+static void cmd_show_port_tm_level_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_level_cap_result *res = parsed_result;
+	struct rte_tm_level_capabilities lcap;
+	struct rte_tm_error error;
+	portid_t port_id = res->port_id;
+	uint32_t level_id = res->level_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	memset(&lcap, 0, sizeof(struct rte_tm_level_capabilities));
+	ret = rte_tm_level_capabilities_get(port_id, level_id, &lcap, &error);
+	if (ret) {
+		print_err_msg(&error);
+		return;
+	}
+	printf("\n**   Port TM Hierarchy level %" PRIu32 " Capability **\n\n",
+		level_id);
+
+	printf("cap.n_nodes_max %" PRIu32 "\n", lcap.n_nodes_max);
+	printf("cap.n_nodes_nonleaf_max %" PRIu32 "\n",
+		lcap.n_nodes_nonleaf_max);
+	printf("cap.n_nodes_leaf_max %" PRIu32 "\n", lcap.n_nodes_leaf_max);
+	printf("cap.non_leaf_nodes_identical %" PRId32 "\n",
+		lcap.non_leaf_nodes_identical);
+	printf("cap.leaf_nodes_identical %" PRId32 "\n",
+		lcap.leaf_nodes_identical);
+	if (level_id <= 3) {
+		printf("cap.nonleaf.shaper_private_supported %" PRId32 "\n",
+			lcap.nonleaf.shaper_private_supported);
+		printf("cap.nonleaf.shaper_private_dual_rate_supported %" PRId32
+			"\n", lcap.nonleaf.shaper_private_dual_rate_supported);
+		printf("cap.nonleaf.shaper_private_rate_min %" PRIu64 "\n",
+			lcap.nonleaf.shaper_private_rate_min);
+		printf("cap.nonleaf.shaper_private_rate_max %" PRIu64 "\n",
+			lcap.nonleaf.shaper_private_rate_max);
+		printf("cap.nonleaf.shaper_shared_n_max %" PRIu32 "\n",
+			lcap.nonleaf.shaper_shared_n_max);
+		printf("cap.nonleaf.sched_n_children_max %" PRIu32 "\n",
+			lcap.nonleaf.sched_n_children_max);
+		printf("cap.nonleaf.sched_sp_n_priorities_max %" PRIu32 "\n",
+			lcap.nonleaf.sched_sp_n_priorities_max);
+		printf("cap.nonleaf.sched_wfq_n_children_per_group_max %" PRIu32
+			"\n", lcap.nonleaf.sched_wfq_n_children_per_group_max);
+		printf("cap.nonleaf.sched_wfq_n_groups_max %" PRIu32 "\n",
+			lcap.nonleaf.sched_wfq_n_groups_max);
+		printf("cap.nonleaf.sched_wfq_weight_max %" PRIu32 "\n",
+			lcap.nonleaf.sched_wfq_weight_max);
+		printf("cap.nonleaf.stats_mask %" PRIx64 "\n",
+			lcap.nonleaf.stats_mask);
+	} else {
+		printf("cap.leaf.shaper_private_supported %" PRId32 "\n",
+			lcap.leaf.shaper_private_supported);
+		printf("cap.leaf.shaper_private_dual_rate_supported %" PRId32
+			"\n", lcap.leaf.shaper_private_dual_rate_supported);
+		printf("cap.leaf.shaper_private_rate_min %" PRIu64 "\n",
+			lcap.leaf.shaper_private_rate_min);
+		printf("cap.leaf.shaper_private_rate_max %" PRIu64 "\n",
+			lcap.leaf.shaper_private_rate_max);
+		printf("cap.leaf.shaper_shared_n_max %" PRIu32 "\n",
+			lcap.leaf.shaper_shared_n_max);
+		printf("cap.leaf.cman_head_drop_supported %" PRId32 "\n",
+			lcap.leaf.cman_head_drop_supported);
+		printf("cap.leaf.cman_wred_context_private_supported %"	PRId32
+			"\n", lcap.leaf.cman_wred_context_private_supported);
+		printf("cap.leaf.cman_wred_context_shared_n_max %" PRIu32 "\n",
+			lcap.leaf.cman_wred_context_shared_n_max);
+		printf("cap.leaf.stats_mask %" PRIx64 "\n",
+			lcap.leaf.stats_mask);
+	}
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_level_cap = {
+	.f = cmd_show_port_tm_level_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Hierarhical level Capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_level_cap_show,
+		(void *)&cmd_show_port_tm_level_cap_port,
+		(void *)&cmd_show_port_tm_level_cap_tm,
+		(void *)&cmd_show_port_tm_level_cap_level,
+		(void *)&cmd_show_port_tm_level_cap_cap,
+		(void *)&cmd_show_port_tm_level_cap_port_id,
+		(void *)&cmd_show_port_tm_level_cap_level_id,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchy Node Capability *** */
+struct cmd_show_port_tm_node_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t cap;
+	uint16_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_node =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_node_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_node_cap_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		 node_id, UINT32);
+
+static void cmd_show_port_tm_node_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_cap_result *res = parsed_result;
+	struct rte_tm_node_capabilities ncap;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	portid_t port_id = res->port_id;
+	int ret, is_leaf = 0;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Node id must be valid */
+	ret = rte_tm_node_type_get(port_id, node_id, &is_leaf, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	memset(&ncap, 0, sizeof(struct rte_tm_node_capabilities));
+	ret = rte_tm_node_capabilities_get(port_id, node_id, &ncap, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+	printf("\n**   Port TM Hierarchy node %" PRIu32 " Capability **\n\n",
+		node_id);
+	printf("cap.shaper_private_supported %" PRId32 "\n",
+		ncap.shaper_private_supported);
+	printf("cap.shaper_private_dual_rate_supported %" PRId32 "\n",
+		ncap.shaper_private_dual_rate_supported);
+	printf("cap.shaper_private_rate_min %" PRIu64 "\n",
+		ncap.shaper_private_rate_min);
+	printf("cap.shaper_private_rate_max %" PRIu64 "\n",
+		ncap.shaper_private_rate_max);
+	printf("cap.shaper_shared_n_max %" PRIu32 "\n",
+		ncap.shaper_shared_n_max);
+	if (!is_leaf) {
+		printf("cap.nonleaf.sched_n_children_max %" PRIu32 "\n",
+			ncap.nonleaf.sched_n_children_max);
+		printf("cap.nonleaf.sched_sp_n_priorities_max %" PRIu32 "\n",
+			ncap.nonleaf.sched_sp_n_priorities_max);
+		printf("cap.nonleaf.sched_wfq_n_children_per_group_max %" PRIu32
+			"\n", ncap.nonleaf.sched_wfq_n_children_per_group_max);
+		printf("cap.nonleaf.sched_wfq_n_groups_max %" PRIu32 "\n",
+			ncap.nonleaf.sched_wfq_n_groups_max);
+		printf("cap.nonleaf.sched_wfq_weight_max %" PRIu32 "\n",
+			ncap.nonleaf.sched_wfq_weight_max);
+	} else {
+		printf("cap.leaf.cman_head_drop_supported %" PRId32 "\n",
+			ncap.leaf.cman_head_drop_supported);
+		printf("cap.leaf.cman_wred_context_private_supported %" PRId32
+			"\n", ncap.leaf.cman_wred_context_private_supported);
+		printf("cap.leaf.cman_wred_context_shared_n_max %" PRIu32 "\n",
+			ncap.leaf.cman_wred_context_shared_n_max);
+	}
+	printf("cap.stats_mask %" PRIx64 "\n", ncap.stats_mask);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_cap = {
+	.f = cmd_show_port_tm_node_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Hierarchy node capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_cap_show,
+		(void *)&cmd_show_port_tm_node_cap_port,
+		(void *)&cmd_show_port_tm_node_cap_tm,
+		(void *)&cmd_show_port_tm_node_cap_node,
+		(void *)&cmd_show_port_tm_node_cap_cap,
+		(void *)&cmd_show_port_tm_node_cap_port_id,
+		(void *)&cmd_show_port_tm_node_cap_node_id,
+		NULL,
+	},
+};
+
+/* *** Show Port TM Node Statistics *** */
+struct cmd_show_port_tm_node_stats_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t stats;
+	uint16_t port_id;
+	uint32_t node_id;
+	uint32_t clear;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_show =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_stats =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, stats, "stats");
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_stats_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result,
+			node_id, UINT32);
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_clear =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, clear, UINT32);
+
+static void cmd_show_port_tm_node_stats_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_stats_result *res = parsed_result;
+	struct rte_tm_node_stats stats;
+	struct rte_tm_error error;
+	uint64_t stats_mask = 0;
+	uint32_t node_id = res->node_id;
+	uint32_t clear = res->clear;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (!port_is_started(port_id)) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	memset(&stats, 0, sizeof(struct rte_tm_node_stats));
+	ret = rte_tm_node_stats_read(port_id, node_id, &stats,
+			&stats_mask, clear, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	/* Display stats */
+	if (stats_mask & RTE_TM_STATS_N_PKTS)
+		printf("\tPkts scheduled from node: %" PRIu64 "\n",
+			stats.n_pkts);
+	if (stats_mask & RTE_TM_STATS_N_BYTES)
+		printf("\tBytes scheduled from node: %" PRIu64 "\n",
+			stats.n_bytes);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_GREEN_DROPPED)
+		printf("\tPkts dropped (green): %" PRIu64 "\n",
+			stats.leaf.n_pkts_dropped[RTE_TM_GREEN]);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_YELLOW_DROPPED)
+		printf("\tPkts dropped (yellow): %" PRIu64 "\n",
+			stats.leaf.n_pkts_dropped[RTE_TM_YELLOW]);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_RED_DROPPED)
+		printf("\tPkts dropped (red): %" PRIu64 "\n",
+			stats.leaf.n_pkts_dropped[RTE_TM_RED]);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_GREEN_DROPPED)
+		printf("\tBytes dropped (green): %" PRIu64 "\n",
+			stats.leaf.n_bytes_dropped[RTE_TM_GREEN]);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_YELLOW_DROPPED)
+		printf("\tBytes dropped (yellow): %" PRIu64 "\n",
+			stats.leaf.n_bytes_dropped[RTE_TM_YELLOW]);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_RED_DROPPED)
+		printf("\tBytes dropped (red): %" PRIu64 "\n",
+			stats.leaf.n_bytes_dropped[RTE_TM_RED]);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_QUEUED)
+		printf("\tPkts queued: %" PRIu64 "\n",
+			stats.leaf.n_pkts_queued);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_QUEUED)
+		printf("\tBytes queued: %" PRIu64 "\n",
+			stats.leaf.n_bytes_queued);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_stats = {
+	.f = cmd_show_port_tm_node_stats_parsed,
+	.data = NULL,
+	.help_str = "Show port tm node stats",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_stats_show,
+		(void *)&cmd_show_port_tm_node_stats_port,
+		(void *)&cmd_show_port_tm_node_stats_tm,
+		(void *)&cmd_show_port_tm_node_stats_node,
+		(void *)&cmd_show_port_tm_node_stats_stats,
+		(void *)&cmd_show_port_tm_node_stats_port_id,
+		(void *)&cmd_show_port_tm_node_stats_node_id,
+		(void *)&cmd_show_port_tm_node_stats_clear,
+		NULL,
+	},
+};
+
+/* *** Show Port TM Node Type *** */
+struct cmd_show_port_tm_node_type_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t type;
+	uint16_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_show =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, type, "type");
+cmdline_parse_token_num_t cmd_show_port_tm_node_type_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_node_type_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result,
+			node_id, UINT32);
+
+static void cmd_show_port_tm_node_type_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_type_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	portid_t port_id = res->port_id;
+	int ret, is_leaf = 0;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_node_type_get(port_id, node_id, &is_leaf, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	if (is_leaf == 1)
+		printf("leaf node\n");
+	else
+		printf("nonleaf node\n");
+
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_type = {
+	.f = cmd_show_port_tm_node_type_parsed,
+	.data = NULL,
+	.help_str = "Show port tm node type",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_type_show,
+		(void *)&cmd_show_port_tm_node_type_port,
+		(void *)&cmd_show_port_tm_node_type_tm,
+		(void *)&cmd_show_port_tm_node_type_node,
+		(void *)&cmd_show_port_tm_node_type_type,
+		(void *)&cmd_show_port_tm_node_type_port_id,
+		(void *)&cmd_show_port_tm_node_type_node_id,
+		NULL,
+	},
+};
diff --git a/app/test-pmd/cmdline_tm.h b/app/test-pmd/cmdline_tm.h
new file mode 100644
index 0000000..945af89
--- /dev/null
+++ b/app/test-pmd/cmdline_tm.h
@@ -0,0 +1,44 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CMDLINE_TM_H_
+#define _CMDLINE_TM_H_
+
+ /* Traffic Management CLI */
+extern cmdline_parse_inst_t cmd_show_port_tm_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_level_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_type;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_stats;
+
+#endif /* _CMDLINE_TM_H_ */
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 2/3] app/test-pmd: add CLI for shaper and wred profiles
  2017-10-11  9:26             ` [PATCH v7 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
@ 2017-10-11  9:26               ` Jasvinder Singh
  2017-10-13  2:33                 ` Wu, Jingjing
  2017-10-11  9:26               ` [PATCH v7 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
                                 ` (4 subsequent siblings)
  5 siblings, 1 reply; 49+ messages in thread
From: Jasvinder Singh @ 2017-10-11  9:26 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu, pablo.de.lara.guarch, yulong.pei

Add following CLIs in testpmd application for device traffic management;
- commands to add/del shaper profile for TM hieraqrchy nodes.
- commands to add/update shared shapers
- commands to add/del WRED profiles for TM hiearchy leaf nodes.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
v6 change:
- change port id type to uint16_t
 
v5 change:
- add packet length adjust parameter to add shaper profile command

v4 change:
- remove softnic specific checks to make it generic for the devices

 app/test-pmd/cmdline.c    |  34 +++
 app/test-pmd/cmdline_tm.c | 748 ++++++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/cmdline_tm.h |   7 +
 3 files changed, 789 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 2376f23..d89583c 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -656,6 +656,33 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"ptype mapping update (port_id) (hw_ptype) (sw_ptype)\n"
 			"    Update a ptype mapping item on a port\n\n"
 
+			"add port tm node shaper profile (port_id) (shaper_profile_id)"
+			" (tb_rate) (tb_size) (packet_length_adjust)\n"
+			"	Add port tm node private shaper profile.\n\n"
+
+			"del port tm node shaper profile (port_id) (shaper_profile_id)\n"
+			"	Delete port tm node private shaper profile.\n\n"
+
+			"add port tm node shared shaper (port_id) (shared_shaper_id)"
+			" (shaper_profile_id)\n"
+			"	Add/update port tm node shared shaper.\n\n"
+
+			"del port tm node shared shaper (port_id) (shared_shaper_id)\n"
+			"	Delete port tm node shared shaper.\n\n"
+
+			"set port tm node shaper profile (port_id) (node_id)"
+			" (shaper_profile_id)\n"
+			"	Set port tm node shaper profile.\n\n"
+
+			"add port tm node wred profile (port_id) (wred_profile_id)"
+			" (color_g) (min_th_g) (max_th_g) (maxp_inv_g) (wq_log2_g)"
+			" (color_y) (min_th_y) (max_th_y) (maxp_inv_y) (wq_log2_y)"
+			" (color_r) (min_th_r) (max_th_r) (maxp_inv_r) (wq_log2_r)\n"
+			"	Add port tm node wred profile.\n\n"
+
+			"del port tm node wred profile (port_id) (wred_profile_id)\n"
+			"	Delete port tm node wred profile.\n\n"
+
 			, list_pkt_forwarding_modes()
 		);
 	}
@@ -14838,6 +14865,13 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_cap,
 	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_type,
 	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_stats,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_shared_shaper,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_shared_shaper,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_wred_profile,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_wred_profile,
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_shaper_profile,
 	NULL,
 };
 
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
index f024372..f1cd810 100644
--- a/app/test-pmd/cmdline_tm.c
+++ b/app/test-pmd/cmdline_tm.c
@@ -679,3 +679,751 @@ cmdline_parse_inst_t cmd_show_port_tm_node_type = {
 		NULL,
 	},
 };
+
+/* *** Add Port TM Private Shaper Profile *** */
+struct cmd_add_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint16_t port_id;
+	uint32_t shaper_id;
+	uint64_t tb_rate;
+	uint64_t tb_size;
+	uint32_t pktlen_adjust;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_tb_rate =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tb_rate, UINT64);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_tb_size =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tb_size, UINT64);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_pktlen_adjust =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			pktlen_adjust, UINT32);
+
+static void cmd_add_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_tm_shaper_params sp;
+	struct rte_tm_error error;
+	uint32_t shaper_id = res->shaper_id;
+	uint32_t pkt_len_adjust = res->pktlen_adjust;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Private shaper profile params */
+	memset(&sp, 0, sizeof(struct rte_tm_shaper_params));
+	sp.peak.rate = res->tb_rate;
+	sp.peak.size = res->tb_size;
+	sp.pkt_length_adjust = pkt_len_adjust;
+
+	ret = rte_tm_shaper_profile_add(port_id, shaper_id, &sp, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_shaper_profile = {
+	.f = cmd_add_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Add port tm node private shaper profile",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_shaper_profile_add,
+		(void *)&cmd_add_port_tm_node_shaper_profile_port,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_add_port_tm_node_shaper_profile_node,
+		(void *)&cmd_add_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_add_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_add_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_add_port_tm_node_shaper_profile_shaper_id,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tb_rate,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tb_size,
+		(void *)&cmd_add_port_tm_node_shaper_profile_pktlen_adjust,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM Private Shaper Profile *** */
+struct cmd_del_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint16_t port_id;
+	uint32_t shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_del_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_tm_node_shaper_profile_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			shaper_id, UINT32);
+
+static void cmd_del_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t shaper_id = res->shaper_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_shaper_profile_delete(port_id, shaper_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_shaper_profile = {
+	.f = cmd_del_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node private shaper profile",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_shaper_profile_del,
+		(void *)&cmd_del_port_tm_node_shaper_profile_port,
+		(void *)&cmd_del_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_del_port_tm_node_shaper_profile_node,
+		(void *)&cmd_del_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_del_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_del_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_del_port_tm_node_shaper_profile_shaper_id,
+		NULL,
+	},
+};
+
+/* *** Add/Update Port TM shared Shaper *** */
+struct cmd_add_port_tm_node_shared_shaper_result {
+	cmdline_fixed_string_t cmd_type;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shared;
+	cmdline_fixed_string_t shaper;
+	uint16_t port_id;
+	uint32_t shared_shaper_id;
+	uint32_t shaper_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_cmd_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			cmd_type, "add#set");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_shared =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shared, "shared");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shaper, "shaper");
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shared_shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shaper_profile_id, UINT32);
+
+static void cmd_add_port_tm_node_shared_shaper_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_shared_shaper_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t shared_shaper_id = res->shared_shaper_id;
+	uint32_t shaper_profile_id = res->shaper_profile_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Command type: add */
+	if ((strcmp(res->cmd_type, "add") == 0) &&
+		(port_is_started(port_id))) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	/* Command type: set (update) */
+	if ((strcmp(res->cmd_type, "set") == 0) &&
+		(!port_is_started(port_id))) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_shared_shaper_add_update(port_id, shared_shaper_id,
+		shaper_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_shared_shaper = {
+	.f = cmd_add_port_tm_node_shared_shaper_parsed,
+	.data = NULL,
+	.help_str = "add/update port tm node shared shaper",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_shared_shaper_cmd_type,
+		(void *)&cmd_add_port_tm_node_shared_shaper_port,
+		(void *)&cmd_add_port_tm_node_shared_shaper_tm,
+		(void *)&cmd_add_port_tm_node_shared_shaper_node,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shared,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shaper,
+		(void *)&cmd_add_port_tm_node_shared_shaper_port_id,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shared_shaper_id,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shaper_profile_id,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM shared Shaper *** */
+struct cmd_del_port_tm_node_shared_shaper_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shared;
+	cmdline_fixed_string_t shaper;
+	uint16_t port_id;
+	uint32_t shared_shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_shared =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shared, "shared");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shaper, "shaper");
+cmdline_parse_token_num_t cmd_del_port_tm_node_shared_shaper_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_tm_node_shared_shaper_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shared_shaper_id, UINT32);
+
+static void cmd_del_port_tm_node_shared_shaper_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_shared_shaper_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t shared_shaper_id = res->shared_shaper_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_shared_shaper_delete(port_id, shared_shaper_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper = {
+	.f = cmd_del_port_tm_node_shared_shaper_parsed,
+	.data = NULL,
+	.help_str = "delete port tm node shared shaper",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_shared_shaper_del,
+		(void *)&cmd_del_port_tm_node_shared_shaper_port,
+		(void *)&cmd_del_port_tm_node_shared_shaper_tm,
+		(void *)&cmd_del_port_tm_node_shared_shaper_node,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shared,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shaper,
+		(void *)&cmd_del_port_tm_node_shared_shaper_port_id,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shared_shaper_id,
+		NULL,
+	},
+};
+
+/* *** Add Port TM Node WRED Profile *** */
+struct cmd_add_port_tm_node_wred_profile_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t wred;
+	cmdline_fixed_string_t profile;
+	uint16_t port_id;
+	uint32_t wred_profile_id;
+	cmdline_fixed_string_t color_g;
+	uint16_t min_th_g;
+	uint16_t max_th_g;
+	uint16_t maxp_inv_g;
+	uint16_t wq_log2_g;
+	cmdline_fixed_string_t color_y;
+	uint16_t min_th_y;
+	uint16_t max_th_y;
+	uint16_t maxp_inv_y;
+	uint16_t wq_log2_y;
+	cmdline_fixed_string_t color_r;
+	uint16_t min_th_r;
+	uint16_t max_th_r;
+	uint16_t maxp_inv_r;
+	uint16_t wq_log2_r;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_wred =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, wred, "wred");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wred_profile_id, UINT32);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_g =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_g, "G#g");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_g, UINT16);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_y =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_y, "Y#y");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_y, UINT16);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_r =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_r, "R#r");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_r, UINT16);
+
+
+static void cmd_add_port_tm_node_wred_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_wred_profile_result *res = parsed_result;
+	struct rte_tm_wred_params wp;
+	enum rte_tm_color color;
+	struct rte_tm_error error;
+	uint32_t wred_profile_id = res->wred_profile_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	memset(&wp, 0, sizeof(struct rte_tm_wred_params));
+
+	/* WRED Params  (Green Color)*/
+	if ((strcmp(res->color_g, "G") == 0) ||
+		(strcmp(res->color_g, "g") == 0)) {
+		color = RTE_TM_GREEN;
+		wp.red_params[color].min_th = res->min_th_g;
+		wp.red_params[color].max_th = res->max_th_g;
+		wp.red_params[color].maxp_inv = res->maxp_inv_g;
+		wp.red_params[color].wq_log2 = res->wq_log2_g;
+	} else {
+		printf("WRED profile error(G or g for green color)!\n");
+		return;
+	}
+
+	/* WRED Params  (Yellow Color)*/
+	if ((strcmp(res->color_y, "Y") == 0) ||
+		(strcmp(res->color_y, "y") == 0)) {
+		color = RTE_TM_YELLOW;
+		wp.red_params[color].min_th = res->min_th_y;
+		wp.red_params[color].max_th = res->max_th_y;
+		wp.red_params[color].maxp_inv = res->maxp_inv_y;
+		wp.red_params[color].wq_log2 = res->wq_log2_y;
+	} else {
+		printf("WRED profile error(Y or y for yellow color)!\n");
+		return;
+	}
+
+	/* WRED Params  (Red Color)*/
+	if ((strcmp(res->color_r, "R") == 0) ||
+		(strcmp(res->color_r, "r") == 0)) {
+		color = RTE_TM_RED;
+		wp.red_params[color].min_th = res->min_th_r;
+		wp.red_params[color].max_th = res->max_th_r;
+		wp.red_params[color].maxp_inv = res->maxp_inv_r;
+		wp.red_params[color].wq_log2 = res->wq_log2_r;
+	} else {
+		printf("WRED profile error(R or r for red color)!\n");
+		return;
+	}
+
+	ret = rte_tm_wred_profile_add(port_id, wred_profile_id, &wp, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile = {
+	.f = cmd_add_port_tm_node_wred_profile_parsed,
+	.data = NULL,
+	.help_str = "Add port tm node wred profile",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_wred_profile_add,
+		(void *)&cmd_add_port_tm_node_wred_profile_port,
+		(void *)&cmd_add_port_tm_node_wred_profile_tm,
+		(void *)&cmd_add_port_tm_node_wred_profile_node,
+		(void *)&cmd_add_port_tm_node_wred_profile_wred,
+		(void *)&cmd_add_port_tm_node_wred_profile_profile,
+		(void *)&cmd_add_port_tm_node_wred_profile_port_id,
+		(void *)&cmd_add_port_tm_node_wred_profile_wred_profile_id,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_r,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM node WRED Profile *** */
+struct cmd_del_port_tm_node_wred_profile_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t wred;
+	cmdline_fixed_string_t profile;
+	uint16_t port_id;
+	uint32_t wred_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_wred =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, wred, "wred");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_del_port_tm_node_wred_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_tm_node_wred_profile_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			wred_profile_id, UINT32);
+
+static void cmd_del_port_tm_node_wred_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_wred_profile_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t wred_profile_id = res->wred_profile_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_wred_profile_delete(port_id, wred_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile = {
+	.f = cmd_del_port_tm_node_wred_profile_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node wred profile",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_wred_profile_del,
+		(void *)&cmd_del_port_tm_node_wred_profile_port,
+		(void *)&cmd_del_port_tm_node_wred_profile_tm,
+		(void *)&cmd_del_port_tm_node_wred_profile_node,
+		(void *)&cmd_del_port_tm_node_wred_profile_wred,
+		(void *)&cmd_del_port_tm_node_wred_profile_profile,
+		(void *)&cmd_del_port_tm_node_wred_profile_port_id,
+		(void *)&cmd_del_port_tm_node_wred_profile_wred_profile_id,
+		NULL,
+	},
+};
+
+/* *** Update Port TM Node Shaper profile *** */
+struct cmd_set_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint16_t port_id;
+	uint32_t node_id;
+	uint32_t shaper_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_set_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_set_port_tm_node_shaper_profile_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_shaper_profile_result,
+		node_id, UINT32);
+cmdline_parse_token_num_t
+	cmd_set_port_tm_node_shaper_shaper_profile_profile_id =
+		TOKEN_NUM_INITIALIZER(
+			struct cmd_set_port_tm_node_shaper_profile_result,
+			shaper_profile_id, UINT32);
+
+static void cmd_set_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint32_t shaper_profile_id = res->shaper_profile_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (!port_is_started(port_id)) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_shaper_update(port_id, node_id,
+		shaper_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile = {
+	.f = cmd_set_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node shaper profile",
+	.tokens = {
+		(void *)&cmd_set_port_tm_node_shaper_profile_set,
+		(void *)&cmd_set_port_tm_node_shaper_profile_port,
+		(void *)&cmd_set_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_set_port_tm_node_shaper_profile_node,
+		(void *)&cmd_set_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_set_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_set_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_set_port_tm_node_shaper_profile_node_id,
+		(void *)&cmd_set_port_tm_node_shaper_shaper_profile_profile_id,
+		NULL,
+	},
+};
diff --git a/app/test-pmd/cmdline_tm.h b/app/test-pmd/cmdline_tm.h
index 945af89..5ed9de0 100644
--- a/app/test-pmd/cmdline_tm.h
+++ b/app/test-pmd/cmdline_tm.h
@@ -40,5 +40,12 @@ extern cmdline_parse_inst_t cmd_show_port_tm_level_cap;
 extern cmdline_parse_inst_t cmd_show_port_tm_node_cap;
 extern cmdline_parse_inst_t cmd_show_port_tm_node_type;
 extern cmdline_parse_inst_t cmd_show_port_tm_node_stats;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_shared_shaper;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile;
+extern cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile;
 
 #endif /* _CMDLINE_TM_H_ */
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v7 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit
  2017-10-11  9:26             ` [PATCH v7 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
  2017-10-11  9:26               ` [PATCH v7 2/3] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
@ 2017-10-11  9:26               ` Jasvinder Singh
  2017-10-13  2:58                 ` Wu, Jingjing
  2017-10-12 20:55               ` [PATCH v7 1/3] app/test-pmd: add CLI for TM capability and stats Thomas Monjalon
                                 ` (3 subsequent siblings)
  5 siblings, 1 reply; 49+ messages in thread
From: Jasvinder Singh @ 2017-10-11  9:26 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu, pablo.de.lara.guarch, yulong.pei

Add following CLIs in testpmd application for device traffic management;
- commands to add TM hierarchy nodes (leaf and nonleaf).
- command for runtime update of node weight.
- command to commit the TM hierarchy

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
v7 change:
- fix the help info on leaf node add

v5 change:
- add shaper related parameters to leaf node add command

v4 change:
- remove softnic specific checks to make it generic for the devices

 app/test-pmd/cmdline.c    |  27 +++
 app/test-pmd/cmdline_tm.c | 526 ++++++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/cmdline_tm.h |   5 +
 3 files changed, 558 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index d89583c..32211ea 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -683,6 +683,28 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"del port tm node wred profile (port_id) (wred_profile_id)\n"
 			"	Delete port tm node wred profile.\n\n"
 
+			"add port tm nonleaf node (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight) (level_id) (shaper_profile_id)"
+			" (shared_shaper_id) (n_shared_shapers) (n_sp_priorities)"
+			" (stats_mask)\n"
+			"	Add port tm nonleaf node.\n\n"
+
+			"add port tm leaf node (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight) (level_id) (shaper_profile_id)"
+			" (shared_shaper_id) (n_shared_shapers) (cman_mode)"
+			" (wred_profile_id) (stats_mask)\n"
+			"	Add port tm leaf node.\n\n"
+
+			"del port tm node (port_id) (node_id)\n"
+			"	Delete port tm node.\n\n"
+
+			"set port tm node parent (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight)\n"
+			"	Set port tm node parent.\n\n"
+
+			"port tm hierarchy commit (port_id) (clean_on_fail)\n"
+			"	Commit tm hierarchy.\n\n"
+
 			, list_pkt_forwarding_modes()
 		);
 	}
@@ -14872,6 +14894,11 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_wred_profile,
 	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_wred_profile,
 	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_nonleaf_node,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_leaf_node,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node,
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_parent,
+	(cmdline_parse_inst_t *)&cmd_port_tm_hierarchy_commit,
 	NULL,
 };
 
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
index f1cd810..a8b7c20 100644
--- a/app/test-pmd/cmdline_tm.c
+++ b/app/test-pmd/cmdline_tm.c
@@ -1427,3 +1427,529 @@ cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile = {
 		NULL,
 	},
 };
+
+/* *** Add Port TM nonleaf node *** */
+struct cmd_add_port_tm_nonleaf_node_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t nonleaf;
+	cmdline_fixed_string_t node;
+	uint16_t port_id;
+	uint32_t node_id;
+	int32_t parent_node_id;
+	uint32_t priority;
+	uint32_t weight;
+	uint32_t level_id;
+	uint32_t shaper_profile_id;
+	uint32_t shared_shaper_id;
+	uint32_t n_shared_shapers;
+	uint32_t n_sp_priorities;
+	uint64_t stats_mask;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_nonleaf =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, nonleaf, "nonleaf");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, node, "node");
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 node_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 parent_node_id, INT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 priority, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 weight, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 level_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 shaper_profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 shared_shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_n_shared_shapers =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 n_shared_shapers, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_n_sp_priorities =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 n_sp_priorities, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_stats_mask =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 stats_mask, UINT64);
+
+static void cmd_add_port_tm_nonleaf_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_nonleaf_node_result *res = parsed_result;
+	struct rte_tm_error error;
+	struct rte_tm_node_params np;
+	uint32_t parent_node_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	/* Node parameters */
+	if (res->parent_node_id < 0)
+		parent_node_id = UINT32_MAX;
+	else
+		parent_node_id = res->parent_node_id;
+
+	memset(&np, 0, sizeof(struct rte_tm_node_params));
+	np.shaper_profile_id = res->shaper_profile_id;
+	np.n_shared_shapers = res->n_shared_shapers;
+
+	if (np.n_shared_shapers == 1)
+		np.shared_shaper_id[0] = res->shared_shaper_id;
+	else
+		np.shared_shaper_id = NULL;
+
+	np.nonleaf.n_sp_priorities = res->n_sp_priorities;
+	np.stats_mask = res->stats_mask;
+	np.nonleaf.wfq_weight_mode = NULL;
+
+	ret = rte_tm_node_add(port_id, res->node_id, parent_node_id,
+				res->priority, res->weight, res->level_id,
+				&np, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_nonleaf_node = {
+	.f = cmd_add_port_tm_nonleaf_node_parsed,
+	.data = NULL,
+	.help_str = "Add port tm nonleaf node",
+	.tokens = {
+		(void *)&cmd_add_port_tm_nonleaf_node_add,
+		(void *)&cmd_add_port_tm_nonleaf_node_port,
+		(void *)&cmd_add_port_tm_nonleaf_node_tm,
+		(void *)&cmd_add_port_tm_nonleaf_node_nonleaf,
+		(void *)&cmd_add_port_tm_nonleaf_node_node,
+		(void *)&cmd_add_port_tm_nonleaf_node_port_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_node_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_parent_node_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_priority,
+		(void *)&cmd_add_port_tm_nonleaf_node_weight,
+		(void *)&cmd_add_port_tm_nonleaf_node_level_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_shaper_profile_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_shared_shaper_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_n_shared_shapers,
+		(void *)&cmd_add_port_tm_nonleaf_node_n_sp_priorities,
+		(void *)&cmd_add_port_tm_nonleaf_node_stats_mask,
+		NULL,
+	},
+};
+
+/* *** Add Port TM leaf node *** */
+struct cmd_add_port_tm_leaf_node_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t leaf;
+	cmdline_fixed_string_t node;
+	uint16_t port_id;
+	uint32_t node_id;
+	int32_t parent_node_id;
+	uint32_t priority;
+	uint32_t weight;
+	uint32_t level_id;
+	uint32_t shaper_profile_id;
+	uint32_t shared_shaper_id;
+	uint32_t n_shared_shapers;
+	uint32_t cman_mode;
+	uint32_t wred_profile_id;
+	uint64_t stats_mask;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_nonleaf =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, leaf, "leaf");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, node, "node");
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 node_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 parent_node_id, INT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 priority, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 weight, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 level_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 shaper_profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 shared_shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_n_shared_shapers =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 n_shared_shapers, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_cman_mode =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 cman_mode, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 wred_profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_stats_mask =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 stats_mask, UINT64);
+
+static void cmd_add_port_tm_leaf_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_leaf_node_result *res = parsed_result;
+	struct rte_tm_error error;
+	struct rte_tm_node_params np;
+	uint32_t parent_node_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	/* Node parameters */
+	if (res->parent_node_id < 0)
+		parent_node_id = UINT32_MAX;
+	else
+		parent_node_id = res->parent_node_id;
+
+	memset(&np, 0, sizeof(struct rte_tm_node_params));
+	np.shaper_profile_id = res->shaper_profile_id;
+	np.n_shared_shapers = res->n_shared_shapers;
+
+	if (np.n_shared_shapers == 1)
+		np.shared_shaper_id[0] = res->shared_shaper_id;
+	else
+		np.shared_shaper_id = NULL;
+
+	np.leaf.cman = res->cman_mode;
+	np.leaf.wred.wred_profile_id = res->wred_profile_id;
+	np.stats_mask = res->stats_mask;
+
+	ret = rte_tm_node_add(port_id, res->node_id, parent_node_id,
+				res->priority, res->weight, res->level_id,
+				&np, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_leaf_node = {
+	.f = cmd_add_port_tm_leaf_node_parsed,
+	.data = NULL,
+	.help_str = "Add port tm leaf node",
+	.tokens = {
+		(void *)&cmd_add_port_tm_leaf_node_add,
+		(void *)&cmd_add_port_tm_leaf_node_port,
+		(void *)&cmd_add_port_tm_leaf_node_tm,
+		(void *)&cmd_add_port_tm_leaf_node_nonleaf,
+		(void *)&cmd_add_port_tm_leaf_node_node,
+		(void *)&cmd_add_port_tm_leaf_node_port_id,
+		(void *)&cmd_add_port_tm_leaf_node_node_id,
+		(void *)&cmd_add_port_tm_leaf_node_parent_node_id,
+		(void *)&cmd_add_port_tm_leaf_node_priority,
+		(void *)&cmd_add_port_tm_leaf_node_weight,
+		(void *)&cmd_add_port_tm_leaf_node_level_id,
+		(void *)&cmd_add_port_tm_leaf_node_shaper_profile_id,
+		(void *)&cmd_add_port_tm_leaf_node_shared_shaper_id,
+		(void *)&cmd_add_port_tm_leaf_node_n_shared_shapers,
+		(void *)&cmd_add_port_tm_leaf_node_cman_mode,
+		(void *)&cmd_add_port_tm_leaf_node_wred_profile_id,
+		(void *)&cmd_add_port_tm_leaf_node_stats_mask,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM Node *** */
+struct cmd_del_port_tm_node_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	uint16_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, node, "node");
+cmdline_parse_token_num_t cmd_del_port_tm_node_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_del_port_tm_node_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_tm_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_del_port_tm_node_result,
+		node_id, UINT32);
+
+static void cmd_del_port_tm_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_delete(port_id, node_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node = {
+	.f = cmd_del_port_tm_node_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_del,
+		(void *)&cmd_del_port_tm_node_port,
+		(void *)&cmd_del_port_tm_node_tm,
+		(void *)&cmd_del_port_tm_node_node,
+		(void *)&cmd_del_port_tm_node_port_id,
+		(void *)&cmd_del_port_tm_node_node_id,
+		NULL,
+	},
+};
+
+/* *** Update Port TM Node Parent *** */
+struct cmd_set_port_tm_node_parent_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t parent;
+	uint16_t port_id;
+	uint32_t node_id;
+	uint32_t parent_id;
+	uint32_t priority;
+	uint32_t weight;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, node, "node");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_parent =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, parent, "parent");
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, port_id, UINT16);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, node_id, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_parent_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		parent_id, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		priority, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		weight, UINT32);
+
+static void cmd_set_port_tm_node_parent_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_node_parent_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint32_t parent_id = res->parent_id;
+	uint32_t priority = res->priority;
+	uint32_t weight = res->weight;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (!port_is_started(port_id)) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_parent_update(port_id, node_id,
+		parent_id, priority, weight, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_node_parent = {
+	.f = cmd_set_port_tm_node_parent_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node parent",
+	.tokens = {
+		(void *)&cmd_set_port_tm_node_parent_set,
+		(void *)&cmd_set_port_tm_node_parent_port,
+		(void *)&cmd_set_port_tm_node_parent_tm,
+		(void *)&cmd_set_port_tm_node_parent_node,
+		(void *)&cmd_set_port_tm_node_parent_parent,
+		(void *)&cmd_set_port_tm_node_parent_port_id,
+		(void *)&cmd_set_port_tm_node_parent_node_id,
+		(void *)&cmd_set_port_tm_node_parent_parent_id,
+		(void *)&cmd_set_port_tm_node_parent_priority,
+		(void *)&cmd_set_port_tm_node_parent_weight,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchy Commit *** */
+struct cmd_port_tm_hierarchy_commit_result {
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t hierarchy;
+	cmdline_fixed_string_t commit;
+	uint16_t port_id;
+	uint32_t clean_on_fail;
+};
+
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, port, "port");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, tm, "tm");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_hierarchy =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result,
+			hierarchy, "hierarchy");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_commit =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, commit, "commit");
+cmdline_parse_token_num_t cmd_port_tm_hierarchy_commit_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_port_tm_hierarchy_commit_clean_on_fail =
+	TOKEN_NUM_INITIALIZER(struct cmd_port_tm_hierarchy_commit_result,
+		 clean_on_fail, UINT32);
+
+static void cmd_port_tm_hierarchy_commit_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_port_tm_hierarchy_commit_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t clean_on_fail = res->clean_on_fail;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_hierarchy_commit(port_id, clean_on_fail, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_port_tm_hierarchy_commit = {
+	.f = cmd_port_tm_hierarchy_commit_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node shaper profile",
+	.tokens = {
+		(void *)&cmd_port_tm_hierarchy_commit_port,
+		(void *)&cmd_port_tm_hierarchy_commit_tm,
+		(void *)&cmd_port_tm_hierarchy_commit_hierarchy,
+		(void *)&cmd_port_tm_hierarchy_commit_commit,
+		(void *)&cmd_port_tm_hierarchy_commit_port_id,
+		(void *)&cmd_port_tm_hierarchy_commit_clean_on_fail,
+		NULL,
+	},
+};
diff --git a/app/test-pmd/cmdline_tm.h b/app/test-pmd/cmdline_tm.h
index 5ed9de0..9d5fdf0 100644
--- a/app/test-pmd/cmdline_tm.h
+++ b/app/test-pmd/cmdline_tm.h
@@ -47,5 +47,10 @@ extern cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper;
 extern cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile;
 extern cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile;
 extern cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_add_port_tm_nonleaf_node;
+extern cmdline_parse_inst_t cmd_add_port_tm_leaf_node;
+extern cmdline_parse_inst_t cmd_del_port_tm_node;
+extern cmdline_parse_inst_t cmd_set_port_tm_node_parent;
+extern cmdline_parse_inst_t cmd_port_tm_hierarchy_commit;
 
 #endif /* _CMDLINE_TM_H_ */
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* Re: [PATCH v7 1/3] app/test-pmd: add CLI for TM capability and stats
  2017-10-11  9:26             ` [PATCH v7 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
  2017-10-11  9:26               ` [PATCH v7 2/3] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
  2017-10-11  9:26               ` [PATCH v7 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
@ 2017-10-12 20:55               ` Thomas Monjalon
  2017-10-13  2:34               ` Wu, Jingjing
                                 ` (2 subsequent siblings)
  5 siblings, 0 replies; 49+ messages in thread
From: Thomas Monjalon @ 2017-10-12 20:55 UTC (permalink / raw)
  To: jingjing.wu
  Cc: dev, Jasvinder Singh, cristian.dumitrescu, pablo.de.lara.guarch,
	yulong.pei

Jingjing, please could you review this series?
Thanks

11/10/2017 11:26, Jasvinder Singh:
> Add following CLIs to testpmd application for device traffic management;
> - commands to display TM capability information.
>   (per port, per hierarchy level and per hierarchy node)
> - command to display hiearchy node type
> - stats collection
> 
> Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7 2/3] app/test-pmd: add CLI for shaper and wred profiles
  2017-10-11  9:26               ` [PATCH v7 2/3] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
@ 2017-10-13  2:33                 ` Wu, Jingjing
  2017-10-13  8:58                   ` Singh, Jasvinder
  0 siblings, 1 reply; 49+ messages in thread
From: Wu, Jingjing @ 2017-10-13  2:33 UTC (permalink / raw)
  To: Singh, Jasvinder, dev
  Cc: Dumitrescu, Cristian, De Lara Guarch, Pablo, Pei, Yulong

> +/* *** Add Port TM Node WRED Profile *** */ struct
> +cmd_add_port_tm_node_wred_profile_result {
> +	cmdline_fixed_string_t add;
> +	cmdline_fixed_string_t port;
> +	cmdline_fixed_string_t tm;
> +	cmdline_fixed_string_t node;
> +	cmdline_fixed_string_t wred;
> +	cmdline_fixed_string_t profile;
> +	uint16_t port_id;
> +	uint32_t wred_profile_id;
> +	cmdline_fixed_string_t color_g;
> +	uint16_t min_th_g;
> +	uint16_t max_th_g;
> +	uint16_t maxp_inv_g;
> +	uint16_t wq_log2_g;
> +	cmdline_fixed_string_t color_y;
> +	uint16_t min_th_y;
> +	uint16_t max_th_y;
> +	uint16_t maxp_inv_y;
> +	uint16_t wq_log2_y;
> +	cmdline_fixed_string_t color_r;
> +	uint16_t min_th_r;
> +	uint16_t max_th_r;
> +	uint16_t maxp_inv_r;
> +	uint16_t wq_log2_r;
> +};
> +
> +cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_add =
> +	TOKEN_STRING_INITIALIZER(
> +		struct cmd_add_port_tm_node_wred_profile_result, add,
> "add");
> +cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_port =
> +	TOKEN_STRING_INITIALIZER(
> +		struct cmd_add_port_tm_node_wred_profile_result, port,
> "port");
> +cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_tm =
> +	TOKEN_STRING_INITIALIZER(
> +		struct cmd_add_port_tm_node_wred_profile_result, tm, "tm");
> +cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_node =
> +	TOKEN_STRING_INITIALIZER(
> +		struct cmd_add_port_tm_node_wred_profile_result, node,
> "node");
> +cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_wred =
> +	TOKEN_STRING_INITIALIZER(
> +		struct cmd_add_port_tm_node_wred_profile_result, wred,
> "wred");
> +cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_profile
> =
> +	TOKEN_STRING_INITIALIZER(
> +		struct cmd_add_port_tm_node_wred_profile_result,
> +			profile, "profile");
> +cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_port_id
> =
> +	TOKEN_NUM_INITIALIZER(
> +		struct cmd_add_port_tm_node_wred_profile_result,
> +			port_id, UINT16);
> +cmdline_parse_token_num_t
> cmd_add_port_tm_node_wred_profile_wred_profile_id =
> +	TOKEN_NUM_INITIALIZER(
> +		struct cmd_add_port_tm_node_wred_profile_result,
> +			wred_profile_id, UINT32);
> +cmdline_parse_token_string_t
> cmd_add_port_tm_node_wred_profile_color_g =
> +	TOKEN_STRING_INITIALIZER(
> +		struct cmd_add_port_tm_node_wred_profile_result,
> +			color_g, "G#g");
> +cmdline_parse_token_num_t
> cmd_add_port_tm_node_wred_profile_min_th_g =
> +	TOKEN_NUM_INITIALIZER(
> +		struct cmd_add_port_tm_node_wred_profile_result,
> +			min_th_g, UINT16);
> +cmdline_parse_token_num_t
> cmd_add_port_tm_node_wred_profile_max_th_g =
> +	TOKEN_NUM_INITIALIZER(
> +		struct cmd_add_port_tm_node_wred_profile_result,
> +			max_th_g, UINT16);
> +cmdline_parse_token_num_t
> cmd_add_port_tm_node_wred_profile_maxp_inv_g =
> +	TOKEN_NUM_INITIALIZER(
> +		struct cmd_add_port_tm_node_wred_profile_result,
> +			maxp_inv_g, UINT16);
> +cmdline_parse_token_num_t
> cmd_add_port_tm_node_wred_profile_wq_log2_g =
> +	TOKEN_NUM_INITIALIZER(
> +		struct cmd_add_port_tm_node_wred_profile_result,
> +			wq_log2_g, UINT16);
> +cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_y
> =
> +	TOKEN_STRING_INITIALIZER(
> +		struct cmd_add_port_tm_node_wred_profile_result,
> +			color_y, "Y#y");
> +cmdline_parse_token_num_t
> cmd_add_port_tm_node_wred_profile_min_th_y =
> +	TOKEN_NUM_INITIALIZER(
> +		struct cmd_add_port_tm_node_wred_profile_result,
> +			min_th_y, UINT16);
> +cmdline_parse_token_num_t
> cmd_add_port_tm_node_wred_profile_max_th_y =
> +	TOKEN_NUM_INITIALIZER(
> +		struct cmd_add_port_tm_node_wred_profile_result,
> +			max_th_y, UINT16);
> +cmdline_parse_token_num_t
> cmd_add_port_tm_node_wred_profile_maxp_inv_y =
> +	TOKEN_NUM_INITIALIZER(
> +		struct cmd_add_port_tm_node_wred_profile_result,
> +			maxp_inv_y, UINT16);
> +cmdline_parse_token_num_t
> cmd_add_port_tm_node_wred_profile_wq_log2_y =
> +	TOKEN_NUM_INITIALIZER(
> +		struct cmd_add_port_tm_node_wred_profile_result,
> +			wq_log2_y, UINT16);
> +cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_r
> =
> +	TOKEN_STRING_INITIALIZER(
> +		struct cmd_add_port_tm_node_wred_profile_result,
> +			color_r, "R#r");
> +cmdline_parse_token_num_t
> cmd_add_port_tm_node_wred_profile_min_th_r =
> +	TOKEN_NUM_INITIALIZER(
> +		struct cmd_add_port_tm_node_wred_profile_result,
> +			min_th_r, UINT16);
> +cmdline_parse_token_num_t
> cmd_add_port_tm_node_wred_profile_max_th_r =
> +	TOKEN_NUM_INITIALIZER(
> +		struct cmd_add_port_tm_node_wred_profile_result,
> +			max_th_r, UINT16);
> +cmdline_parse_token_num_t
> cmd_add_port_tm_node_wred_profile_maxp_inv_r =
> +	TOKEN_NUM_INITIALIZER(
> +		struct cmd_add_port_tm_node_wred_profile_result,
> +			maxp_inv_r, UINT16);
> +cmdline_parse_token_num_t
> cmd_add_port_tm_node_wred_profile_wq_log2_r =
> +	TOKEN_NUM_INITIALIZER(
> +		struct cmd_add_port_tm_node_wred_profile_result,
> +			wq_log2_r, UINT16);
> +
> +
> +static void cmd_add_port_tm_node_wred_profile_parsed(void *parsed_result,
> +	__attribute__((unused)) struct cmdline *cl,
> +	__attribute__((unused)) void *data)
> +{
> +	struct cmd_add_port_tm_node_wred_profile_result *res =
> parsed_result;
> +	struct rte_tm_wred_params wp;
> +	enum rte_tm_color color;
> +	struct rte_tm_error error;
> +	uint32_t wred_profile_id = res->wred_profile_id;
> +	portid_t port_id = res->port_id;
> +	int ret;
> +
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))
> +		return;
> +
> +	memset(&wp, 0, sizeof(struct rte_tm_wred_params));
> +
> +	/* WRED Params  (Green Color)*/
> +	if ((strcmp(res->color_g, "G") == 0) ||
> +		(strcmp(res->color_g, "g") == 0)) {
> +		color = RTE_TM_GREEN;
> +		wp.red_params[color].min_th = res->min_th_g;
> +		wp.red_params[color].max_th = res->max_th_g;
> +		wp.red_params[color].maxp_inv = res->maxp_inv_g;
> +		wp.red_params[color].wq_log2 = res->wq_log2_g;
> +	} else {
> +		printf("WRED profile error(G or g for green color)!\n");
> +		return;
> +	}
> +
No need to check the res->color_g, because it already be checked by cmdline.
Because you defined it like
cmd_add_port_tm_node_wred_profile_color_g =
	TOKEN_STRING_INITIALIZER(
		struct cmd_add_port_tm_node_wred_profile_result,
			color_g, "G#g");
You can just assign wp.red_params[RTE_TM_GREEN] directly.
The similar as color_y, color_r.

And is that possible for you to set WERD with less than 3 colors? If so, you may need
to change your command definition. 

Thanks
Jingjing

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7 1/3] app/test-pmd: add CLI for TM capability and stats
  2017-10-11  9:26             ` [PATCH v7 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
                                 ` (2 preceding siblings ...)
  2017-10-12 20:55               ` [PATCH v7 1/3] app/test-pmd: add CLI for TM capability and stats Thomas Monjalon
@ 2017-10-13  2:34               ` Wu, Jingjing
  2017-10-13  6:22               ` Pei, Yulong
  2017-10-13 16:59               ` [PATCH v8 " Jasvinder Singh
  5 siblings, 0 replies; 49+ messages in thread
From: Wu, Jingjing @ 2017-10-13  2:34 UTC (permalink / raw)
  To: Singh, Jasvinder, dev
  Cc: Dumitrescu, Cristian, De Lara Guarch, Pablo, Pei, Yulong



> -----Original Message-----
> From: Singh, Jasvinder
> Sent: Wednesday, October 11, 2017 5:26 PM
> To: dev@dpdk.org
> Cc: Dumitrescu, Cristian <cristian.dumitrescu@intel.com>; Wu, Jingjing
> <jingjing.wu@intel.com>; De Lara Guarch, Pablo
> <pablo.de.lara.guarch@intel.com>; Pei, Yulong <yulong.pei@intel.com>
> Subject: [PATCH v7 1/3] app/test-pmd: add CLI for TM capability and stats
> 
> Add following CLIs to testpmd application for device traffic management;
> - commands to display TM capability information.
>   (per port, per hierarchy level and per hierarchy node)
> - command to display hiearchy node type
> - stats collection
> 
> Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>

Reviewed-by: Jingjing Wu <jingjing.wu@intel.com>

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit
  2017-10-11  9:26               ` [PATCH v7 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
@ 2017-10-13  2:58                 ` Wu, Jingjing
  2017-10-13 10:50                   ` Singh, Jasvinder
  0 siblings, 1 reply; 49+ messages in thread
From: Wu, Jingjing @ 2017-10-13  2:58 UTC (permalink / raw)
  To: Singh, Jasvinder, dev
  Cc: Dumitrescu, Cristian, De Lara Guarch, Pablo, Pei, Yulong

> +	/* Port status */
> +	if (port_is_started(port_id)) {
> +		printf(" Port %u not stopped (error)\n", port_id);
> +		return;
> +	}
> +
> +	/* Node parameters */
> +	if (res->parent_node_id < 0)
> +		parent_node_id = UINT32_MAX;
> +	else
> +		parent_node_id = res->parent_node_id;
> +
> +	memset(&np, 0, sizeof(struct rte_tm_node_params));
> +	np.shaper_profile_id = res->shaper_profile_id;
> +	np.n_shared_shapers = res->n_shared_shapers;
> +
> +	if (np.n_shared_shapers == 1)
> +		np.shared_shaper_id[0] = res->shared_shaper_id;
> +	else
> +		np.shared_shaper_id = NULL;
> +

Does n_shared_shapers means number of shared_shapers? And now we only support 1?
When refer to the definition of struct rte_tm_node_params, the shared_shaper_id arry need to
be allocated by user, but I didn't find the allocation here or even in patch 2/3.

The same comments for below commands.

[......]

> +/* *** Port TM Hierarchy Commit *** */
> +struct cmd_port_tm_hierarchy_commit_result {
> +	cmdline_fixed_string_t port;
> +	cmdline_fixed_string_t tm;
> +	cmdline_fixed_string_t hierarchy;
> +	cmdline_fixed_string_t commit;
> +	uint16_t port_id;
> +	uint32_t clean_on_fail;
> +};
> +
> +cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_port =
> +	TOKEN_STRING_INITIALIZER(
> +		struct cmd_port_tm_hierarchy_commit_result, port, "port");
> +cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_tm =
> +	TOKEN_STRING_INITIALIZER(
> +		struct cmd_port_tm_hierarchy_commit_result, tm, "tm");
> +cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_hierarchy =
> +	TOKEN_STRING_INITIALIZER(
> +		struct cmd_port_tm_hierarchy_commit_result,
> +			hierarchy, "hierarchy");
> +cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_commit =
> +	TOKEN_STRING_INITIALIZER(
> +		struct cmd_port_tm_hierarchy_commit_result, commit,
> "commit");
> +cmdline_parse_token_num_t cmd_port_tm_hierarchy_commit_port_id =
> +	TOKEN_NUM_INITIALIZER(
> +		struct cmd_port_tm_hierarchy_commit_result,
> +			port_id, UINT16);
> +cmdline_parse_token_num_t cmd_port_tm_hierarchy_commit_clean_on_fail
> =
> +	TOKEN_NUM_INITIALIZER(struct
> cmd_port_tm_hierarchy_commit_result,
> +		 clean_on_fail, UINT32);
How about the define clean_on_fail to be a string like "(clean|no_clean)" or "clean_on_fail (yes|no)"?

And don't forget the doc update for all the new commands.

Thanks
Jingjing

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7 1/3] app/test-pmd: add CLI for TM capability and stats
  2017-10-11  9:26             ` [PATCH v7 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
                                 ` (3 preceding siblings ...)
  2017-10-13  2:34               ` Wu, Jingjing
@ 2017-10-13  6:22               ` Pei, Yulong
  2017-10-13 16:59               ` [PATCH v8 " Jasvinder Singh
  5 siblings, 0 replies; 49+ messages in thread
From: Pei, Yulong @ 2017-10-13  6:22 UTC (permalink / raw)
  To: Singh, Jasvinder, dev
  Cc: Dumitrescu, Cristian, Wu, Jingjing, De Lara Guarch, Pablo,
	Thomas Monjalon

Tested  testpmd CLI for TM with ixgbe, i40e and softnic.

Tested-by: Yulong Pei  <yulong.pei@intel.com>

-----Original Message-----
From: Singh, Jasvinder 
Sent: Wednesday, October 11, 2017 5:26 PM
To: dev@dpdk.org
Cc: Dumitrescu, Cristian <cristian.dumitrescu@intel.com>; Wu, Jingjing <jingjing.wu@intel.com>; De Lara Guarch, Pablo <pablo.de.lara.guarch@intel.com>; Pei, Yulong <yulong.pei@intel.com>
Subject: [PATCH v7 1/3] app/test-pmd: add CLI for TM capability and stats

Add following CLIs to testpmd application for device traffic management;
- commands to display TM capability information.
  (per port, per hierarchy level and per hierarchy node)
- command to display hiearchy node type
- stats collection

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
v6 change:
- fix compilation warning
- change port_id type to uint16_t

v4 change:
 - remove softnic specific checks to make it generic for the devices

v3 change:
- Implements feedback from Pablo[1]
 - move TM API related CLIs into cmdline_tm.c
 - split patch into small patches
 - replace link status check with testpmd fn port_is_started()

[1]http://dpdk.org/ml/archives/dev/2017-September/075748.html
---
 app/test-pmd/Makefile     |   1 +
 app/test-pmd/cmdline.c    |  20 ++
 app/test-pmd/cmdline_tm.c | 681 ++++++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/cmdline_tm.h |  44 +++
 4 files changed, 746 insertions(+)
 create mode 100644 app/test-pmd/cmdline_tm.c  create mode 100644 app/test-pmd/cmdline_tm.h

diff --git a/app/test-pmd/Makefile b/app/test-pmd/Makefile index b6e80dd..b78c73a 100644
--- a/app/test-pmd/Makefile
+++ b/app/test-pmd/Makefile
@@ -48,6 +48,7 @@ SRCS-y := testpmd.c
 SRCS-y += parameters.c
 SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline.c
 SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline_flow.c
+SRCS-y += cmdline_tm.c
 SRCS-y += config.c
 SRCS-y += iofwd.c
 SRCS-y += macfwd.c
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index 91766bc..2376f23 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -99,6 +99,7 @@
 #include <rte_pmd_bnxt.h>
 #endif
 #include "testpmd.h"
+#include "cmdline_tm.h"
 
 static struct cmdline *testpmd_cl;
 
@@ -234,6 +235,20 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"show port (port_id) pctype mapping\n"
 			"    Get flow ptype to pctype mapping on a port\n\n"
 
+			"show port tm cap (port_id)\n"
+			"	Display the port TM capability.\n\n"
+
+			"show port tm level cap (port_id) (level_id)\n"
+			"	Display the port TM hierarchical level capability.\n\n"
+
+			"show port tm node cap (port_id) (node_id)\n"
+			"	Display the port TM node capability.\n\n"
+
+			"show port tm node type (port_id) (node_id)\n"
+			"	Display the port TM node type.\n\n"
+
+			"show port tm node stats (port_id) (node_id) (clear)\n"
+			"	Display the port TM node stats.\n\n"
 		);
 	}
 
@@ -14818,6 +14833,11 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_pctype_mapping_get,
 	(cmdline_parse_inst_t *)&cmd_pctype_mapping_reset,
 	(cmdline_parse_inst_t *)&cmd_pctype_mapping_update,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_level_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_type,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_stats,
 	NULL,
 };
 
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c new file mode 100644 index 0000000..f024372
--- /dev/null
+++ b/app/test-pmd/cmdline_tm.c
@@ -0,0 +1,681 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+
+#include <rte_ethdev.h>
+#include <rte_flow.h>
+#include <rte_tm.h>
+
+#include "testpmd.h"
+#include "cmdline_tm.h"
+
+/** Display TM Error Message */
+static void
+print_err_msg(struct rte_tm_error *error) {
+	static const char *const errstrlist[] = {
+		[RTE_TM_ERROR_TYPE_NONE] = "no error",
+		[RTE_TM_ERROR_TYPE_UNSPECIFIED] = "cause unspecified",
+		[RTE_TM_ERROR_TYPE_CAPABILITIES]
+			= "capability parameter null",
+		[RTE_TM_ERROR_TYPE_LEVEL_ID] = "level id",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE]
+			= "wred profile null",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_GREEN] = "wred profile(green)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_YELLOW]
+			= "wred profile(yellow)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_RED] = "wred profile(red)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_ID] = "wred profile id",
+		[RTE_TM_ERROR_TYPE_SHARED_WRED_CONTEXT_ID]
+			= "shared wred context id",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE] = "shaper profile null",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE]
+			= "committed rate field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE]
+			= "committed size field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE]
+			= "peak rate field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE]
+			= "peak size field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN]
+			= "packet adjust length field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID] = "shaper profile id",
+		[RTE_TM_ERROR_TYPE_SHARED_SHAPER_ID] = "shared shaper id",
+		[RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID] = "parent node id",
+		[RTE_TM_ERROR_TYPE_NODE_PRIORITY] = "node priority",
+		[RTE_TM_ERROR_TYPE_NODE_WEIGHT] = "node weight",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS] = "node parameter null",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID]
+			= "shaper profile id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID]
+			= "shared shaper id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS]
+			= "num shared shapers field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE]
+			= "wfq weght mode field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES]
+			= "num strict priorities field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN]
+			= "congestion management mode field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID] =
+			"wred profile id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID]
+			= "shared wred context id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS]
+			= "num shared wred contexts field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS]
+			= "stats field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_ID] = "node id",
+	};
+
+	const char *errstr;
+	char buf[64];
+
+	if ((unsigned int)error->type >= RTE_DIM(errstrlist) ||
+		!errstrlist[error->type])
+		errstr = "unknown type";
+	else
+		errstr = errstrlist[error->type];
+
+	if (error->cause)
+		snprintf(buf, sizeof(buf), "cause: %p, ", error->cause);
+
+	printf("%s: %s%s (error %d)\n", errstr, error->cause ? buf : "",
+		error->message ? error->message : "(no stated reason)",
+		error->type);
+}
+
+/* *** Port TM Capability *** */
+struct cmd_show_port_tm_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t cap;
+	uint16_t port_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		 port_id, UINT16);
+
+static void cmd_show_port_tm_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_cap_result *res = parsed_result;
+	struct rte_tm_capabilities cap;
+	struct rte_tm_error error;
+	portid_t port_id = res->port_id;
+	uint32_t i;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	memset(&cap, 0, sizeof(struct rte_tm_capabilities));
+	ret = rte_tm_capabilities_get(port_id, &cap, &error);
+	if (ret) {
+		print_err_msg(&error);
+		return;
+	}
+
+	printf("\n****   Port TM Capabilities ****\n\n");
+	printf("cap.n_nodes_max %" PRIu32 "\n", cap.n_nodes_max);
+	printf("cap.n_levels_max %" PRIu32 "\n", cap.n_levels_max);
+	printf("cap.non_leaf_nodes_identical %" PRId32 "\n",
+		cap.non_leaf_nodes_identical);
+	printf("cap.leaf_nodes_identical %" PRId32 "\n",
+		cap.leaf_nodes_identical);
+	printf("cap.shaper_n_max %u\n", cap.shaper_n_max);
+	printf("cap.shaper_private_n_max %" PRIu32 "\n",
+		cap.shaper_private_n_max);
+	printf("cap.shaper_private_dual_rate_n_max %" PRId32 "\n",
+		cap.shaper_private_dual_rate_n_max);
+	printf("cap.shaper_private_rate_min %" PRIu64 "\n",
+		cap.shaper_private_rate_min);
+	printf("cap.shaper_private_rate_max %" PRIu64 "\n",
+		cap.shaper_private_rate_max);
+	printf("cap.shaper_shared_n_max %" PRIu32 "\n",
+		cap.shaper_shared_n_max);
+	printf("cap.shaper_shared_n_nodes_per_shaper_max %" PRIu32 "\n",
+		cap.shaper_shared_n_nodes_per_shaper_max);
+	printf("cap.shaper_shared_n_shapers_per_node_max %" PRIu32 "\n",
+		cap.shaper_shared_n_shapers_per_node_max);
+	printf("cap.shaper_shared_dual_rate_n_max %" PRIu32 "\n",
+		cap.shaper_shared_dual_rate_n_max);
+	printf("cap.shaper_shared_rate_min %" PRIu64 "\n",
+		cap.shaper_shared_rate_min);
+	printf("cap.shaper_shared_rate_max %" PRIu64 "\n",
+		cap.shaper_shared_rate_max);
+	printf("cap.shaper_pkt_length_adjust_min %" PRId32 "\n",
+		cap.shaper_pkt_length_adjust_min);
+	printf("cap.shaper_pkt_length_adjust_max %" PRId32 "\n",
+		cap.shaper_pkt_length_adjust_max);
+	printf("cap.sched_n_children_max %" PRIu32 "\n",
+		cap.sched_n_children_max);
+	printf("cap.sched_sp_n_priorities_max %" PRIu32 "\n",
+		cap.sched_sp_n_priorities_max);
+	printf("cap.sched_wfq_n_children_per_group_max %" PRIu32 "\n",
+		cap.sched_wfq_n_children_per_group_max);
+	printf("cap.sched_wfq_n_groups_max %" PRIu32 "\n",
+		cap.sched_wfq_n_groups_max);
+	printf("cap.sched_wfq_weight_max %" PRIu32 "\n",
+		cap.sched_wfq_weight_max);
+	printf("cap.cman_head_drop_supported %" PRId32 "\n",
+		cap.cman_head_drop_supported);
+	printf("cap.cman_wred_context_n_max %" PRIu32 "\n",
+		cap.cman_wred_context_n_max);
+	printf("cap.cman_wred_context_private_n_max %" PRIu32 "\n",
+		cap.cman_wred_context_private_n_max);
+	printf("cap.cman_wred_context_shared_n_max %" PRIu32 "\n",
+		cap.cman_wred_context_shared_n_max);
+	printf("cap.cman_wred_context_shared_n_nodes_per_context_max %" PRIu32
+		"\n", cap.cman_wred_context_shared_n_nodes_per_context_max);
+	printf("cap.cman_wred_context_shared_n_contexts_per_node_max %" PRIu32
+		"\n", cap.cman_wred_context_shared_n_contexts_per_node_max);
+
+	for (i = 0; i < RTE_TM_COLORS; i++) {
+		printf("cap.mark_vlan_dei_supported %" PRId32 "\n",
+			cap.mark_vlan_dei_supported[i]);
+		printf("cap.mark_ip_ecn_tcp_supported %" PRId32 "\n",
+			cap.mark_ip_ecn_tcp_supported[i]);
+		printf("cap.mark_ip_ecn_sctp_supported %" PRId32 "\n",
+			cap.mark_ip_ecn_sctp_supported[i]);
+		printf("cap.mark_ip_dscp_supported %" PRId32 "\n",
+			cap.mark_ip_dscp_supported[i]);
+	}
+
+	printf("cap.dynamic_update_mask %" PRIx64 "\n",
+		cap.dynamic_update_mask);
+	printf("cap.stats_mask %" PRIx64 "\n", cap.stats_mask); }
+
+cmdline_parse_inst_t cmd_show_port_tm_cap = {
+	.f = cmd_show_port_tm_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_cap_show,
+		(void *)&cmd_show_port_tm_cap_port,
+		(void *)&cmd_show_port_tm_cap_tm,
+		(void *)&cmd_show_port_tm_cap_cap,
+		(void *)&cmd_show_port_tm_cap_port_id,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchical Level Capability *** */ struct 
+cmd_show_port_tm_level_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t level;
+	cmdline_fixed_string_t cap;
+	uint16_t port_id;
+	uint32_t level_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_level =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		level, "level");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_level_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_level_cap_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		 level_id, UINT32);
+
+
+static void cmd_show_port_tm_level_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_level_cap_result *res = parsed_result;
+	struct rte_tm_level_capabilities lcap;
+	struct rte_tm_error error;
+	portid_t port_id = res->port_id;
+	uint32_t level_id = res->level_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	memset(&lcap, 0, sizeof(struct rte_tm_level_capabilities));
+	ret = rte_tm_level_capabilities_get(port_id, level_id, &lcap, &error);
+	if (ret) {
+		print_err_msg(&error);
+		return;
+	}
+	printf("\n**   Port TM Hierarchy level %" PRIu32 " Capability **\n\n",
+		level_id);
+
+	printf("cap.n_nodes_max %" PRIu32 "\n", lcap.n_nodes_max);
+	printf("cap.n_nodes_nonleaf_max %" PRIu32 "\n",
+		lcap.n_nodes_nonleaf_max);
+	printf("cap.n_nodes_leaf_max %" PRIu32 "\n", lcap.n_nodes_leaf_max);
+	printf("cap.non_leaf_nodes_identical %" PRId32 "\n",
+		lcap.non_leaf_nodes_identical);
+	printf("cap.leaf_nodes_identical %" PRId32 "\n",
+		lcap.leaf_nodes_identical);
+	if (level_id <= 3) {
+		printf("cap.nonleaf.shaper_private_supported %" PRId32 "\n",
+			lcap.nonleaf.shaper_private_supported);
+		printf("cap.nonleaf.shaper_private_dual_rate_supported %" PRId32
+			"\n", lcap.nonleaf.shaper_private_dual_rate_supported);
+		printf("cap.nonleaf.shaper_private_rate_min %" PRIu64 "\n",
+			lcap.nonleaf.shaper_private_rate_min);
+		printf("cap.nonleaf.shaper_private_rate_max %" PRIu64 "\n",
+			lcap.nonleaf.shaper_private_rate_max);
+		printf("cap.nonleaf.shaper_shared_n_max %" PRIu32 "\n",
+			lcap.nonleaf.shaper_shared_n_max);
+		printf("cap.nonleaf.sched_n_children_max %" PRIu32 "\n",
+			lcap.nonleaf.sched_n_children_max);
+		printf("cap.nonleaf.sched_sp_n_priorities_max %" PRIu32 "\n",
+			lcap.nonleaf.sched_sp_n_priorities_max);
+		printf("cap.nonleaf.sched_wfq_n_children_per_group_max %" PRIu32
+			"\n", lcap.nonleaf.sched_wfq_n_children_per_group_max);
+		printf("cap.nonleaf.sched_wfq_n_groups_max %" PRIu32 "\n",
+			lcap.nonleaf.sched_wfq_n_groups_max);
+		printf("cap.nonleaf.sched_wfq_weight_max %" PRIu32 "\n",
+			lcap.nonleaf.sched_wfq_weight_max);
+		printf("cap.nonleaf.stats_mask %" PRIx64 "\n",
+			lcap.nonleaf.stats_mask);
+	} else {
+		printf("cap.leaf.shaper_private_supported %" PRId32 "\n",
+			lcap.leaf.shaper_private_supported);
+		printf("cap.leaf.shaper_private_dual_rate_supported %" PRId32
+			"\n", lcap.leaf.shaper_private_dual_rate_supported);
+		printf("cap.leaf.shaper_private_rate_min %" PRIu64 "\n",
+			lcap.leaf.shaper_private_rate_min);
+		printf("cap.leaf.shaper_private_rate_max %" PRIu64 "\n",
+			lcap.leaf.shaper_private_rate_max);
+		printf("cap.leaf.shaper_shared_n_max %" PRIu32 "\n",
+			lcap.leaf.shaper_shared_n_max);
+		printf("cap.leaf.cman_head_drop_supported %" PRId32 "\n",
+			lcap.leaf.cman_head_drop_supported);
+		printf("cap.leaf.cman_wred_context_private_supported %"	PRId32
+			"\n", lcap.leaf.cman_wred_context_private_supported);
+		printf("cap.leaf.cman_wred_context_shared_n_max %" PRIu32 "\n",
+			lcap.leaf.cman_wred_context_shared_n_max);
+		printf("cap.leaf.stats_mask %" PRIx64 "\n",
+			lcap.leaf.stats_mask);
+	}
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_level_cap = {
+	.f = cmd_show_port_tm_level_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Hierarhical level Capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_level_cap_show,
+		(void *)&cmd_show_port_tm_level_cap_port,
+		(void *)&cmd_show_port_tm_level_cap_tm,
+		(void *)&cmd_show_port_tm_level_cap_level,
+		(void *)&cmd_show_port_tm_level_cap_cap,
+		(void *)&cmd_show_port_tm_level_cap_port_id,
+		(void *)&cmd_show_port_tm_level_cap_level_id,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchy Node Capability *** */ struct 
+cmd_show_port_tm_node_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t cap;
+	uint16_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_node =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_node_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_node_cap_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		 node_id, UINT32);
+
+static void cmd_show_port_tm_node_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_cap_result *res = parsed_result;
+	struct rte_tm_node_capabilities ncap;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	portid_t port_id = res->port_id;
+	int ret, is_leaf = 0;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Node id must be valid */
+	ret = rte_tm_node_type_get(port_id, node_id, &is_leaf, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	memset(&ncap, 0, sizeof(struct rte_tm_node_capabilities));
+	ret = rte_tm_node_capabilities_get(port_id, node_id, &ncap, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+	printf("\n**   Port TM Hierarchy node %" PRIu32 " Capability **\n\n",
+		node_id);
+	printf("cap.shaper_private_supported %" PRId32 "\n",
+		ncap.shaper_private_supported);
+	printf("cap.shaper_private_dual_rate_supported %" PRId32 "\n",
+		ncap.shaper_private_dual_rate_supported);
+	printf("cap.shaper_private_rate_min %" PRIu64 "\n",
+		ncap.shaper_private_rate_min);
+	printf("cap.shaper_private_rate_max %" PRIu64 "\n",
+		ncap.shaper_private_rate_max);
+	printf("cap.shaper_shared_n_max %" PRIu32 "\n",
+		ncap.shaper_shared_n_max);
+	if (!is_leaf) {
+		printf("cap.nonleaf.sched_n_children_max %" PRIu32 "\n",
+			ncap.nonleaf.sched_n_children_max);
+		printf("cap.nonleaf.sched_sp_n_priorities_max %" PRIu32 "\n",
+			ncap.nonleaf.sched_sp_n_priorities_max);
+		printf("cap.nonleaf.sched_wfq_n_children_per_group_max %" PRIu32
+			"\n", ncap.nonleaf.sched_wfq_n_children_per_group_max);
+		printf("cap.nonleaf.sched_wfq_n_groups_max %" PRIu32 "\n",
+			ncap.nonleaf.sched_wfq_n_groups_max);
+		printf("cap.nonleaf.sched_wfq_weight_max %" PRIu32 "\n",
+			ncap.nonleaf.sched_wfq_weight_max);
+	} else {
+		printf("cap.leaf.cman_head_drop_supported %" PRId32 "\n",
+			ncap.leaf.cman_head_drop_supported);
+		printf("cap.leaf.cman_wred_context_private_supported %" PRId32
+			"\n", ncap.leaf.cman_wred_context_private_supported);
+		printf("cap.leaf.cman_wred_context_shared_n_max %" PRIu32 "\n",
+			ncap.leaf.cman_wred_context_shared_n_max);
+	}
+	printf("cap.stats_mask %" PRIx64 "\n", ncap.stats_mask); }
+
+cmdline_parse_inst_t cmd_show_port_tm_node_cap = {
+	.f = cmd_show_port_tm_node_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Hierarchy node capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_cap_show,
+		(void *)&cmd_show_port_tm_node_cap_port,
+		(void *)&cmd_show_port_tm_node_cap_tm,
+		(void *)&cmd_show_port_tm_node_cap_node,
+		(void *)&cmd_show_port_tm_node_cap_cap,
+		(void *)&cmd_show_port_tm_node_cap_port_id,
+		(void *)&cmd_show_port_tm_node_cap_node_id,
+		NULL,
+	},
+};
+
+/* *** Show Port TM Node Statistics *** */ struct 
+cmd_show_port_tm_node_stats_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t stats;
+	uint16_t port_id;
+	uint32_t node_id;
+	uint32_t clear;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_show =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, show, "show"); 
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, port, "port"); 
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, tm, "tm"); 
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, node, "node"); 
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_stats =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, stats, "stats"); 
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_stats_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result,
+			node_id, UINT32);
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_clear =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, clear, UINT32);
+
+static void cmd_show_port_tm_node_stats_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_stats_result *res = parsed_result;
+	struct rte_tm_node_stats stats;
+	struct rte_tm_error error;
+	uint64_t stats_mask = 0;
+	uint32_t node_id = res->node_id;
+	uint32_t clear = res->clear;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (!port_is_started(port_id)) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	memset(&stats, 0, sizeof(struct rte_tm_node_stats));
+	ret = rte_tm_node_stats_read(port_id, node_id, &stats,
+			&stats_mask, clear, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	/* Display stats */
+	if (stats_mask & RTE_TM_STATS_N_PKTS)
+		printf("\tPkts scheduled from node: %" PRIu64 "\n",
+			stats.n_pkts);
+	if (stats_mask & RTE_TM_STATS_N_BYTES)
+		printf("\tBytes scheduled from node: %" PRIu64 "\n",
+			stats.n_bytes);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_GREEN_DROPPED)
+		printf("\tPkts dropped (green): %" PRIu64 "\n",
+			stats.leaf.n_pkts_dropped[RTE_TM_GREEN]);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_YELLOW_DROPPED)
+		printf("\tPkts dropped (yellow): %" PRIu64 "\n",
+			stats.leaf.n_pkts_dropped[RTE_TM_YELLOW]);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_RED_DROPPED)
+		printf("\tPkts dropped (red): %" PRIu64 "\n",
+			stats.leaf.n_pkts_dropped[RTE_TM_RED]);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_GREEN_DROPPED)
+		printf("\tBytes dropped (green): %" PRIu64 "\n",
+			stats.leaf.n_bytes_dropped[RTE_TM_GREEN]);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_YELLOW_DROPPED)
+		printf("\tBytes dropped (yellow): %" PRIu64 "\n",
+			stats.leaf.n_bytes_dropped[RTE_TM_YELLOW]);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_RED_DROPPED)
+		printf("\tBytes dropped (red): %" PRIu64 "\n",
+			stats.leaf.n_bytes_dropped[RTE_TM_RED]);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_QUEUED)
+		printf("\tPkts queued: %" PRIu64 "\n",
+			stats.leaf.n_pkts_queued);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_QUEUED)
+		printf("\tBytes queued: %" PRIu64 "\n",
+			stats.leaf.n_bytes_queued);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_stats = {
+	.f = cmd_show_port_tm_node_stats_parsed,
+	.data = NULL,
+	.help_str = "Show port tm node stats",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_stats_show,
+		(void *)&cmd_show_port_tm_node_stats_port,
+		(void *)&cmd_show_port_tm_node_stats_tm,
+		(void *)&cmd_show_port_tm_node_stats_node,
+		(void *)&cmd_show_port_tm_node_stats_stats,
+		(void *)&cmd_show_port_tm_node_stats_port_id,
+		(void *)&cmd_show_port_tm_node_stats_node_id,
+		(void *)&cmd_show_port_tm_node_stats_clear,
+		NULL,
+	},
+};
+
+/* *** Show Port TM Node Type *** */
+struct cmd_show_port_tm_node_type_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t type;
+	uint16_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_show =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, show, "show"); 
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, port, "port"); 
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, tm, "tm"); 
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, node, "node"); 
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, type, "type"); 
+cmdline_parse_token_num_t cmd_show_port_tm_node_type_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_node_type_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result,
+			node_id, UINT32);
+
+static void cmd_show_port_tm_node_type_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_type_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	portid_t port_id = res->port_id;
+	int ret, is_leaf = 0;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_node_type_get(port_id, node_id, &is_leaf, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	if (is_leaf == 1)
+		printf("leaf node\n");
+	else
+		printf("nonleaf node\n");
+
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_type = {
+	.f = cmd_show_port_tm_node_type_parsed,
+	.data = NULL,
+	.help_str = "Show port tm node type",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_type_show,
+		(void *)&cmd_show_port_tm_node_type_port,
+		(void *)&cmd_show_port_tm_node_type_tm,
+		(void *)&cmd_show_port_tm_node_type_node,
+		(void *)&cmd_show_port_tm_node_type_type,
+		(void *)&cmd_show_port_tm_node_type_port_id,
+		(void *)&cmd_show_port_tm_node_type_node_id,
+		NULL,
+	},
+};
diff --git a/app/test-pmd/cmdline_tm.h b/app/test-pmd/cmdline_tm.h new file mode 100644 index 0000000..945af89
--- /dev/null
+++ b/app/test-pmd/cmdline_tm.h
@@ -0,0 +1,44 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CMDLINE_TM_H_
+#define _CMDLINE_TM_H_
+
+ /* Traffic Management CLI */
+extern cmdline_parse_inst_t cmd_show_port_tm_cap; extern 
+cmdline_parse_inst_t cmd_show_port_tm_level_cap; extern 
+cmdline_parse_inst_t cmd_show_port_tm_node_cap; extern 
+cmdline_parse_inst_t cmd_show_port_tm_node_type; extern 
+cmdline_parse_inst_t cmd_show_port_tm_node_stats;
+
+#endif /* _CMDLINE_TM_H_ */
--
2.9.3

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7 2/3] app/test-pmd: add CLI for shaper and wred profiles
  2017-10-13  2:33                 ` Wu, Jingjing
@ 2017-10-13  8:58                   ` Singh, Jasvinder
  0 siblings, 0 replies; 49+ messages in thread
From: Singh, Jasvinder @ 2017-10-13  8:58 UTC (permalink / raw)
  To: Wu, Jingjing, dev
  Cc: Dumitrescu, Cristian, De Lara Guarch, Pablo, Pei, Yulong

<snip>
 
> > +/* *** Add Port TM Node WRED Profile *** */ struct
> > +cmd_add_port_tm_node_wred_profile_result {
> > +	cmdline_fixed_string_t add;
> > +	cmdline_fixed_string_t port;
> > +	cmdline_fixed_string_t tm;
> > +	cmdline_fixed_string_t node;
> > +	cmdline_fixed_string_t wred;
> > +	cmdline_fixed_string_t profile;
> > +	uint16_t port_id;
> > +	uint32_t wred_profile_id;
> > +	cmdline_fixed_string_t color_g;
> > +	uint16_t min_th_g;
> > +	uint16_t max_th_g;
> > +	uint16_t maxp_inv_g;
> > +	uint16_t wq_log2_g;
> > +	cmdline_fixed_string_t color_y;
> > +	uint16_t min_th_y;
> > +	uint16_t max_th_y;
> > +	uint16_t maxp_inv_y;
> > +	uint16_t wq_log2_y;
> > +	cmdline_fixed_string_t color_r;
> > +	uint16_t min_th_r;
> > +	uint16_t max_th_r;
> > +	uint16_t maxp_inv_r;
> > +	uint16_t wq_log2_r;
> > +};
> > +
> > +cmdline_parse_token_string_t
> cmd_add_port_tm_node_wred_profile_add =
> > +	TOKEN_STRING_INITIALIZER(
> > +		struct cmd_add_port_tm_node_wred_profile_result, add,
> > "add");
> > +cmdline_parse_token_string_t
> cmd_add_port_tm_node_wred_profile_port =
> > +	TOKEN_STRING_INITIALIZER(
> > +		struct cmd_add_port_tm_node_wred_profile_result, port,
> > "port");
> > +cmdline_parse_token_string_t
> cmd_add_port_tm_node_wred_profile_tm =
> > +	TOKEN_STRING_INITIALIZER(
> > +		struct cmd_add_port_tm_node_wred_profile_result, tm,
> "tm");
> > +cmdline_parse_token_string_t
> cmd_add_port_tm_node_wred_profile_node =
> > +	TOKEN_STRING_INITIALIZER(
> > +		struct cmd_add_port_tm_node_wred_profile_result, node,
> > "node");
> > +cmdline_parse_token_string_t
> cmd_add_port_tm_node_wred_profile_wred =
> > +	TOKEN_STRING_INITIALIZER(
> > +		struct cmd_add_port_tm_node_wred_profile_result, wred,
> > "wred");
> > +cmdline_parse_token_string_t
> > +cmd_add_port_tm_node_wred_profile_profile
> > =
> > +	TOKEN_STRING_INITIALIZER(
> > +		struct cmd_add_port_tm_node_wred_profile_result,
> > +			profile, "profile");
> > +cmdline_parse_token_num_t
> cmd_add_port_tm_node_wred_profile_port_id
> > =
> > +	TOKEN_NUM_INITIALIZER(
> > +		struct cmd_add_port_tm_node_wred_profile_result,
> > +			port_id, UINT16);
> > +cmdline_parse_token_num_t
> > cmd_add_port_tm_node_wred_profile_wred_profile_id =
> > +	TOKEN_NUM_INITIALIZER(
> > +		struct cmd_add_port_tm_node_wred_profile_result,
> > +			wred_profile_id, UINT32);
> > +cmdline_parse_token_string_t
> > cmd_add_port_tm_node_wred_profile_color_g =
> > +	TOKEN_STRING_INITIALIZER(
> > +		struct cmd_add_port_tm_node_wred_profile_result,
> > +			color_g, "G#g");
> > +cmdline_parse_token_num_t
> > cmd_add_port_tm_node_wred_profile_min_th_g =
> > +	TOKEN_NUM_INITIALIZER(
> > +		struct cmd_add_port_tm_node_wred_profile_result,
> > +			min_th_g, UINT16);
> > +cmdline_parse_token_num_t
> > cmd_add_port_tm_node_wred_profile_max_th_g =
> > +	TOKEN_NUM_INITIALIZER(
> > +		struct cmd_add_port_tm_node_wred_profile_result,
> > +			max_th_g, UINT16);
> > +cmdline_parse_token_num_t
> > cmd_add_port_tm_node_wred_profile_maxp_inv_g =
> > +	TOKEN_NUM_INITIALIZER(
> > +		struct cmd_add_port_tm_node_wred_profile_result,
> > +			maxp_inv_g, UINT16);
> > +cmdline_parse_token_num_t
> > cmd_add_port_tm_node_wred_profile_wq_log2_g =
> > +	TOKEN_NUM_INITIALIZER(
> > +		struct cmd_add_port_tm_node_wred_profile_result,
> > +			wq_log2_g, UINT16);
> > +cmdline_parse_token_string_t
> > +cmd_add_port_tm_node_wred_profile_color_y
> > =
> > +	TOKEN_STRING_INITIALIZER(
> > +		struct cmd_add_port_tm_node_wred_profile_result,
> > +			color_y, "Y#y");
> > +cmdline_parse_token_num_t
> > cmd_add_port_tm_node_wred_profile_min_th_y =
> > +	TOKEN_NUM_INITIALIZER(
> > +		struct cmd_add_port_tm_node_wred_profile_result,
> > +			min_th_y, UINT16);
> > +cmdline_parse_token_num_t
> > cmd_add_port_tm_node_wred_profile_max_th_y =
> > +	TOKEN_NUM_INITIALIZER(
> > +		struct cmd_add_port_tm_node_wred_profile_result,
> > +			max_th_y, UINT16);
> > +cmdline_parse_token_num_t
> > cmd_add_port_tm_node_wred_profile_maxp_inv_y =
> > +	TOKEN_NUM_INITIALIZER(
> > +		struct cmd_add_port_tm_node_wred_profile_result,
> > +			maxp_inv_y, UINT16);
> > +cmdline_parse_token_num_t
> > cmd_add_port_tm_node_wred_profile_wq_log2_y =
> > +	TOKEN_NUM_INITIALIZER(
> > +		struct cmd_add_port_tm_node_wred_profile_result,
> > +			wq_log2_y, UINT16);
> > +cmdline_parse_token_string_t
> > +cmd_add_port_tm_node_wred_profile_color_r
> > =
> > +	TOKEN_STRING_INITIALIZER(
> > +		struct cmd_add_port_tm_node_wred_profile_result,
> > +			color_r, "R#r");
> > +cmdline_parse_token_num_t
> > cmd_add_port_tm_node_wred_profile_min_th_r =
> > +	TOKEN_NUM_INITIALIZER(
> > +		struct cmd_add_port_tm_node_wred_profile_result,
> > +			min_th_r, UINT16);
> > +cmdline_parse_token_num_t
> > cmd_add_port_tm_node_wred_profile_max_th_r =
> > +	TOKEN_NUM_INITIALIZER(
> > +		struct cmd_add_port_tm_node_wred_profile_result,
> > +			max_th_r, UINT16);
> > +cmdline_parse_token_num_t
> > cmd_add_port_tm_node_wred_profile_maxp_inv_r =
> > +	TOKEN_NUM_INITIALIZER(
> > +		struct cmd_add_port_tm_node_wred_profile_result,
> > +			maxp_inv_r, UINT16);
> > +cmdline_parse_token_num_t
> > cmd_add_port_tm_node_wred_profile_wq_log2_r =
> > +	TOKEN_NUM_INITIALIZER(
> > +		struct cmd_add_port_tm_node_wred_profile_result,
> > +			wq_log2_r, UINT16);
> > +
> > +
> > +static void cmd_add_port_tm_node_wred_profile_parsed(void
> *parsed_result,
> > +	__attribute__((unused)) struct cmdline *cl,
> > +	__attribute__((unused)) void *data)
> > +{
> > +	struct cmd_add_port_tm_node_wred_profile_result *res =
> > parsed_result;
> > +	struct rte_tm_wred_params wp;
> > +	enum rte_tm_color color;
> > +	struct rte_tm_error error;
> > +	uint32_t wred_profile_id = res->wred_profile_id;
> > +	portid_t port_id = res->port_id;
> > +	int ret;
> > +
> > +	if (port_id_is_invalid(port_id, ENABLED_WARN))
> > +		return;
> > +
> > +	memset(&wp, 0, sizeof(struct rte_tm_wred_params));
> > +
> > +	/* WRED Params  (Green Color)*/
> > +	if ((strcmp(res->color_g, "G") == 0) ||
> > +		(strcmp(res->color_g, "g") == 0)) {
> > +		color = RTE_TM_GREEN;
> > +		wp.red_params[color].min_th = res->min_th_g;
> > +		wp.red_params[color].max_th = res->max_th_g;
> > +		wp.red_params[color].maxp_inv = res->maxp_inv_g;
> > +		wp.red_params[color].wq_log2 = res->wq_log2_g;
> > +	} else {
> > +		printf("WRED profile error(G or g for green color)!\n");
> > +		return;
> > +	}
> > +
> No need to check the res->color_g, because it already be checked by
> cmdline.
> Because you defined it like
> cmd_add_port_tm_node_wred_profile_color_g =
> 	TOKEN_STRING_INITIALIZER(
> 		struct cmd_add_port_tm_node_wred_profile_result,
> 			color_g, "G#g");
> You can just assign wp.red_params[RTE_TM_GREEN] directly.
> The similar as color_y, color_r.

> And is that possible for you to set WERD with less than 3 colors? If so, you
> may need to change your command definition.

Ok, I will remove the extra check which seems unnecessary. Also, will try to simplify the command to single color
instead of three color at a time. Thanks.

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v7 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit
  2017-10-13  2:58                 ` Wu, Jingjing
@ 2017-10-13 10:50                   ` Singh, Jasvinder
  0 siblings, 0 replies; 49+ messages in thread
From: Singh, Jasvinder @ 2017-10-13 10:50 UTC (permalink / raw)
  To: Wu, Jingjing, dev
  Cc: Dumitrescu, Cristian, De Lara Guarch, Pablo, Pei, Yulong



> -----Original Message-----
> From: Wu, Jingjing
> Sent: Friday, October 13, 2017 3:59 AM
> To: Singh, Jasvinder <jasvinder.singh@intel.com>; dev@dpdk.org
> Cc: Dumitrescu, Cristian <cristian.dumitrescu@intel.com>; De Lara Guarch,
> Pablo <pablo.de.lara.guarch@intel.com>; Pei, Yulong
> <yulong.pei@intel.com>
> Subject: RE: [PATCH v7 3/3] app/test-pmd: add CLI for TM nodes and
> hierarchy commit
> 
> > +	/* Port status */
> > +	if (port_is_started(port_id)) {
> > +		printf(" Port %u not stopped (error)\n", port_id);
> > +		return;
> > +	}
> > +
> > +	/* Node parameters */
> > +	if (res->parent_node_id < 0)
> > +		parent_node_id = UINT32_MAX;
> > +	else
> > +		parent_node_id = res->parent_node_id;
> > +
> > +	memset(&np, 0, sizeof(struct rte_tm_node_params));
> > +	np.shaper_profile_id = res->shaper_profile_id;
> > +	np.n_shared_shapers = res->n_shared_shapers;
> > +
> > +	if (np.n_shared_shapers == 1)
> > +		np.shared_shaper_id[0] = res->shared_shaper_id;
> > +	else
> > +		np.shared_shaper_id = NULL;
> > +
> 
> Does n_shared_shapers means number of shared_shapers? And now we
> only support 1?

Yes. It is number of shared shapers. The ixgbe and i40e doesn't support shared shapers, while softnic support single shared shaper. 

> When refer to the definition of struct rte_tm_node_params, the
> shared_shaper_id arry need to be allocated by user, but I didn't find the
> allocation here or even in patch 2/3.
> 
> The same comments for below commands.

Will fix this. 

> [......]
> 
> > +/* *** Port TM Hierarchy Commit *** */ struct
> > +cmd_port_tm_hierarchy_commit_result {
> > +	cmdline_fixed_string_t port;
> > +	cmdline_fixed_string_t tm;
> > +	cmdline_fixed_string_t hierarchy;
> > +	cmdline_fixed_string_t commit;
> > +	uint16_t port_id;
> > +	uint32_t clean_on_fail;
> > +};
> > +
> > +cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_port =
> > +	TOKEN_STRING_INITIALIZER(
> > +		struct cmd_port_tm_hierarchy_commit_result, port, "port");
> > +cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_tm =
> > +	TOKEN_STRING_INITIALIZER(
> > +		struct cmd_port_tm_hierarchy_commit_result, tm, "tm");
> > +cmdline_parse_token_string_t
> cmd_port_tm_hierarchy_commit_hierarchy =
> > +	TOKEN_STRING_INITIALIZER(
> > +		struct cmd_port_tm_hierarchy_commit_result,
> > +			hierarchy, "hierarchy");
> > +cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_commit
> =
> > +	TOKEN_STRING_INITIALIZER(
> > +		struct cmd_port_tm_hierarchy_commit_result, commit,
> > "commit");
> > +cmdline_parse_token_num_t cmd_port_tm_hierarchy_commit_port_id
> =
> > +	TOKEN_NUM_INITIALIZER(
> > +		struct cmd_port_tm_hierarchy_commit_result,
> > +			port_id, UINT16);
> > +cmdline_parse_token_num_t
> cmd_port_tm_hierarchy_commit_clean_on_fail
> > =
> > +	TOKEN_NUM_INITIALIZER(struct
> > cmd_port_tm_hierarchy_commit_result,
> > +		 clean_on_fail, UINT32);
> How about the define clean_on_fail to be a string like "(clean|no_clean)" or
> "clean_on_fail (yes|no)"?

Will make this string.

> And don't forget the doc update for all the new commands.

Yes, will update the doc accordingly. Thanks.

> Thanks
> Jingjing

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [PATCH v8 1/3] app/test-pmd: add CLI for TM capability and stats
  2017-10-11  9:26             ` [PATCH v7 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
                                 ` (4 preceding siblings ...)
  2017-10-13  6:22               ` Pei, Yulong
@ 2017-10-13 16:59               ` Jasvinder Singh
  2017-10-13 16:59                 ` [PATCH v8 2/3] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
                                   ` (2 more replies)
  5 siblings, 3 replies; 49+ messages in thread
From: Jasvinder Singh @ 2017-10-13 16:59 UTC (permalink / raw)
  To: dev
  Cc: cristian.dumitrescu, jingjing.wu, pablo.de.lara.guarch,
	yulong.pei, thomas

Add following CLIs to testpmd application for device traffic management;
- commands to display TM capability information.
  (per port, per hierarchy level and per hierarchy node)
- command to display hiearchy node type
- stats collection

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Tested-by: Yulong Pei  <yulong.pei@intel.com>
Reviewed-by: Jingjing Wu <jingjing.wu@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
v6 change:
- fix compilation warning
- change port_id type to uint16_t

v4 change:
 - remove softnic specific checks to make it generic for the devices

v3 change:
- Implements feedback from Pablo[1]
 - move TM API related CLIs into cmdline_tm.c
 - split patch into small patches
 - replace link status check with testpmd fn port_is_started()

[1]http://dpdk.org/ml/archives/dev/2017-September/075748.html

 app/test-pmd/Makefile     |   1 +
 app/test-pmd/cmdline.c    |  20 ++
 app/test-pmd/cmdline_tm.c | 681 ++++++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/cmdline_tm.h |  44 +++
 4 files changed, 746 insertions(+)
 create mode 100644 app/test-pmd/cmdline_tm.c
 create mode 100644 app/test-pmd/cmdline_tm.h

diff --git a/app/test-pmd/Makefile b/app/test-pmd/Makefile
index 2c50f68..e4a6352 100644
--- a/app/test-pmd/Makefile
+++ b/app/test-pmd/Makefile
@@ -48,6 +48,7 @@ SRCS-y := testpmd.c
 SRCS-y += parameters.c
 SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline.c
 SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline_flow.c
+SRCS-y += cmdline_tm.c
 SRCS-y += config.c
 SRCS-y += iofwd.c
 SRCS-y += macfwd.c
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index bb19d72..72e0628 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -99,6 +99,7 @@
 #include <rte_pmd_bnxt.h>
 #endif
 #include "testpmd.h"
+#include "cmdline_tm.h"
 
 static struct cmdline *testpmd_cl;
 
@@ -234,6 +235,20 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"show port (port_id) pctype mapping\n"
 			"    Get flow ptype to pctype mapping on a port\n\n"
 
+			"show port tm cap (port_id)\n"
+			"	Display the port TM capability.\n\n"
+
+			"show port tm level cap (port_id) (level_id)\n"
+			"	Display the port TM hierarchical level capability.\n\n"
+
+			"show port tm node cap (port_id) (node_id)\n"
+			"	Display the port TM node capability.\n\n"
+
+			"show port tm node type (port_id) (node_id)\n"
+			"	Display the port TM node type.\n\n"
+
+			"show port tm node stats (port_id) (node_id) (clear)\n"
+			"	Display the port TM node stats.\n\n"
 		);
 	}
 
@@ -15596,6 +15611,11 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_user_priority_region,
 	(cmdline_parse_inst_t *)&cmd_flush_queue_region,
 	(cmdline_parse_inst_t *)&cmd_show_queue_region_info_all,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_level_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_type,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_stats,
 	NULL,
 };
 
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
new file mode 100644
index 0000000..f024372
--- /dev/null
+++ b/app/test-pmd/cmdline_tm.c
@@ -0,0 +1,681 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+
+#include <rte_ethdev.h>
+#include <rte_flow.h>
+#include <rte_tm.h>
+
+#include "testpmd.h"
+#include "cmdline_tm.h"
+
+/** Display TM Error Message */
+static void
+print_err_msg(struct rte_tm_error *error)
+{
+	static const char *const errstrlist[] = {
+		[RTE_TM_ERROR_TYPE_NONE] = "no error",
+		[RTE_TM_ERROR_TYPE_UNSPECIFIED] = "cause unspecified",
+		[RTE_TM_ERROR_TYPE_CAPABILITIES]
+			= "capability parameter null",
+		[RTE_TM_ERROR_TYPE_LEVEL_ID] = "level id",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE]
+			= "wred profile null",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_GREEN] = "wred profile(green)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_YELLOW]
+			= "wred profile(yellow)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_RED] = "wred profile(red)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_ID] = "wred profile id",
+		[RTE_TM_ERROR_TYPE_SHARED_WRED_CONTEXT_ID]
+			= "shared wred context id",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE] = "shaper profile null",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE]
+			= "committed rate field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE]
+			= "committed size field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE]
+			= "peak rate field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE]
+			= "peak size field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN]
+			= "packet adjust length field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID] = "shaper profile id",
+		[RTE_TM_ERROR_TYPE_SHARED_SHAPER_ID] = "shared shaper id",
+		[RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID] = "parent node id",
+		[RTE_TM_ERROR_TYPE_NODE_PRIORITY] = "node priority",
+		[RTE_TM_ERROR_TYPE_NODE_WEIGHT] = "node weight",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS] = "node parameter null",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID]
+			= "shaper profile id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID]
+			= "shared shaper id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS]
+			= "num shared shapers field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE]
+			= "wfq weght mode field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES]
+			= "num strict priorities field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN]
+			= "congestion management mode field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID] =
+			"wred profile id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID]
+			= "shared wred context id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS]
+			= "num shared wred contexts field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS]
+			= "stats field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_ID] = "node id",
+	};
+
+	const char *errstr;
+	char buf[64];
+
+	if ((unsigned int)error->type >= RTE_DIM(errstrlist) ||
+		!errstrlist[error->type])
+		errstr = "unknown type";
+	else
+		errstr = errstrlist[error->type];
+
+	if (error->cause)
+		snprintf(buf, sizeof(buf), "cause: %p, ", error->cause);
+
+	printf("%s: %s%s (error %d)\n", errstr, error->cause ? buf : "",
+		error->message ? error->message : "(no stated reason)",
+		error->type);
+}
+
+/* *** Port TM Capability *** */
+struct cmd_show_port_tm_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t cap;
+	uint16_t port_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		 port_id, UINT16);
+
+static void cmd_show_port_tm_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_cap_result *res = parsed_result;
+	struct rte_tm_capabilities cap;
+	struct rte_tm_error error;
+	portid_t port_id = res->port_id;
+	uint32_t i;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	memset(&cap, 0, sizeof(struct rte_tm_capabilities));
+	ret = rte_tm_capabilities_get(port_id, &cap, &error);
+	if (ret) {
+		print_err_msg(&error);
+		return;
+	}
+
+	printf("\n****   Port TM Capabilities ****\n\n");
+	printf("cap.n_nodes_max %" PRIu32 "\n", cap.n_nodes_max);
+	printf("cap.n_levels_max %" PRIu32 "\n", cap.n_levels_max);
+	printf("cap.non_leaf_nodes_identical %" PRId32 "\n",
+		cap.non_leaf_nodes_identical);
+	printf("cap.leaf_nodes_identical %" PRId32 "\n",
+		cap.leaf_nodes_identical);
+	printf("cap.shaper_n_max %u\n", cap.shaper_n_max);
+	printf("cap.shaper_private_n_max %" PRIu32 "\n",
+		cap.shaper_private_n_max);
+	printf("cap.shaper_private_dual_rate_n_max %" PRId32 "\n",
+		cap.shaper_private_dual_rate_n_max);
+	printf("cap.shaper_private_rate_min %" PRIu64 "\n",
+		cap.shaper_private_rate_min);
+	printf("cap.shaper_private_rate_max %" PRIu64 "\n",
+		cap.shaper_private_rate_max);
+	printf("cap.shaper_shared_n_max %" PRIu32 "\n",
+		cap.shaper_shared_n_max);
+	printf("cap.shaper_shared_n_nodes_per_shaper_max %" PRIu32 "\n",
+		cap.shaper_shared_n_nodes_per_shaper_max);
+	printf("cap.shaper_shared_n_shapers_per_node_max %" PRIu32 "\n",
+		cap.shaper_shared_n_shapers_per_node_max);
+	printf("cap.shaper_shared_dual_rate_n_max %" PRIu32 "\n",
+		cap.shaper_shared_dual_rate_n_max);
+	printf("cap.shaper_shared_rate_min %" PRIu64 "\n",
+		cap.shaper_shared_rate_min);
+	printf("cap.shaper_shared_rate_max %" PRIu64 "\n",
+		cap.shaper_shared_rate_max);
+	printf("cap.shaper_pkt_length_adjust_min %" PRId32 "\n",
+		cap.shaper_pkt_length_adjust_min);
+	printf("cap.shaper_pkt_length_adjust_max %" PRId32 "\n",
+		cap.shaper_pkt_length_adjust_max);
+	printf("cap.sched_n_children_max %" PRIu32 "\n",
+		cap.sched_n_children_max);
+	printf("cap.sched_sp_n_priorities_max %" PRIu32 "\n",
+		cap.sched_sp_n_priorities_max);
+	printf("cap.sched_wfq_n_children_per_group_max %" PRIu32 "\n",
+		cap.sched_wfq_n_children_per_group_max);
+	printf("cap.sched_wfq_n_groups_max %" PRIu32 "\n",
+		cap.sched_wfq_n_groups_max);
+	printf("cap.sched_wfq_weight_max %" PRIu32 "\n",
+		cap.sched_wfq_weight_max);
+	printf("cap.cman_head_drop_supported %" PRId32 "\n",
+		cap.cman_head_drop_supported);
+	printf("cap.cman_wred_context_n_max %" PRIu32 "\n",
+		cap.cman_wred_context_n_max);
+	printf("cap.cman_wred_context_private_n_max %" PRIu32 "\n",
+		cap.cman_wred_context_private_n_max);
+	printf("cap.cman_wred_context_shared_n_max %" PRIu32 "\n",
+		cap.cman_wred_context_shared_n_max);
+	printf("cap.cman_wred_context_shared_n_nodes_per_context_max %" PRIu32
+		"\n", cap.cman_wred_context_shared_n_nodes_per_context_max);
+	printf("cap.cman_wred_context_shared_n_contexts_per_node_max %" PRIu32
+		"\n", cap.cman_wred_context_shared_n_contexts_per_node_max);
+
+	for (i = 0; i < RTE_TM_COLORS; i++) {
+		printf("cap.mark_vlan_dei_supported %" PRId32 "\n",
+			cap.mark_vlan_dei_supported[i]);
+		printf("cap.mark_ip_ecn_tcp_supported %" PRId32 "\n",
+			cap.mark_ip_ecn_tcp_supported[i]);
+		printf("cap.mark_ip_ecn_sctp_supported %" PRId32 "\n",
+			cap.mark_ip_ecn_sctp_supported[i]);
+		printf("cap.mark_ip_dscp_supported %" PRId32 "\n",
+			cap.mark_ip_dscp_supported[i]);
+	}
+
+	printf("cap.dynamic_update_mask %" PRIx64 "\n",
+		cap.dynamic_update_mask);
+	printf("cap.stats_mask %" PRIx64 "\n", cap.stats_mask);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_cap = {
+	.f = cmd_show_port_tm_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_cap_show,
+		(void *)&cmd_show_port_tm_cap_port,
+		(void *)&cmd_show_port_tm_cap_tm,
+		(void *)&cmd_show_port_tm_cap_cap,
+		(void *)&cmd_show_port_tm_cap_port_id,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchical Level Capability *** */
+struct cmd_show_port_tm_level_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t level;
+	cmdline_fixed_string_t cap;
+	uint16_t port_id;
+	uint32_t level_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_level =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		level, "level");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_level_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_level_cap_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		 level_id, UINT32);
+
+
+static void cmd_show_port_tm_level_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_level_cap_result *res = parsed_result;
+	struct rte_tm_level_capabilities lcap;
+	struct rte_tm_error error;
+	portid_t port_id = res->port_id;
+	uint32_t level_id = res->level_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	memset(&lcap, 0, sizeof(struct rte_tm_level_capabilities));
+	ret = rte_tm_level_capabilities_get(port_id, level_id, &lcap, &error);
+	if (ret) {
+		print_err_msg(&error);
+		return;
+	}
+	printf("\n**   Port TM Hierarchy level %" PRIu32 " Capability **\n\n",
+		level_id);
+
+	printf("cap.n_nodes_max %" PRIu32 "\n", lcap.n_nodes_max);
+	printf("cap.n_nodes_nonleaf_max %" PRIu32 "\n",
+		lcap.n_nodes_nonleaf_max);
+	printf("cap.n_nodes_leaf_max %" PRIu32 "\n", lcap.n_nodes_leaf_max);
+	printf("cap.non_leaf_nodes_identical %" PRId32 "\n",
+		lcap.non_leaf_nodes_identical);
+	printf("cap.leaf_nodes_identical %" PRId32 "\n",
+		lcap.leaf_nodes_identical);
+	if (level_id <= 3) {
+		printf("cap.nonleaf.shaper_private_supported %" PRId32 "\n",
+			lcap.nonleaf.shaper_private_supported);
+		printf("cap.nonleaf.shaper_private_dual_rate_supported %" PRId32
+			"\n", lcap.nonleaf.shaper_private_dual_rate_supported);
+		printf("cap.nonleaf.shaper_private_rate_min %" PRIu64 "\n",
+			lcap.nonleaf.shaper_private_rate_min);
+		printf("cap.nonleaf.shaper_private_rate_max %" PRIu64 "\n",
+			lcap.nonleaf.shaper_private_rate_max);
+		printf("cap.nonleaf.shaper_shared_n_max %" PRIu32 "\n",
+			lcap.nonleaf.shaper_shared_n_max);
+		printf("cap.nonleaf.sched_n_children_max %" PRIu32 "\n",
+			lcap.nonleaf.sched_n_children_max);
+		printf("cap.nonleaf.sched_sp_n_priorities_max %" PRIu32 "\n",
+			lcap.nonleaf.sched_sp_n_priorities_max);
+		printf("cap.nonleaf.sched_wfq_n_children_per_group_max %" PRIu32
+			"\n", lcap.nonleaf.sched_wfq_n_children_per_group_max);
+		printf("cap.nonleaf.sched_wfq_n_groups_max %" PRIu32 "\n",
+			lcap.nonleaf.sched_wfq_n_groups_max);
+		printf("cap.nonleaf.sched_wfq_weight_max %" PRIu32 "\n",
+			lcap.nonleaf.sched_wfq_weight_max);
+		printf("cap.nonleaf.stats_mask %" PRIx64 "\n",
+			lcap.nonleaf.stats_mask);
+	} else {
+		printf("cap.leaf.shaper_private_supported %" PRId32 "\n",
+			lcap.leaf.shaper_private_supported);
+		printf("cap.leaf.shaper_private_dual_rate_supported %" PRId32
+			"\n", lcap.leaf.shaper_private_dual_rate_supported);
+		printf("cap.leaf.shaper_private_rate_min %" PRIu64 "\n",
+			lcap.leaf.shaper_private_rate_min);
+		printf("cap.leaf.shaper_private_rate_max %" PRIu64 "\n",
+			lcap.leaf.shaper_private_rate_max);
+		printf("cap.leaf.shaper_shared_n_max %" PRIu32 "\n",
+			lcap.leaf.shaper_shared_n_max);
+		printf("cap.leaf.cman_head_drop_supported %" PRId32 "\n",
+			lcap.leaf.cman_head_drop_supported);
+		printf("cap.leaf.cman_wred_context_private_supported %"	PRId32
+			"\n", lcap.leaf.cman_wred_context_private_supported);
+		printf("cap.leaf.cman_wred_context_shared_n_max %" PRIu32 "\n",
+			lcap.leaf.cman_wred_context_shared_n_max);
+		printf("cap.leaf.stats_mask %" PRIx64 "\n",
+			lcap.leaf.stats_mask);
+	}
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_level_cap = {
+	.f = cmd_show_port_tm_level_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Hierarhical level Capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_level_cap_show,
+		(void *)&cmd_show_port_tm_level_cap_port,
+		(void *)&cmd_show_port_tm_level_cap_tm,
+		(void *)&cmd_show_port_tm_level_cap_level,
+		(void *)&cmd_show_port_tm_level_cap_cap,
+		(void *)&cmd_show_port_tm_level_cap_port_id,
+		(void *)&cmd_show_port_tm_level_cap_level_id,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchy Node Capability *** */
+struct cmd_show_port_tm_node_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t cap;
+	uint16_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_node =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_node_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_node_cap_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		 node_id, UINT32);
+
+static void cmd_show_port_tm_node_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_cap_result *res = parsed_result;
+	struct rte_tm_node_capabilities ncap;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	portid_t port_id = res->port_id;
+	int ret, is_leaf = 0;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Node id must be valid */
+	ret = rte_tm_node_type_get(port_id, node_id, &is_leaf, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	memset(&ncap, 0, sizeof(struct rte_tm_node_capabilities));
+	ret = rte_tm_node_capabilities_get(port_id, node_id, &ncap, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+	printf("\n**   Port TM Hierarchy node %" PRIu32 " Capability **\n\n",
+		node_id);
+	printf("cap.shaper_private_supported %" PRId32 "\n",
+		ncap.shaper_private_supported);
+	printf("cap.shaper_private_dual_rate_supported %" PRId32 "\n",
+		ncap.shaper_private_dual_rate_supported);
+	printf("cap.shaper_private_rate_min %" PRIu64 "\n",
+		ncap.shaper_private_rate_min);
+	printf("cap.shaper_private_rate_max %" PRIu64 "\n",
+		ncap.shaper_private_rate_max);
+	printf("cap.shaper_shared_n_max %" PRIu32 "\n",
+		ncap.shaper_shared_n_max);
+	if (!is_leaf) {
+		printf("cap.nonleaf.sched_n_children_max %" PRIu32 "\n",
+			ncap.nonleaf.sched_n_children_max);
+		printf("cap.nonleaf.sched_sp_n_priorities_max %" PRIu32 "\n",
+			ncap.nonleaf.sched_sp_n_priorities_max);
+		printf("cap.nonleaf.sched_wfq_n_children_per_group_max %" PRIu32
+			"\n", ncap.nonleaf.sched_wfq_n_children_per_group_max);
+		printf("cap.nonleaf.sched_wfq_n_groups_max %" PRIu32 "\n",
+			ncap.nonleaf.sched_wfq_n_groups_max);
+		printf("cap.nonleaf.sched_wfq_weight_max %" PRIu32 "\n",
+			ncap.nonleaf.sched_wfq_weight_max);
+	} else {
+		printf("cap.leaf.cman_head_drop_supported %" PRId32 "\n",
+			ncap.leaf.cman_head_drop_supported);
+		printf("cap.leaf.cman_wred_context_private_supported %" PRId32
+			"\n", ncap.leaf.cman_wred_context_private_supported);
+		printf("cap.leaf.cman_wred_context_shared_n_max %" PRIu32 "\n",
+			ncap.leaf.cman_wred_context_shared_n_max);
+	}
+	printf("cap.stats_mask %" PRIx64 "\n", ncap.stats_mask);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_cap = {
+	.f = cmd_show_port_tm_node_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Hierarchy node capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_cap_show,
+		(void *)&cmd_show_port_tm_node_cap_port,
+		(void *)&cmd_show_port_tm_node_cap_tm,
+		(void *)&cmd_show_port_tm_node_cap_node,
+		(void *)&cmd_show_port_tm_node_cap_cap,
+		(void *)&cmd_show_port_tm_node_cap_port_id,
+		(void *)&cmd_show_port_tm_node_cap_node_id,
+		NULL,
+	},
+};
+
+/* *** Show Port TM Node Statistics *** */
+struct cmd_show_port_tm_node_stats_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t stats;
+	uint16_t port_id;
+	uint32_t node_id;
+	uint32_t clear;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_show =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_stats =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, stats, "stats");
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_stats_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result,
+			node_id, UINT32);
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_clear =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, clear, UINT32);
+
+static void cmd_show_port_tm_node_stats_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_stats_result *res = parsed_result;
+	struct rte_tm_node_stats stats;
+	struct rte_tm_error error;
+	uint64_t stats_mask = 0;
+	uint32_t node_id = res->node_id;
+	uint32_t clear = res->clear;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (!port_is_started(port_id)) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	memset(&stats, 0, sizeof(struct rte_tm_node_stats));
+	ret = rte_tm_node_stats_read(port_id, node_id, &stats,
+			&stats_mask, clear, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	/* Display stats */
+	if (stats_mask & RTE_TM_STATS_N_PKTS)
+		printf("\tPkts scheduled from node: %" PRIu64 "\n",
+			stats.n_pkts);
+	if (stats_mask & RTE_TM_STATS_N_BYTES)
+		printf("\tBytes scheduled from node: %" PRIu64 "\n",
+			stats.n_bytes);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_GREEN_DROPPED)
+		printf("\tPkts dropped (green): %" PRIu64 "\n",
+			stats.leaf.n_pkts_dropped[RTE_TM_GREEN]);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_YELLOW_DROPPED)
+		printf("\tPkts dropped (yellow): %" PRIu64 "\n",
+			stats.leaf.n_pkts_dropped[RTE_TM_YELLOW]);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_RED_DROPPED)
+		printf("\tPkts dropped (red): %" PRIu64 "\n",
+			stats.leaf.n_pkts_dropped[RTE_TM_RED]);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_GREEN_DROPPED)
+		printf("\tBytes dropped (green): %" PRIu64 "\n",
+			stats.leaf.n_bytes_dropped[RTE_TM_GREEN]);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_YELLOW_DROPPED)
+		printf("\tBytes dropped (yellow): %" PRIu64 "\n",
+			stats.leaf.n_bytes_dropped[RTE_TM_YELLOW]);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_RED_DROPPED)
+		printf("\tBytes dropped (red): %" PRIu64 "\n",
+			stats.leaf.n_bytes_dropped[RTE_TM_RED]);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_QUEUED)
+		printf("\tPkts queued: %" PRIu64 "\n",
+			stats.leaf.n_pkts_queued);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_QUEUED)
+		printf("\tBytes queued: %" PRIu64 "\n",
+			stats.leaf.n_bytes_queued);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_stats = {
+	.f = cmd_show_port_tm_node_stats_parsed,
+	.data = NULL,
+	.help_str = "Show port tm node stats",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_stats_show,
+		(void *)&cmd_show_port_tm_node_stats_port,
+		(void *)&cmd_show_port_tm_node_stats_tm,
+		(void *)&cmd_show_port_tm_node_stats_node,
+		(void *)&cmd_show_port_tm_node_stats_stats,
+		(void *)&cmd_show_port_tm_node_stats_port_id,
+		(void *)&cmd_show_port_tm_node_stats_node_id,
+		(void *)&cmd_show_port_tm_node_stats_clear,
+		NULL,
+	},
+};
+
+/* *** Show Port TM Node Type *** */
+struct cmd_show_port_tm_node_type_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t type;
+	uint16_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_show =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, type, "type");
+cmdline_parse_token_num_t cmd_show_port_tm_node_type_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_node_type_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result,
+			node_id, UINT32);
+
+static void cmd_show_port_tm_node_type_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_type_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	portid_t port_id = res->port_id;
+	int ret, is_leaf = 0;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_node_type_get(port_id, node_id, &is_leaf, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	if (is_leaf == 1)
+		printf("leaf node\n");
+	else
+		printf("nonleaf node\n");
+
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_type = {
+	.f = cmd_show_port_tm_node_type_parsed,
+	.data = NULL,
+	.help_str = "Show port tm node type",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_type_show,
+		(void *)&cmd_show_port_tm_node_type_port,
+		(void *)&cmd_show_port_tm_node_type_tm,
+		(void *)&cmd_show_port_tm_node_type_node,
+		(void *)&cmd_show_port_tm_node_type_type,
+		(void *)&cmd_show_port_tm_node_type_port_id,
+		(void *)&cmd_show_port_tm_node_type_node_id,
+		NULL,
+	},
+};
diff --git a/app/test-pmd/cmdline_tm.h b/app/test-pmd/cmdline_tm.h
new file mode 100644
index 0000000..945af89
--- /dev/null
+++ b/app/test-pmd/cmdline_tm.h
@@ -0,0 +1,44 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CMDLINE_TM_H_
+#define _CMDLINE_TM_H_
+
+ /* Traffic Management CLI */
+extern cmdline_parse_inst_t cmd_show_port_tm_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_level_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_type;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_stats;
+
+#endif /* _CMDLINE_TM_H_ */
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v8 2/3] app/test-pmd: add CLI for shaper and wred profiles
  2017-10-13 16:59               ` [PATCH v8 " Jasvinder Singh
@ 2017-10-13 16:59                 ` Jasvinder Singh
  2017-10-13 17:00                 ` [PATCH v8 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
  2017-10-14 10:20                 ` [PATCH v9 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
  2 siblings, 0 replies; 49+ messages in thread
From: Jasvinder Singh @ 2017-10-13 16:59 UTC (permalink / raw)
  To: dev
  Cc: cristian.dumitrescu, jingjing.wu, pablo.de.lara.guarch,
	yulong.pei, thomas

Add following CLIs in testpmd application for device traffic management;
- commands to add/del shaper profile for TM hieraqrchy nodes.
- commands to add/update shared shapers
- commands to add/del WRED profiles for TM hiearchy leaf nodes.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
v7 change:
- remove unnecessary checks on wred profile color string, api doesn't
  allow to set WRED with less than 3 colors. 

v6 change:
- change port id type to uint16_t
 
v5 change:
- add packet length adjust parameter to add shaper profile command

v4 change:
- remove softnic specific checks to make it generic for the devices

 app/test-pmd/cmdline.c    |  34 +++
 app/test-pmd/cmdline_tm.c | 731 ++++++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/cmdline_tm.h |   7 +
 3 files changed, 772 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 72e0628..4259012 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -693,6 +693,33 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"show port (port_id) queue-region\n"
 			"    show all queue region related configuration info\n\n"
 
+			"add port tm node shaper profile (port_id) (shaper_profile_id)"
+			" (tb_rate) (tb_size) (packet_length_adjust)\n"
+			"	Add port tm node private shaper profile.\n\n"
+
+			"del port tm node shaper profile (port_id) (shaper_profile_id)\n"
+			"	Delete port tm node private shaper profile.\n\n"
+
+			"add port tm node shared shaper (port_id) (shared_shaper_id)"
+			" (shaper_profile_id)\n"
+			"	Add/update port tm node shared shaper.\n\n"
+
+			"del port tm node shared shaper (port_id) (shared_shaper_id)\n"
+			"	Delete port tm node shared shaper.\n\n"
+
+			"set port tm node shaper profile (port_id) (node_id)"
+			" (shaper_profile_id)\n"
+			"	Set port tm node shaper profile.\n\n"
+
+			"add port tm node wred profile (port_id) (wred_profile_id)"
+			" (color_g) (min_th_g) (max_th_g) (maxp_inv_g) (wq_log2_g)"
+			" (color_y) (min_th_y) (max_th_y) (maxp_inv_y) (wq_log2_y)"
+			" (color_r) (min_th_r) (max_th_r) (maxp_inv_r) (wq_log2_r)\n"
+			"	Add port tm node wred profile.\n\n"
+
+			"del port tm node wred profile (port_id) (wred_profile_id)\n"
+			"	Delete port tm node wred profile.\n\n"
+
 			, list_pkt_forwarding_modes()
 		);
 	}
@@ -15616,6 +15643,13 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_cap,
 	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_type,
 	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_stats,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_shared_shaper,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_shared_shaper,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_wred_profile,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_wred_profile,
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_shaper_profile,
 	NULL,
 };
 
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
index f024372..38048ae 100644
--- a/app/test-pmd/cmdline_tm.c
+++ b/app/test-pmd/cmdline_tm.c
@@ -679,3 +679,734 @@ cmdline_parse_inst_t cmd_show_port_tm_node_type = {
 		NULL,
 	},
 };
+
+/* *** Add Port TM Private Shaper Profile *** */
+struct cmd_add_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint16_t port_id;
+	uint32_t shaper_id;
+	uint64_t tb_rate;
+	uint64_t tb_size;
+	uint32_t pktlen_adjust;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_tb_rate =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tb_rate, UINT64);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_tb_size =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tb_size, UINT64);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_pktlen_adjust =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			pktlen_adjust, UINT32);
+
+static void cmd_add_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_tm_shaper_params sp;
+	struct rte_tm_error error;
+	uint32_t shaper_id = res->shaper_id;
+	uint32_t pkt_len_adjust = res->pktlen_adjust;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Private shaper profile params */
+	memset(&sp, 0, sizeof(struct rte_tm_shaper_params));
+	sp.peak.rate = res->tb_rate;
+	sp.peak.size = res->tb_size;
+	sp.pkt_length_adjust = pkt_len_adjust;
+
+	ret = rte_tm_shaper_profile_add(port_id, shaper_id, &sp, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_shaper_profile = {
+	.f = cmd_add_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Add port tm node private shaper profile",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_shaper_profile_add,
+		(void *)&cmd_add_port_tm_node_shaper_profile_port,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_add_port_tm_node_shaper_profile_node,
+		(void *)&cmd_add_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_add_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_add_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_add_port_tm_node_shaper_profile_shaper_id,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tb_rate,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tb_size,
+		(void *)&cmd_add_port_tm_node_shaper_profile_pktlen_adjust,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM Private Shaper Profile *** */
+struct cmd_del_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint16_t port_id;
+	uint32_t shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_del_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_tm_node_shaper_profile_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			shaper_id, UINT32);
+
+static void cmd_del_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t shaper_id = res->shaper_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_shaper_profile_delete(port_id, shaper_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_shaper_profile = {
+	.f = cmd_del_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node private shaper profile",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_shaper_profile_del,
+		(void *)&cmd_del_port_tm_node_shaper_profile_port,
+		(void *)&cmd_del_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_del_port_tm_node_shaper_profile_node,
+		(void *)&cmd_del_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_del_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_del_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_del_port_tm_node_shaper_profile_shaper_id,
+		NULL,
+	},
+};
+
+/* *** Add/Update Port TM shared Shaper *** */
+struct cmd_add_port_tm_node_shared_shaper_result {
+	cmdline_fixed_string_t cmd_type;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shared;
+	cmdline_fixed_string_t shaper;
+	uint16_t port_id;
+	uint32_t shared_shaper_id;
+	uint32_t shaper_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_cmd_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			cmd_type, "add#set");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_shared =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shared, "shared");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shaper, "shaper");
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shared_shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shaper_profile_id, UINT32);
+
+static void cmd_add_port_tm_node_shared_shaper_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_shared_shaper_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t shared_shaper_id = res->shared_shaper_id;
+	uint32_t shaper_profile_id = res->shaper_profile_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Command type: add */
+	if ((strcmp(res->cmd_type, "add") == 0) &&
+		(port_is_started(port_id))) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	/* Command type: set (update) */
+	if ((strcmp(res->cmd_type, "set") == 0) &&
+		(!port_is_started(port_id))) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_shared_shaper_add_update(port_id, shared_shaper_id,
+		shaper_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_shared_shaper = {
+	.f = cmd_add_port_tm_node_shared_shaper_parsed,
+	.data = NULL,
+	.help_str = "add/update port tm node shared shaper",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_shared_shaper_cmd_type,
+		(void *)&cmd_add_port_tm_node_shared_shaper_port,
+		(void *)&cmd_add_port_tm_node_shared_shaper_tm,
+		(void *)&cmd_add_port_tm_node_shared_shaper_node,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shared,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shaper,
+		(void *)&cmd_add_port_tm_node_shared_shaper_port_id,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shared_shaper_id,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shaper_profile_id,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM shared Shaper *** */
+struct cmd_del_port_tm_node_shared_shaper_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shared;
+	cmdline_fixed_string_t shaper;
+	uint16_t port_id;
+	uint32_t shared_shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_shared =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shared, "shared");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shaper, "shaper");
+cmdline_parse_token_num_t cmd_del_port_tm_node_shared_shaper_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_tm_node_shared_shaper_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shared_shaper_id, UINT32);
+
+static void cmd_del_port_tm_node_shared_shaper_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_shared_shaper_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t shared_shaper_id = res->shared_shaper_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_shared_shaper_delete(port_id, shared_shaper_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper = {
+	.f = cmd_del_port_tm_node_shared_shaper_parsed,
+	.data = NULL,
+	.help_str = "delete port tm node shared shaper",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_shared_shaper_del,
+		(void *)&cmd_del_port_tm_node_shared_shaper_port,
+		(void *)&cmd_del_port_tm_node_shared_shaper_tm,
+		(void *)&cmd_del_port_tm_node_shared_shaper_node,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shared,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shaper,
+		(void *)&cmd_del_port_tm_node_shared_shaper_port_id,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shared_shaper_id,
+		NULL,
+	},
+};
+
+/* *** Add Port TM Node WRED Profile *** */
+struct cmd_add_port_tm_node_wred_profile_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t wred;
+	cmdline_fixed_string_t profile;
+	uint16_t port_id;
+	uint32_t wred_profile_id;
+	cmdline_fixed_string_t color_g;
+	uint16_t min_th_g;
+	uint16_t max_th_g;
+	uint16_t maxp_inv_g;
+	uint16_t wq_log2_g;
+	cmdline_fixed_string_t color_y;
+	uint16_t min_th_y;
+	uint16_t max_th_y;
+	uint16_t maxp_inv_y;
+	uint16_t wq_log2_y;
+	cmdline_fixed_string_t color_r;
+	uint16_t min_th_r;
+	uint16_t max_th_r;
+	uint16_t maxp_inv_r;
+	uint16_t wq_log2_r;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_wred =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, wred, "wred");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wred_profile_id, UINT32);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_g =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_g, "G#g");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_g, UINT16);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_y =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_y, "Y#y");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_y, UINT16);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_r =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_r, "R#r");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_r, UINT16);
+
+
+static void cmd_add_port_tm_node_wred_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_wred_profile_result *res = parsed_result;
+	struct rte_tm_wred_params wp;
+	enum rte_tm_color color;
+	struct rte_tm_error error;
+	uint32_t wred_profile_id = res->wred_profile_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	memset(&wp, 0, sizeof(struct rte_tm_wred_params));
+
+	/* WRED Params  (Green Color)*/
+	color = RTE_TM_GREEN;
+	wp.red_params[color].min_th = res->min_th_g;
+	wp.red_params[color].max_th = res->max_th_g;
+	wp.red_params[color].maxp_inv = res->maxp_inv_g;
+	wp.red_params[color].wq_log2 = res->wq_log2_g;
+
+
+	/* WRED Params  (Yellow Color)*/
+	color = RTE_TM_YELLOW;
+	wp.red_params[color].min_th = res->min_th_y;
+	wp.red_params[color].max_th = res->max_th_y;
+	wp.red_params[color].maxp_inv = res->maxp_inv_y;
+	wp.red_params[color].wq_log2 = res->wq_log2_y;
+
+	/* WRED Params  (Red Color)*/
+	color = RTE_TM_RED;
+	wp.red_params[color].min_th = res->min_th_r;
+	wp.red_params[color].max_th = res->max_th_r;
+	wp.red_params[color].maxp_inv = res->maxp_inv_r;
+	wp.red_params[color].wq_log2 = res->wq_log2_r;
+
+	ret = rte_tm_wred_profile_add(port_id, wred_profile_id, &wp, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile = {
+	.f = cmd_add_port_tm_node_wred_profile_parsed,
+	.data = NULL,
+	.help_str = "Add port tm node wred profile",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_wred_profile_add,
+		(void *)&cmd_add_port_tm_node_wred_profile_port,
+		(void *)&cmd_add_port_tm_node_wred_profile_tm,
+		(void *)&cmd_add_port_tm_node_wred_profile_node,
+		(void *)&cmd_add_port_tm_node_wred_profile_wred,
+		(void *)&cmd_add_port_tm_node_wred_profile_profile,
+		(void *)&cmd_add_port_tm_node_wred_profile_port_id,
+		(void *)&cmd_add_port_tm_node_wred_profile_wred_profile_id,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_r,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM node WRED Profile *** */
+struct cmd_del_port_tm_node_wred_profile_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t wred;
+	cmdline_fixed_string_t profile;
+	uint16_t port_id;
+	uint32_t wred_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_wred =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, wred, "wred");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_del_port_tm_node_wred_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_tm_node_wred_profile_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			wred_profile_id, UINT32);
+
+static void cmd_del_port_tm_node_wred_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_wred_profile_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t wred_profile_id = res->wred_profile_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_wred_profile_delete(port_id, wred_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile = {
+	.f = cmd_del_port_tm_node_wred_profile_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node wred profile",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_wred_profile_del,
+		(void *)&cmd_del_port_tm_node_wred_profile_port,
+		(void *)&cmd_del_port_tm_node_wred_profile_tm,
+		(void *)&cmd_del_port_tm_node_wred_profile_node,
+		(void *)&cmd_del_port_tm_node_wred_profile_wred,
+		(void *)&cmd_del_port_tm_node_wred_profile_profile,
+		(void *)&cmd_del_port_tm_node_wred_profile_port_id,
+		(void *)&cmd_del_port_tm_node_wred_profile_wred_profile_id,
+		NULL,
+	},
+};
+
+/* *** Update Port TM Node Shaper profile *** */
+struct cmd_set_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint16_t port_id;
+	uint32_t node_id;
+	uint32_t shaper_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_set_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_set_port_tm_node_shaper_profile_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_shaper_profile_result,
+		node_id, UINT32);
+cmdline_parse_token_num_t
+	cmd_set_port_tm_node_shaper_shaper_profile_profile_id =
+		TOKEN_NUM_INITIALIZER(
+			struct cmd_set_port_tm_node_shaper_profile_result,
+			shaper_profile_id, UINT32);
+
+static void cmd_set_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint32_t shaper_profile_id = res->shaper_profile_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (!port_is_started(port_id)) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_shaper_update(port_id, node_id,
+		shaper_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile = {
+	.f = cmd_set_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node shaper profile",
+	.tokens = {
+		(void *)&cmd_set_port_tm_node_shaper_profile_set,
+		(void *)&cmd_set_port_tm_node_shaper_profile_port,
+		(void *)&cmd_set_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_set_port_tm_node_shaper_profile_node,
+		(void *)&cmd_set_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_set_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_set_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_set_port_tm_node_shaper_profile_node_id,
+		(void *)&cmd_set_port_tm_node_shaper_shaper_profile_profile_id,
+		NULL,
+	},
+};
diff --git a/app/test-pmd/cmdline_tm.h b/app/test-pmd/cmdline_tm.h
index 945af89..5ed9de0 100644
--- a/app/test-pmd/cmdline_tm.h
+++ b/app/test-pmd/cmdline_tm.h
@@ -40,5 +40,12 @@ extern cmdline_parse_inst_t cmd_show_port_tm_level_cap;
 extern cmdline_parse_inst_t cmd_show_port_tm_node_cap;
 extern cmdline_parse_inst_t cmd_show_port_tm_node_type;
 extern cmdline_parse_inst_t cmd_show_port_tm_node_stats;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_shared_shaper;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile;
+extern cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile;
 
 #endif /* _CMDLINE_TM_H_ */
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v8 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit
  2017-10-13 16:59               ` [PATCH v8 " Jasvinder Singh
  2017-10-13 16:59                 ` [PATCH v8 2/3] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
@ 2017-10-13 17:00                 ` Jasvinder Singh
  2017-10-14 10:20                 ` [PATCH v9 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
  2 siblings, 0 replies; 49+ messages in thread
From: Jasvinder Singh @ 2017-10-13 17:00 UTC (permalink / raw)
  To: dev
  Cc: cristian.dumitrescu, jingjing.wu, pablo.de.lara.guarch,
	yulong.pei, thomas

Add following CLIs in testpmd application for device traffic management;
- commands to add TM hierarchy nodes (leaf and nonleaf).
- command for runtime update of node weight.
- command to commit the TM hierarchy

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
v8 change:
- change command defintion for leaf and nonleaf nodes (mulitple shared
  shapers can be specified)
- pre-allocate memory for shared shaper ids array in nonleaf and leaf
  node add cli.
- change clean_on_fail to string type in hierarchy commit cli
 
v7 change:
- fix the help info on leaf node add

v5 change:
- add shaper related parameters to leaf node add command

v4 change:
- remove softnic specific checks to make it generic for the devices

 app/test-pmd/cmdline.c    |  27 ++
 app/test-pmd/cmdline_tm.c | 647 ++++++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/cmdline_tm.h |   5 +
 3 files changed, 679 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 4259012..094cbb8 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -720,6 +720,28 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"del port tm node wred profile (port_id) (wred_profile_id)\n"
 			"	Delete port tm node wred profile.\n\n"
 
+			"add port tm nonleaf node (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight) (level_id) (shaper_profile_id)"
+			" (n_sp_priorities) (stats_mask) (n_shared_shapers)"
+			" [(shared_shaper_id_0) (shared_shaper_id_1)...]\n"
+			"	Add port tm nonleaf node.\n\n"
+
+			"add port tm leaf node (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight) (level_id) (shaper_profile_id)"
+			" (cman_mode) (wred_profile_id) (stats_mask) (n_shared_shapers)"
+			" [(shared_shaper_id_0) (shared_shaper_id_1)...]\n"
+			"	Add port tm leaf node.\n\n"
+
+			"del port tm node (port_id) (node_id)\n"
+			"	Delete port tm node.\n\n"
+
+			"set port tm node parent (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight)\n"
+			"	Set port tm node parent.\n\n"
+
+			"port tm hierarchy commit (port_id) (clean_on_fail)\n"
+			"	Commit tm hierarchy.\n\n"
+
 			, list_pkt_forwarding_modes()
 		);
 	}
@@ -15650,6 +15672,11 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_wred_profile,
 	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_wred_profile,
 	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_nonleaf_node,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_leaf_node,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node,
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_parent,
+	(cmdline_parse_inst_t *)&cmd_port_tm_hierarchy_commit,
 	NULL,
 };
 
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
index 38048ae..ba909ff 100644
--- a/app/test-pmd/cmdline_tm.c
+++ b/app/test-pmd/cmdline_tm.c
@@ -42,6 +42,17 @@
 #include "testpmd.h"
 #include "cmdline_tm.h"
 
+#define PARSE_DELIMITER				" \f\n\r\t\v"
+#define MAX_NUM_SHARED_SHAPERS		256
+
+#define skip_white_spaces(pos)			\
+({						\
+	__typeof__(pos) _p = (pos);		\
+	for ( ; isspace(*_p); _p++)		\
+		;				\
+	_p;					\
+})
+
 /** Display TM Error Message */
 static void
 print_err_msg(struct rte_tm_error *error)
@@ -118,6 +129,100 @@ print_err_msg(struct rte_tm_error *error)
 		error->type);
 }
 
+static int
+read_uint64(uint64_t *value, const char *p)
+{
+	char *next;
+	uint64_t val;
+
+	p = skip_white_spaces(p);
+	if (!isdigit(*p))
+		return -EINVAL;
+
+	val = strtoul(p, &next, 10);
+	if (p == next)
+		return -EINVAL;
+
+	p = next;
+	switch (*p) {
+	case 'T':
+		val *= 1024ULL;
+		/* fall through */
+	case 'G':
+		val *= 1024ULL;
+		/* fall through */
+	case 'M':
+		val *= 1024ULL;
+		/* fall through */
+	case 'k':
+	case 'K':
+		val *= 1024ULL;
+		p++;
+		break;
+	}
+
+	p = skip_white_spaces(p);
+	if (*p != '\0')
+		return -EINVAL;
+
+	*value = val;
+	return 0;
+}
+
+static int
+read_uint32(uint32_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = read_uint64(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT32_MAX)
+		return -ERANGE;
+
+	*value = val;
+	return 0;
+}
+
+static int
+parse_multi_ss_id_str(char *s_str, uint32_t *n_ssp, uint32_t shaper_id[])
+{
+	uint32_t n_shared_shapers = 0, i = 0;
+	char *token;
+
+	/* First token: num of shared shapers */
+	token = strtok_r(s_str, PARSE_DELIMITER, &s_str);
+	if (token ==  NULL)
+		return -1;
+
+	if (read_uint32(&n_shared_shapers, token))
+		return -1;
+
+	/* Check: num of shared shaper */
+	if (n_shared_shapers >= MAX_NUM_SHARED_SHAPERS) {
+		printf(" Number of shared shapers exceed the max (error)\n");
+		return -1;
+	}
+
+	/* Parse shared shaper ids */
+	while (1) {
+		token = strtok_r(s_str, PARSE_DELIMITER, &s_str);
+		if ((token !=  NULL && n_shared_shapers == 0) ||
+			(token == NULL && i < n_shared_shapers))
+			return -1;
+
+		if (token == NULL)
+			break;
+
+		if (read_uint32(&shaper_id[i], token))
+			return -1;
+		i++;
+	}
+	*n_ssp = n_shared_shapers;
+
+	return 0;
+}
 /* *** Port TM Capability *** */
 struct cmd_show_port_tm_cap_result {
 	cmdline_fixed_string_t show;
@@ -1410,3 +1515,545 @@ cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile = {
 		NULL,
 	},
 };
+
+/* *** Add Port TM nonleaf node *** */
+struct cmd_add_port_tm_nonleaf_node_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t nonleaf;
+	cmdline_fixed_string_t node;
+	uint16_t port_id;
+	uint32_t node_id;
+	int32_t parent_node_id;
+	uint32_t priority;
+	uint32_t weight;
+	uint32_t level_id;
+	uint32_t shaper_profile_id;
+	uint32_t n_sp_priorities;
+	uint64_t stats_mask;
+	cmdline_multi_string_t multi_shared_shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_nonleaf =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, nonleaf, "nonleaf");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, node, "node");
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 node_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 parent_node_id, INT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 priority, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 weight, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 level_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 shaper_profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_n_sp_priorities =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 n_sp_priorities, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_stats_mask =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 stats_mask, UINT64);
+cmdline_parse_token_string_t
+	cmd_add_port_tm_nonleaf_node_multi_shared_shaper_id =
+	TOKEN_STRING_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 multi_shared_shaper_id, TOKEN_STRING_MULTI);
+
+static void cmd_add_port_tm_nonleaf_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_nonleaf_node_result *res = parsed_result;
+	struct rte_tm_error error;
+	struct rte_tm_node_params np;
+	uint32_t shared_shaper_id[MAX_NUM_SHARED_SHAPERS];
+	uint32_t parent_node_id, n_shared_shapers = 0;
+	char *s_str = res->multi_shared_shaper_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	memset(&np, 0, sizeof(struct rte_tm_node_params));
+
+	/* Node parameters */
+	if (res->parent_node_id < 0)
+		parent_node_id = UINT32_MAX;
+	else
+		parent_node_id = res->parent_node_id;
+
+	/* Parse multi shared shaper id string */
+	ret = parse_multi_ss_id_str(s_str, &n_shared_shapers, shared_shaper_id);
+	if (ret) {
+		printf(" Shared shapers params string parse error\n");
+		return;
+	}
+
+	np.shaper_profile_id = res->shaper_profile_id;
+	np.n_shared_shapers = n_shared_shapers;
+	if (np.n_shared_shapers)
+		np.shared_shaper_id = &shared_shaper_id[0];
+	else
+		np.shared_shaper_id = NULL;
+
+	np.nonleaf.n_sp_priorities = res->n_sp_priorities;
+	np.stats_mask = res->stats_mask;
+	np.nonleaf.wfq_weight_mode = NULL;
+
+	ret = rte_tm_node_add(port_id, res->node_id, parent_node_id,
+				res->priority, res->weight, res->level_id,
+				&np, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_nonleaf_node = {
+	.f = cmd_add_port_tm_nonleaf_node_parsed,
+	.data = NULL,
+	.help_str = "Add port tm nonleaf node",
+	.tokens = {
+		(void *)&cmd_add_port_tm_nonleaf_node_add,
+		(void *)&cmd_add_port_tm_nonleaf_node_port,
+		(void *)&cmd_add_port_tm_nonleaf_node_tm,
+		(void *)&cmd_add_port_tm_nonleaf_node_nonleaf,
+		(void *)&cmd_add_port_tm_nonleaf_node_node,
+		(void *)&cmd_add_port_tm_nonleaf_node_port_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_node_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_parent_node_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_priority,
+		(void *)&cmd_add_port_tm_nonleaf_node_weight,
+		(void *)&cmd_add_port_tm_nonleaf_node_level_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_shaper_profile_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_n_sp_priorities,
+		(void *)&cmd_add_port_tm_nonleaf_node_stats_mask,
+		(void *)&cmd_add_port_tm_nonleaf_node_multi_shared_shaper_id,
+		NULL,
+	},
+};
+
+/* *** Add Port TM leaf node *** */
+struct cmd_add_port_tm_leaf_node_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t leaf;
+	cmdline_fixed_string_t node;
+	uint16_t port_id;
+	uint32_t node_id;
+	int32_t parent_node_id;
+	uint32_t priority;
+	uint32_t weight;
+	uint32_t level_id;
+	uint32_t shaper_profile_id;
+	uint32_t cman_mode;
+	uint32_t wred_profile_id;
+	uint64_t stats_mask;
+	cmdline_multi_string_t multi_shared_shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_nonleaf =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, leaf, "leaf");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, node, "node");
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 node_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 parent_node_id, INT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 priority, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 weight, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 level_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 shaper_profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_cman_mode =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 cman_mode, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 wred_profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_stats_mask =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 stats_mask, UINT64);
+cmdline_parse_token_string_t
+	cmd_add_port_tm_leaf_node_multi_shared_shaper_id =
+	TOKEN_STRING_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 multi_shared_shaper_id, TOKEN_STRING_MULTI);
+
+static void cmd_add_port_tm_leaf_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_leaf_node_result *res = parsed_result;
+	struct rte_tm_error error;
+	struct rte_tm_node_params np;
+	uint32_t shared_shaper_id[MAX_NUM_SHARED_SHAPERS];
+	uint32_t parent_node_id, n_shared_shapers = 0;
+	portid_t port_id = res->port_id;
+	char *s_str = res->multi_shared_shaper_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	memset(&np, 0, sizeof(struct rte_tm_node_params));
+
+	/* Node parameters */
+	if (res->parent_node_id < 0)
+		parent_node_id = UINT32_MAX;
+	else
+		parent_node_id = res->parent_node_id;
+
+	/* Parse multi shared shaper id string */
+	ret = parse_multi_ss_id_str(s_str, &n_shared_shapers, shared_shaper_id);
+	if (ret) {
+		printf(" Shared shapers params string parse error\n");
+		return;
+	}
+
+	np.shaper_profile_id = res->shaper_profile_id;
+	np.n_shared_shapers = n_shared_shapers;
+
+	if (np.n_shared_shapers)
+		np.shared_shaper_id = &shared_shaper_id[0];
+	else
+		np.shared_shaper_id = NULL;
+
+	np.leaf.cman = res->cman_mode;
+	np.leaf.wred.wred_profile_id = res->wred_profile_id;
+	np.stats_mask = res->stats_mask;
+
+	ret = rte_tm_node_add(port_id, res->node_id, parent_node_id,
+				res->priority, res->weight, res->level_id,
+				&np, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_leaf_node = {
+	.f = cmd_add_port_tm_leaf_node_parsed,
+	.data = NULL,
+	.help_str = "Add port tm leaf node",
+	.tokens = {
+		(void *)&cmd_add_port_tm_leaf_node_add,
+		(void *)&cmd_add_port_tm_leaf_node_port,
+		(void *)&cmd_add_port_tm_leaf_node_tm,
+		(void *)&cmd_add_port_tm_leaf_node_nonleaf,
+		(void *)&cmd_add_port_tm_leaf_node_node,
+		(void *)&cmd_add_port_tm_leaf_node_port_id,
+		(void *)&cmd_add_port_tm_leaf_node_node_id,
+		(void *)&cmd_add_port_tm_leaf_node_parent_node_id,
+		(void *)&cmd_add_port_tm_leaf_node_priority,
+		(void *)&cmd_add_port_tm_leaf_node_weight,
+		(void *)&cmd_add_port_tm_leaf_node_level_id,
+		(void *)&cmd_add_port_tm_leaf_node_shaper_profile_id,
+		(void *)&cmd_add_port_tm_leaf_node_cman_mode,
+		(void *)&cmd_add_port_tm_leaf_node_wred_profile_id,
+		(void *)&cmd_add_port_tm_leaf_node_stats_mask,
+		(void *)&cmd_add_port_tm_leaf_node_multi_shared_shaper_id,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM Node *** */
+struct cmd_del_port_tm_node_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	uint16_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, node, "node");
+cmdline_parse_token_num_t cmd_del_port_tm_node_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_del_port_tm_node_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_tm_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_del_port_tm_node_result,
+		node_id, UINT32);
+
+static void cmd_del_port_tm_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_delete(port_id, node_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node = {
+	.f = cmd_del_port_tm_node_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_del,
+		(void *)&cmd_del_port_tm_node_port,
+		(void *)&cmd_del_port_tm_node_tm,
+		(void *)&cmd_del_port_tm_node_node,
+		(void *)&cmd_del_port_tm_node_port_id,
+		(void *)&cmd_del_port_tm_node_node_id,
+		NULL,
+	},
+};
+
+/* *** Update Port TM Node Parent *** */
+struct cmd_set_port_tm_node_parent_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t parent;
+	uint16_t port_id;
+	uint32_t node_id;
+	uint32_t parent_id;
+	uint32_t priority;
+	uint32_t weight;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, node, "node");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_parent =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, parent, "parent");
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, port_id, UINT16);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, node_id, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_parent_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		parent_id, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		priority, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		weight, UINT32);
+
+static void cmd_set_port_tm_node_parent_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_node_parent_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint32_t parent_id = res->parent_id;
+	uint32_t priority = res->priority;
+	uint32_t weight = res->weight;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (!port_is_started(port_id)) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_parent_update(port_id, node_id,
+		parent_id, priority, weight, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_node_parent = {
+	.f = cmd_set_port_tm_node_parent_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node parent",
+	.tokens = {
+		(void *)&cmd_set_port_tm_node_parent_set,
+		(void *)&cmd_set_port_tm_node_parent_port,
+		(void *)&cmd_set_port_tm_node_parent_tm,
+		(void *)&cmd_set_port_tm_node_parent_node,
+		(void *)&cmd_set_port_tm_node_parent_parent,
+		(void *)&cmd_set_port_tm_node_parent_port_id,
+		(void *)&cmd_set_port_tm_node_parent_node_id,
+		(void *)&cmd_set_port_tm_node_parent_parent_id,
+		(void *)&cmd_set_port_tm_node_parent_priority,
+		(void *)&cmd_set_port_tm_node_parent_weight,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchy Commit *** */
+struct cmd_port_tm_hierarchy_commit_result {
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t hierarchy;
+	cmdline_fixed_string_t commit;
+	uint16_t port_id;
+	cmdline_fixed_string_t clean_on_fail;
+};
+
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, port, "port");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, tm, "tm");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_hierarchy =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result,
+			hierarchy, "hierarchy");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_commit =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, commit, "commit");
+cmdline_parse_token_num_t cmd_port_tm_hierarchy_commit_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result,
+			port_id, UINT16);
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_clean_on_fail =
+	TOKEN_STRING_INITIALIZER(struct cmd_port_tm_hierarchy_commit_result,
+		 clean_on_fail, "yes#no");
+
+static void cmd_port_tm_hierarchy_commit_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_port_tm_hierarchy_commit_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t clean_on_fail;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	if (strcmp(res->clean_on_fail, "yes") == 0)
+		clean_on_fail = 1;
+	else
+		clean_on_fail = 0;
+
+	ret = rte_tm_hierarchy_commit(port_id, clean_on_fail, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_port_tm_hierarchy_commit = {
+	.f = cmd_port_tm_hierarchy_commit_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node shaper profile",
+	.tokens = {
+		(void *)&cmd_port_tm_hierarchy_commit_port,
+		(void *)&cmd_port_tm_hierarchy_commit_tm,
+		(void *)&cmd_port_tm_hierarchy_commit_hierarchy,
+		(void *)&cmd_port_tm_hierarchy_commit_commit,
+		(void *)&cmd_port_tm_hierarchy_commit_port_id,
+		(void *)&cmd_port_tm_hierarchy_commit_clean_on_fail,
+		NULL,
+	},
+};
diff --git a/app/test-pmd/cmdline_tm.h b/app/test-pmd/cmdline_tm.h
index 5ed9de0..9d5fdf0 100644
--- a/app/test-pmd/cmdline_tm.h
+++ b/app/test-pmd/cmdline_tm.h
@@ -47,5 +47,10 @@ extern cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper;
 extern cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile;
 extern cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile;
 extern cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_add_port_tm_nonleaf_node;
+extern cmdline_parse_inst_t cmd_add_port_tm_leaf_node;
+extern cmdline_parse_inst_t cmd_del_port_tm_node;
+extern cmdline_parse_inst_t cmd_set_port_tm_node_parent;
+extern cmdline_parse_inst_t cmd_port_tm_hierarchy_commit;
 
 #endif /* _CMDLINE_TM_H_ */
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v9 1/3] app/test-pmd: add CLI for TM capability and stats
  2017-10-13 16:59               ` [PATCH v8 " Jasvinder Singh
  2017-10-13 16:59                 ` [PATCH v8 2/3] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
  2017-10-13 17:00                 ` [PATCH v8 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
@ 2017-10-14 10:20                 ` Jasvinder Singh
  2017-10-14 10:20                   ` [PATCH v9 2/3] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
                                     ` (2 more replies)
  2 siblings, 3 replies; 49+ messages in thread
From: Jasvinder Singh @ 2017-10-14 10:20 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu, yulong.pei

Add following CLIs to testpmd application for device traffic management;
- commands to display TM capability information.
  (per port, per hierarchy level and per hierarchy node)
- command to display hiearchy node type
- stats collection

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Tested-by: Yulong Pei <yulong.pei@intel.com>
Reviewed-by: Jingjing Wu <jingjing.wu@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
v9 change:
- fix checkpatch warnings

v6 change:
- fix compilation warning
- change port_id type to uint16_t

v4 change:
 - remove softnic specific checks to make it generic for the devices

v3 change:
- Implements feedback from Pablo[1]
 - move TM API related CLIs into cmdline_tm.c
 - split patch into small patches
 - replace link status check with testpmd fn port_is_started()

[1]http://dpdk.org/ml/archives/dev/2017-September/075748.html

 app/test-pmd/Makefile     |   1 +
 app/test-pmd/cmdline.c    |  20 ++
 app/test-pmd/cmdline_tm.c | 681 ++++++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/cmdline_tm.h |  44 +++
 4 files changed, 746 insertions(+)
 create mode 100644 app/test-pmd/cmdline_tm.c
 create mode 100644 app/test-pmd/cmdline_tm.h

diff --git a/app/test-pmd/Makefile b/app/test-pmd/Makefile
index 2c50f68..e4a6352 100644
--- a/app/test-pmd/Makefile
+++ b/app/test-pmd/Makefile
@@ -48,6 +48,7 @@ SRCS-y := testpmd.c
 SRCS-y += parameters.c
 SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline.c
 SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline_flow.c
+SRCS-y += cmdline_tm.c
 SRCS-y += config.c
 SRCS-y += iofwd.c
 SRCS-y += macfwd.c
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index bb19d72..72e0628 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -99,6 +99,7 @@
 #include <rte_pmd_bnxt.h>
 #endif
 #include "testpmd.h"
+#include "cmdline_tm.h"
 
 static struct cmdline *testpmd_cl;
 
@@ -234,6 +235,20 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"show port (port_id) pctype mapping\n"
 			"    Get flow ptype to pctype mapping on a port\n\n"
 
+			"show port tm cap (port_id)\n"
+			"	Display the port TM capability.\n\n"
+
+			"show port tm level cap (port_id) (level_id)\n"
+			"	Display the port TM hierarchical level capability.\n\n"
+
+			"show port tm node cap (port_id) (node_id)\n"
+			"	Display the port TM node capability.\n\n"
+
+			"show port tm node type (port_id) (node_id)\n"
+			"	Display the port TM node type.\n\n"
+
+			"show port tm node stats (port_id) (node_id) (clear)\n"
+			"	Display the port TM node stats.\n\n"
 		);
 	}
 
@@ -15596,6 +15611,11 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_user_priority_region,
 	(cmdline_parse_inst_t *)&cmd_flush_queue_region,
 	(cmdline_parse_inst_t *)&cmd_show_queue_region_info_all,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_level_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_type,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_stats,
 	NULL,
 };
 
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
new file mode 100644
index 0000000..f024372
--- /dev/null
+++ b/app/test-pmd/cmdline_tm.c
@@ -0,0 +1,681 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+
+#include <rte_ethdev.h>
+#include <rte_flow.h>
+#include <rte_tm.h>
+
+#include "testpmd.h"
+#include "cmdline_tm.h"
+
+/** Display TM Error Message */
+static void
+print_err_msg(struct rte_tm_error *error)
+{
+	static const char *const errstrlist[] = {
+		[RTE_TM_ERROR_TYPE_NONE] = "no error",
+		[RTE_TM_ERROR_TYPE_UNSPECIFIED] = "cause unspecified",
+		[RTE_TM_ERROR_TYPE_CAPABILITIES]
+			= "capability parameter null",
+		[RTE_TM_ERROR_TYPE_LEVEL_ID] = "level id",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE]
+			= "wred profile null",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_GREEN] = "wred profile(green)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_YELLOW]
+			= "wred profile(yellow)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_RED] = "wred profile(red)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_ID] = "wred profile id",
+		[RTE_TM_ERROR_TYPE_SHARED_WRED_CONTEXT_ID]
+			= "shared wred context id",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE] = "shaper profile null",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE]
+			= "committed rate field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE]
+			= "committed size field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE]
+			= "peak rate field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE]
+			= "peak size field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN]
+			= "packet adjust length field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID] = "shaper profile id",
+		[RTE_TM_ERROR_TYPE_SHARED_SHAPER_ID] = "shared shaper id",
+		[RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID] = "parent node id",
+		[RTE_TM_ERROR_TYPE_NODE_PRIORITY] = "node priority",
+		[RTE_TM_ERROR_TYPE_NODE_WEIGHT] = "node weight",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS] = "node parameter null",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID]
+			= "shaper profile id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID]
+			= "shared shaper id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS]
+			= "num shared shapers field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE]
+			= "wfq weght mode field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES]
+			= "num strict priorities field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN]
+			= "congestion management mode field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID] =
+			"wred profile id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID]
+			= "shared wred context id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS]
+			= "num shared wred contexts field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS]
+			= "stats field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_ID] = "node id",
+	};
+
+	const char *errstr;
+	char buf[64];
+
+	if ((unsigned int)error->type >= RTE_DIM(errstrlist) ||
+		!errstrlist[error->type])
+		errstr = "unknown type";
+	else
+		errstr = errstrlist[error->type];
+
+	if (error->cause)
+		snprintf(buf, sizeof(buf), "cause: %p, ", error->cause);
+
+	printf("%s: %s%s (error %d)\n", errstr, error->cause ? buf : "",
+		error->message ? error->message : "(no stated reason)",
+		error->type);
+}
+
+/* *** Port TM Capability *** */
+struct cmd_show_port_tm_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t cap;
+	uint16_t port_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		 port_id, UINT16);
+
+static void cmd_show_port_tm_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_cap_result *res = parsed_result;
+	struct rte_tm_capabilities cap;
+	struct rte_tm_error error;
+	portid_t port_id = res->port_id;
+	uint32_t i;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	memset(&cap, 0, sizeof(struct rte_tm_capabilities));
+	ret = rte_tm_capabilities_get(port_id, &cap, &error);
+	if (ret) {
+		print_err_msg(&error);
+		return;
+	}
+
+	printf("\n****   Port TM Capabilities ****\n\n");
+	printf("cap.n_nodes_max %" PRIu32 "\n", cap.n_nodes_max);
+	printf("cap.n_levels_max %" PRIu32 "\n", cap.n_levels_max);
+	printf("cap.non_leaf_nodes_identical %" PRId32 "\n",
+		cap.non_leaf_nodes_identical);
+	printf("cap.leaf_nodes_identical %" PRId32 "\n",
+		cap.leaf_nodes_identical);
+	printf("cap.shaper_n_max %u\n", cap.shaper_n_max);
+	printf("cap.shaper_private_n_max %" PRIu32 "\n",
+		cap.shaper_private_n_max);
+	printf("cap.shaper_private_dual_rate_n_max %" PRId32 "\n",
+		cap.shaper_private_dual_rate_n_max);
+	printf("cap.shaper_private_rate_min %" PRIu64 "\n",
+		cap.shaper_private_rate_min);
+	printf("cap.shaper_private_rate_max %" PRIu64 "\n",
+		cap.shaper_private_rate_max);
+	printf("cap.shaper_shared_n_max %" PRIu32 "\n",
+		cap.shaper_shared_n_max);
+	printf("cap.shaper_shared_n_nodes_per_shaper_max %" PRIu32 "\n",
+		cap.shaper_shared_n_nodes_per_shaper_max);
+	printf("cap.shaper_shared_n_shapers_per_node_max %" PRIu32 "\n",
+		cap.shaper_shared_n_shapers_per_node_max);
+	printf("cap.shaper_shared_dual_rate_n_max %" PRIu32 "\n",
+		cap.shaper_shared_dual_rate_n_max);
+	printf("cap.shaper_shared_rate_min %" PRIu64 "\n",
+		cap.shaper_shared_rate_min);
+	printf("cap.shaper_shared_rate_max %" PRIu64 "\n",
+		cap.shaper_shared_rate_max);
+	printf("cap.shaper_pkt_length_adjust_min %" PRId32 "\n",
+		cap.shaper_pkt_length_adjust_min);
+	printf("cap.shaper_pkt_length_adjust_max %" PRId32 "\n",
+		cap.shaper_pkt_length_adjust_max);
+	printf("cap.sched_n_children_max %" PRIu32 "\n",
+		cap.sched_n_children_max);
+	printf("cap.sched_sp_n_priorities_max %" PRIu32 "\n",
+		cap.sched_sp_n_priorities_max);
+	printf("cap.sched_wfq_n_children_per_group_max %" PRIu32 "\n",
+		cap.sched_wfq_n_children_per_group_max);
+	printf("cap.sched_wfq_n_groups_max %" PRIu32 "\n",
+		cap.sched_wfq_n_groups_max);
+	printf("cap.sched_wfq_weight_max %" PRIu32 "\n",
+		cap.sched_wfq_weight_max);
+	printf("cap.cman_head_drop_supported %" PRId32 "\n",
+		cap.cman_head_drop_supported);
+	printf("cap.cman_wred_context_n_max %" PRIu32 "\n",
+		cap.cman_wred_context_n_max);
+	printf("cap.cman_wred_context_private_n_max %" PRIu32 "\n",
+		cap.cman_wred_context_private_n_max);
+	printf("cap.cman_wred_context_shared_n_max %" PRIu32 "\n",
+		cap.cman_wred_context_shared_n_max);
+	printf("cap.cman_wred_context_shared_n_nodes_per_context_max %" PRIu32
+		"\n", cap.cman_wred_context_shared_n_nodes_per_context_max);
+	printf("cap.cman_wred_context_shared_n_contexts_per_node_max %" PRIu32
+		"\n", cap.cman_wred_context_shared_n_contexts_per_node_max);
+
+	for (i = 0; i < RTE_TM_COLORS; i++) {
+		printf("cap.mark_vlan_dei_supported %" PRId32 "\n",
+			cap.mark_vlan_dei_supported[i]);
+		printf("cap.mark_ip_ecn_tcp_supported %" PRId32 "\n",
+			cap.mark_ip_ecn_tcp_supported[i]);
+		printf("cap.mark_ip_ecn_sctp_supported %" PRId32 "\n",
+			cap.mark_ip_ecn_sctp_supported[i]);
+		printf("cap.mark_ip_dscp_supported %" PRId32 "\n",
+			cap.mark_ip_dscp_supported[i]);
+	}
+
+	printf("cap.dynamic_update_mask %" PRIx64 "\n",
+		cap.dynamic_update_mask);
+	printf("cap.stats_mask %" PRIx64 "\n", cap.stats_mask);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_cap = {
+	.f = cmd_show_port_tm_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_cap_show,
+		(void *)&cmd_show_port_tm_cap_port,
+		(void *)&cmd_show_port_tm_cap_tm,
+		(void *)&cmd_show_port_tm_cap_cap,
+		(void *)&cmd_show_port_tm_cap_port_id,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchical Level Capability *** */
+struct cmd_show_port_tm_level_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t level;
+	cmdline_fixed_string_t cap;
+	uint16_t port_id;
+	uint32_t level_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_level =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		level, "level");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_level_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_level_cap_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		 level_id, UINT32);
+
+
+static void cmd_show_port_tm_level_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_level_cap_result *res = parsed_result;
+	struct rte_tm_level_capabilities lcap;
+	struct rte_tm_error error;
+	portid_t port_id = res->port_id;
+	uint32_t level_id = res->level_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	memset(&lcap, 0, sizeof(struct rte_tm_level_capabilities));
+	ret = rte_tm_level_capabilities_get(port_id, level_id, &lcap, &error);
+	if (ret) {
+		print_err_msg(&error);
+		return;
+	}
+	printf("\n**   Port TM Hierarchy level %" PRIu32 " Capability **\n\n",
+		level_id);
+
+	printf("cap.n_nodes_max %" PRIu32 "\n", lcap.n_nodes_max);
+	printf("cap.n_nodes_nonleaf_max %" PRIu32 "\n",
+		lcap.n_nodes_nonleaf_max);
+	printf("cap.n_nodes_leaf_max %" PRIu32 "\n", lcap.n_nodes_leaf_max);
+	printf("cap.non_leaf_nodes_identical %" PRId32 "\n",
+		lcap.non_leaf_nodes_identical);
+	printf("cap.leaf_nodes_identical %" PRId32 "\n",
+		lcap.leaf_nodes_identical);
+	if (level_id <= 3) {
+		printf("cap.nonleaf.shaper_private_supported %" PRId32 "\n",
+			lcap.nonleaf.shaper_private_supported);
+		printf("cap.nonleaf.shaper_private_dual_rate_supported %" PRId32
+			"\n", lcap.nonleaf.shaper_private_dual_rate_supported);
+		printf("cap.nonleaf.shaper_private_rate_min %" PRIu64 "\n",
+			lcap.nonleaf.shaper_private_rate_min);
+		printf("cap.nonleaf.shaper_private_rate_max %" PRIu64 "\n",
+			lcap.nonleaf.shaper_private_rate_max);
+		printf("cap.nonleaf.shaper_shared_n_max %" PRIu32 "\n",
+			lcap.nonleaf.shaper_shared_n_max);
+		printf("cap.nonleaf.sched_n_children_max %" PRIu32 "\n",
+			lcap.nonleaf.sched_n_children_max);
+		printf("cap.nonleaf.sched_sp_n_priorities_max %" PRIu32 "\n",
+			lcap.nonleaf.sched_sp_n_priorities_max);
+		printf("cap.nonleaf.sched_wfq_n_children_per_group_max %" PRIu32
+			"\n", lcap.nonleaf.sched_wfq_n_children_per_group_max);
+		printf("cap.nonleaf.sched_wfq_n_groups_max %" PRIu32 "\n",
+			lcap.nonleaf.sched_wfq_n_groups_max);
+		printf("cap.nonleaf.sched_wfq_weight_max %" PRIu32 "\n",
+			lcap.nonleaf.sched_wfq_weight_max);
+		printf("cap.nonleaf.stats_mask %" PRIx64 "\n",
+			lcap.nonleaf.stats_mask);
+	} else {
+		printf("cap.leaf.shaper_private_supported %" PRId32 "\n",
+			lcap.leaf.shaper_private_supported);
+		printf("cap.leaf.shaper_private_dual_rate_supported %" PRId32
+			"\n", lcap.leaf.shaper_private_dual_rate_supported);
+		printf("cap.leaf.shaper_private_rate_min %" PRIu64 "\n",
+			lcap.leaf.shaper_private_rate_min);
+		printf("cap.leaf.shaper_private_rate_max %" PRIu64 "\n",
+			lcap.leaf.shaper_private_rate_max);
+		printf("cap.leaf.shaper_shared_n_max %" PRIu32 "\n",
+			lcap.leaf.shaper_shared_n_max);
+		printf("cap.leaf.cman_head_drop_supported %" PRId32 "\n",
+			lcap.leaf.cman_head_drop_supported);
+		printf("cap.leaf.cman_wred_context_private_supported %"	PRId32
+			"\n", lcap.leaf.cman_wred_context_private_supported);
+		printf("cap.leaf.cman_wred_context_shared_n_max %" PRIu32 "\n",
+			lcap.leaf.cman_wred_context_shared_n_max);
+		printf("cap.leaf.stats_mask %" PRIx64 "\n",
+			lcap.leaf.stats_mask);
+	}
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_level_cap = {
+	.f = cmd_show_port_tm_level_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Hierarhical level Capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_level_cap_show,
+		(void *)&cmd_show_port_tm_level_cap_port,
+		(void *)&cmd_show_port_tm_level_cap_tm,
+		(void *)&cmd_show_port_tm_level_cap_level,
+		(void *)&cmd_show_port_tm_level_cap_cap,
+		(void *)&cmd_show_port_tm_level_cap_port_id,
+		(void *)&cmd_show_port_tm_level_cap_level_id,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchy Node Capability *** */
+struct cmd_show_port_tm_node_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t cap;
+	uint16_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_node =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_node_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_node_cap_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		 node_id, UINT32);
+
+static void cmd_show_port_tm_node_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_cap_result *res = parsed_result;
+	struct rte_tm_node_capabilities ncap;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	portid_t port_id = res->port_id;
+	int ret, is_leaf = 0;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Node id must be valid */
+	ret = rte_tm_node_type_get(port_id, node_id, &is_leaf, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	memset(&ncap, 0, sizeof(struct rte_tm_node_capabilities));
+	ret = rte_tm_node_capabilities_get(port_id, node_id, &ncap, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+	printf("\n**   Port TM Hierarchy node %" PRIu32 " Capability **\n\n",
+		node_id);
+	printf("cap.shaper_private_supported %" PRId32 "\n",
+		ncap.shaper_private_supported);
+	printf("cap.shaper_private_dual_rate_supported %" PRId32 "\n",
+		ncap.shaper_private_dual_rate_supported);
+	printf("cap.shaper_private_rate_min %" PRIu64 "\n",
+		ncap.shaper_private_rate_min);
+	printf("cap.shaper_private_rate_max %" PRIu64 "\n",
+		ncap.shaper_private_rate_max);
+	printf("cap.shaper_shared_n_max %" PRIu32 "\n",
+		ncap.shaper_shared_n_max);
+	if (!is_leaf) {
+		printf("cap.nonleaf.sched_n_children_max %" PRIu32 "\n",
+			ncap.nonleaf.sched_n_children_max);
+		printf("cap.nonleaf.sched_sp_n_priorities_max %" PRIu32 "\n",
+			ncap.nonleaf.sched_sp_n_priorities_max);
+		printf("cap.nonleaf.sched_wfq_n_children_per_group_max %" PRIu32
+			"\n", ncap.nonleaf.sched_wfq_n_children_per_group_max);
+		printf("cap.nonleaf.sched_wfq_n_groups_max %" PRIu32 "\n",
+			ncap.nonleaf.sched_wfq_n_groups_max);
+		printf("cap.nonleaf.sched_wfq_weight_max %" PRIu32 "\n",
+			ncap.nonleaf.sched_wfq_weight_max);
+	} else {
+		printf("cap.leaf.cman_head_drop_supported %" PRId32 "\n",
+			ncap.leaf.cman_head_drop_supported);
+		printf("cap.leaf.cman_wred_context_private_supported %" PRId32
+			"\n", ncap.leaf.cman_wred_context_private_supported);
+		printf("cap.leaf.cman_wred_context_shared_n_max %" PRIu32 "\n",
+			ncap.leaf.cman_wred_context_shared_n_max);
+	}
+	printf("cap.stats_mask %" PRIx64 "\n", ncap.stats_mask);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_cap = {
+	.f = cmd_show_port_tm_node_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Hierarchy node capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_cap_show,
+		(void *)&cmd_show_port_tm_node_cap_port,
+		(void *)&cmd_show_port_tm_node_cap_tm,
+		(void *)&cmd_show_port_tm_node_cap_node,
+		(void *)&cmd_show_port_tm_node_cap_cap,
+		(void *)&cmd_show_port_tm_node_cap_port_id,
+		(void *)&cmd_show_port_tm_node_cap_node_id,
+		NULL,
+	},
+};
+
+/* *** Show Port TM Node Statistics *** */
+struct cmd_show_port_tm_node_stats_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t stats;
+	uint16_t port_id;
+	uint32_t node_id;
+	uint32_t clear;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_show =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_stats =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, stats, "stats");
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_stats_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result,
+			node_id, UINT32);
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_clear =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, clear, UINT32);
+
+static void cmd_show_port_tm_node_stats_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_stats_result *res = parsed_result;
+	struct rte_tm_node_stats stats;
+	struct rte_tm_error error;
+	uint64_t stats_mask = 0;
+	uint32_t node_id = res->node_id;
+	uint32_t clear = res->clear;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (!port_is_started(port_id)) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	memset(&stats, 0, sizeof(struct rte_tm_node_stats));
+	ret = rte_tm_node_stats_read(port_id, node_id, &stats,
+			&stats_mask, clear, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	/* Display stats */
+	if (stats_mask & RTE_TM_STATS_N_PKTS)
+		printf("\tPkts scheduled from node: %" PRIu64 "\n",
+			stats.n_pkts);
+	if (stats_mask & RTE_TM_STATS_N_BYTES)
+		printf("\tBytes scheduled from node: %" PRIu64 "\n",
+			stats.n_bytes);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_GREEN_DROPPED)
+		printf("\tPkts dropped (green): %" PRIu64 "\n",
+			stats.leaf.n_pkts_dropped[RTE_TM_GREEN]);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_YELLOW_DROPPED)
+		printf("\tPkts dropped (yellow): %" PRIu64 "\n",
+			stats.leaf.n_pkts_dropped[RTE_TM_YELLOW]);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_RED_DROPPED)
+		printf("\tPkts dropped (red): %" PRIu64 "\n",
+			stats.leaf.n_pkts_dropped[RTE_TM_RED]);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_GREEN_DROPPED)
+		printf("\tBytes dropped (green): %" PRIu64 "\n",
+			stats.leaf.n_bytes_dropped[RTE_TM_GREEN]);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_YELLOW_DROPPED)
+		printf("\tBytes dropped (yellow): %" PRIu64 "\n",
+			stats.leaf.n_bytes_dropped[RTE_TM_YELLOW]);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_RED_DROPPED)
+		printf("\tBytes dropped (red): %" PRIu64 "\n",
+			stats.leaf.n_bytes_dropped[RTE_TM_RED]);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_QUEUED)
+		printf("\tPkts queued: %" PRIu64 "\n",
+			stats.leaf.n_pkts_queued);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_QUEUED)
+		printf("\tBytes queued: %" PRIu64 "\n",
+			stats.leaf.n_bytes_queued);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_stats = {
+	.f = cmd_show_port_tm_node_stats_parsed,
+	.data = NULL,
+	.help_str = "Show port tm node stats",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_stats_show,
+		(void *)&cmd_show_port_tm_node_stats_port,
+		(void *)&cmd_show_port_tm_node_stats_tm,
+		(void *)&cmd_show_port_tm_node_stats_node,
+		(void *)&cmd_show_port_tm_node_stats_stats,
+		(void *)&cmd_show_port_tm_node_stats_port_id,
+		(void *)&cmd_show_port_tm_node_stats_node_id,
+		(void *)&cmd_show_port_tm_node_stats_clear,
+		NULL,
+	},
+};
+
+/* *** Show Port TM Node Type *** */
+struct cmd_show_port_tm_node_type_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t type;
+	uint16_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_show =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, type, "type");
+cmdline_parse_token_num_t cmd_show_port_tm_node_type_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_node_type_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result,
+			node_id, UINT32);
+
+static void cmd_show_port_tm_node_type_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_type_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	portid_t port_id = res->port_id;
+	int ret, is_leaf = 0;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_node_type_get(port_id, node_id, &is_leaf, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	if (is_leaf == 1)
+		printf("leaf node\n");
+	else
+		printf("nonleaf node\n");
+
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_type = {
+	.f = cmd_show_port_tm_node_type_parsed,
+	.data = NULL,
+	.help_str = "Show port tm node type",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_type_show,
+		(void *)&cmd_show_port_tm_node_type_port,
+		(void *)&cmd_show_port_tm_node_type_tm,
+		(void *)&cmd_show_port_tm_node_type_node,
+		(void *)&cmd_show_port_tm_node_type_type,
+		(void *)&cmd_show_port_tm_node_type_port_id,
+		(void *)&cmd_show_port_tm_node_type_node_id,
+		NULL,
+	},
+};
diff --git a/app/test-pmd/cmdline_tm.h b/app/test-pmd/cmdline_tm.h
new file mode 100644
index 0000000..945af89
--- /dev/null
+++ b/app/test-pmd/cmdline_tm.h
@@ -0,0 +1,44 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CMDLINE_TM_H_
+#define _CMDLINE_TM_H_
+
+ /* Traffic Management CLI */
+extern cmdline_parse_inst_t cmd_show_port_tm_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_level_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_type;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_stats;
+
+#endif /* _CMDLINE_TM_H_ */
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v9 2/3] app/test-pmd: add CLI for shaper and wred profiles
  2017-10-14 10:20                 ` [PATCH v9 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
@ 2017-10-14 10:20                   ` Jasvinder Singh
  2017-10-14 10:20                   ` [PATCH v9 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
  2017-10-16 18:55                   ` [PATCH v10 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
  2 siblings, 0 replies; 49+ messages in thread
From: Jasvinder Singh @ 2017-10-14 10:20 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu, yulong.pei

Add following CLIs in testpmd application for device traffic management;
- commands to add/del shaper profile for TM hieraqrchy nodes.
- commands to add/update shared shapers
- commands to add/del WRED profiles for TM hiearchy leaf nodes.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
v7 change:
- remove unnecessary checks on wred profile color string, api doesn't
  allow to set WRED with less than 3 colors. 

v6 change:
- change port id type to uint16_t
 
v5 change:
- add packet length adjust parameter to add shaper profile command

v4 change:
- remove softnic specific checks to make it generic for the devices

 app/test-pmd/cmdline.c    |  34 +++
 app/test-pmd/cmdline_tm.c | 731 ++++++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/cmdline_tm.h |   7 +
 3 files changed, 772 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 72e0628..4259012 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -693,6 +693,33 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"show port (port_id) queue-region\n"
 			"    show all queue region related configuration info\n\n"
 
+			"add port tm node shaper profile (port_id) (shaper_profile_id)"
+			" (tb_rate) (tb_size) (packet_length_adjust)\n"
+			"	Add port tm node private shaper profile.\n\n"
+
+			"del port tm node shaper profile (port_id) (shaper_profile_id)\n"
+			"	Delete port tm node private shaper profile.\n\n"
+
+			"add port tm node shared shaper (port_id) (shared_shaper_id)"
+			" (shaper_profile_id)\n"
+			"	Add/update port tm node shared shaper.\n\n"
+
+			"del port tm node shared shaper (port_id) (shared_shaper_id)\n"
+			"	Delete port tm node shared shaper.\n\n"
+
+			"set port tm node shaper profile (port_id) (node_id)"
+			" (shaper_profile_id)\n"
+			"	Set port tm node shaper profile.\n\n"
+
+			"add port tm node wred profile (port_id) (wred_profile_id)"
+			" (color_g) (min_th_g) (max_th_g) (maxp_inv_g) (wq_log2_g)"
+			" (color_y) (min_th_y) (max_th_y) (maxp_inv_y) (wq_log2_y)"
+			" (color_r) (min_th_r) (max_th_r) (maxp_inv_r) (wq_log2_r)\n"
+			"	Add port tm node wred profile.\n\n"
+
+			"del port tm node wred profile (port_id) (wred_profile_id)\n"
+			"	Delete port tm node wred profile.\n\n"
+
 			, list_pkt_forwarding_modes()
 		);
 	}
@@ -15616,6 +15643,13 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_cap,
 	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_type,
 	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_stats,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_shared_shaper,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_shared_shaper,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_wred_profile,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_wred_profile,
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_shaper_profile,
 	NULL,
 };
 
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
index f024372..38048ae 100644
--- a/app/test-pmd/cmdline_tm.c
+++ b/app/test-pmd/cmdline_tm.c
@@ -679,3 +679,734 @@ cmdline_parse_inst_t cmd_show_port_tm_node_type = {
 		NULL,
 	},
 };
+
+/* *** Add Port TM Private Shaper Profile *** */
+struct cmd_add_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint16_t port_id;
+	uint32_t shaper_id;
+	uint64_t tb_rate;
+	uint64_t tb_size;
+	uint32_t pktlen_adjust;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_tb_rate =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tb_rate, UINT64);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_tb_size =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tb_size, UINT64);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_pktlen_adjust =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			pktlen_adjust, UINT32);
+
+static void cmd_add_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_tm_shaper_params sp;
+	struct rte_tm_error error;
+	uint32_t shaper_id = res->shaper_id;
+	uint32_t pkt_len_adjust = res->pktlen_adjust;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Private shaper profile params */
+	memset(&sp, 0, sizeof(struct rte_tm_shaper_params));
+	sp.peak.rate = res->tb_rate;
+	sp.peak.size = res->tb_size;
+	sp.pkt_length_adjust = pkt_len_adjust;
+
+	ret = rte_tm_shaper_profile_add(port_id, shaper_id, &sp, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_shaper_profile = {
+	.f = cmd_add_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Add port tm node private shaper profile",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_shaper_profile_add,
+		(void *)&cmd_add_port_tm_node_shaper_profile_port,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_add_port_tm_node_shaper_profile_node,
+		(void *)&cmd_add_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_add_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_add_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_add_port_tm_node_shaper_profile_shaper_id,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tb_rate,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tb_size,
+		(void *)&cmd_add_port_tm_node_shaper_profile_pktlen_adjust,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM Private Shaper Profile *** */
+struct cmd_del_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint16_t port_id;
+	uint32_t shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_del_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_tm_node_shaper_profile_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			shaper_id, UINT32);
+
+static void cmd_del_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t shaper_id = res->shaper_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_shaper_profile_delete(port_id, shaper_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_shaper_profile = {
+	.f = cmd_del_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node private shaper profile",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_shaper_profile_del,
+		(void *)&cmd_del_port_tm_node_shaper_profile_port,
+		(void *)&cmd_del_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_del_port_tm_node_shaper_profile_node,
+		(void *)&cmd_del_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_del_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_del_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_del_port_tm_node_shaper_profile_shaper_id,
+		NULL,
+	},
+};
+
+/* *** Add/Update Port TM shared Shaper *** */
+struct cmd_add_port_tm_node_shared_shaper_result {
+	cmdline_fixed_string_t cmd_type;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shared;
+	cmdline_fixed_string_t shaper;
+	uint16_t port_id;
+	uint32_t shared_shaper_id;
+	uint32_t shaper_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_cmd_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			cmd_type, "add#set");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_shared =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shared, "shared");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shaper, "shaper");
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shared_shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shaper_profile_id, UINT32);
+
+static void cmd_add_port_tm_node_shared_shaper_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_shared_shaper_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t shared_shaper_id = res->shared_shaper_id;
+	uint32_t shaper_profile_id = res->shaper_profile_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Command type: add */
+	if ((strcmp(res->cmd_type, "add") == 0) &&
+		(port_is_started(port_id))) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	/* Command type: set (update) */
+	if ((strcmp(res->cmd_type, "set") == 0) &&
+		(!port_is_started(port_id))) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_shared_shaper_add_update(port_id, shared_shaper_id,
+		shaper_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_shared_shaper = {
+	.f = cmd_add_port_tm_node_shared_shaper_parsed,
+	.data = NULL,
+	.help_str = "add/update port tm node shared shaper",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_shared_shaper_cmd_type,
+		(void *)&cmd_add_port_tm_node_shared_shaper_port,
+		(void *)&cmd_add_port_tm_node_shared_shaper_tm,
+		(void *)&cmd_add_port_tm_node_shared_shaper_node,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shared,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shaper,
+		(void *)&cmd_add_port_tm_node_shared_shaper_port_id,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shared_shaper_id,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shaper_profile_id,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM shared Shaper *** */
+struct cmd_del_port_tm_node_shared_shaper_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shared;
+	cmdline_fixed_string_t shaper;
+	uint16_t port_id;
+	uint32_t shared_shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_shared =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shared, "shared");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shaper, "shaper");
+cmdline_parse_token_num_t cmd_del_port_tm_node_shared_shaper_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_tm_node_shared_shaper_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shared_shaper_id, UINT32);
+
+static void cmd_del_port_tm_node_shared_shaper_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_shared_shaper_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t shared_shaper_id = res->shared_shaper_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_shared_shaper_delete(port_id, shared_shaper_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper = {
+	.f = cmd_del_port_tm_node_shared_shaper_parsed,
+	.data = NULL,
+	.help_str = "delete port tm node shared shaper",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_shared_shaper_del,
+		(void *)&cmd_del_port_tm_node_shared_shaper_port,
+		(void *)&cmd_del_port_tm_node_shared_shaper_tm,
+		(void *)&cmd_del_port_tm_node_shared_shaper_node,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shared,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shaper,
+		(void *)&cmd_del_port_tm_node_shared_shaper_port_id,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shared_shaper_id,
+		NULL,
+	},
+};
+
+/* *** Add Port TM Node WRED Profile *** */
+struct cmd_add_port_tm_node_wred_profile_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t wred;
+	cmdline_fixed_string_t profile;
+	uint16_t port_id;
+	uint32_t wred_profile_id;
+	cmdline_fixed_string_t color_g;
+	uint16_t min_th_g;
+	uint16_t max_th_g;
+	uint16_t maxp_inv_g;
+	uint16_t wq_log2_g;
+	cmdline_fixed_string_t color_y;
+	uint16_t min_th_y;
+	uint16_t max_th_y;
+	uint16_t maxp_inv_y;
+	uint16_t wq_log2_y;
+	cmdline_fixed_string_t color_r;
+	uint16_t min_th_r;
+	uint16_t max_th_r;
+	uint16_t maxp_inv_r;
+	uint16_t wq_log2_r;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_wred =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, wred, "wred");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wred_profile_id, UINT32);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_g =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_g, "G#g");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_g, UINT16);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_y =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_y, "Y#y");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_y, UINT16);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_r =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_r, "R#r");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_r, UINT16);
+
+
+static void cmd_add_port_tm_node_wred_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_wred_profile_result *res = parsed_result;
+	struct rte_tm_wred_params wp;
+	enum rte_tm_color color;
+	struct rte_tm_error error;
+	uint32_t wred_profile_id = res->wred_profile_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	memset(&wp, 0, sizeof(struct rte_tm_wred_params));
+
+	/* WRED Params  (Green Color)*/
+	color = RTE_TM_GREEN;
+	wp.red_params[color].min_th = res->min_th_g;
+	wp.red_params[color].max_th = res->max_th_g;
+	wp.red_params[color].maxp_inv = res->maxp_inv_g;
+	wp.red_params[color].wq_log2 = res->wq_log2_g;
+
+
+	/* WRED Params  (Yellow Color)*/
+	color = RTE_TM_YELLOW;
+	wp.red_params[color].min_th = res->min_th_y;
+	wp.red_params[color].max_th = res->max_th_y;
+	wp.red_params[color].maxp_inv = res->maxp_inv_y;
+	wp.red_params[color].wq_log2 = res->wq_log2_y;
+
+	/* WRED Params  (Red Color)*/
+	color = RTE_TM_RED;
+	wp.red_params[color].min_th = res->min_th_r;
+	wp.red_params[color].max_th = res->max_th_r;
+	wp.red_params[color].maxp_inv = res->maxp_inv_r;
+	wp.red_params[color].wq_log2 = res->wq_log2_r;
+
+	ret = rte_tm_wred_profile_add(port_id, wred_profile_id, &wp, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile = {
+	.f = cmd_add_port_tm_node_wred_profile_parsed,
+	.data = NULL,
+	.help_str = "Add port tm node wred profile",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_wred_profile_add,
+		(void *)&cmd_add_port_tm_node_wred_profile_port,
+		(void *)&cmd_add_port_tm_node_wred_profile_tm,
+		(void *)&cmd_add_port_tm_node_wred_profile_node,
+		(void *)&cmd_add_port_tm_node_wred_profile_wred,
+		(void *)&cmd_add_port_tm_node_wred_profile_profile,
+		(void *)&cmd_add_port_tm_node_wred_profile_port_id,
+		(void *)&cmd_add_port_tm_node_wred_profile_wred_profile_id,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_r,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM node WRED Profile *** */
+struct cmd_del_port_tm_node_wred_profile_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t wred;
+	cmdline_fixed_string_t profile;
+	uint16_t port_id;
+	uint32_t wred_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_wred =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, wred, "wred");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_del_port_tm_node_wred_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_tm_node_wred_profile_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			wred_profile_id, UINT32);
+
+static void cmd_del_port_tm_node_wred_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_wred_profile_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t wred_profile_id = res->wred_profile_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_wred_profile_delete(port_id, wred_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile = {
+	.f = cmd_del_port_tm_node_wred_profile_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node wred profile",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_wred_profile_del,
+		(void *)&cmd_del_port_tm_node_wred_profile_port,
+		(void *)&cmd_del_port_tm_node_wred_profile_tm,
+		(void *)&cmd_del_port_tm_node_wred_profile_node,
+		(void *)&cmd_del_port_tm_node_wred_profile_wred,
+		(void *)&cmd_del_port_tm_node_wred_profile_profile,
+		(void *)&cmd_del_port_tm_node_wred_profile_port_id,
+		(void *)&cmd_del_port_tm_node_wred_profile_wred_profile_id,
+		NULL,
+	},
+};
+
+/* *** Update Port TM Node Shaper profile *** */
+struct cmd_set_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint16_t port_id;
+	uint32_t node_id;
+	uint32_t shaper_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_set_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_set_port_tm_node_shaper_profile_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_shaper_profile_result,
+		node_id, UINT32);
+cmdline_parse_token_num_t
+	cmd_set_port_tm_node_shaper_shaper_profile_profile_id =
+		TOKEN_NUM_INITIALIZER(
+			struct cmd_set_port_tm_node_shaper_profile_result,
+			shaper_profile_id, UINT32);
+
+static void cmd_set_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint32_t shaper_profile_id = res->shaper_profile_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (!port_is_started(port_id)) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_shaper_update(port_id, node_id,
+		shaper_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile = {
+	.f = cmd_set_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node shaper profile",
+	.tokens = {
+		(void *)&cmd_set_port_tm_node_shaper_profile_set,
+		(void *)&cmd_set_port_tm_node_shaper_profile_port,
+		(void *)&cmd_set_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_set_port_tm_node_shaper_profile_node,
+		(void *)&cmd_set_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_set_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_set_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_set_port_tm_node_shaper_profile_node_id,
+		(void *)&cmd_set_port_tm_node_shaper_shaper_profile_profile_id,
+		NULL,
+	},
+};
diff --git a/app/test-pmd/cmdline_tm.h b/app/test-pmd/cmdline_tm.h
index 945af89..5ed9de0 100644
--- a/app/test-pmd/cmdline_tm.h
+++ b/app/test-pmd/cmdline_tm.h
@@ -40,5 +40,12 @@ extern cmdline_parse_inst_t cmd_show_port_tm_level_cap;
 extern cmdline_parse_inst_t cmd_show_port_tm_node_cap;
 extern cmdline_parse_inst_t cmd_show_port_tm_node_type;
 extern cmdline_parse_inst_t cmd_show_port_tm_node_stats;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_shared_shaper;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile;
+extern cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile;
 
 #endif /* _CMDLINE_TM_H_ */
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v9 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit
  2017-10-14 10:20                 ` [PATCH v9 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
  2017-10-14 10:20                   ` [PATCH v9 2/3] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
@ 2017-10-14 10:20                   ` Jasvinder Singh
  2017-10-16 10:18                     ` Wu, Jingjing
  2017-10-16 18:55                   ` [PATCH v10 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
  2 siblings, 1 reply; 49+ messages in thread
From: Jasvinder Singh @ 2017-10-14 10:20 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu, yulong.pei

Add following CLIs in testpmd application for device traffic management;
- commands to add TM hierarchy nodes (leaf and nonleaf).
- command for runtime update of node weight.
- command to commit the TM hierarchy

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
v8 change:
- change command defintion for leaf and nonleaf nodes (mulitple shared
  shapers can be specified)
- pre-allocate memory for shared shaper ids array in nonleaf and leaf
  node add cli.
- change clean_on_fail to string type in hierarchy commit cli
 
v7 change:
- fix the help info on leaf node add

v5 change:
- add shaper related parameters to leaf node add command

v4 change:
- remove softnic specific checks to make it generic for the devices

 app/test-pmd/cmdline.c    |  27 ++
 app/test-pmd/cmdline_tm.c | 651 ++++++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/cmdline_tm.h |   5 +
 3 files changed, 683 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 4259012..094cbb8 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -720,6 +720,28 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"del port tm node wred profile (port_id) (wred_profile_id)\n"
 			"	Delete port tm node wred profile.\n\n"
 
+			"add port tm nonleaf node (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight) (level_id) (shaper_profile_id)"
+			" (n_sp_priorities) (stats_mask) (n_shared_shapers)"
+			" [(shared_shaper_id_0) (shared_shaper_id_1)...]\n"
+			"	Add port tm nonleaf node.\n\n"
+
+			"add port tm leaf node (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight) (level_id) (shaper_profile_id)"
+			" (cman_mode) (wred_profile_id) (stats_mask) (n_shared_shapers)"
+			" [(shared_shaper_id_0) (shared_shaper_id_1)...]\n"
+			"	Add port tm leaf node.\n\n"
+
+			"del port tm node (port_id) (node_id)\n"
+			"	Delete port tm node.\n\n"
+
+			"set port tm node parent (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight)\n"
+			"	Set port tm node parent.\n\n"
+
+			"port tm hierarchy commit (port_id) (clean_on_fail)\n"
+			"	Commit tm hierarchy.\n\n"
+
 			, list_pkt_forwarding_modes()
 		);
 	}
@@ -15650,6 +15672,11 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_wred_profile,
 	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_wred_profile,
 	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_nonleaf_node,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_leaf_node,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node,
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_parent,
+	(cmdline_parse_inst_t *)&cmd_port_tm_hierarchy_commit,
 	NULL,
 };
 
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
index 38048ae..002209c 100644
--- a/app/test-pmd/cmdline_tm.c
+++ b/app/test-pmd/cmdline_tm.c
@@ -42,6 +42,17 @@
 #include "testpmd.h"
 #include "cmdline_tm.h"
 
+#define PARSE_DELIMITER				" \f\n\r\t\v"
+#define MAX_NUM_SHARED_SHAPERS		256
+
+#define skip_white_spaces(pos)			\
+({						\
+	__typeof__(pos) _p = (pos);		\
+	for ( ; isspace(*_p); _p++)		\
+		;				\
+	_p;					\
+})
+
 /** Display TM Error Message */
 static void
 print_err_msg(struct rte_tm_error *error)
@@ -118,6 +129,100 @@ print_err_msg(struct rte_tm_error *error)
 		error->type);
 }
 
+static int
+read_uint64(uint64_t *value, const char *p)
+{
+	char *next;
+	uint64_t val;
+
+	p = skip_white_spaces(p);
+	if (!isdigit(*p))
+		return -EINVAL;
+
+	val = strtoul(p, &next, 10);
+	if (p == next)
+		return -EINVAL;
+
+	p = next;
+	switch (*p) {
+	case 'T':
+		val *= 1024ULL;
+		/* fall through */
+	case 'G':
+		val *= 1024ULL;
+		/* fall through */
+	case 'M':
+		val *= 1024ULL;
+		/* fall through */
+	case 'k':
+	case 'K':
+		val *= 1024ULL;
+		p++;
+		break;
+	}
+
+	p = skip_white_spaces(p);
+	if (*p != '\0')
+		return -EINVAL;
+
+	*value = val;
+	return 0;
+}
+
+static int
+read_uint32(uint32_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = read_uint64(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT32_MAX)
+		return -ERANGE;
+
+	*value = val;
+	return 0;
+}
+
+static int
+parse_multi_ss_id_str(char *s_str, uint32_t *n_ssp, uint32_t shaper_id[])
+{
+	uint32_t n_shared_shapers = 0, i = 0;
+	char *token;
+
+	/* First token: num of shared shapers */
+	token = strtok_r(s_str, PARSE_DELIMITER, &s_str);
+	if (token ==  NULL)
+		return -1;
+
+	if (read_uint32(&n_shared_shapers, token))
+		return -1;
+
+	/* Check: num of shared shaper */
+	if (n_shared_shapers >= MAX_NUM_SHARED_SHAPERS) {
+		printf(" Number of shared shapers exceed the max (error)\n");
+		return -1;
+	}
+
+	/* Parse shared shaper ids */
+	while (1) {
+		token = strtok_r(s_str, PARSE_DELIMITER, &s_str);
+		if ((token !=  NULL && n_shared_shapers == 0) ||
+			(token == NULL && i < n_shared_shapers))
+			return -1;
+
+		if (token == NULL)
+			break;
+
+		if (read_uint32(&shaper_id[i], token))
+			return -1;
+		i++;
+	}
+	*n_ssp = n_shared_shapers;
+
+	return 0;
+}
 /* *** Port TM Capability *** */
 struct cmd_show_port_tm_cap_result {
 	cmdline_fixed_string_t show;
@@ -1410,3 +1515,549 @@ cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile = {
 		NULL,
 	},
 };
+
+/* *** Add Port TM nonleaf node *** */
+struct cmd_add_port_tm_nonleaf_node_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t nonleaf;
+	cmdline_fixed_string_t node;
+	uint16_t port_id;
+	uint32_t node_id;
+	int32_t parent_node_id;
+	uint32_t priority;
+	uint32_t weight;
+	uint32_t level_id;
+	uint32_t shaper_profile_id;
+	uint32_t n_sp_priorities;
+	uint64_t stats_mask;
+	cmdline_multi_string_t multi_shared_shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_nonleaf =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, nonleaf, "nonleaf");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, node, "node");
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 node_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 parent_node_id, INT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 priority, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 weight, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 level_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 shaper_profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_n_sp_priorities =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 n_sp_priorities, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_stats_mask =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 stats_mask, UINT64);
+cmdline_parse_token_string_t
+	cmd_add_port_tm_nonleaf_node_multi_shared_shaper_id =
+	TOKEN_STRING_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 multi_shared_shaper_id, TOKEN_STRING_MULTI);
+
+static void cmd_add_port_tm_nonleaf_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_nonleaf_node_result *res = parsed_result;
+	struct rte_tm_error error;
+	struct rte_tm_node_params np;
+	uint32_t *shared_shaper_id;
+	uint32_t parent_node_id, n_shared_shapers = 0;
+	char *s_str = res->multi_shared_shaper_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	memset(&np, 0, sizeof(struct rte_tm_node_params));
+
+	/* Node parameters */
+	if (res->parent_node_id < 0)
+		parent_node_id = UINT32_MAX;
+	else
+		parent_node_id = res->parent_node_id;
+
+	shared_shaper_id = (uint32_t *)malloc(MAX_NUM_SHARED_SHAPERS *
+		sizeof(uint32_t));
+	/* Parse multi shared shaper id string */
+	ret = parse_multi_ss_id_str(s_str, &n_shared_shapers, shared_shaper_id);
+	if (ret) {
+		printf(" Shared shapers params string parse error\n");
+		return;
+	}
+
+	np.shaper_profile_id = res->shaper_profile_id;
+	np.n_shared_shapers = n_shared_shapers;
+	if (np.n_shared_shapers)
+		np.shared_shaper_id = &shared_shaper_id[0];
+	else
+		np.shared_shaper_id = NULL;
+
+	np.nonleaf.n_sp_priorities = res->n_sp_priorities;
+	np.stats_mask = res->stats_mask;
+	np.nonleaf.wfq_weight_mode = NULL;
+
+	ret = rte_tm_node_add(port_id, res->node_id, parent_node_id,
+				res->priority, res->weight, res->level_id,
+				&np, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_nonleaf_node = {
+	.f = cmd_add_port_tm_nonleaf_node_parsed,
+	.data = NULL,
+	.help_str = "Add port tm nonleaf node",
+	.tokens = {
+		(void *)&cmd_add_port_tm_nonleaf_node_add,
+		(void *)&cmd_add_port_tm_nonleaf_node_port,
+		(void *)&cmd_add_port_tm_nonleaf_node_tm,
+		(void *)&cmd_add_port_tm_nonleaf_node_nonleaf,
+		(void *)&cmd_add_port_tm_nonleaf_node_node,
+		(void *)&cmd_add_port_tm_nonleaf_node_port_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_node_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_parent_node_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_priority,
+		(void *)&cmd_add_port_tm_nonleaf_node_weight,
+		(void *)&cmd_add_port_tm_nonleaf_node_level_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_shaper_profile_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_n_sp_priorities,
+		(void *)&cmd_add_port_tm_nonleaf_node_stats_mask,
+		(void *)&cmd_add_port_tm_nonleaf_node_multi_shared_shaper_id,
+		NULL,
+	},
+};
+
+/* *** Add Port TM leaf node *** */
+struct cmd_add_port_tm_leaf_node_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t leaf;
+	cmdline_fixed_string_t node;
+	uint16_t port_id;
+	uint32_t node_id;
+	int32_t parent_node_id;
+	uint32_t priority;
+	uint32_t weight;
+	uint32_t level_id;
+	uint32_t shaper_profile_id;
+	uint32_t cman_mode;
+	uint32_t wred_profile_id;
+	uint64_t stats_mask;
+	cmdline_multi_string_t multi_shared_shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_nonleaf =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, leaf, "leaf");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, node, "node");
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 node_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 parent_node_id, INT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 priority, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 weight, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 level_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 shaper_profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_cman_mode =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 cman_mode, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 wred_profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_stats_mask =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 stats_mask, UINT64);
+cmdline_parse_token_string_t
+	cmd_add_port_tm_leaf_node_multi_shared_shaper_id =
+	TOKEN_STRING_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 multi_shared_shaper_id, TOKEN_STRING_MULTI);
+
+static void cmd_add_port_tm_leaf_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_leaf_node_result *res = parsed_result;
+	struct rte_tm_error error;
+	struct rte_tm_node_params np;
+	uint32_t *shared_shaper_id;
+	uint32_t parent_node_id, n_shared_shapers = 0;
+	portid_t port_id = res->port_id;
+	char *s_str = res->multi_shared_shaper_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	memset(&np, 0, sizeof(struct rte_tm_node_params));
+
+	/* Node parameters */
+	if (res->parent_node_id < 0)
+		parent_node_id = UINT32_MAX;
+	else
+		parent_node_id = res->parent_node_id;
+
+	shared_shaper_id = (uint32_t *)malloc(MAX_NUM_SHARED_SHAPERS *
+		sizeof(uint32_t));
+	/* Parse multi shared shaper id string */
+	ret = parse_multi_ss_id_str(s_str, &n_shared_shapers, shared_shaper_id);
+	if (ret) {
+		printf(" Shared shapers params string parse error\n");
+		return;
+	}
+
+	np.shaper_profile_id = res->shaper_profile_id;
+	np.n_shared_shapers = n_shared_shapers;
+
+	if (np.n_shared_shapers)
+		np.shared_shaper_id = &shared_shaper_id[0];
+	else
+		np.shared_shaper_id = NULL;
+
+	np.leaf.cman = res->cman_mode;
+	np.leaf.wred.wred_profile_id = res->wred_profile_id;
+	np.stats_mask = res->stats_mask;
+
+	ret = rte_tm_node_add(port_id, res->node_id, parent_node_id,
+				res->priority, res->weight, res->level_id,
+				&np, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_leaf_node = {
+	.f = cmd_add_port_tm_leaf_node_parsed,
+	.data = NULL,
+	.help_str = "Add port tm leaf node",
+	.tokens = {
+		(void *)&cmd_add_port_tm_leaf_node_add,
+		(void *)&cmd_add_port_tm_leaf_node_port,
+		(void *)&cmd_add_port_tm_leaf_node_tm,
+		(void *)&cmd_add_port_tm_leaf_node_nonleaf,
+		(void *)&cmd_add_port_tm_leaf_node_node,
+		(void *)&cmd_add_port_tm_leaf_node_port_id,
+		(void *)&cmd_add_port_tm_leaf_node_node_id,
+		(void *)&cmd_add_port_tm_leaf_node_parent_node_id,
+		(void *)&cmd_add_port_tm_leaf_node_priority,
+		(void *)&cmd_add_port_tm_leaf_node_weight,
+		(void *)&cmd_add_port_tm_leaf_node_level_id,
+		(void *)&cmd_add_port_tm_leaf_node_shaper_profile_id,
+		(void *)&cmd_add_port_tm_leaf_node_cman_mode,
+		(void *)&cmd_add_port_tm_leaf_node_wred_profile_id,
+		(void *)&cmd_add_port_tm_leaf_node_stats_mask,
+		(void *)&cmd_add_port_tm_leaf_node_multi_shared_shaper_id,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM Node *** */
+struct cmd_del_port_tm_node_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	uint16_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, node, "node");
+cmdline_parse_token_num_t cmd_del_port_tm_node_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_del_port_tm_node_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_tm_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_del_port_tm_node_result,
+		node_id, UINT32);
+
+static void cmd_del_port_tm_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_delete(port_id, node_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node = {
+	.f = cmd_del_port_tm_node_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_del,
+		(void *)&cmd_del_port_tm_node_port,
+		(void *)&cmd_del_port_tm_node_tm,
+		(void *)&cmd_del_port_tm_node_node,
+		(void *)&cmd_del_port_tm_node_port_id,
+		(void *)&cmd_del_port_tm_node_node_id,
+		NULL,
+	},
+};
+
+/* *** Update Port TM Node Parent *** */
+struct cmd_set_port_tm_node_parent_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t parent;
+	uint16_t port_id;
+	uint32_t node_id;
+	uint32_t parent_id;
+	uint32_t priority;
+	uint32_t weight;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, node, "node");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_parent =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, parent, "parent");
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, port_id, UINT16);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, node_id, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_parent_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		parent_id, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		priority, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		weight, UINT32);
+
+static void cmd_set_port_tm_node_parent_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_node_parent_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint32_t parent_id = res->parent_id;
+	uint32_t priority = res->priority;
+	uint32_t weight = res->weight;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (!port_is_started(port_id)) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_parent_update(port_id, node_id,
+		parent_id, priority, weight, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_node_parent = {
+	.f = cmd_set_port_tm_node_parent_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node parent",
+	.tokens = {
+		(void *)&cmd_set_port_tm_node_parent_set,
+		(void *)&cmd_set_port_tm_node_parent_port,
+		(void *)&cmd_set_port_tm_node_parent_tm,
+		(void *)&cmd_set_port_tm_node_parent_node,
+		(void *)&cmd_set_port_tm_node_parent_parent,
+		(void *)&cmd_set_port_tm_node_parent_port_id,
+		(void *)&cmd_set_port_tm_node_parent_node_id,
+		(void *)&cmd_set_port_tm_node_parent_parent_id,
+		(void *)&cmd_set_port_tm_node_parent_priority,
+		(void *)&cmd_set_port_tm_node_parent_weight,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchy Commit *** */
+struct cmd_port_tm_hierarchy_commit_result {
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t hierarchy;
+	cmdline_fixed_string_t commit;
+	uint16_t port_id;
+	cmdline_fixed_string_t clean_on_fail;
+};
+
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, port, "port");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, tm, "tm");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_hierarchy =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result,
+			hierarchy, "hierarchy");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_commit =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, commit, "commit");
+cmdline_parse_token_num_t cmd_port_tm_hierarchy_commit_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result,
+			port_id, UINT16);
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_clean_on_fail =
+	TOKEN_STRING_INITIALIZER(struct cmd_port_tm_hierarchy_commit_result,
+		 clean_on_fail, "yes#no");
+
+static void cmd_port_tm_hierarchy_commit_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_port_tm_hierarchy_commit_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t clean_on_fail;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	if (strcmp(res->clean_on_fail, "yes") == 0)
+		clean_on_fail = 1;
+	else
+		clean_on_fail = 0;
+
+	ret = rte_tm_hierarchy_commit(port_id, clean_on_fail, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_port_tm_hierarchy_commit = {
+	.f = cmd_port_tm_hierarchy_commit_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node shaper profile",
+	.tokens = {
+		(void *)&cmd_port_tm_hierarchy_commit_port,
+		(void *)&cmd_port_tm_hierarchy_commit_tm,
+		(void *)&cmd_port_tm_hierarchy_commit_hierarchy,
+		(void *)&cmd_port_tm_hierarchy_commit_commit,
+		(void *)&cmd_port_tm_hierarchy_commit_port_id,
+		(void *)&cmd_port_tm_hierarchy_commit_clean_on_fail,
+		NULL,
+	},
+};
diff --git a/app/test-pmd/cmdline_tm.h b/app/test-pmd/cmdline_tm.h
index 5ed9de0..9d5fdf0 100644
--- a/app/test-pmd/cmdline_tm.h
+++ b/app/test-pmd/cmdline_tm.h
@@ -47,5 +47,10 @@ extern cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper;
 extern cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile;
 extern cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile;
 extern cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_add_port_tm_nonleaf_node;
+extern cmdline_parse_inst_t cmd_add_port_tm_leaf_node;
+extern cmdline_parse_inst_t cmd_del_port_tm_node;
+extern cmdline_parse_inst_t cmd_set_port_tm_node_parent;
+extern cmdline_parse_inst_t cmd_port_tm_hierarchy_commit;
 
 #endif /* _CMDLINE_TM_H_ */
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* Re: [PATCH v9 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit
  2017-10-14 10:20                   ` [PATCH v9 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
@ 2017-10-16 10:18                     ` Wu, Jingjing
  2017-10-16 18:18                       ` Singh, Jasvinder
  0 siblings, 1 reply; 49+ messages in thread
From: Wu, Jingjing @ 2017-10-16 10:18 UTC (permalink / raw)
  To: Singh, Jasvinder, dev; +Cc: Dumitrescu, Cristian, Pei, Yulong



> -----Original Message-----
> From: Singh, Jasvinder
> Sent: Saturday, October 14, 2017 6:20 PM
> To: dev@dpdk.org
> Cc: Dumitrescu, Cristian <cristian.dumitrescu@intel.com>; Wu, Jingjing
> <jingjing.wu@intel.com>; Pei, Yulong <yulong.pei@intel.com>
> Subject: [PATCH v9 3/3] app/test-pmd: add CLI for TM nodes and hierarchy
> commit
> 
> Add following CLIs in testpmd application for device traffic management;
> - commands to add TM hierarchy nodes (leaf and nonleaf).
> - command for runtime update of node weight.
> - command to commit the TM hierarchy
> 
> Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
> ---
> v8 change:
> - change command defintion for leaf and nonleaf nodes (mulitple shared
>   shapers can be specified)
> - pre-allocate memory for shared shaper ids array in nonleaf and leaf
>   node add cli.
> - change clean_on_fail to string type in hierarchy commit cli
> 
> v7 change:
> - fix the help info on leaf node add
> 
> v5 change:
> - add shaper related parameters to leaf node add command
> 
> v4 change:
> - remove softnic specific checks to make it generic for the devices
> 
>  app/test-pmd/cmdline.c    |  27 ++
>  app/test-pmd/cmdline_tm.c | 651
> ++++++++++++++++++++++++++++++++++++++++++++++
>  app/test-pmd/cmdline_tm.h |   5 +
>  3 files changed, 683 insertions(+)
> 
> diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c index
> 4259012..094cbb8 100644
> --- a/app/test-pmd/cmdline.c
> +++ b/app/test-pmd/cmdline.c
> @@ -720,6 +720,28 @@ static void cmd_help_long_parsed(void
> *parsed_result,
>  			"del port tm node wred profile (port_id)
> (wred_profile_id)\n"
>  			"	Delete port tm node wred profile.\n\n"
> 
> +			"add port tm nonleaf node (port_id) (node_id)
> (parent_node_id)"
> +			" (priority) (weight) (level_id) (shaper_profile_id)"
> +			" (n_sp_priorities) (stats_mask) (n_shared_shapers)"
> +			" [(shared_shaper_id_0) (shared_shaper_id_1)...]\n"
> +			"	Add port tm nonleaf node.\n\n"
> +
> +			"add port tm leaf node (port_id) (node_id)
> (parent_node_id)"
> +			" (priority) (weight) (level_id) (shaper_profile_id)"
> +			" (cman_mode) (wred_profile_id) (stats_mask)
> (n_shared_shapers)"
> +			" [(shared_shaper_id_0) (shared_shaper_id_1)...]\n"
> +			"	Add port tm leaf node.\n\n"
> +
> +			"del port tm node (port_id) (node_id)\n"
> +			"	Delete port tm node.\n\n"
> +
> +			"set port tm node parent (port_id) (node_id)
> (parent_node_id)"
> +			" (priority) (weight)\n"
> +			"	Set port tm node parent.\n\n"
> +
> +			"port tm hierarchy commit (port_id) (clean_on_fail)\n"
> +			"	Commit tm hierarchy.\n\n"
> +
>  			, list_pkt_forwarding_modes()
>  		);
>  	}
> @@ -15650,6 +15672,11 @@ cmdline_parse_ctx_t main_ctx[] = {
>  	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_wred_profile,
>  	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_wred_profile,
>  	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_shaper_profile,
> +	(cmdline_parse_inst_t *)&cmd_add_port_tm_nonleaf_node,
> +	(cmdline_parse_inst_t *)&cmd_add_port_tm_leaf_node,
> +	(cmdline_parse_inst_t *)&cmd_del_port_tm_node,
> +	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_parent,
> +	(cmdline_parse_inst_t *)&cmd_port_tm_hierarchy_commit,
>  	NULL,
>  };
> 
> diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c index
> 38048ae..002209c 100644
> --- a/app/test-pmd/cmdline_tm.c
> +++ b/app/test-pmd/cmdline_tm.c
> @@ -42,6 +42,17 @@
>  #include "testpmd.h"
>  #include "cmdline_tm.h"
> 
> +#define PARSE_DELIMITER				" \f\n\r\t\v"
> +#define MAX_NUM_SHARED_SHAPERS		256
> +
> +#define skip_white_spaces(pos)			\
> +({						\
> +	__typeof__(pos) _p = (pos);		\
> +	for ( ; isspace(*_p); _p++)		\
> +		;				\
> +	_p;					\
> +})
> +
>  /** Display TM Error Message */
>  static void
>  print_err_msg(struct rte_tm_error *error) @@ -118,6 +129,100 @@
> print_err_msg(struct rte_tm_error *error)
>  		error->type);
>  }
> 
> +static int
> +read_uint64(uint64_t *value, const char *p) {
> +	char *next;
> +	uint64_t val;
> +
> +	p = skip_white_spaces(p);
> +	if (!isdigit(*p))
> +		return -EINVAL;
> +
> +	val = strtoul(p, &next, 10);
> +	if (p == next)
> +		return -EINVAL;
> +
> +	p = next;
> +	switch (*p) {
> +	case 'T':
> +		val *= 1024ULL;
> +		/* fall through */
> +	case 'G':
> +		val *= 1024ULL;
> +		/* fall through */
> +	case 'M':
> +		val *= 1024ULL;
> +		/* fall through */
> +	case 'k':
> +	case 'K':
> +		val *= 1024ULL;
> +		p++;
> +		break;
> +	}
> +
> +	p = skip_white_spaces(p);
> +	if (*p != '\0')
> +		return -EINVAL;
> +
> +	*value = val;
> +	return 0;
> +}
> +
> +static int
> +read_uint32(uint32_t *value, const char *p) {
> +	uint64_t val = 0;
> +	int ret = read_uint64(&val, p);
> +
> +	if (ret < 0)
> +		return ret;
> +
> +	if (val > UINT32_MAX)
> +		return -ERANGE;
> +
> +	*value = val;
> +	return 0;
> +}
> +
> +static int
> +parse_multi_ss_id_str(char *s_str, uint32_t *n_ssp, uint32_t
> +shaper_id[]) {
> +	uint32_t n_shared_shapers = 0, i = 0;
> +	char *token;
> +
> +	/* First token: num of shared shapers */
> +	token = strtok_r(s_str, PARSE_DELIMITER, &s_str);
> +	if (token ==  NULL)
> +		return -1;
> +
> +	if (read_uint32(&n_shared_shapers, token))
> +		return -1;
> +
> +	/* Check: num of shared shaper */
> +	if (n_shared_shapers >= MAX_NUM_SHARED_SHAPERS) {
> +		printf(" Number of shared shapers exceed the max (error)\n");
> +		return -1;
> +	}
> +
> +	/* Parse shared shaper ids */
> +	while (1) {
> +		token = strtok_r(s_str, PARSE_DELIMITER, &s_str);
> +		if ((token !=  NULL && n_shared_shapers == 0) ||
> +			(token == NULL && i < n_shared_shapers))
> +			return -1;
> +
> +		if (token == NULL)
> +			break;
> +
> +		if (read_uint32(&shaper_id[i], token))
> +			return -1;
> +		i++;
> +	}
> +	*n_ssp = n_shared_shapers;
> +
> +	return 0;
> +}

Thanks for the change, can those be done by rte_strsplit?

>  /* *** Port TM Capability *** */
>  struct cmd_show_port_tm_cap_result {
>  	cmdline_fixed_string_t show;
> @@ -1410,3 +1515,549 @@ cmdline_parse_inst_t
> cmd_set_port_tm_node_shaper_profile = {
>  		NULL,
>  	},
>  };
> +
> +/* *** Add Port TM nonleaf node *** */
> +struct cmd_add_port_tm_nonleaf_node_result {
> +	cmdline_fixed_string_t add;
> +	cmdline_fixed_string_t port;
> +	cmdline_fixed_string_t tm;
> +	cmdline_fixed_string_t nonleaf;
> +	cmdline_fixed_string_t node;
> +	uint16_t port_id;
> +	uint32_t node_id;
> +	int32_t parent_node_id;
> +	uint32_t priority;
> +	uint32_t weight;
> +	uint32_t level_id;
> +	uint32_t shaper_profile_id;
> +	uint32_t n_sp_priorities;
> +	uint64_t stats_mask;
> +	cmdline_multi_string_t multi_shared_shaper_id; };
> +
> +cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_add =
> +	TOKEN_STRING_INITIALIZER(
> +		struct cmd_add_port_tm_nonleaf_node_result, add, "add");
> +cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_port =
> +	TOKEN_STRING_INITIALIZER(
> +		struct cmd_add_port_tm_nonleaf_node_result, port, "port");
> +cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_tm =
> +	TOKEN_STRING_INITIALIZER(
> +		struct cmd_add_port_tm_nonleaf_node_result, tm, "tm");
> +cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_nonleaf =
> +	TOKEN_STRING_INITIALIZER(
> +		struct cmd_add_port_tm_nonleaf_node_result, nonleaf,
> "nonleaf");
> +cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_node =
> +	TOKEN_STRING_INITIALIZER(
> +		struct cmd_add_port_tm_nonleaf_node_result, node, "node");
> +cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_port_id =
> +	TOKEN_NUM_INITIALIZER(
> +		struct cmd_add_port_tm_nonleaf_node_result,
> +		 port_id, UINT16);
> +cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_node_id =
> +	TOKEN_NUM_INITIALIZER(struct
> cmd_add_port_tm_nonleaf_node_result,
> +		 node_id, UINT32);
> +cmdline_parse_token_num_t
> cmd_add_port_tm_nonleaf_node_parent_node_id =
> +	TOKEN_NUM_INITIALIZER(struct
> cmd_add_port_tm_nonleaf_node_result,
> +		 parent_node_id, INT32);
> +cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_priority =
> +	TOKEN_NUM_INITIALIZER(struct
> cmd_add_port_tm_nonleaf_node_result,
> +		 priority, UINT32);
> +cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_weight =
> +	TOKEN_NUM_INITIALIZER(struct
> cmd_add_port_tm_nonleaf_node_result,
> +		 weight, UINT32);
> +cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_level_id =
> +	TOKEN_NUM_INITIALIZER(struct
> cmd_add_port_tm_nonleaf_node_result,
> +		 level_id, UINT32);
> +cmdline_parse_token_num_t
> cmd_add_port_tm_nonleaf_node_shaper_profile_id =
> +	TOKEN_NUM_INITIALIZER(struct
> cmd_add_port_tm_nonleaf_node_result,
> +		 shaper_profile_id, UINT32);
> +cmdline_parse_token_num_t
> cmd_add_port_tm_nonleaf_node_n_sp_priorities =
> +	TOKEN_NUM_INITIALIZER(struct
> cmd_add_port_tm_nonleaf_node_result,
> +		 n_sp_priorities, UINT32);
> +cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_stats_mask =
> +	TOKEN_NUM_INITIALIZER(struct
> cmd_add_port_tm_nonleaf_node_result,
> +		 stats_mask, UINT64);
> +cmdline_parse_token_string_t
> +	cmd_add_port_tm_nonleaf_node_multi_shared_shaper_id =
> +	TOKEN_STRING_INITIALIZER(struct
> cmd_add_port_tm_nonleaf_node_result,
> +		 multi_shared_shaper_id, TOKEN_STRING_MULTI);
> +
> +static void cmd_add_port_tm_nonleaf_node_parsed(void *parsed_result,
> +	__attribute__((unused)) struct cmdline *cl,
> +	__attribute__((unused)) void *data)
> +{
> +	struct cmd_add_port_tm_nonleaf_node_result *res = parsed_result;
> +	struct rte_tm_error error;
> +	struct rte_tm_node_params np;
> +	uint32_t *shared_shaper_id;
> +	uint32_t parent_node_id, n_shared_shapers = 0;
> +	char *s_str = res->multi_shared_shaper_id;
> +	portid_t port_id = res->port_id;
> +	int ret;
> +
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))
> +		return;
> +
> +	/* Port status */
> +	if (port_is_started(port_id)) {
> +		printf(" Port %u not stopped (error)\n", port_id);
> +		return;
> +	}
> +
> +	memset(&np, 0, sizeof(struct rte_tm_node_params));
> +
> +	/* Node parameters */
> +	if (res->parent_node_id < 0)
> +		parent_node_id = UINT32_MAX;
> +	else
> +		parent_node_id = res->parent_node_id;
> +
> +	shared_shaper_id = (uint32_t *)malloc(MAX_NUM_SHARED_SHAPERS
> *
> +		sizeof(uint32_t));
> +	/* Parse multi shared shaper id string */
> +	ret = parse_multi_ss_id_str(s_str, &n_shared_shapers,
> shared_shaper_id);
> +	if (ret) {
> +		printf(" Shared shapers params string parse error\n");
> +		return;

You forgot to free shared_shaper_id. 

> +	}
> +
> +	np.shaper_profile_id = res->shaper_profile_id;
> +	np.n_shared_shapers = n_shared_shapers;
> +	if (np.n_shared_shapers)
> +		np.shared_shaper_id = &shared_shaper_id[0];
> +	else
> +		np.shared_shaper_id = NULL;
> +
> +	np.nonleaf.n_sp_priorities = res->n_sp_priorities;
> +	np.stats_mask = res->stats_mask;
> +	np.nonleaf.wfq_weight_mode = NULL;
> +
> +	ret = rte_tm_node_add(port_id, res->node_id, parent_node_id,
> +				res->priority, res->weight, res->level_id,
> +				&np, &error);
> +	if (ret != 0) {
> +		print_err_msg(&error);
> +		return;
> +	}

You forgot to free shared_shaper_id.

> +}
> +
> +cmdline_parse_inst_t cmd_add_port_tm_nonleaf_node = {
> +	.f = cmd_add_port_tm_nonleaf_node_parsed,
> +	.data = NULL,
> +	.help_str = "Add port tm nonleaf node",
> +	.tokens = {
> +		(void *)&cmd_add_port_tm_nonleaf_node_add,
> +		(void *)&cmd_add_port_tm_nonleaf_node_port,
> +		(void *)&cmd_add_port_tm_nonleaf_node_tm,
> +		(void *)&cmd_add_port_tm_nonleaf_node_nonleaf,
> +		(void *)&cmd_add_port_tm_nonleaf_node_node,
> +		(void *)&cmd_add_port_tm_nonleaf_node_port_id,
> +		(void *)&cmd_add_port_tm_nonleaf_node_node_id,
> +		(void *)&cmd_add_port_tm_nonleaf_node_parent_node_id,
> +		(void *)&cmd_add_port_tm_nonleaf_node_priority,
> +		(void *)&cmd_add_port_tm_nonleaf_node_weight,
> +		(void *)&cmd_add_port_tm_nonleaf_node_level_id,
> +		(void *)&cmd_add_port_tm_nonleaf_node_shaper_profile_id,
> +		(void *)&cmd_add_port_tm_nonleaf_node_n_sp_priorities,
> +		(void *)&cmd_add_port_tm_nonleaf_node_stats_mask,
> +		(void
> *)&cmd_add_port_tm_nonleaf_node_multi_shared_shaper_id,
> +		NULL,
> +	},
> +};
> +
> +/* *** Add Port TM leaf node *** */
> +struct cmd_add_port_tm_leaf_node_result {
> +	cmdline_fixed_string_t add;
> +	cmdline_fixed_string_t port;
> +	cmdline_fixed_string_t tm;
> +	cmdline_fixed_string_t leaf;
> +	cmdline_fixed_string_t node;
> +	uint16_t port_id;
> +	uint32_t node_id;
> +	int32_t parent_node_id;
> +	uint32_t priority;
> +	uint32_t weight;
> +	uint32_t level_id;
> +	uint32_t shaper_profile_id;
> +	uint32_t cman_mode;
> +	uint32_t wred_profile_id;
> +	uint64_t stats_mask;
> +	cmdline_multi_string_t multi_shared_shaper_id; };
> +
> +cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_add =
> +	TOKEN_STRING_INITIALIZER(
> +		struct cmd_add_port_tm_leaf_node_result, add, "add");
> +cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_port =
> +	TOKEN_STRING_INITIALIZER(
> +		struct cmd_add_port_tm_leaf_node_result, port, "port");
> +cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_tm =
> +	TOKEN_STRING_INITIALIZER(
> +		struct cmd_add_port_tm_leaf_node_result, tm, "tm");
> +cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_nonleaf =
> +	TOKEN_STRING_INITIALIZER(
> +		struct cmd_add_port_tm_leaf_node_result, leaf, "leaf");
> +cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_node =
> +	TOKEN_STRING_INITIALIZER(
> +		struct cmd_add_port_tm_leaf_node_result, node, "node");
> +cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_port_id =
> +	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
> +		 port_id, UINT16);
> +cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_node_id =
> +	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
> +		 node_id, UINT32);
> +cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_parent_node_id =
> +	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
> +		 parent_node_id, INT32);
> +cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_priority =
> +	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
> +		 priority, UINT32);
> +cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_weight =
> +	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
> +		 weight, UINT32);
> +cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_level_id =
> +	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
> +		 level_id, UINT32);
> +cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_shaper_profile_id
> =
> +	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
> +		 shaper_profile_id, UINT32);
> +cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_cman_mode =
> +	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
> +		 cman_mode, UINT32);
> +cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_wred_profile_id
> =
> +	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
> +		 wred_profile_id, UINT32);
> +cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_stats_mask =
> +	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
> +		 stats_mask, UINT64);
> +cmdline_parse_token_string_t
> +	cmd_add_port_tm_leaf_node_multi_shared_shaper_id =
> +	TOKEN_STRING_INITIALIZER(struct
> cmd_add_port_tm_leaf_node_result,
> +		 multi_shared_shaper_id, TOKEN_STRING_MULTI);
> +
> +static void cmd_add_port_tm_leaf_node_parsed(void *parsed_result,
> +	__attribute__((unused)) struct cmdline *cl,
> +	__attribute__((unused)) void *data)
> +{
> +	struct cmd_add_port_tm_leaf_node_result *res = parsed_result;
> +	struct rte_tm_error error;
> +	struct rte_tm_node_params np;
> +	uint32_t *shared_shaper_id;
> +	uint32_t parent_node_id, n_shared_shapers = 0;
> +	portid_t port_id = res->port_id;
> +	char *s_str = res->multi_shared_shaper_id;
> +	int ret;
> +
> +	if (port_id_is_invalid(port_id, ENABLED_WARN))
> +		return;
> +
> +	/* Port status */
> +	if (port_is_started(port_id)) {
> +		printf(" Port %u not stopped (error)\n", port_id);
> +		return;
> +	}
> +
> +	memset(&np, 0, sizeof(struct rte_tm_node_params));
> +
> +	/* Node parameters */
> +	if (res->parent_node_id < 0)
> +		parent_node_id = UINT32_MAX;
> +	else
> +		parent_node_id = res->parent_node_id;
> +
> +	shared_shaper_id = (uint32_t *)malloc(MAX_NUM_SHARED_SHAPERS
> *
> +		sizeof(uint32_t));
> +	/* Parse multi shared shaper id string */
> +	ret = parse_multi_ss_id_str(s_str, &n_shared_shapers,
> shared_shaper_id);
> +	if (ret) {
> +		printf(" Shared shapers params string parse error\n");
The same, free the memory you malloced.

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v9 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit
  2017-10-16 10:18                     ` Wu, Jingjing
@ 2017-10-16 18:18                       ` Singh, Jasvinder
  0 siblings, 0 replies; 49+ messages in thread
From: Singh, Jasvinder @ 2017-10-16 18:18 UTC (permalink / raw)
  To: Wu, Jingjing, dev; +Cc: Dumitrescu, Cristian, Pei, Yulong

<snip>

> > diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
> > index 38048ae..002209c 100644
> > --- a/app/test-pmd/cmdline_tm.c
> > +++ b/app/test-pmd/cmdline_tm.c
> > @@ -42,6 +42,17 @@
> >  #include "testpmd.h"
> >  #include "cmdline_tm.h"
> >
> > +#define PARSE_DELIMITER				" \f\n\r\t\v"
> > +#define MAX_NUM_SHARED_SHAPERS		256
> > +
> > +#define skip_white_spaces(pos)			\
> > +({						\
> > +	__typeof__(pos) _p = (pos);		\
> > +	for ( ; isspace(*_p); _p++)		\
> > +		;				\
> > +	_p;					\
> > +})
> > +
> >  /** Display TM Error Message */
> >  static void
> >  print_err_msg(struct rte_tm_error *error) @@ -118,6 +129,100 @@
> > print_err_msg(struct rte_tm_error *error)
> >  		error->type);
> >  }
> >
> > +static int
> > +read_uint64(uint64_t *value, const char *p) {
> > +	char *next;
> > +	uint64_t val;
> > +
> > +	p = skip_white_spaces(p);
> > +	if (!isdigit(*p))
> > +		return -EINVAL;
> > +
> > +	val = strtoul(p, &next, 10);
> > +	if (p == next)
> > +		return -EINVAL;
> > +
> > +	p = next;
> > +	switch (*p) {
> > +	case 'T':
> > +		val *= 1024ULL;
> > +		/* fall through */
> > +	case 'G':
> > +		val *= 1024ULL;
> > +		/* fall through */
> > +	case 'M':
> > +		val *= 1024ULL;
> > +		/* fall through */
> > +	case 'k':
> > +	case 'K':
> > +		val *= 1024ULL;
> > +		p++;
> > +		break;
> > +	}
> > +
> > +	p = skip_white_spaces(p);
> > +	if (*p != '\0')
> > +		return -EINVAL;
> > +
> > +	*value = val;
> > +	return 0;
> > +}
> > +
> > +static int
> > +read_uint32(uint32_t *value, const char *p) {
> > +	uint64_t val = 0;
> > +	int ret = read_uint64(&val, p);
> > +
> > +	if (ret < 0)
> > +		return ret;
> > +
> > +	if (val > UINT32_MAX)
> > +		return -ERANGE;
> > +
> > +	*value = val;
> > +	return 0;
> > +}
> > +
> > +static int
> > +parse_multi_ss_id_str(char *s_str, uint32_t *n_ssp, uint32_t
> > +shaper_id[]) {
> > +	uint32_t n_shared_shapers = 0, i = 0;
> > +	char *token;
> > +
> > +	/* First token: num of shared shapers */
> > +	token = strtok_r(s_str, PARSE_DELIMITER, &s_str);
> > +	if (token ==  NULL)
> > +		return -1;
> > +
> > +	if (read_uint32(&n_shared_shapers, token))
> > +		return -1;
> > +
> > +	/* Check: num of shared shaper */
> > +	if (n_shared_shapers >= MAX_NUM_SHARED_SHAPERS) {
> > +		printf(" Number of shared shapers exceed the max
> (error)\n");
> > +		return -1;
> > +	}
> > +
> > +	/* Parse shared shaper ids */
> > +	while (1) {
> > +		token = strtok_r(s_str, PARSE_DELIMITER, &s_str);
> > +		if ((token !=  NULL && n_shared_shapers == 0) ||
> > +			(token == NULL && i < n_shared_shapers))
> > +			return -1;
> > +
> > +		if (token == NULL)
> > +			break;
> > +
> > +		if (read_uint32(&shaper_id[i], token))
> > +			return -1;
> > +		i++;
> > +	}
> > +	*n_ssp = n_shared_shapers;
> > +
> > +	return 0;
> > +}
> 
> Thanks for the change, can those be done by rte_strsplit?

On CLI, user can inadvertently press tab, etc., instead of space character while specifying the cli arguments.  The above approach is robust to such incidents by allowing range of characters to be used as delim. On the other hand, rte_strsplit() allows only one character to be used as delim and restricts the user to specify only that character on CLI.

> >  /* *** Port TM Capability *** */
> >  struct cmd_show_port_tm_cap_result {
> >  	cmdline_fixed_string_t show;
> > @@ -1410,3 +1515,549 @@ cmdline_parse_inst_t
> > cmd_set_port_tm_node_shaper_profile = {
> >  		NULL,
> >  	},
> >  };
> > +
> > +/* *** Add Port TM nonleaf node *** */ struct
> > +cmd_add_port_tm_nonleaf_node_result {
> > +	cmdline_fixed_string_t add;
> > +	cmdline_fixed_string_t port;
> > +	cmdline_fixed_string_t tm;
> > +	cmdline_fixed_string_t nonleaf;
> > +	cmdline_fixed_string_t node;
> > +	uint16_t port_id;
> > +	uint32_t node_id;
> > +	int32_t parent_node_id;
> > +	uint32_t priority;
> > +	uint32_t weight;
> > +	uint32_t level_id;
> > +	uint32_t shaper_profile_id;
> > +	uint32_t n_sp_priorities;
> > +	uint64_t stats_mask;
> > +	cmdline_multi_string_t multi_shared_shaper_id; };
> > +
> > +cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_add =
> > +	TOKEN_STRING_INITIALIZER(
> > +		struct cmd_add_port_tm_nonleaf_node_result, add, "add");
> > +cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_port =
> > +	TOKEN_STRING_INITIALIZER(
> > +		struct cmd_add_port_tm_nonleaf_node_result, port, "port");
> > +cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_tm =
> > +	TOKEN_STRING_INITIALIZER(
> > +		struct cmd_add_port_tm_nonleaf_node_result, tm, "tm");
> > +cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_nonleaf
> =
> > +	TOKEN_STRING_INITIALIZER(
> > +		struct cmd_add_port_tm_nonleaf_node_result, nonleaf,
> > "nonleaf");
> > +cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_node =
> > +	TOKEN_STRING_INITIALIZER(
> > +		struct cmd_add_port_tm_nonleaf_node_result, node,
> "node");
> > +cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_port_id =
> > +	TOKEN_NUM_INITIALIZER(
> > +		struct cmd_add_port_tm_nonleaf_node_result,
> > +		 port_id, UINT16);
> > +cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_node_id
> =
> > +	TOKEN_NUM_INITIALIZER(struct
> > cmd_add_port_tm_nonleaf_node_result,
> > +		 node_id, UINT32);
> > +cmdline_parse_token_num_t
> > cmd_add_port_tm_nonleaf_node_parent_node_id =
> > +	TOKEN_NUM_INITIALIZER(struct
> > cmd_add_port_tm_nonleaf_node_result,
> > +		 parent_node_id, INT32);
> > +cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_priority =
> > +	TOKEN_NUM_INITIALIZER(struct
> > cmd_add_port_tm_nonleaf_node_result,
> > +		 priority, UINT32);
> > +cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_weight =
> > +	TOKEN_NUM_INITIALIZER(struct
> > cmd_add_port_tm_nonleaf_node_result,
> > +		 weight, UINT32);
> > +cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_level_id
> =
> > +	TOKEN_NUM_INITIALIZER(struct
> > cmd_add_port_tm_nonleaf_node_result,
> > +		 level_id, UINT32);
> > +cmdline_parse_token_num_t
> > cmd_add_port_tm_nonleaf_node_shaper_profile_id =
> > +	TOKEN_NUM_INITIALIZER(struct
> > cmd_add_port_tm_nonleaf_node_result,
> > +		 shaper_profile_id, UINT32);
> > +cmdline_parse_token_num_t
> > cmd_add_port_tm_nonleaf_node_n_sp_priorities =
> > +	TOKEN_NUM_INITIALIZER(struct
> > cmd_add_port_tm_nonleaf_node_result,
> > +		 n_sp_priorities, UINT32);
> > +cmdline_parse_token_num_t
> cmd_add_port_tm_nonleaf_node_stats_mask =
> > +	TOKEN_NUM_INITIALIZER(struct
> > cmd_add_port_tm_nonleaf_node_result,
> > +		 stats_mask, UINT64);
> > +cmdline_parse_token_string_t
> > +	cmd_add_port_tm_nonleaf_node_multi_shared_shaper_id =
> > +	TOKEN_STRING_INITIALIZER(struct
> > cmd_add_port_tm_nonleaf_node_result,
> > +		 multi_shared_shaper_id, TOKEN_STRING_MULTI);
> > +
> > +static void cmd_add_port_tm_nonleaf_node_parsed(void *parsed_result,
> > +	__attribute__((unused)) struct cmdline *cl,
> > +	__attribute__((unused)) void *data)
> > +{
> > +	struct cmd_add_port_tm_nonleaf_node_result *res = parsed_result;
> > +	struct rte_tm_error error;
> > +	struct rte_tm_node_params np;
> > +	uint32_t *shared_shaper_id;
> > +	uint32_t parent_node_id, n_shared_shapers = 0;
> > +	char *s_str = res->multi_shared_shaper_id;
> > +	portid_t port_id = res->port_id;
> > +	int ret;
> > +
> > +	if (port_id_is_invalid(port_id, ENABLED_WARN))
> > +		return;
> > +
> > +	/* Port status */
> > +	if (port_is_started(port_id)) {
> > +		printf(" Port %u not stopped (error)\n", port_id);
> > +		return;
> > +	}
> > +
> > +	memset(&np, 0, sizeof(struct rte_tm_node_params));
> > +
> > +	/* Node parameters */
> > +	if (res->parent_node_id < 0)
> > +		parent_node_id = UINT32_MAX;
> > +	else
> > +		parent_node_id = res->parent_node_id;
> > +
> > +	shared_shaper_id = (uint32_t
> *)malloc(MAX_NUM_SHARED_SHAPERS
> > *
> > +		sizeof(uint32_t));
> > +	/* Parse multi shared shaper id string */
> > +	ret = parse_multi_ss_id_str(s_str, &n_shared_shapers,
> > shared_shaper_id);
> > +	if (ret) {
> > +		printf(" Shared shapers params string parse error\n");
> > +		return;
> 
> You forgot to free shared_shaper_id.
> 
> > +	}
> > +
> > +	np.shaper_profile_id = res->shaper_profile_id;
> > +	np.n_shared_shapers = n_shared_shapers;
> > +	if (np.n_shared_shapers)
> > +		np.shared_shaper_id = &shared_shaper_id[0];
> > +	else
> > +		np.shared_shaper_id = NULL;
> > +
> > +	np.nonleaf.n_sp_priorities = res->n_sp_priorities;
> > +	np.stats_mask = res->stats_mask;
> > +	np.nonleaf.wfq_weight_mode = NULL;
> > +
> > +	ret = rte_tm_node_add(port_id, res->node_id, parent_node_id,
> > +				res->priority, res->weight, res->level_id,
> > +				&np, &error);
> > +	if (ret != 0) {
> > +		print_err_msg(&error);
> > +		return;
> > +	}
> 
> You forgot to free shared_shaper_id.
> 
> > +}
> > +
> > +cmdline_parse_inst_t cmd_add_port_tm_nonleaf_node = {
> > +	.f = cmd_add_port_tm_nonleaf_node_parsed,
> > +	.data = NULL,
> > +	.help_str = "Add port tm nonleaf node",
> > +	.tokens = {
> > +		(void *)&cmd_add_port_tm_nonleaf_node_add,
> > +		(void *)&cmd_add_port_tm_nonleaf_node_port,
> > +		(void *)&cmd_add_port_tm_nonleaf_node_tm,
> > +		(void *)&cmd_add_port_tm_nonleaf_node_nonleaf,
> > +		(void *)&cmd_add_port_tm_nonleaf_node_node,
> > +		(void *)&cmd_add_port_tm_nonleaf_node_port_id,
> > +		(void *)&cmd_add_port_tm_nonleaf_node_node_id,
> > +		(void *)&cmd_add_port_tm_nonleaf_node_parent_node_id,
> > +		(void *)&cmd_add_port_tm_nonleaf_node_priority,
> > +		(void *)&cmd_add_port_tm_nonleaf_node_weight,
> > +		(void *)&cmd_add_port_tm_nonleaf_node_level_id,
> > +		(void
> *)&cmd_add_port_tm_nonleaf_node_shaper_profile_id,
> > +		(void *)&cmd_add_port_tm_nonleaf_node_n_sp_priorities,
> > +		(void *)&cmd_add_port_tm_nonleaf_node_stats_mask,
> > +		(void
> > *)&cmd_add_port_tm_nonleaf_node_multi_shared_shaper_id,
> > +		NULL,
> > +	},
> > +};
> > +
> > +/* *** Add Port TM leaf node *** */
> > +struct cmd_add_port_tm_leaf_node_result {
> > +	cmdline_fixed_string_t add;
> > +	cmdline_fixed_string_t port;
> > +	cmdline_fixed_string_t tm;
> > +	cmdline_fixed_string_t leaf;
> > +	cmdline_fixed_string_t node;
> > +	uint16_t port_id;
> > +	uint32_t node_id;
> > +	int32_t parent_node_id;
> > +	uint32_t priority;
> > +	uint32_t weight;
> > +	uint32_t level_id;
> > +	uint32_t shaper_profile_id;
> > +	uint32_t cman_mode;
> > +	uint32_t wred_profile_id;
> > +	uint64_t stats_mask;
> > +	cmdline_multi_string_t multi_shared_shaper_id; };
> > +
> > +cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_add =
> > +	TOKEN_STRING_INITIALIZER(
> > +		struct cmd_add_port_tm_leaf_node_result, add, "add");
> > +cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_port =
> > +	TOKEN_STRING_INITIALIZER(
> > +		struct cmd_add_port_tm_leaf_node_result, port, "port");
> > +cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_tm =
> > +	TOKEN_STRING_INITIALIZER(
> > +		struct cmd_add_port_tm_leaf_node_result, tm, "tm");
> > +cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_nonleaf =
> > +	TOKEN_STRING_INITIALIZER(
> > +		struct cmd_add_port_tm_leaf_node_result, leaf, "leaf");
> > +cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_node =
> > +	TOKEN_STRING_INITIALIZER(
> > +		struct cmd_add_port_tm_leaf_node_result, node, "node");
> > +cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_port_id =
> > +	TOKEN_NUM_INITIALIZER(struct
> cmd_add_port_tm_leaf_node_result,
> > +		 port_id, UINT16);
> > +cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_node_id =
> > +	TOKEN_NUM_INITIALIZER(struct
> cmd_add_port_tm_leaf_node_result,
> > +		 node_id, UINT32);
> > +cmdline_parse_token_num_t
> cmd_add_port_tm_leaf_node_parent_node_id =
> > +	TOKEN_NUM_INITIALIZER(struct
> cmd_add_port_tm_leaf_node_result,
> > +		 parent_node_id, INT32);
> > +cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_priority =
> > +	TOKEN_NUM_INITIALIZER(struct
> cmd_add_port_tm_leaf_node_result,
> > +		 priority, UINT32);
> > +cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_weight =
> > +	TOKEN_NUM_INITIALIZER(struct
> cmd_add_port_tm_leaf_node_result,
> > +		 weight, UINT32);
> > +cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_level_id =
> > +	TOKEN_NUM_INITIALIZER(struct
> cmd_add_port_tm_leaf_node_result,
> > +		 level_id, UINT32);
> > +cmdline_parse_token_num_t
> cmd_add_port_tm_leaf_node_shaper_profile_id
> > =
> > +	TOKEN_NUM_INITIALIZER(struct
> cmd_add_port_tm_leaf_node_result,
> > +		 shaper_profile_id, UINT32);
> > +cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_cman_mode
> =
> > +	TOKEN_NUM_INITIALIZER(struct
> cmd_add_port_tm_leaf_node_result,
> > +		 cman_mode, UINT32);
> > +cmdline_parse_token_num_t
> cmd_add_port_tm_leaf_node_wred_profile_id
> > =
> > +	TOKEN_NUM_INITIALIZER(struct
> cmd_add_port_tm_leaf_node_result,
> > +		 wred_profile_id, UINT32);
> > +cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_stats_mask =
> > +	TOKEN_NUM_INITIALIZER(struct
> cmd_add_port_tm_leaf_node_result,
> > +		 stats_mask, UINT64);
> > +cmdline_parse_token_string_t
> > +	cmd_add_port_tm_leaf_node_multi_shared_shaper_id =
> > +	TOKEN_STRING_INITIALIZER(struct
> > cmd_add_port_tm_leaf_node_result,
> > +		 multi_shared_shaper_id, TOKEN_STRING_MULTI);
> > +
> > +static void cmd_add_port_tm_leaf_node_parsed(void *parsed_result,
> > +	__attribute__((unused)) struct cmdline *cl,
> > +	__attribute__((unused)) void *data)
> > +{
> > +	struct cmd_add_port_tm_leaf_node_result *res = parsed_result;
> > +	struct rte_tm_error error;
> > +	struct rte_tm_node_params np;
> > +	uint32_t *shared_shaper_id;
> > +	uint32_t parent_node_id, n_shared_shapers = 0;
> > +	portid_t port_id = res->port_id;
> > +	char *s_str = res->multi_shared_shaper_id;
> > +	int ret;
> > +
> > +	if (port_id_is_invalid(port_id, ENABLED_WARN))
> > +		return;
> > +
> > +	/* Port status */
> > +	if (port_is_started(port_id)) {
> > +		printf(" Port %u not stopped (error)\n", port_id);
> > +		return;
> > +	}
> > +
> > +	memset(&np, 0, sizeof(struct rte_tm_node_params));
> > +
> > +	/* Node parameters */
> > +	if (res->parent_node_id < 0)
> > +		parent_node_id = UINT32_MAX;
> > +	else
> > +		parent_node_id = res->parent_node_id;
> > +
> > +	shared_shaper_id = (uint32_t
> *)malloc(MAX_NUM_SHARED_SHAPERS
> > *
> > +		sizeof(uint32_t));
> > +	/* Parse multi shared shaper id string */
> > +	ret = parse_multi_ss_id_str(s_str, &n_shared_shapers,
> > shared_shaper_id);
> > +	if (ret) {
> > +		printf(" Shared shapers params string parse error\n");
> The same, free the memory you malloced.

Oops, will fix this in next version. Thanks.

^ permalink raw reply	[flat|nested] 49+ messages in thread

* [PATCH v10 1/3] app/test-pmd: add CLI for TM capability and stats
  2017-10-14 10:20                 ` [PATCH v9 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
  2017-10-14 10:20                   ` [PATCH v9 2/3] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
  2017-10-14 10:20                   ` [PATCH v9 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
@ 2017-10-16 18:55                   ` Jasvinder Singh
  2017-10-16 18:55                     ` [PATCH v10 2/3] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
                                       ` (2 more replies)
  2 siblings, 3 replies; 49+ messages in thread
From: Jasvinder Singh @ 2017-10-16 18:55 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu, yulong.pei

Add following CLIs to testpmd application for device traffic management;
- commands to display TM capability information.
  (per port, per hierarchy level and per hierarchy node)
- command to display hiearchy node type
- stats collection

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Tested-by: Yulong Pei <yulong.pei@intel.com>
Reviewed-by: Jingjing Wu <jingjing.wu@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
v9 change:
- fix checkpatch warnings

v6 change:
- fix compilation warning
- change port_id type to uint16_t

v4 change:
 - remove softnic specific checks to make it generic for the devices

v3 change:
- Implements feedback from Pablo[1]
 - move TM API related CLIs into cmdline_tm.c
 - split patch into small patches
 - replace link status check with testpmd fn port_is_started()

[1]http://dpdk.org/ml/archives/dev/2017-September/075748.html

 app/test-pmd/Makefile     |   1 +
 app/test-pmd/cmdline.c    |  20 ++
 app/test-pmd/cmdline_tm.c | 681 ++++++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/cmdline_tm.h |  44 +++
 4 files changed, 746 insertions(+)
 create mode 100644 app/test-pmd/cmdline_tm.c
 create mode 100644 app/test-pmd/cmdline_tm.h

diff --git a/app/test-pmd/Makefile b/app/test-pmd/Makefile
index 2c50f68..e4a6352 100644
--- a/app/test-pmd/Makefile
+++ b/app/test-pmd/Makefile
@@ -48,6 +48,7 @@ SRCS-y := testpmd.c
 SRCS-y += parameters.c
 SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline.c
 SRCS-$(CONFIG_RTE_LIBRTE_CMDLINE) += cmdline_flow.c
+SRCS-y += cmdline_tm.c
 SRCS-y += config.c
 SRCS-y += iofwd.c
 SRCS-y += macfwd.c
diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index bb01e98..07d0bda 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -99,6 +99,7 @@
 #include <rte_pmd_bnxt.h>
 #endif
 #include "testpmd.h"
+#include "cmdline_tm.h"
 
 static struct cmdline *testpmd_cl;
 
@@ -234,6 +235,20 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"show port (port_id) pctype mapping\n"
 			"    Get flow ptype to pctype mapping on a port\n\n"
 
+			"show port tm cap (port_id)\n"
+			"	Display the port TM capability.\n\n"
+
+			"show port tm level cap (port_id) (level_id)\n"
+			"	Display the port TM hierarchical level capability.\n\n"
+
+			"show port tm node cap (port_id) (node_id)\n"
+			"	Display the port TM node capability.\n\n"
+
+			"show port tm node type (port_id) (node_id)\n"
+			"	Display the port TM node type.\n\n"
+
+			"show port tm node stats (port_id) (node_id) (clear)\n"
+			"	Display the port TM node stats.\n\n"
 		);
 	}
 
@@ -15598,6 +15613,11 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_user_priority_region,
 	(cmdline_parse_inst_t *)&cmd_flush_queue_region,
 	(cmdline_parse_inst_t *)&cmd_show_queue_region_info_all,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_level_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_cap,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_type,
+	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_stats,
 	NULL,
 };
 
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
new file mode 100644
index 0000000..f024372
--- /dev/null
+++ b/app/test-pmd/cmdline_tm.c
@@ -0,0 +1,681 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <cmdline_parse.h>
+#include <cmdline_parse_num.h>
+#include <cmdline_parse_string.h>
+
+#include <rte_ethdev.h>
+#include <rte_flow.h>
+#include <rte_tm.h>
+
+#include "testpmd.h"
+#include "cmdline_tm.h"
+
+/** Display TM Error Message */
+static void
+print_err_msg(struct rte_tm_error *error)
+{
+	static const char *const errstrlist[] = {
+		[RTE_TM_ERROR_TYPE_NONE] = "no error",
+		[RTE_TM_ERROR_TYPE_UNSPECIFIED] = "cause unspecified",
+		[RTE_TM_ERROR_TYPE_CAPABILITIES]
+			= "capability parameter null",
+		[RTE_TM_ERROR_TYPE_LEVEL_ID] = "level id",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE]
+			= "wred profile null",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_GREEN] = "wred profile(green)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_YELLOW]
+			= "wred profile(yellow)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_RED] = "wred profile(red)",
+		[RTE_TM_ERROR_TYPE_WRED_PROFILE_ID] = "wred profile id",
+		[RTE_TM_ERROR_TYPE_SHARED_WRED_CONTEXT_ID]
+			= "shared wred context id",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE] = "shaper profile null",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_RATE]
+			= "committed rate field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_COMMITTED_SIZE]
+			= "committed size field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_RATE]
+			= "peak rate field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PEAK_SIZE]
+			= "peak size field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_PKT_ADJUST_LEN]
+			= "packet adjust length field (shaper profile)",
+		[RTE_TM_ERROR_TYPE_SHAPER_PROFILE_ID] = "shaper profile id",
+		[RTE_TM_ERROR_TYPE_SHARED_SHAPER_ID] = "shared shaper id",
+		[RTE_TM_ERROR_TYPE_NODE_PARENT_NODE_ID] = "parent node id",
+		[RTE_TM_ERROR_TYPE_NODE_PRIORITY] = "node priority",
+		[RTE_TM_ERROR_TYPE_NODE_WEIGHT] = "node weight",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS] = "node parameter null",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHAPER_PROFILE_ID]
+			= "shaper profile id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_SHAPER_ID]
+			= "shared shaper id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_SHAPERS]
+			= "num shared shapers field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_WFQ_WEIGHT_MODE]
+			= "wfq weght mode field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SP_PRIORITIES]
+			= "num strict priorities field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_CMAN]
+			= "congestion management mode field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_WRED_PROFILE_ID] =
+			"wred profile id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_SHARED_WRED_CONTEXT_ID]
+			= "shared wred context id field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_N_SHARED_WRED_CONTEXTS]
+			= "num shared wred contexts field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_PARAMS_STATS]
+			= "stats field (node params)",
+		[RTE_TM_ERROR_TYPE_NODE_ID] = "node id",
+	};
+
+	const char *errstr;
+	char buf[64];
+
+	if ((unsigned int)error->type >= RTE_DIM(errstrlist) ||
+		!errstrlist[error->type])
+		errstr = "unknown type";
+	else
+		errstr = errstrlist[error->type];
+
+	if (error->cause)
+		snprintf(buf, sizeof(buf), "cause: %p, ", error->cause);
+
+	printf("%s: %s%s (error %d)\n", errstr, error->cause ? buf : "",
+		error->message ? error->message : "(no stated reason)",
+		error->type);
+}
+
+/* *** Port TM Capability *** */
+struct cmd_show_port_tm_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t cap;
+	uint16_t port_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_cap_result,
+		 port_id, UINT16);
+
+static void cmd_show_port_tm_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_cap_result *res = parsed_result;
+	struct rte_tm_capabilities cap;
+	struct rte_tm_error error;
+	portid_t port_id = res->port_id;
+	uint32_t i;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	memset(&cap, 0, sizeof(struct rte_tm_capabilities));
+	ret = rte_tm_capabilities_get(port_id, &cap, &error);
+	if (ret) {
+		print_err_msg(&error);
+		return;
+	}
+
+	printf("\n****   Port TM Capabilities ****\n\n");
+	printf("cap.n_nodes_max %" PRIu32 "\n", cap.n_nodes_max);
+	printf("cap.n_levels_max %" PRIu32 "\n", cap.n_levels_max);
+	printf("cap.non_leaf_nodes_identical %" PRId32 "\n",
+		cap.non_leaf_nodes_identical);
+	printf("cap.leaf_nodes_identical %" PRId32 "\n",
+		cap.leaf_nodes_identical);
+	printf("cap.shaper_n_max %u\n", cap.shaper_n_max);
+	printf("cap.shaper_private_n_max %" PRIu32 "\n",
+		cap.shaper_private_n_max);
+	printf("cap.shaper_private_dual_rate_n_max %" PRId32 "\n",
+		cap.shaper_private_dual_rate_n_max);
+	printf("cap.shaper_private_rate_min %" PRIu64 "\n",
+		cap.shaper_private_rate_min);
+	printf("cap.shaper_private_rate_max %" PRIu64 "\n",
+		cap.shaper_private_rate_max);
+	printf("cap.shaper_shared_n_max %" PRIu32 "\n",
+		cap.shaper_shared_n_max);
+	printf("cap.shaper_shared_n_nodes_per_shaper_max %" PRIu32 "\n",
+		cap.shaper_shared_n_nodes_per_shaper_max);
+	printf("cap.shaper_shared_n_shapers_per_node_max %" PRIu32 "\n",
+		cap.shaper_shared_n_shapers_per_node_max);
+	printf("cap.shaper_shared_dual_rate_n_max %" PRIu32 "\n",
+		cap.shaper_shared_dual_rate_n_max);
+	printf("cap.shaper_shared_rate_min %" PRIu64 "\n",
+		cap.shaper_shared_rate_min);
+	printf("cap.shaper_shared_rate_max %" PRIu64 "\n",
+		cap.shaper_shared_rate_max);
+	printf("cap.shaper_pkt_length_adjust_min %" PRId32 "\n",
+		cap.shaper_pkt_length_adjust_min);
+	printf("cap.shaper_pkt_length_adjust_max %" PRId32 "\n",
+		cap.shaper_pkt_length_adjust_max);
+	printf("cap.sched_n_children_max %" PRIu32 "\n",
+		cap.sched_n_children_max);
+	printf("cap.sched_sp_n_priorities_max %" PRIu32 "\n",
+		cap.sched_sp_n_priorities_max);
+	printf("cap.sched_wfq_n_children_per_group_max %" PRIu32 "\n",
+		cap.sched_wfq_n_children_per_group_max);
+	printf("cap.sched_wfq_n_groups_max %" PRIu32 "\n",
+		cap.sched_wfq_n_groups_max);
+	printf("cap.sched_wfq_weight_max %" PRIu32 "\n",
+		cap.sched_wfq_weight_max);
+	printf("cap.cman_head_drop_supported %" PRId32 "\n",
+		cap.cman_head_drop_supported);
+	printf("cap.cman_wred_context_n_max %" PRIu32 "\n",
+		cap.cman_wred_context_n_max);
+	printf("cap.cman_wred_context_private_n_max %" PRIu32 "\n",
+		cap.cman_wred_context_private_n_max);
+	printf("cap.cman_wred_context_shared_n_max %" PRIu32 "\n",
+		cap.cman_wred_context_shared_n_max);
+	printf("cap.cman_wred_context_shared_n_nodes_per_context_max %" PRIu32
+		"\n", cap.cman_wred_context_shared_n_nodes_per_context_max);
+	printf("cap.cman_wred_context_shared_n_contexts_per_node_max %" PRIu32
+		"\n", cap.cman_wred_context_shared_n_contexts_per_node_max);
+
+	for (i = 0; i < RTE_TM_COLORS; i++) {
+		printf("cap.mark_vlan_dei_supported %" PRId32 "\n",
+			cap.mark_vlan_dei_supported[i]);
+		printf("cap.mark_ip_ecn_tcp_supported %" PRId32 "\n",
+			cap.mark_ip_ecn_tcp_supported[i]);
+		printf("cap.mark_ip_ecn_sctp_supported %" PRId32 "\n",
+			cap.mark_ip_ecn_sctp_supported[i]);
+		printf("cap.mark_ip_dscp_supported %" PRId32 "\n",
+			cap.mark_ip_dscp_supported[i]);
+	}
+
+	printf("cap.dynamic_update_mask %" PRIx64 "\n",
+		cap.dynamic_update_mask);
+	printf("cap.stats_mask %" PRIx64 "\n", cap.stats_mask);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_cap = {
+	.f = cmd_show_port_tm_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_cap_show,
+		(void *)&cmd_show_port_tm_cap_port,
+		(void *)&cmd_show_port_tm_cap_tm,
+		(void *)&cmd_show_port_tm_cap_cap,
+		(void *)&cmd_show_port_tm_cap_port_id,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchical Level Capability *** */
+struct cmd_show_port_tm_level_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t level;
+	cmdline_fixed_string_t cap;
+	uint16_t port_id;
+	uint32_t level_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_level =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		level, "level");
+cmdline_parse_token_string_t cmd_show_port_tm_level_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_level_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_level_cap_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_level_cap_result,
+		 level_id, UINT32);
+
+
+static void cmd_show_port_tm_level_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_level_cap_result *res = parsed_result;
+	struct rte_tm_level_capabilities lcap;
+	struct rte_tm_error error;
+	portid_t port_id = res->port_id;
+	uint32_t level_id = res->level_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	memset(&lcap, 0, sizeof(struct rte_tm_level_capabilities));
+	ret = rte_tm_level_capabilities_get(port_id, level_id, &lcap, &error);
+	if (ret) {
+		print_err_msg(&error);
+		return;
+	}
+	printf("\n**   Port TM Hierarchy level %" PRIu32 " Capability **\n\n",
+		level_id);
+
+	printf("cap.n_nodes_max %" PRIu32 "\n", lcap.n_nodes_max);
+	printf("cap.n_nodes_nonleaf_max %" PRIu32 "\n",
+		lcap.n_nodes_nonleaf_max);
+	printf("cap.n_nodes_leaf_max %" PRIu32 "\n", lcap.n_nodes_leaf_max);
+	printf("cap.non_leaf_nodes_identical %" PRId32 "\n",
+		lcap.non_leaf_nodes_identical);
+	printf("cap.leaf_nodes_identical %" PRId32 "\n",
+		lcap.leaf_nodes_identical);
+	if (level_id <= 3) {
+		printf("cap.nonleaf.shaper_private_supported %" PRId32 "\n",
+			lcap.nonleaf.shaper_private_supported);
+		printf("cap.nonleaf.shaper_private_dual_rate_supported %" PRId32
+			"\n", lcap.nonleaf.shaper_private_dual_rate_supported);
+		printf("cap.nonleaf.shaper_private_rate_min %" PRIu64 "\n",
+			lcap.nonleaf.shaper_private_rate_min);
+		printf("cap.nonleaf.shaper_private_rate_max %" PRIu64 "\n",
+			lcap.nonleaf.shaper_private_rate_max);
+		printf("cap.nonleaf.shaper_shared_n_max %" PRIu32 "\n",
+			lcap.nonleaf.shaper_shared_n_max);
+		printf("cap.nonleaf.sched_n_children_max %" PRIu32 "\n",
+			lcap.nonleaf.sched_n_children_max);
+		printf("cap.nonleaf.sched_sp_n_priorities_max %" PRIu32 "\n",
+			lcap.nonleaf.sched_sp_n_priorities_max);
+		printf("cap.nonleaf.sched_wfq_n_children_per_group_max %" PRIu32
+			"\n", lcap.nonleaf.sched_wfq_n_children_per_group_max);
+		printf("cap.nonleaf.sched_wfq_n_groups_max %" PRIu32 "\n",
+			lcap.nonleaf.sched_wfq_n_groups_max);
+		printf("cap.nonleaf.sched_wfq_weight_max %" PRIu32 "\n",
+			lcap.nonleaf.sched_wfq_weight_max);
+		printf("cap.nonleaf.stats_mask %" PRIx64 "\n",
+			lcap.nonleaf.stats_mask);
+	} else {
+		printf("cap.leaf.shaper_private_supported %" PRId32 "\n",
+			lcap.leaf.shaper_private_supported);
+		printf("cap.leaf.shaper_private_dual_rate_supported %" PRId32
+			"\n", lcap.leaf.shaper_private_dual_rate_supported);
+		printf("cap.leaf.shaper_private_rate_min %" PRIu64 "\n",
+			lcap.leaf.shaper_private_rate_min);
+		printf("cap.leaf.shaper_private_rate_max %" PRIu64 "\n",
+			lcap.leaf.shaper_private_rate_max);
+		printf("cap.leaf.shaper_shared_n_max %" PRIu32 "\n",
+			lcap.leaf.shaper_shared_n_max);
+		printf("cap.leaf.cman_head_drop_supported %" PRId32 "\n",
+			lcap.leaf.cman_head_drop_supported);
+		printf("cap.leaf.cman_wred_context_private_supported %"	PRId32
+			"\n", lcap.leaf.cman_wred_context_private_supported);
+		printf("cap.leaf.cman_wred_context_shared_n_max %" PRIu32 "\n",
+			lcap.leaf.cman_wred_context_shared_n_max);
+		printf("cap.leaf.stats_mask %" PRIx64 "\n",
+			lcap.leaf.stats_mask);
+	}
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_level_cap = {
+	.f = cmd_show_port_tm_level_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Hierarhical level Capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_level_cap_show,
+		(void *)&cmd_show_port_tm_level_cap_port,
+		(void *)&cmd_show_port_tm_level_cap_tm,
+		(void *)&cmd_show_port_tm_level_cap_level,
+		(void *)&cmd_show_port_tm_level_cap_cap,
+		(void *)&cmd_show_port_tm_level_cap_port_id,
+		(void *)&cmd_show_port_tm_level_cap_level_id,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchy Node Capability *** */
+struct cmd_show_port_tm_node_cap_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t cap;
+	uint16_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_show =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_port =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_tm =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_node =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_cap_cap =
+	TOKEN_STRING_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		cap, "cap");
+cmdline_parse_token_num_t cmd_show_port_tm_node_cap_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_node_cap_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_cap_result,
+		 node_id, UINT32);
+
+static void cmd_show_port_tm_node_cap_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_cap_result *res = parsed_result;
+	struct rte_tm_node_capabilities ncap;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	portid_t port_id = res->port_id;
+	int ret, is_leaf = 0;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Node id must be valid */
+	ret = rte_tm_node_type_get(port_id, node_id, &is_leaf, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	memset(&ncap, 0, sizeof(struct rte_tm_node_capabilities));
+	ret = rte_tm_node_capabilities_get(port_id, node_id, &ncap, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+	printf("\n**   Port TM Hierarchy node %" PRIu32 " Capability **\n\n",
+		node_id);
+	printf("cap.shaper_private_supported %" PRId32 "\n",
+		ncap.shaper_private_supported);
+	printf("cap.shaper_private_dual_rate_supported %" PRId32 "\n",
+		ncap.shaper_private_dual_rate_supported);
+	printf("cap.shaper_private_rate_min %" PRIu64 "\n",
+		ncap.shaper_private_rate_min);
+	printf("cap.shaper_private_rate_max %" PRIu64 "\n",
+		ncap.shaper_private_rate_max);
+	printf("cap.shaper_shared_n_max %" PRIu32 "\n",
+		ncap.shaper_shared_n_max);
+	if (!is_leaf) {
+		printf("cap.nonleaf.sched_n_children_max %" PRIu32 "\n",
+			ncap.nonleaf.sched_n_children_max);
+		printf("cap.nonleaf.sched_sp_n_priorities_max %" PRIu32 "\n",
+			ncap.nonleaf.sched_sp_n_priorities_max);
+		printf("cap.nonleaf.sched_wfq_n_children_per_group_max %" PRIu32
+			"\n", ncap.nonleaf.sched_wfq_n_children_per_group_max);
+		printf("cap.nonleaf.sched_wfq_n_groups_max %" PRIu32 "\n",
+			ncap.nonleaf.sched_wfq_n_groups_max);
+		printf("cap.nonleaf.sched_wfq_weight_max %" PRIu32 "\n",
+			ncap.nonleaf.sched_wfq_weight_max);
+	} else {
+		printf("cap.leaf.cman_head_drop_supported %" PRId32 "\n",
+			ncap.leaf.cman_head_drop_supported);
+		printf("cap.leaf.cman_wred_context_private_supported %" PRId32
+			"\n", ncap.leaf.cman_wred_context_private_supported);
+		printf("cap.leaf.cman_wred_context_shared_n_max %" PRIu32 "\n",
+			ncap.leaf.cman_wred_context_shared_n_max);
+	}
+	printf("cap.stats_mask %" PRIx64 "\n", ncap.stats_mask);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_cap = {
+	.f = cmd_show_port_tm_node_cap_parsed,
+	.data = NULL,
+	.help_str = "Show Port TM Hierarchy node capabilities",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_cap_show,
+		(void *)&cmd_show_port_tm_node_cap_port,
+		(void *)&cmd_show_port_tm_node_cap_tm,
+		(void *)&cmd_show_port_tm_node_cap_node,
+		(void *)&cmd_show_port_tm_node_cap_cap,
+		(void *)&cmd_show_port_tm_node_cap_port_id,
+		(void *)&cmd_show_port_tm_node_cap_node_id,
+		NULL,
+	},
+};
+
+/* *** Show Port TM Node Statistics *** */
+struct cmd_show_port_tm_node_stats_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t stats;
+	uint16_t port_id;
+	uint32_t node_id;
+	uint32_t clear;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_show =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_stats_stats =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, stats, "stats");
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_show_port_tm_node_stats_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result,
+			node_id, UINT32);
+cmdline_parse_token_num_t cmd_show_port_tm_node_stats_clear =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_stats_result, clear, UINT32);
+
+static void cmd_show_port_tm_node_stats_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_stats_result *res = parsed_result;
+	struct rte_tm_node_stats stats;
+	struct rte_tm_error error;
+	uint64_t stats_mask = 0;
+	uint32_t node_id = res->node_id;
+	uint32_t clear = res->clear;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (!port_is_started(port_id)) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	memset(&stats, 0, sizeof(struct rte_tm_node_stats));
+	ret = rte_tm_node_stats_read(port_id, node_id, &stats,
+			&stats_mask, clear, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	/* Display stats */
+	if (stats_mask & RTE_TM_STATS_N_PKTS)
+		printf("\tPkts scheduled from node: %" PRIu64 "\n",
+			stats.n_pkts);
+	if (stats_mask & RTE_TM_STATS_N_BYTES)
+		printf("\tBytes scheduled from node: %" PRIu64 "\n",
+			stats.n_bytes);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_GREEN_DROPPED)
+		printf("\tPkts dropped (green): %" PRIu64 "\n",
+			stats.leaf.n_pkts_dropped[RTE_TM_GREEN]);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_YELLOW_DROPPED)
+		printf("\tPkts dropped (yellow): %" PRIu64 "\n",
+			stats.leaf.n_pkts_dropped[RTE_TM_YELLOW]);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_RED_DROPPED)
+		printf("\tPkts dropped (red): %" PRIu64 "\n",
+			stats.leaf.n_pkts_dropped[RTE_TM_RED]);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_GREEN_DROPPED)
+		printf("\tBytes dropped (green): %" PRIu64 "\n",
+			stats.leaf.n_bytes_dropped[RTE_TM_GREEN]);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_YELLOW_DROPPED)
+		printf("\tBytes dropped (yellow): %" PRIu64 "\n",
+			stats.leaf.n_bytes_dropped[RTE_TM_YELLOW]);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_RED_DROPPED)
+		printf("\tBytes dropped (red): %" PRIu64 "\n",
+			stats.leaf.n_bytes_dropped[RTE_TM_RED]);
+	if (stats_mask & RTE_TM_STATS_N_PKTS_QUEUED)
+		printf("\tPkts queued: %" PRIu64 "\n",
+			stats.leaf.n_pkts_queued);
+	if (stats_mask & RTE_TM_STATS_N_BYTES_QUEUED)
+		printf("\tBytes queued: %" PRIu64 "\n",
+			stats.leaf.n_bytes_queued);
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_stats = {
+	.f = cmd_show_port_tm_node_stats_parsed,
+	.data = NULL,
+	.help_str = "Show port tm node stats",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_stats_show,
+		(void *)&cmd_show_port_tm_node_stats_port,
+		(void *)&cmd_show_port_tm_node_stats_tm,
+		(void *)&cmd_show_port_tm_node_stats_node,
+		(void *)&cmd_show_port_tm_node_stats_stats,
+		(void *)&cmd_show_port_tm_node_stats_port_id,
+		(void *)&cmd_show_port_tm_node_stats_node_id,
+		(void *)&cmd_show_port_tm_node_stats_clear,
+		NULL,
+	},
+};
+
+/* *** Show Port TM Node Type *** */
+struct cmd_show_port_tm_node_type_result {
+	cmdline_fixed_string_t show;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t type;
+	uint16_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_show =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, show, "show");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, port, "port");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, tm, "tm");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, node, "node");
+cmdline_parse_token_string_t cmd_show_port_tm_node_type_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result, type, "type");
+cmdline_parse_token_num_t cmd_show_port_tm_node_type_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_show_port_tm_node_type_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_show_port_tm_node_type_result,
+			node_id, UINT32);
+
+static void cmd_show_port_tm_node_type_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_show_port_tm_node_type_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	portid_t port_id = res->port_id;
+	int ret, is_leaf = 0;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_node_type_get(port_id, node_id, &is_leaf, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+
+	if (is_leaf == 1)
+		printf("leaf node\n");
+	else
+		printf("nonleaf node\n");
+
+}
+
+cmdline_parse_inst_t cmd_show_port_tm_node_type = {
+	.f = cmd_show_port_tm_node_type_parsed,
+	.data = NULL,
+	.help_str = "Show port tm node type",
+	.tokens = {
+		(void *)&cmd_show_port_tm_node_type_show,
+		(void *)&cmd_show_port_tm_node_type_port,
+		(void *)&cmd_show_port_tm_node_type_tm,
+		(void *)&cmd_show_port_tm_node_type_node,
+		(void *)&cmd_show_port_tm_node_type_type,
+		(void *)&cmd_show_port_tm_node_type_port_id,
+		(void *)&cmd_show_port_tm_node_type_node_id,
+		NULL,
+	},
+};
diff --git a/app/test-pmd/cmdline_tm.h b/app/test-pmd/cmdline_tm.h
new file mode 100644
index 0000000..945af89
--- /dev/null
+++ b/app/test-pmd/cmdline_tm.h
@@ -0,0 +1,44 @@
+/*-
+ *   BSD LICENSE
+ *
+ *   Copyright(c) 2017 Intel Corporation. All rights reserved.
+ *   All rights reserved.
+ *
+ *   Redistribution and use in source and binary forms, with or without
+ *   modification, are permitted provided that the following conditions
+ *   are met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ *       notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above copyright
+ *       notice, this list of conditions and the following disclaimer in
+ *       the documentation and/or other materials provided with the
+ *       distribution.
+ *     * Neither the name of Intel Corporation nor the names of its
+ *       contributors may be used to endorse or promote products derived
+ *       from this software without specific prior written permission.
+ *
+ *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _CMDLINE_TM_H_
+#define _CMDLINE_TM_H_
+
+ /* Traffic Management CLI */
+extern cmdline_parse_inst_t cmd_show_port_tm_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_level_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_cap;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_type;
+extern cmdline_parse_inst_t cmd_show_port_tm_node_stats;
+
+#endif /* _CMDLINE_TM_H_ */
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v10 2/3] app/test-pmd: add CLI for shaper and wred profiles
  2017-10-16 18:55                   ` [PATCH v10 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
@ 2017-10-16 18:55                     ` Jasvinder Singh
  2017-10-16 18:55                     ` [PATCH v10 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
  2017-10-17  8:44                     ` [PATCH v10 1/3] app/test-pmd: add CLI for TM capability and stats Wu, Jingjing
  2 siblings, 0 replies; 49+ messages in thread
From: Jasvinder Singh @ 2017-10-16 18:55 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu, yulong.pei

Add following CLIs in testpmd application for device traffic management;
- commands to add/del shaper profile for TM hieraqrchy nodes.
- commands to add/update shared shapers
- commands to add/del WRED profiles for TM hiearchy leaf nodes.

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
v7 change:
- remove unnecessary checks on wred profile color string, api doesn't
  allow to set WRED with less than 3 colors. 

v6 change:
- change port id type to uint16_t
 
v5 change:
- add packet length adjust parameter to add shaper profile command

v4 change:
- remove softnic specific checks to make it generic for the devices

 app/test-pmd/cmdline.c    |  34 +++
 app/test-pmd/cmdline_tm.c | 731 ++++++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/cmdline_tm.h |   7 +
 3 files changed, 772 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 07d0bda..9b742d8 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -693,6 +693,33 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"show port (port_id) queue-region\n"
 			"    show all queue region related configuration info\n\n"
 
+			"add port tm node shaper profile (port_id) (shaper_profile_id)"
+			" (tb_rate) (tb_size) (packet_length_adjust)\n"
+			"	Add port tm node private shaper profile.\n\n"
+
+			"del port tm node shaper profile (port_id) (shaper_profile_id)\n"
+			"	Delete port tm node private shaper profile.\n\n"
+
+			"add port tm node shared shaper (port_id) (shared_shaper_id)"
+			" (shaper_profile_id)\n"
+			"	Add/update port tm node shared shaper.\n\n"
+
+			"del port tm node shared shaper (port_id) (shared_shaper_id)\n"
+			"	Delete port tm node shared shaper.\n\n"
+
+			"set port tm node shaper profile (port_id) (node_id)"
+			" (shaper_profile_id)\n"
+			"	Set port tm node shaper profile.\n\n"
+
+			"add port tm node wred profile (port_id) (wred_profile_id)"
+			" (color_g) (min_th_g) (max_th_g) (maxp_inv_g) (wq_log2_g)"
+			" (color_y) (min_th_y) (max_th_y) (maxp_inv_y) (wq_log2_y)"
+			" (color_r) (min_th_r) (max_th_r) (maxp_inv_r) (wq_log2_r)\n"
+			"	Add port tm node wred profile.\n\n"
+
+			"del port tm node wred profile (port_id) (wred_profile_id)\n"
+			"	Delete port tm node wred profile.\n\n"
+
 			, list_pkt_forwarding_modes()
 		);
 	}
@@ -15618,6 +15645,13 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_cap,
 	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_type,
 	(cmdline_parse_inst_t *)&cmd_show_port_tm_node_stats,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_shared_shaper,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_shared_shaper,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_wred_profile,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_wred_profile,
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_shaper_profile,
 	NULL,
 };
 
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
index f024372..38048ae 100644
--- a/app/test-pmd/cmdline_tm.c
+++ b/app/test-pmd/cmdline_tm.c
@@ -679,3 +679,734 @@ cmdline_parse_inst_t cmd_show_port_tm_node_type = {
 		NULL,
 	},
 };
+
+/* *** Add Port TM Private Shaper Profile *** */
+struct cmd_add_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint16_t port_id;
+	uint32_t shaper_id;
+	uint64_t tb_rate;
+	uint64_t tb_size;
+	uint32_t pktlen_adjust;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_tb_rate =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tb_rate, UINT64);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_tb_size =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			tb_size, UINT64);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shaper_profile_pktlen_adjust =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shaper_profile_result,
+			pktlen_adjust, UINT32);
+
+static void cmd_add_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_tm_shaper_params sp;
+	struct rte_tm_error error;
+	uint32_t shaper_id = res->shaper_id;
+	uint32_t pkt_len_adjust = res->pktlen_adjust;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Private shaper profile params */
+	memset(&sp, 0, sizeof(struct rte_tm_shaper_params));
+	sp.peak.rate = res->tb_rate;
+	sp.peak.size = res->tb_size;
+	sp.pkt_length_adjust = pkt_len_adjust;
+
+	ret = rte_tm_shaper_profile_add(port_id, shaper_id, &sp, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_shaper_profile = {
+	.f = cmd_add_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Add port tm node private shaper profile",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_shaper_profile_add,
+		(void *)&cmd_add_port_tm_node_shaper_profile_port,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_add_port_tm_node_shaper_profile_node,
+		(void *)&cmd_add_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_add_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_add_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_add_port_tm_node_shaper_profile_shaper_id,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tb_rate,
+		(void *)&cmd_add_port_tm_node_shaper_profile_tb_size,
+		(void *)&cmd_add_port_tm_node_shaper_profile_pktlen_adjust,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM Private Shaper Profile *** */
+struct cmd_del_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint16_t port_id;
+	uint32_t shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_del_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_tm_node_shaper_profile_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shaper_profile_result,
+			shaper_id, UINT32);
+
+static void cmd_del_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t shaper_id = res->shaper_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_shaper_profile_delete(port_id, shaper_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_shaper_profile = {
+	.f = cmd_del_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node private shaper profile",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_shaper_profile_del,
+		(void *)&cmd_del_port_tm_node_shaper_profile_port,
+		(void *)&cmd_del_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_del_port_tm_node_shaper_profile_node,
+		(void *)&cmd_del_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_del_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_del_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_del_port_tm_node_shaper_profile_shaper_id,
+		NULL,
+	},
+};
+
+/* *** Add/Update Port TM shared Shaper *** */
+struct cmd_add_port_tm_node_shared_shaper_result {
+	cmdline_fixed_string_t cmd_type;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shared;
+	cmdline_fixed_string_t shaper;
+	uint16_t port_id;
+	uint32_t shared_shaper_id;
+	uint32_t shaper_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_cmd_type =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			cmd_type, "add#set");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result, node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_shared =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shared, "shared");
+cmdline_parse_token_string_t cmd_add_port_tm_node_shared_shaper_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shaper, "shaper");
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shared_shaper_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_node_shared_shaper_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_shared_shaper_result,
+			shaper_profile_id, UINT32);
+
+static void cmd_add_port_tm_node_shared_shaper_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_shared_shaper_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t shared_shaper_id = res->shared_shaper_id;
+	uint32_t shaper_profile_id = res->shaper_profile_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Command type: add */
+	if ((strcmp(res->cmd_type, "add") == 0) &&
+		(port_is_started(port_id))) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	/* Command type: set (update) */
+	if ((strcmp(res->cmd_type, "set") == 0) &&
+		(!port_is_started(port_id))) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_shared_shaper_add_update(port_id, shared_shaper_id,
+		shaper_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_shared_shaper = {
+	.f = cmd_add_port_tm_node_shared_shaper_parsed,
+	.data = NULL,
+	.help_str = "add/update port tm node shared shaper",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_shared_shaper_cmd_type,
+		(void *)&cmd_add_port_tm_node_shared_shaper_port,
+		(void *)&cmd_add_port_tm_node_shared_shaper_tm,
+		(void *)&cmd_add_port_tm_node_shared_shaper_node,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shared,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shaper,
+		(void *)&cmd_add_port_tm_node_shared_shaper_port_id,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shared_shaper_id,
+		(void *)&cmd_add_port_tm_node_shared_shaper_shaper_profile_id,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM shared Shaper *** */
+struct cmd_del_port_tm_node_shared_shaper_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shared;
+	cmdline_fixed_string_t shaper;
+	uint16_t port_id;
+	uint32_t shared_shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result, node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_shared =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shared, "shared");
+cmdline_parse_token_string_t cmd_del_port_tm_node_shared_shaper_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shaper, "shaper");
+cmdline_parse_token_num_t cmd_del_port_tm_node_shared_shaper_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_tm_node_shared_shaper_shared_shaper_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_shared_shaper_result,
+			shared_shaper_id, UINT32);
+
+static void cmd_del_port_tm_node_shared_shaper_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_shared_shaper_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t shared_shaper_id = res->shared_shaper_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_shared_shaper_delete(port_id, shared_shaper_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper = {
+	.f = cmd_del_port_tm_node_shared_shaper_parsed,
+	.data = NULL,
+	.help_str = "delete port tm node shared shaper",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_shared_shaper_del,
+		(void *)&cmd_del_port_tm_node_shared_shaper_port,
+		(void *)&cmd_del_port_tm_node_shared_shaper_tm,
+		(void *)&cmd_del_port_tm_node_shared_shaper_node,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shared,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shaper,
+		(void *)&cmd_del_port_tm_node_shared_shaper_port_id,
+		(void *)&cmd_del_port_tm_node_shared_shaper_shared_shaper_id,
+		NULL,
+	},
+};
+
+/* *** Add Port TM Node WRED Profile *** */
+struct cmd_add_port_tm_node_wred_profile_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t wred;
+	cmdline_fixed_string_t profile;
+	uint16_t port_id;
+	uint32_t wred_profile_id;
+	cmdline_fixed_string_t color_g;
+	uint16_t min_th_g;
+	uint16_t max_th_g;
+	uint16_t maxp_inv_g;
+	uint16_t wq_log2_g;
+	cmdline_fixed_string_t color_y;
+	uint16_t min_th_y;
+	uint16_t max_th_y;
+	uint16_t maxp_inv_y;
+	uint16_t wq_log2_y;
+	cmdline_fixed_string_t color_r;
+	uint16_t min_th_r;
+	uint16_t max_th_r;
+	uint16_t maxp_inv_r;
+	uint16_t wq_log2_r;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, node, "node");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_wred =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result, wred, "wred");
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wred_profile_id, UINT32);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_g =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_g, "G#g");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_g, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_g =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_g, UINT16);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_y =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_y, "Y#y");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_y, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_y =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_y, UINT16);
+cmdline_parse_token_string_t cmd_add_port_tm_node_wred_profile_color_r =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			color_r, "R#r");
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_min_th_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			min_th_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_max_th_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			max_th_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_maxp_inv_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			maxp_inv_r, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_node_wred_profile_wq_log2_r =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_node_wred_profile_result,
+			wq_log2_r, UINT16);
+
+
+static void cmd_add_port_tm_node_wred_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_node_wred_profile_result *res = parsed_result;
+	struct rte_tm_wred_params wp;
+	enum rte_tm_color color;
+	struct rte_tm_error error;
+	uint32_t wred_profile_id = res->wred_profile_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	memset(&wp, 0, sizeof(struct rte_tm_wred_params));
+
+	/* WRED Params  (Green Color)*/
+	color = RTE_TM_GREEN;
+	wp.red_params[color].min_th = res->min_th_g;
+	wp.red_params[color].max_th = res->max_th_g;
+	wp.red_params[color].maxp_inv = res->maxp_inv_g;
+	wp.red_params[color].wq_log2 = res->wq_log2_g;
+
+
+	/* WRED Params  (Yellow Color)*/
+	color = RTE_TM_YELLOW;
+	wp.red_params[color].min_th = res->min_th_y;
+	wp.red_params[color].max_th = res->max_th_y;
+	wp.red_params[color].maxp_inv = res->maxp_inv_y;
+	wp.red_params[color].wq_log2 = res->wq_log2_y;
+
+	/* WRED Params  (Red Color)*/
+	color = RTE_TM_RED;
+	wp.red_params[color].min_th = res->min_th_r;
+	wp.red_params[color].max_th = res->max_th_r;
+	wp.red_params[color].maxp_inv = res->maxp_inv_r;
+	wp.red_params[color].wq_log2 = res->wq_log2_r;
+
+	ret = rte_tm_wred_profile_add(port_id, wred_profile_id, &wp, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile = {
+	.f = cmd_add_port_tm_node_wred_profile_parsed,
+	.data = NULL,
+	.help_str = "Add port tm node wred profile",
+	.tokens = {
+		(void *)&cmd_add_port_tm_node_wred_profile_add,
+		(void *)&cmd_add_port_tm_node_wred_profile_port,
+		(void *)&cmd_add_port_tm_node_wred_profile_tm,
+		(void *)&cmd_add_port_tm_node_wred_profile_node,
+		(void *)&cmd_add_port_tm_node_wred_profile_wred,
+		(void *)&cmd_add_port_tm_node_wred_profile_profile,
+		(void *)&cmd_add_port_tm_node_wred_profile_port_id,
+		(void *)&cmd_add_port_tm_node_wred_profile_wred_profile_id,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_g,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_y,
+		(void *)&cmd_add_port_tm_node_wred_profile_color_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_min_th_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_max_th_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_maxp_inv_r,
+		(void *)&cmd_add_port_tm_node_wred_profile_wq_log2_r,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM node WRED Profile *** */
+struct cmd_del_port_tm_node_wred_profile_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t wred;
+	cmdline_fixed_string_t profile;
+	uint16_t port_id;
+	uint32_t wred_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, node, "node");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_wred =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result, wred, "wred");
+cmdline_parse_token_string_t cmd_del_port_tm_node_wred_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_del_port_tm_node_wred_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_tm_node_wred_profile_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_del_port_tm_node_wred_profile_result,
+			wred_profile_id, UINT32);
+
+static void cmd_del_port_tm_node_wred_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_wred_profile_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t wred_profile_id = res->wred_profile_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	ret = rte_tm_wred_profile_delete(port_id, wred_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile = {
+	.f = cmd_del_port_tm_node_wred_profile_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node wred profile",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_wred_profile_del,
+		(void *)&cmd_del_port_tm_node_wred_profile_port,
+		(void *)&cmd_del_port_tm_node_wred_profile_tm,
+		(void *)&cmd_del_port_tm_node_wred_profile_node,
+		(void *)&cmd_del_port_tm_node_wred_profile_wred,
+		(void *)&cmd_del_port_tm_node_wred_profile_profile,
+		(void *)&cmd_del_port_tm_node_wred_profile_port_id,
+		(void *)&cmd_del_port_tm_node_wred_profile_wred_profile_id,
+		NULL,
+	},
+};
+
+/* *** Update Port TM Node Shaper profile *** */
+struct cmd_set_port_tm_node_shaper_profile_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t shaper;
+	cmdline_fixed_string_t profile;
+	uint16_t port_id;
+	uint32_t node_id;
+	uint32_t shaper_profile_id;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result, tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			node, "node");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_shaper =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			shaper, "shaper");
+cmdline_parse_token_string_t cmd_set_port_tm_node_shaper_profile_profile =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			profile, "profile");
+cmdline_parse_token_num_t cmd_set_port_tm_node_shaper_profile_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_shaper_profile_result,
+			port_id, UINT16);
+cmdline_parse_token_num_t cmd_set_port_tm_node_shaper_profile_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_shaper_profile_result,
+		node_id, UINT32);
+cmdline_parse_token_num_t
+	cmd_set_port_tm_node_shaper_shaper_profile_profile_id =
+		TOKEN_NUM_INITIALIZER(
+			struct cmd_set_port_tm_node_shaper_profile_result,
+			shaper_profile_id, UINT32);
+
+static void cmd_set_port_tm_node_shaper_profile_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_node_shaper_profile_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint32_t shaper_profile_id = res->shaper_profile_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (!port_is_started(port_id)) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_shaper_update(port_id, node_id,
+		shaper_profile_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile = {
+	.f = cmd_set_port_tm_node_shaper_profile_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node shaper profile",
+	.tokens = {
+		(void *)&cmd_set_port_tm_node_shaper_profile_set,
+		(void *)&cmd_set_port_tm_node_shaper_profile_port,
+		(void *)&cmd_set_port_tm_node_shaper_profile_tm,
+		(void *)&cmd_set_port_tm_node_shaper_profile_node,
+		(void *)&cmd_set_port_tm_node_shaper_profile_shaper,
+		(void *)&cmd_set_port_tm_node_shaper_profile_profile,
+		(void *)&cmd_set_port_tm_node_shaper_profile_port_id,
+		(void *)&cmd_set_port_tm_node_shaper_profile_node_id,
+		(void *)&cmd_set_port_tm_node_shaper_shaper_profile_profile_id,
+		NULL,
+	},
+};
diff --git a/app/test-pmd/cmdline_tm.h b/app/test-pmd/cmdline_tm.h
index 945af89..5ed9de0 100644
--- a/app/test-pmd/cmdline_tm.h
+++ b/app/test-pmd/cmdline_tm.h
@@ -40,5 +40,12 @@ extern cmdline_parse_inst_t cmd_show_port_tm_level_cap;
 extern cmdline_parse_inst_t cmd_show_port_tm_node_cap;
 extern cmdline_parse_inst_t cmd_show_port_tm_node_type;
 extern cmdline_parse_inst_t cmd_show_port_tm_node_stats;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_shared_shaper;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper;
+extern cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile;
+extern cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile;
+extern cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile;
 
 #endif /* _CMDLINE_TM_H_ */
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* [PATCH v10 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit
  2017-10-16 18:55                   ` [PATCH v10 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
  2017-10-16 18:55                     ` [PATCH v10 2/3] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
@ 2017-10-16 18:55                     ` Jasvinder Singh
  2017-10-17  8:44                     ` [PATCH v10 1/3] app/test-pmd: add CLI for TM capability and stats Wu, Jingjing
  2 siblings, 0 replies; 49+ messages in thread
From: Jasvinder Singh @ 2017-10-16 18:55 UTC (permalink / raw)
  To: dev; +Cc: cristian.dumitrescu, jingjing.wu, yulong.pei

Add following CLIs in testpmd application for device traffic management;
- commands to add TM hierarchy nodes (leaf and nonleaf).
- command for runtime update of node weight.
- command to commit the TM hierarchy

Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
---
v10 change:
- free memory allocated using malloc

v8 change:
- change command defintion for leaf and nonleaf nodes (mulitple shared
  shapers can be specified)
- pre-allocate memory for shared shaper ids array in nonleaf and leaf
  node add cli.
- change clean_on_fail to string type in hierarchy commit cli
 
v7 change:
- fix the help info on leaf node add

v5 change:
- add shaper related parameters to leaf node add command

v4 change:
- remove softnic specific checks to make it generic for the devices

 app/test-pmd/cmdline.c    |  27 ++
 app/test-pmd/cmdline_tm.c | 655 ++++++++++++++++++++++++++++++++++++++++++++++
 app/test-pmd/cmdline_tm.h |   5 +
 3 files changed, 687 insertions(+)

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 9b742d8..8b8e682 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -720,6 +720,28 @@ static void cmd_help_long_parsed(void *parsed_result,
 			"del port tm node wred profile (port_id) (wred_profile_id)\n"
 			"	Delete port tm node wred profile.\n\n"
 
+			"add port tm nonleaf node (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight) (level_id) (shaper_profile_id)"
+			" (n_sp_priorities) (stats_mask) (n_shared_shapers)"
+			" [(shared_shaper_id_0) (shared_shaper_id_1)...]\n"
+			"	Add port tm nonleaf node.\n\n"
+
+			"add port tm leaf node (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight) (level_id) (shaper_profile_id)"
+			" (cman_mode) (wred_profile_id) (stats_mask) (n_shared_shapers)"
+			" [(shared_shaper_id_0) (shared_shaper_id_1)...]\n"
+			"	Add port tm leaf node.\n\n"
+
+			"del port tm node (port_id) (node_id)\n"
+			"	Delete port tm node.\n\n"
+
+			"set port tm node parent (port_id) (node_id) (parent_node_id)"
+			" (priority) (weight)\n"
+			"	Set port tm node parent.\n\n"
+
+			"port tm hierarchy commit (port_id) (clean_on_fail)\n"
+			"	Commit tm hierarchy.\n\n"
+
 			, list_pkt_forwarding_modes()
 		);
 	}
@@ -15652,6 +15674,11 @@ cmdline_parse_ctx_t main_ctx[] = {
 	(cmdline_parse_inst_t *)&cmd_add_port_tm_node_wred_profile,
 	(cmdline_parse_inst_t *)&cmd_del_port_tm_node_wred_profile,
 	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_shaper_profile,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_nonleaf_node,
+	(cmdline_parse_inst_t *)&cmd_add_port_tm_leaf_node,
+	(cmdline_parse_inst_t *)&cmd_del_port_tm_node,
+	(cmdline_parse_inst_t *)&cmd_set_port_tm_node_parent,
+	(cmdline_parse_inst_t *)&cmd_port_tm_hierarchy_commit,
 	NULL,
 };
 
diff --git a/app/test-pmd/cmdline_tm.c b/app/test-pmd/cmdline_tm.c
index 38048ae..964ce9d 100644
--- a/app/test-pmd/cmdline_tm.c
+++ b/app/test-pmd/cmdline_tm.c
@@ -42,6 +42,17 @@
 #include "testpmd.h"
 #include "cmdline_tm.h"
 
+#define PARSE_DELIMITER				" \f\n\r\t\v"
+#define MAX_NUM_SHARED_SHAPERS		256
+
+#define skip_white_spaces(pos)			\
+({						\
+	__typeof__(pos) _p = (pos);		\
+	for ( ; isspace(*_p); _p++)		\
+		;				\
+	_p;					\
+})
+
 /** Display TM Error Message */
 static void
 print_err_msg(struct rte_tm_error *error)
@@ -118,6 +129,100 @@ print_err_msg(struct rte_tm_error *error)
 		error->type);
 }
 
+static int
+read_uint64(uint64_t *value, const char *p)
+{
+	char *next;
+	uint64_t val;
+
+	p = skip_white_spaces(p);
+	if (!isdigit(*p))
+		return -EINVAL;
+
+	val = strtoul(p, &next, 10);
+	if (p == next)
+		return -EINVAL;
+
+	p = next;
+	switch (*p) {
+	case 'T':
+		val *= 1024ULL;
+		/* fall through */
+	case 'G':
+		val *= 1024ULL;
+		/* fall through */
+	case 'M':
+		val *= 1024ULL;
+		/* fall through */
+	case 'k':
+	case 'K':
+		val *= 1024ULL;
+		p++;
+		break;
+	}
+
+	p = skip_white_spaces(p);
+	if (*p != '\0')
+		return -EINVAL;
+
+	*value = val;
+	return 0;
+}
+
+static int
+read_uint32(uint32_t *value, const char *p)
+{
+	uint64_t val = 0;
+	int ret = read_uint64(&val, p);
+
+	if (ret < 0)
+		return ret;
+
+	if (val > UINT32_MAX)
+		return -ERANGE;
+
+	*value = val;
+	return 0;
+}
+
+static int
+parse_multi_ss_id_str(char *s_str, uint32_t *n_ssp, uint32_t shaper_id[])
+{
+	uint32_t n_shared_shapers = 0, i = 0;
+	char *token;
+
+	/* First token: num of shared shapers */
+	token = strtok_r(s_str, PARSE_DELIMITER, &s_str);
+	if (token ==  NULL)
+		return -1;
+
+	if (read_uint32(&n_shared_shapers, token))
+		return -1;
+
+	/* Check: num of shared shaper */
+	if (n_shared_shapers >= MAX_NUM_SHARED_SHAPERS) {
+		printf(" Number of shared shapers exceed the max (error)\n");
+		return -1;
+	}
+
+	/* Parse shared shaper ids */
+	while (1) {
+		token = strtok_r(s_str, PARSE_DELIMITER, &s_str);
+		if ((token !=  NULL && n_shared_shapers == 0) ||
+			(token == NULL && i < n_shared_shapers))
+			return -1;
+
+		if (token == NULL)
+			break;
+
+		if (read_uint32(&shaper_id[i], token))
+			return -1;
+		i++;
+	}
+	*n_ssp = n_shared_shapers;
+
+	return 0;
+}
 /* *** Port TM Capability *** */
 struct cmd_show_port_tm_cap_result {
 	cmdline_fixed_string_t show;
@@ -1410,3 +1515,553 @@ cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile = {
 		NULL,
 	},
 };
+
+/* *** Add Port TM nonleaf node *** */
+struct cmd_add_port_tm_nonleaf_node_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t nonleaf;
+	cmdline_fixed_string_t node;
+	uint16_t port_id;
+	uint32_t node_id;
+	int32_t parent_node_id;
+	uint32_t priority;
+	uint32_t weight;
+	uint32_t level_id;
+	uint32_t shaper_profile_id;
+	uint32_t n_sp_priorities;
+	uint64_t stats_mask;
+	cmdline_multi_string_t multi_shared_shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_nonleaf =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, nonleaf, "nonleaf");
+cmdline_parse_token_string_t cmd_add_port_tm_nonleaf_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result, node, "node");
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_add_port_tm_nonleaf_node_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 node_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 parent_node_id, INT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 priority, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 weight, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 level_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 shaper_profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_n_sp_priorities =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 n_sp_priorities, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_nonleaf_node_stats_mask =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 stats_mask, UINT64);
+cmdline_parse_token_string_t
+	cmd_add_port_tm_nonleaf_node_multi_shared_shaper_id =
+	TOKEN_STRING_INITIALIZER(struct cmd_add_port_tm_nonleaf_node_result,
+		 multi_shared_shaper_id, TOKEN_STRING_MULTI);
+
+static void cmd_add_port_tm_nonleaf_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_nonleaf_node_result *res = parsed_result;
+	struct rte_tm_error error;
+	struct rte_tm_node_params np;
+	uint32_t *shared_shaper_id;
+	uint32_t parent_node_id, n_shared_shapers = 0;
+	char *s_str = res->multi_shared_shaper_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	memset(&np, 0, sizeof(struct rte_tm_node_params));
+
+	/* Node parameters */
+	if (res->parent_node_id < 0)
+		parent_node_id = UINT32_MAX;
+	else
+		parent_node_id = res->parent_node_id;
+
+	shared_shaper_id = (uint32_t *)malloc(MAX_NUM_SHARED_SHAPERS *
+		sizeof(uint32_t));
+	/* Parse multi shared shaper id string */
+	ret = parse_multi_ss_id_str(s_str, &n_shared_shapers, shared_shaper_id);
+	if (ret) {
+		printf(" Shared shapers params string parse error\n");
+		free(shared_shaper_id);
+		return;
+	}
+
+	np.shaper_profile_id = res->shaper_profile_id;
+	np.n_shared_shapers = n_shared_shapers;
+	if (np.n_shared_shapers)
+		np.shared_shaper_id = &shared_shaper_id[0];
+	else
+		np.shared_shaper_id = NULL;
+
+	np.nonleaf.n_sp_priorities = res->n_sp_priorities;
+	np.stats_mask = res->stats_mask;
+	np.nonleaf.wfq_weight_mode = NULL;
+
+	ret = rte_tm_node_add(port_id, res->node_id, parent_node_id,
+				res->priority, res->weight, res->level_id,
+				&np, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		free(shared_shaper_id);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_nonleaf_node = {
+	.f = cmd_add_port_tm_nonleaf_node_parsed,
+	.data = NULL,
+	.help_str = "Add port tm nonleaf node",
+	.tokens = {
+		(void *)&cmd_add_port_tm_nonleaf_node_add,
+		(void *)&cmd_add_port_tm_nonleaf_node_port,
+		(void *)&cmd_add_port_tm_nonleaf_node_tm,
+		(void *)&cmd_add_port_tm_nonleaf_node_nonleaf,
+		(void *)&cmd_add_port_tm_nonleaf_node_node,
+		(void *)&cmd_add_port_tm_nonleaf_node_port_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_node_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_parent_node_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_priority,
+		(void *)&cmd_add_port_tm_nonleaf_node_weight,
+		(void *)&cmd_add_port_tm_nonleaf_node_level_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_shaper_profile_id,
+		(void *)&cmd_add_port_tm_nonleaf_node_n_sp_priorities,
+		(void *)&cmd_add_port_tm_nonleaf_node_stats_mask,
+		(void *)&cmd_add_port_tm_nonleaf_node_multi_shared_shaper_id,
+		NULL,
+	},
+};
+
+/* *** Add Port TM leaf node *** */
+struct cmd_add_port_tm_leaf_node_result {
+	cmdline_fixed_string_t add;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t leaf;
+	cmdline_fixed_string_t node;
+	uint16_t port_id;
+	uint32_t node_id;
+	int32_t parent_node_id;
+	uint32_t priority;
+	uint32_t weight;
+	uint32_t level_id;
+	uint32_t shaper_profile_id;
+	uint32_t cman_mode;
+	uint32_t wred_profile_id;
+	uint64_t stats_mask;
+	cmdline_multi_string_t multi_shared_shaper_id;
+};
+
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_add =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, add, "add");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, port, "port");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_nonleaf =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, leaf, "leaf");
+cmdline_parse_token_string_t cmd_add_port_tm_leaf_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_add_port_tm_leaf_node_result, node, "node");
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 node_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 parent_node_id, INT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 priority, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 weight, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_level_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 level_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_shaper_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 shaper_profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_cman_mode =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 cman_mode, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_wred_profile_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 wred_profile_id, UINT32);
+cmdline_parse_token_num_t cmd_add_port_tm_leaf_node_stats_mask =
+	TOKEN_NUM_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 stats_mask, UINT64);
+cmdline_parse_token_string_t
+	cmd_add_port_tm_leaf_node_multi_shared_shaper_id =
+	TOKEN_STRING_INITIALIZER(struct cmd_add_port_tm_leaf_node_result,
+		 multi_shared_shaper_id, TOKEN_STRING_MULTI);
+
+static void cmd_add_port_tm_leaf_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_add_port_tm_leaf_node_result *res = parsed_result;
+	struct rte_tm_error error;
+	struct rte_tm_node_params np;
+	uint32_t *shared_shaper_id;
+	uint32_t parent_node_id, n_shared_shapers = 0;
+	portid_t port_id = res->port_id;
+	char *s_str = res->multi_shared_shaper_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	memset(&np, 0, sizeof(struct rte_tm_node_params));
+
+	/* Node parameters */
+	if (res->parent_node_id < 0)
+		parent_node_id = UINT32_MAX;
+	else
+		parent_node_id = res->parent_node_id;
+
+	shared_shaper_id = (uint32_t *)malloc(MAX_NUM_SHARED_SHAPERS *
+		sizeof(uint32_t));
+	/* Parse multi shared shaper id string */
+	ret = parse_multi_ss_id_str(s_str, &n_shared_shapers, shared_shaper_id);
+	if (ret) {
+		printf(" Shared shapers params string parse error\n");
+		free(shared_shaper_id);
+		return;
+	}
+
+	np.shaper_profile_id = res->shaper_profile_id;
+	np.n_shared_shapers = n_shared_shapers;
+
+	if (np.n_shared_shapers)
+		np.shared_shaper_id = &shared_shaper_id[0];
+	else
+		np.shared_shaper_id = NULL;
+
+	np.leaf.cman = res->cman_mode;
+	np.leaf.wred.wred_profile_id = res->wred_profile_id;
+	np.stats_mask = res->stats_mask;
+
+	ret = rte_tm_node_add(port_id, res->node_id, parent_node_id,
+				res->priority, res->weight, res->level_id,
+				&np, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		free(shared_shaper_id);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_add_port_tm_leaf_node = {
+	.f = cmd_add_port_tm_leaf_node_parsed,
+	.data = NULL,
+	.help_str = "Add port tm leaf node",
+	.tokens = {
+		(void *)&cmd_add_port_tm_leaf_node_add,
+		(void *)&cmd_add_port_tm_leaf_node_port,
+		(void *)&cmd_add_port_tm_leaf_node_tm,
+		(void *)&cmd_add_port_tm_leaf_node_nonleaf,
+		(void *)&cmd_add_port_tm_leaf_node_node,
+		(void *)&cmd_add_port_tm_leaf_node_port_id,
+		(void *)&cmd_add_port_tm_leaf_node_node_id,
+		(void *)&cmd_add_port_tm_leaf_node_parent_node_id,
+		(void *)&cmd_add_port_tm_leaf_node_priority,
+		(void *)&cmd_add_port_tm_leaf_node_weight,
+		(void *)&cmd_add_port_tm_leaf_node_level_id,
+		(void *)&cmd_add_port_tm_leaf_node_shaper_profile_id,
+		(void *)&cmd_add_port_tm_leaf_node_cman_mode,
+		(void *)&cmd_add_port_tm_leaf_node_wred_profile_id,
+		(void *)&cmd_add_port_tm_leaf_node_stats_mask,
+		(void *)&cmd_add_port_tm_leaf_node_multi_shared_shaper_id,
+		NULL,
+	},
+};
+
+/* *** Delete Port TM Node *** */
+struct cmd_del_port_tm_node_result {
+	cmdline_fixed_string_t del;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	uint16_t port_id;
+	uint32_t node_id;
+};
+
+cmdline_parse_token_string_t cmd_del_port_tm_node_del =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, del, "del");
+cmdline_parse_token_string_t cmd_del_port_tm_node_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, port, "port");
+cmdline_parse_token_string_t cmd_del_port_tm_node_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, tm, "tm");
+cmdline_parse_token_string_t cmd_del_port_tm_node_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_del_port_tm_node_result, node, "node");
+cmdline_parse_token_num_t cmd_del_port_tm_node_port_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_del_port_tm_node_result,
+		 port_id, UINT16);
+cmdline_parse_token_num_t cmd_del_port_tm_node_node_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_del_port_tm_node_result,
+		node_id, UINT32);
+
+static void cmd_del_port_tm_node_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_del_port_tm_node_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_delete(port_id, node_id, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_del_port_tm_node = {
+	.f = cmd_del_port_tm_node_parsed,
+	.data = NULL,
+	.help_str = "Delete port tm node",
+	.tokens = {
+		(void *)&cmd_del_port_tm_node_del,
+		(void *)&cmd_del_port_tm_node_port,
+		(void *)&cmd_del_port_tm_node_tm,
+		(void *)&cmd_del_port_tm_node_node,
+		(void *)&cmd_del_port_tm_node_port_id,
+		(void *)&cmd_del_port_tm_node_node_id,
+		NULL,
+	},
+};
+
+/* *** Update Port TM Node Parent *** */
+struct cmd_set_port_tm_node_parent_result {
+	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t node;
+	cmdline_fixed_string_t parent;
+	uint16_t port_id;
+	uint32_t node_id;
+	uint32_t parent_id;
+	uint32_t priority;
+	uint32_t weight;
+};
+
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_set =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, set, "set");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, port, "port");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, tm, "tm");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_node =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, node, "node");
+cmdline_parse_token_string_t cmd_set_port_tm_node_parent_parent =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, parent, "parent");
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, port_id, UINT16);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_node_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_set_port_tm_node_parent_result, node_id, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_parent_id =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		parent_id, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_priority =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		priority, UINT32);
+cmdline_parse_token_num_t cmd_set_port_tm_node_parent_weight =
+	TOKEN_NUM_INITIALIZER(struct cmd_set_port_tm_node_parent_result,
+		weight, UINT32);
+
+static void cmd_set_port_tm_node_parent_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_set_port_tm_node_parent_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t node_id = res->node_id;
+	uint32_t parent_id = res->parent_id;
+	uint32_t priority = res->priority;
+	uint32_t weight = res->weight;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (!port_is_started(port_id)) {
+		printf(" Port %u not started (error)\n", port_id);
+		return;
+	}
+
+	ret = rte_tm_node_parent_update(port_id, node_id,
+		parent_id, priority, weight, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_set_port_tm_node_parent = {
+	.f = cmd_set_port_tm_node_parent_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node parent",
+	.tokens = {
+		(void *)&cmd_set_port_tm_node_parent_set,
+		(void *)&cmd_set_port_tm_node_parent_port,
+		(void *)&cmd_set_port_tm_node_parent_tm,
+		(void *)&cmd_set_port_tm_node_parent_node,
+		(void *)&cmd_set_port_tm_node_parent_parent,
+		(void *)&cmd_set_port_tm_node_parent_port_id,
+		(void *)&cmd_set_port_tm_node_parent_node_id,
+		(void *)&cmd_set_port_tm_node_parent_parent_id,
+		(void *)&cmd_set_port_tm_node_parent_priority,
+		(void *)&cmd_set_port_tm_node_parent_weight,
+		NULL,
+	},
+};
+
+/* *** Port TM Hierarchy Commit *** */
+struct cmd_port_tm_hierarchy_commit_result {
+	cmdline_fixed_string_t port;
+	cmdline_fixed_string_t tm;
+	cmdline_fixed_string_t hierarchy;
+	cmdline_fixed_string_t commit;
+	uint16_t port_id;
+	cmdline_fixed_string_t clean_on_fail;
+};
+
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_port =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, port, "port");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_tm =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, tm, "tm");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_hierarchy =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result,
+			hierarchy, "hierarchy");
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_commit =
+	TOKEN_STRING_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result, commit, "commit");
+cmdline_parse_token_num_t cmd_port_tm_hierarchy_commit_port_id =
+	TOKEN_NUM_INITIALIZER(
+		struct cmd_port_tm_hierarchy_commit_result,
+			port_id, UINT16);
+cmdline_parse_token_string_t cmd_port_tm_hierarchy_commit_clean_on_fail =
+	TOKEN_STRING_INITIALIZER(struct cmd_port_tm_hierarchy_commit_result,
+		 clean_on_fail, "yes#no");
+
+static void cmd_port_tm_hierarchy_commit_parsed(void *parsed_result,
+	__attribute__((unused)) struct cmdline *cl,
+	__attribute__((unused)) void *data)
+{
+	struct cmd_port_tm_hierarchy_commit_result *res = parsed_result;
+	struct rte_tm_error error;
+	uint32_t clean_on_fail;
+	portid_t port_id = res->port_id;
+	int ret;
+
+	if (port_id_is_invalid(port_id, ENABLED_WARN))
+		return;
+
+	/* Port status */
+	if (port_is_started(port_id)) {
+		printf(" Port %u not stopped (error)\n", port_id);
+		return;
+	}
+
+	if (strcmp(res->clean_on_fail, "yes") == 0)
+		clean_on_fail = 1;
+	else
+		clean_on_fail = 0;
+
+	ret = rte_tm_hierarchy_commit(port_id, clean_on_fail, &error);
+	if (ret != 0) {
+		print_err_msg(&error);
+		return;
+	}
+}
+
+cmdline_parse_inst_t cmd_port_tm_hierarchy_commit = {
+	.f = cmd_port_tm_hierarchy_commit_parsed,
+	.data = NULL,
+	.help_str = "Set port tm node shaper profile",
+	.tokens = {
+		(void *)&cmd_port_tm_hierarchy_commit_port,
+		(void *)&cmd_port_tm_hierarchy_commit_tm,
+		(void *)&cmd_port_tm_hierarchy_commit_hierarchy,
+		(void *)&cmd_port_tm_hierarchy_commit_commit,
+		(void *)&cmd_port_tm_hierarchy_commit_port_id,
+		(void *)&cmd_port_tm_hierarchy_commit_clean_on_fail,
+		NULL,
+	},
+};
diff --git a/app/test-pmd/cmdline_tm.h b/app/test-pmd/cmdline_tm.h
index 5ed9de0..9d5fdf0 100644
--- a/app/test-pmd/cmdline_tm.h
+++ b/app/test-pmd/cmdline_tm.h
@@ -47,5 +47,10 @@ extern cmdline_parse_inst_t cmd_del_port_tm_node_shared_shaper;
 extern cmdline_parse_inst_t cmd_add_port_tm_node_wred_profile;
 extern cmdline_parse_inst_t cmd_del_port_tm_node_wred_profile;
 extern cmdline_parse_inst_t cmd_set_port_tm_node_shaper_profile;
+extern cmdline_parse_inst_t cmd_add_port_tm_nonleaf_node;
+extern cmdline_parse_inst_t cmd_add_port_tm_leaf_node;
+extern cmdline_parse_inst_t cmd_del_port_tm_node;
+extern cmdline_parse_inst_t cmd_set_port_tm_node_parent;
+extern cmdline_parse_inst_t cmd_port_tm_hierarchy_commit;
 
 #endif /* _CMDLINE_TM_H_ */
-- 
2.9.3

^ permalink raw reply related	[flat|nested] 49+ messages in thread

* Re: [PATCH v10 1/3] app/test-pmd: add CLI for TM capability and stats
  2017-10-16 18:55                   ` [PATCH v10 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
  2017-10-16 18:55                     ` [PATCH v10 2/3] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
  2017-10-16 18:55                     ` [PATCH v10 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
@ 2017-10-17  8:44                     ` Wu, Jingjing
  2017-10-20 14:08                       ` Dumitrescu, Cristian
  2 siblings, 1 reply; 49+ messages in thread
From: Wu, Jingjing @ 2017-10-17  8:44 UTC (permalink / raw)
  To: Singh, Jasvinder, dev; +Cc: Dumitrescu, Cristian, Pei, Yulong



> -----Original Message-----
> From: Singh, Jasvinder
> Sent: Tuesday, October 17, 2017 2:55 AM
> To: dev@dpdk.org
> Cc: Dumitrescu, Cristian <cristian.dumitrescu@intel.com>; Wu, Jingjing
> <jingjing.wu@intel.com>; Pei, Yulong <yulong.pei@intel.com>
> Subject: [PATCH v10 1/3] app/test-pmd: add CLI for TM capability and stats
> 
> Add following CLIs to testpmd application for device traffic management;
> - commands to display TM capability information.
>   (per port, per hierarchy level and per hierarchy node)
> - command to display hiearchy node type
> - stats collection
> 
> Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> Tested-by: Yulong Pei <yulong.pei@intel.com>
> Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
> ---

Series Acked-by: Jingjing Wu <jingjing.wu@intel.com>

Thanks
Jingjing

^ permalink raw reply	[flat|nested] 49+ messages in thread

* Re: [PATCH v10 1/3] app/test-pmd: add CLI for TM capability and stats
  2017-10-17  8:44                     ` [PATCH v10 1/3] app/test-pmd: add CLI for TM capability and stats Wu, Jingjing
@ 2017-10-20 14:08                       ` Dumitrescu, Cristian
  0 siblings, 0 replies; 49+ messages in thread
From: Dumitrescu, Cristian @ 2017-10-20 14:08 UTC (permalink / raw)
  To: Wu, Jingjing, Singh, Jasvinder, dev; +Cc: Pei, Yulong

> 
> > -----Original Message-----
> > From: Singh, Jasvinder
> > Sent: Tuesday, October 17, 2017 2:55 AM
> > To: dev@dpdk.org
> > Cc: Dumitrescu, Cristian <cristian.dumitrescu@intel.com>; Wu, Jingjing
> > <jingjing.wu@intel.com>; Pei, Yulong <yulong.pei@intel.com>
> > Subject: [PATCH v10 1/3] app/test-pmd: add CLI for TM capability and stats
> >
> > Add following CLIs to testpmd application for device traffic management;
> > - commands to display TM capability information.
> >   (per port, per hierarchy level and per hierarchy node)
> > - command to display hiearchy node type
> > - stats collection
> >
> > Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> > Tested-by: Yulong Pei <yulong.pei@intel.com>
> > Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
> > ---
> 
> Series Acked-by: Jingjing Wu <jingjing.wu@intel.com>
> 
> Thanks
> Jingjing

Series applied to next-tm tree, thanks!

^ permalink raw reply	[flat|nested] 49+ messages in thread

end of thread, other threads:[~2017-10-20 14:08 UTC | newest]

Thread overview: 49+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-08-22 17:02 [PATCH 1/2] app/testpmd: add traffic management forwarding mode Jasvinder Singh
2017-08-22 17:02 ` [PATCH 2/2] app/testpmd: add CLI for tm mode Jasvinder Singh
2017-09-14 11:53 ` [PATCH v2 1/2] app/testpmd: add traffic management forwarding mode Jasvinder Singh
2017-09-14 11:53   ` [PATCH v2 2/2] app/testpmd: add CLI for tm mode Jasvinder Singh
2017-09-18 14:03     ` De Lara Guarch, Pablo
2017-09-19 15:06       ` Singh, Jasvinder
2017-09-18 13:54   ` [PATCH v2 1/2] app/testpmd: add traffic management forwarding mode De Lara Guarch, Pablo
2017-09-19 15:04     ` Singh, Jasvinder
2017-09-20  9:56   ` [PATCH v3 1/5] " Jasvinder Singh
2017-09-20  9:56     ` [PATCH v3 2/5] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
2017-09-20  9:56     ` [PATCH v3 3/5] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
2017-09-20  9:56     ` [PATCH v3 4/5] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
2017-09-20  9:56     ` [PATCH v3 5/5] app/test-pmd: add CLI for TM packet classification Jasvinder Singh
2017-09-22 16:35     ` [PATCH v4 1/5] app/testpmd: add traffic management forwarding mode Jasvinder Singh
2017-09-22 16:35       ` [PATCH v4 2/5] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
2017-09-29 12:38         ` [PATCH v5 1/3] " Jasvinder Singh
2017-09-29 12:38           ` [PATCH v5 2/3] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
2017-09-29 12:38           ` [PATCH v5 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
2017-10-09 19:07           ` [PATCH v6 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
2017-10-09 19:07             ` [PATCH v6 2/3] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
2017-10-09 19:07             ` [PATCH v6 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
2017-10-11  8:40               ` Pei, Yulong
2017-10-11  8:51                 ` Singh, Jasvinder
2017-10-11  9:26             ` [PATCH v7 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
2017-10-11  9:26               ` [PATCH v7 2/3] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
2017-10-13  2:33                 ` Wu, Jingjing
2017-10-13  8:58                   ` Singh, Jasvinder
2017-10-11  9:26               ` [PATCH v7 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
2017-10-13  2:58                 ` Wu, Jingjing
2017-10-13 10:50                   ` Singh, Jasvinder
2017-10-12 20:55               ` [PATCH v7 1/3] app/test-pmd: add CLI for TM capability and stats Thomas Monjalon
2017-10-13  2:34               ` Wu, Jingjing
2017-10-13  6:22               ` Pei, Yulong
2017-10-13 16:59               ` [PATCH v8 " Jasvinder Singh
2017-10-13 16:59                 ` [PATCH v8 2/3] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
2017-10-13 17:00                 ` [PATCH v8 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
2017-10-14 10:20                 ` [PATCH v9 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
2017-10-14 10:20                   ` [PATCH v9 2/3] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
2017-10-14 10:20                   ` [PATCH v9 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
2017-10-16 10:18                     ` Wu, Jingjing
2017-10-16 18:18                       ` Singh, Jasvinder
2017-10-16 18:55                   ` [PATCH v10 1/3] app/test-pmd: add CLI for TM capability and stats Jasvinder Singh
2017-10-16 18:55                     ` [PATCH v10 2/3] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
2017-10-16 18:55                     ` [PATCH v10 3/3] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
2017-10-17  8:44                     ` [PATCH v10 1/3] app/test-pmd: add CLI for TM capability and stats Wu, Jingjing
2017-10-20 14:08                       ` Dumitrescu, Cristian
2017-09-22 16:35       ` [PATCH v4 3/5] app/test-pmd: add CLI for shaper and wred profiles Jasvinder Singh
2017-09-22 16:35       ` [PATCH v4 4/5] app/test-pmd: add CLI for TM nodes and hierarchy commit Jasvinder Singh
2017-09-22 16:35       ` [PATCH v4 5/5] app/test-pmd: add CLI for TM packet classification Jasvinder Singh

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.