DPDK patches and discussions
 help / color / mirror / Atom feed
* [dpdk-dev] [RFC PATCH 0/2] Enable dyynamic configuration of subport bandwidth profile
@ 2020-07-15 18:27 Savinay Dharmappa
  2020-07-15 18:27 ` [dpdk-dev] [RFC PATCH 1/2] sched: add dynamic config " Savinay Dharmappa
                   ` (2 more replies)
  0 siblings, 3 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-07-15 18:27 UTC (permalink / raw)
  To: savinay.dharmappa, jasvinder.singh, dev

DPDK sched library allows runtime configuration of the pipe profiles to the
pipes of the subport once scheduler hierarchy is constructed. However, to
change the subport level bandwidth, existing hierarchy needs to be dismantled
and whole process of building hierarchy under subport nodes needs to be
repeated which might result in router downtime. Furthermore, due to lack of
dynamic configuration of the subport bandwidth profile configuration
(shaper and Traffic class rates), the user application is unable to dynamically
re-distribute the excess-bandwidth of one subport among other subports in the
scheduler hierarchy. Therefore, it is also not possible to adjust the subport
bandwidth profile in sync with dynamic changes in pipe profiles of subscribers
who want to consume higher bandwidth opportunistically. 

This RFC proposes dynamic configuration of the subport bandwidth profile to
overcome the runtime situation when group of subscribers are not using the
allotted bandwidth and dynamic bandwidth re-distribution is needed the without
making any structural changes in the hierarchy.

The implementation work includes refactoring the existing data structures
defined for port and subport level, new APIs for adding subport level
bandwidth profiles that can be used in runtime which causes API/ABI change.
Therefore, deprecation notice will be sent out soon.

Savinay Dharmappa (2):
  sched: add dynamic config of subport bandwidth profile
  example/qos_sched: subport bandwidth dynmaic conf

 examples/qos_sched/cfg_file.c          | 158 ++++++-----
 examples/qos_sched/cfg_file.h          |   4 +
 examples/qos_sched/init.c              |  24 +-
 examples/qos_sched/main.h              |   1 +
 examples/qos_sched/profile.cfg         |   3 +
 lib/librte_sched/rte_sched.c           | 486 ++++++++++++++++++++++++---------
 lib/librte_sched/rte_sched.h           |  82 +++++-
 lib/librte_sched/rte_sched_version.map |   2 +
 8 files changed, 544 insertions(+), 216 deletions(-)

-- 
2.7.4


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

* [dpdk-dev] [RFC PATCH 1/2] sched: add dynamic config of subport bandwidth profile
  2020-07-15 18:27 [dpdk-dev] [RFC PATCH 0/2] Enable dyynamic configuration of subport bandwidth profile Savinay Dharmappa
@ 2020-07-15 18:27 ` Savinay Dharmappa
  2020-07-16  8:14   ` Singh, Jasvinder
                     ` (2 more replies)
  2020-07-15 18:27 ` [dpdk-dev] [RFC PATCH 2/2] example/qos_sched: subport bandwidth profile config Savinay Dharmappa
  2020-07-16  8:14 ` [dpdk-dev] [RFC PATCH 0/2] Enable dyynamic configuration of subport bandwidth profile Singh, Jasvinder
  2 siblings, 3 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-07-15 18:27 UTC (permalink / raw)
  To: savinay.dharmappa, jasvinder.singh, dev

This patch modifies the subport level data structures
and add new API to allow dynamic configuration of the
subport bandwidth profile.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c           | 486 ++++++++++++++++++++++++---------
 lib/librte_sched/rte_sched.h           |  82 +++++-
 lib/librte_sched/rte_sched_version.map |   2 +
 3 files changed, 424 insertions(+), 146 deletions(-)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index c0983dd..5bb0d2b 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -2,6 +2,7 @@
  * Copyright(c) 2010-2014 Intel Corporation
  */
 
+#include <stdint.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -101,6 +102,16 @@ enum grinder_state {
 	e_GRINDER_READ_MBUF
 };
 
+struct rte_sched_subport_profile {
+	/* Token bucket (TB) */
+	uint64_t tb_period;
+	uint64_t tb_credits_per_period;
+	uint64_t tb_size;
+
+	uint64_t tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+	uint64_t tc_period;
+};
+
 struct rte_sched_grinder {
 	/* Pipe cache */
 	uint16_t pcache_qmask[RTE_SCHED_GRINDER_PCACHE_SIZE];
@@ -113,6 +124,7 @@ struct rte_sched_grinder {
 	uint32_t productive;
 	uint32_t pindex;
 	struct rte_sched_subport *subport;
+	struct rte_sched_subport_profile *subport_params;
 	struct rte_sched_pipe *pipe;
 	struct rte_sched_pipe_profile *pipe_params;
 
@@ -139,18 +151,13 @@ struct rte_sched_grinder {
 };
 
 struct rte_sched_subport {
-	/* Token bucket (TB) */
+
 	uint64_t tb_time; /* time of last update */
-	uint64_t tb_period;
-	uint64_t tb_credits_per_period;
-	uint64_t tb_size;
 	uint64_t tb_credits;
 
 	/* Traffic classes (TCs) */
 	uint64_t tc_time; /* time of next update */
-	uint64_t tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
 	uint64_t tc_credits[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
-	uint64_t tc_period;
 
 	/* TC oversubscription */
 	uint64_t tc_ov_wm;
@@ -164,6 +171,8 @@ struct rte_sched_subport {
 	/* Statistics */
 	struct rte_sched_subport_stats stats __rte_cache_aligned;
 
+	/* subport profile flag */
+	uint32_t profile;
 	/* Subport pipes */
 	uint32_t n_pipes_per_subport_enabled;
 	uint32_t n_pipe_profiles;
@@ -212,6 +221,8 @@ struct rte_sched_port {
 	uint16_t pipe_queue[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
 	uint8_t pipe_tc[RTE_SCHED_QUEUES_PER_PIPE];
 	uint8_t tc_queue[RTE_SCHED_QUEUES_PER_PIPE];
+	uint32_t n_subport_profiles;
+	uint32_t n_max_subport_profiles;
 	uint64_t rate;
 	uint32_t mtu;
 	uint32_t frame_overhead;
@@ -229,6 +240,7 @@ struct rte_sched_port {
 	uint32_t subport_id;
 
 	/* Large data structures */
+	struct rte_sched_subport_profile *subport_profiles;
 	struct rte_sched_subport *subports[0] __rte_cache_aligned;
 } __rte_cache_aligned;
 
@@ -375,8 +387,60 @@ pipe_profile_check(struct rte_sched_pipe_params *params,
 }
 
 static int
+subport_profile_check(struct rte_sched_subport_profile_params *params,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	/* Check user parameters */
+	if (params == NULL) {
+		RTE_LOG(ERR, SCHED,
+			"%s: Incorrect value for parameter params\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tb_rate == 0 || params->tb_rate > rate) {
+		RTE_LOG(ERR, SCHED,
+			"%s: Incorrect value for tb rate\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tb_size == 0) {
+		RTE_LOG(ERR, SCHED,
+			"%s: Incorrect value for tb size\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
+		uint64_t tc_rate = params->tc_rate[i];
+
+		if (tc_rate == 0 || (tc_rate > params->tb_rate)) {
+			RTE_LOG(ERR, SCHED,
+				"%s: Incorrect value for tc rate\n", __func__);
+			return -EINVAL;
+		}
+	}
+
+	if (params->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
+		RTE_LOG(ERR, SCHED,
+			"%s: Incorrect tc rate(best effort)\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tc_period == 0) {
+		RTE_LOG(ERR, SCHED,
+			"%s: Incorrect value for tc period\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
 rte_sched_port_check_params(struct rte_sched_port_params *params)
 {
+	uint32_t i;
+
 	if (params == NULL) {
 		RTE_LOG(ERR, SCHED,
 			"%s: Incorrect value for parameter params\n", __func__);
@@ -413,6 +477,29 @@ rte_sched_port_check_params(struct rte_sched_port_params *params)
 		return -EINVAL;
 	}
 
+	if (params->subport_profiles == NULL ||
+		params->n_subport_profiles == 0 ||
+		params->n_max_subport_profiles == 0 ||
+		params->n_subport_profiles > params->n_max_subport_profiles) {
+		RTE_LOG(ERR, SCHED,
+		"%s: Incorrect value for subport profiles\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < params->n_subport_profiles; i++) {
+		struct rte_sched_subport_profile_params *p =
+						params->subport_profiles + i;
+		int status;
+
+		status = subport_profile_check(p, params->rate);
+		if (status != 0) {
+			RTE_LOG(ERR, SCHED,
+			"%s: subport profile check failed(%d)\n",
+			__func__, status);
+			return -EINVAL;
+		}
+	}
+
 	/* n_pipes_per_subport: non-zero, power of 2 */
 	if (params->n_pipes_per_subport == 0 ||
 	    !rte_is_power_of_2(params->n_pipes_per_subport)) {
@@ -554,6 +641,42 @@ rte_sched_port_log_pipe_profile(struct rte_sched_subport *subport, uint32_t i)
 		p->wrr_cost[0], p->wrr_cost[1], p->wrr_cost[2], p->wrr_cost[3]);
 }
 
+static void
+rte_sched_port_log_subport_profile(struct rte_sched_port *port, uint32_t i)
+{
+	struct rte_sched_subport_profile *p = port->subport_profiles + i;
+
+	RTE_LOG(DEBUG, SCHED, "Low level config for subport profile %u:\n"
+	"Token bucket: period = %"PRIu64", credits per period = %"PRIu64",\
+	size = %"PRIu64"\n"
+	"Traffic classes: period = %"PRIu64",\n"
+	"credits per period = [%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
+	" %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
+	" %"PRIu64", %"PRIu64", %"PRIu64"]\n",
+	i,
+
+	/* Token bucket */
+	p->tb_period,
+	p->tb_credits_per_period,
+	p->tb_size,
+
+	/* Traffic classes */
+	p->tc_period,
+	p->tc_credits_per_period[0],
+	p->tc_credits_per_period[1],
+	p->tc_credits_per_period[2],
+	p->tc_credits_per_period[3],
+	p->tc_credits_per_period[4],
+	p->tc_credits_per_period[5],
+	p->tc_credits_per_period[6],
+	p->tc_credits_per_period[7],
+	p->tc_credits_per_period[8],
+	p->tc_credits_per_period[9],
+	p->tc_credits_per_period[10],
+	p->tc_credits_per_period[11],
+	p->tc_credits_per_period[12]);
+}
+
 static inline uint64_t
 rte_sched_time_ms_to_bytes(uint64_t time_ms, uint64_t rate)
 {
@@ -623,6 +746,37 @@ rte_sched_pipe_profile_convert(struct rte_sched_subport *subport,
 }
 
 static void
+rte_sched_subport_profile_convert(struct rte_sched_subport_profile_params *src,
+	struct rte_sched_subport_profile *dst,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	/* Token Bucket */
+	if (src->tb_rate == rate) {
+		dst->tb_credits_per_period = 1;
+		dst->tb_period = 1;
+	} else {
+		double tb_rate = (double) src->tb_rate
+				/ (double) rate;
+		double d = RTE_SCHED_TB_RATE_CONFIG_ERR;
+
+		rte_approx_64(tb_rate, d, &dst->tb_credits_per_period,
+			&dst->tb_period);
+	}
+
+	dst->tb_size = src->tb_size;
+
+	/* Traffic Classes */
+	dst->tc_period = rte_sched_time_ms_to_bytes(src->tc_period, rate);
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		dst->tc_credits_per_period[i]
+			= rte_sched_time_ms_to_bytes(src->tc_period,
+				src->tc_rate[i]);
+}
+
+static void
 rte_sched_subport_config_pipe_profile_table(struct rte_sched_subport *subport,
 	struct rte_sched_subport_params *params, uint32_t rate)
 {
@@ -646,6 +800,24 @@ rte_sched_subport_config_pipe_profile_table(struct rte_sched_subport *subport,
 	}
 }
 
+static void
+rte_sched_port_config_subport_profile_table(struct rte_sched_port *port,
+	struct rte_sched_port_params *params,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	for (i = 0; i < port->n_subport_profiles; i++) {
+		struct rte_sched_subport_profile_params *src
+				= params->subport_profiles + i;
+		struct rte_sched_subport_profile *dst
+				= port->subport_profiles + i;
+
+		rte_sched_subport_profile_convert(src, dst, rate);
+		rte_sched_port_log_subport_profile(port, i);
+	}
+}
+
 static int
 rte_sched_subport_check_params(struct rte_sched_subport_params *params,
 	uint32_t n_max_pipes_per_subport,
@@ -660,18 +832,6 @@ rte_sched_subport_check_params(struct rte_sched_subport_params *params,
 		return -EINVAL;
 	}
 
-	if (params->tb_rate == 0 || params->tb_rate > rate) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect value for tb rate\n", __func__);
-		return -EINVAL;
-	}
-
-	if (params->tb_size == 0) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect value for tb size\n", __func__);
-		return -EINVAL;
-	}
-
 	/* qsize: if non-zero, power of 2,
 	 * no bigger than 32K (due to 16-bit read/write pointers)
 	 */
@@ -685,32 +845,12 @@ rte_sched_subport_check_params(struct rte_sched_subport_params *params,
 		}
 	}
 
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
-		uint64_t tc_rate = params->tc_rate[i];
-		uint16_t qsize = params->qsize[i];
-
-		if ((qsize == 0 && tc_rate != 0) ||
-			(qsize != 0 && tc_rate == 0) ||
-			(tc_rate > params->tb_rate)) {
-			RTE_LOG(ERR, SCHED,
-				"%s: Incorrect value for tc rate\n", __func__);
-			return -EINVAL;
-		}
-	}
-
-	if (params->qsize[RTE_SCHED_TRAFFIC_CLASS_BE] == 0 ||
-		params->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
+	if (params->qsize[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
 		RTE_LOG(ERR, SCHED,
 			"%s: Incorrect qsize or tc rate(best effort)\n", __func__);
 		return -EINVAL;
 	}
 
-	if (params->tc_period == 0) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect value for tc period\n", __func__);
-		return -EINVAL;
-	}
-
 	/* n_pipes_per_subport: non-zero, power of 2 */
 	if (params->n_pipes_per_subport_enabled == 0 ||
 		params->n_pipes_per_subport_enabled > n_max_pipes_per_subport ||
@@ -792,7 +932,7 @@ struct rte_sched_port *
 rte_sched_port_config(struct rte_sched_port_params *params)
 {
 	struct rte_sched_port *port = NULL;
-	uint32_t size0, size1;
+	uint32_t size0, size1, size2;
 	uint32_t cycles_per_byte;
 	uint32_t i, j;
 	int status;
@@ -807,10 +947,21 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 
 	size0 = sizeof(struct rte_sched_port);
 	size1 = params->n_subports_per_port * sizeof(struct rte_sched_subport *);
+	size2 = params->n_max_subport_profiles *
+		sizeof(struct rte_sched_subport_profile);
 
 	/* Allocate memory to store the data structures */
-	port = rte_zmalloc_socket("qos_params", size0 + size1, RTE_CACHE_LINE_SIZE,
-		params->socket);
+	port = rte_zmalloc_socket("qos_params", size0 + size1,
+				 RTE_CACHE_LINE_SIZE, params->socket);
+	if (port == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: Memory allocation fails\n", __func__);
+
+		return NULL;
+	}
+
+	/* Allocate memory to store the subport profile */
+	port->subport_profiles  = rte_zmalloc_socket("subport_profile", size2,
+					RTE_CACHE_LINE_SIZE, params->socket);
 	if (port == NULL) {
 		RTE_LOG(ERR, SCHED, "%s: Memory allocation fails\n", __func__);
 
@@ -819,6 +970,8 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 
 	/* User parameters */
 	port->n_subports_per_port = params->n_subports_per_port;
+	port->n_subport_profiles = params->n_subport_profiles;
+	port->n_max_subport_profiles = params->n_max_subport_profiles;
 	port->n_pipes_per_subport = params->n_pipes_per_subport;
 	port->n_pipes_per_subport_log2 =
 			__builtin_ctz(params->n_pipes_per_subport);
@@ -849,6 +1002,9 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 	port->time_cpu_bytes = 0;
 	port->time = 0;
 
+	/* Subport profile table */
+	rte_sched_port_config_subport_profile_table(port, params, port->rate);
+
 	cycles_per_byte = (rte_get_tsc_hz() << RTE_SCHED_TIME_SHIFT)
 		/ params->rate;
 	port->inv_cycles_per_byte = rte_reciprocal_value(cycles_per_byte);
@@ -907,48 +1063,6 @@ rte_sched_port_free(struct rte_sched_port *port)
 }
 
 static void
-rte_sched_port_log_subport_config(struct rte_sched_port *port, uint32_t i)
-{
-	struct rte_sched_subport *s = port->subports[i];
-
-	RTE_LOG(DEBUG, SCHED, "Low level config for subport %u:\n"
-		"	Token bucket: period = %"PRIu64", credits per period = %"PRIu64
-		", size = %"PRIu64"\n"
-		"	Traffic classes: period = %"PRIu64"\n"
-		"	credits per period = [%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
-		", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
-		", %"PRIu64", %"PRIu64", %"PRIu64"]\n"
-		"	Best effort traffic class oversubscription: wm min = %"PRIu64
-		", wm max = %"PRIu64"\n",
-		i,
-
-		/* Token bucket */
-		s->tb_period,
-		s->tb_credits_per_period,
-		s->tb_size,
-
-		/* Traffic classes */
-		s->tc_period,
-		s->tc_credits_per_period[0],
-		s->tc_credits_per_period[1],
-		s->tc_credits_per_period[2],
-		s->tc_credits_per_period[3],
-		s->tc_credits_per_period[4],
-		s->tc_credits_per_period[5],
-		s->tc_credits_per_period[6],
-		s->tc_credits_per_period[7],
-		s->tc_credits_per_period[8],
-		s->tc_credits_per_period[9],
-		s->tc_credits_per_period[10],
-		s->tc_credits_per_period[11],
-		s->tc_credits_per_period[12],
-
-		/* Best effort traffic class oversubscription */
-		s->tc_ov_wm_min,
-		s->tc_ov_wm_max);
-}
-
-static void
 rte_sched_free_memory(struct rte_sched_port *port, uint32_t n_subports)
 {
 	uint32_t i;
@@ -1021,33 +1135,7 @@ rte_sched_subport_config(struct rte_sched_port *port,
 	/* Port */
 	port->subports[subport_id] = s;
 
-	/* Token Bucket (TB) */
-	if (params->tb_rate == port->rate) {
-		s->tb_credits_per_period = 1;
-		s->tb_period = 1;
-	} else {
-		double tb_rate = ((double) params->tb_rate) / ((double) port->rate);
-		double d = RTE_SCHED_TB_RATE_CONFIG_ERR;
-
-		rte_approx_64(tb_rate, d, &s->tb_credits_per_period, &s->tb_period);
-	}
-
-	s->tb_size = params->tb_size;
 	s->tb_time = port->time;
-	s->tb_credits = s->tb_size / 2;
-
-	/* Traffic Classes (TCs) */
-	s->tc_period = rte_sched_time_ms_to_bytes(params->tc_period, port->rate);
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
-		if (params->qsize[i])
-			s->tc_credits_per_period[i]
-				= rte_sched_time_ms_to_bytes(params->tc_period,
-					params->tc_rate[i]);
-	}
-	s->tc_time = port->time + s->tc_period;
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-		if (params->qsize[i])
-			s->tc_credits[i] = s->tc_credits_per_period[i];
 
 	/* compile time checks */
 	RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS == 0);
@@ -1137,8 +1225,6 @@ rte_sched_subport_config(struct rte_sched_port *port,
 #ifdef RTE_SCHED_SUBPORT_TC_OV
 	/* TC oversubscription */
 	s->tc_ov_wm_min = port->mtu;
-	s->tc_ov_wm_max = rte_sched_time_ms_to_bytes(params->tc_period,
-						     s->pipe_tc_be_rate_max);
 	s->tc_ov_wm = s->tc_ov_wm_max;
 	s->tc_ov_period_id = 0;
 	s->tc_ov = 0;
@@ -1146,7 +1232,54 @@ rte_sched_subport_config(struct rte_sched_port *port,
 	s->tc_ov_rate = 0;
 #endif
 
-	rte_sched_port_log_subport_config(port, subport_id);
+	return 0;
+}
+
+int
+rte_sched_subport_profile_config(struct rte_sched_port *port,
+	uint32_t subport_id,
+	uint32_t profile_id)
+{
+	int i;
+	struct rte_sched_subport_profile *params;
+	uint32_t n_subports = subport_id + 1;
+	struct rte_sched_subport *s;
+
+	if (port == NULL) {
+		RTE_LOG(ERR, SCHED,
+			"%s: Incorrect value for parameter port\n", __func__);
+		return -EINVAL;
+	}
+
+	if (subport_id >= port->n_subports_per_port) {
+		RTE_LOG(ERR, SCHED,
+			"%s: Incorrect value for parameter subport id\n", __func__);
+
+		rte_sched_free_memory(port, n_subports);
+		return -EINVAL;
+	}
+
+	params =  port->subport_profiles + profile_id;
+
+	s = port->subports[subport_id];
+
+	s->tb_credits = params->tb_size / 2;
+
+	s->tc_time = port->time + params->tc_period;
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		if (s->qsize[i])
+			s->tc_credits[i] = params->tc_credits_per_period[i];
+		else
+			params->tc_credits_per_period[i] = 0;
+
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+	s->tc_ov_wm_max = rte_sched_time_ms_to_bytes(params->tc_period,
+						     s->pipe_tc_be_rate_max);
+#endif
+	s->profile = profile_id;
+
+	rte_sched_port_log_subport_profile(port, profile_id);
 
 	return 0;
 }
@@ -1158,6 +1291,7 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 	int32_t pipe_profile)
 {
 	struct rte_sched_subport *s;
+	struct rte_sched_subport_profile *sp;
 	struct rte_sched_pipe *p;
 	struct rte_sched_pipe_profile *params;
 	uint32_t n_subports = subport_id + 1;
@@ -1198,14 +1332,16 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 		return -EINVAL;
 	}
 
+	sp = port->subport_profiles + s->profile;
+
 	/* Handle the case when pipe already has a valid configuration */
 	p = s->pipe + pipe_id;
 	if (p->tb_time) {
 		params = s->pipe_profiles + p->profile;
 
 		double subport_tc_be_rate =
-			(double) s->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
-			/ (double) s->tc_period;
+		(double) sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
+		/ (double) sp->tc_period;
 		double pipe_tc_be_rate =
 			(double) params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
 			/ (double) params->tc_period;
@@ -1247,8 +1383,8 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 	{
 		/* Subport best effort tc oversubscription */
 		double subport_tc_be_rate =
-			(double) s->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
-			/ (double) s->tc_period;
+		(double) sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
+			/ (double) sp->tc_period;
 		double pipe_tc_be_rate =
 			(double) params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
 			/ (double) params->tc_period;
@@ -1260,8 +1396,9 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 
 		if (s->tc_ov != tc_be_ov) {
 			RTE_LOG(DEBUG, SCHED,
-				"Subport %u Best effort TC oversubscription is ON (%.4lf < %.4lf)\n",
-				subport_id, subport_tc_be_rate, s->tc_ov_rate);
+			"Subport %u Best effort TC oversubscription is ON \
+			(%.4lf < %.4lf)\n",
+			subport_id, subport_tc_be_rate, s->tc_ov_rate);
 		}
 		p->tc_ov_period_id = s->tc_ov_period_id;
 		p->tc_ov_credits = s->tc_ov_wm;
@@ -1335,6 +1472,72 @@ rte_sched_subport_pipe_profile_add(struct rte_sched_port *port,
 	return 0;
 }
 
+int
+rte_sched_port_subport_profile_add(struct rte_sched_port *port,
+	struct rte_sched_subport_profile_params *params,
+	uint32_t *subport_profile_id)
+{
+	int status;
+	uint32_t i;
+	struct rte_sched_subport_profile *dst;
+
+	/* Port */
+	if (port == NULL) {
+		RTE_LOG(ERR, SCHED,
+		"%s: Incorrect value for parameter port\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params == NULL) {
+		RTE_LOG(ERR, SCHED,
+		"%s: Incorrect value for parameter profile\n", __func__);
+		return -EINVAL;
+	}
+
+	if (subport_profile_id == NULL) {
+		RTE_LOG(ERR, SCHED,
+		"%s: Incorrect value for parameter \
+		subport_profile_id\n", __func__);
+		return -EINVAL;
+	}
+
+	dst = port->subport_profiles + port->n_subport_profiles;
+
+	/* Subport profiles exceeds the max limit */
+	if (port->n_subport_profiles >= port->n_max_subport_profiles) {
+		RTE_LOG(ERR, SCHED,
+		"%s: Number of subport profiles exceeds \
+		the max limit\n", __func__);
+		return -EINVAL;
+	}
+
+	status = subport_profile_check(params, port->rate);
+	if (status != 0) {
+		RTE_LOG(ERR, SCHED,
+		"%s: subport profile check failed(%d)\n", __func__, status);
+		return -EINVAL;
+	}
+
+	rte_sched_subport_profile_convert(params, dst, port->rate);
+
+	/* Subport profile should not exists */
+	for (i = 0; i < port->n_subport_profiles; i++)
+		if (memcmp(port->subport_profiles + i,
+		    params, sizeof(*params)) == 0) {
+			RTE_LOG(ERR, SCHED,
+			"%s: subport profile exists\n", __func__);
+			return -EINVAL;
+		}
+
+	/* Subport profile commit */
+	*subport_profile_id = port->n_subport_profiles;
+	port->n_subport_profiles++;
+
+	rte_sched_port_log_subport_profile(port, *subport_profile_id);
+
+	return 0;
+}
+
 static inline uint32_t
 rte_sched_port_qindex(struct rte_sched_port *port,
 	uint32_t subport,
@@ -1970,14 +2173,18 @@ grinder_credits_update(struct rte_sched_port *port,
 	struct rte_sched_grinder *grinder = subport->grinder + pos;
 	struct rte_sched_pipe *pipe = grinder->pipe;
 	struct rte_sched_pipe_profile *params = grinder->pipe_params;
+	struct rte_sched_subport_profile *subport_params =
+						grinder->subport_params;
 	uint64_t n_periods;
 	uint32_t i;
 
 	/* Subport TB */
-	n_periods = (port->time - subport->tb_time) / subport->tb_period;
-	subport->tb_credits += n_periods * subport->tb_credits_per_period;
-	subport->tb_credits = RTE_MIN(subport->tb_credits, subport->tb_size);
-	subport->tb_time += n_periods * subport->tb_period;
+	n_periods = (port->time - subport->tb_time) / subport_params->tb_period;
+	subport->tb_credits += n_periods *
+			       subport_params->tb_credits_per_period;
+	subport->tb_credits = RTE_MIN(subport->tb_credits,
+				      subport_params->tb_size);
+	subport->tb_time += n_periods * subport_params->tb_period;
 
 	/* Pipe TB */
 	n_periods = (port->time - pipe->tb_time) / params->tb_period;
@@ -1988,9 +2195,10 @@ grinder_credits_update(struct rte_sched_port *port,
 	/* Subport TCs */
 	if (unlikely(port->time >= subport->tc_time)) {
 		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-			subport->tc_credits[i] = subport->tc_credits_per_period[i];
+			subport->tc_credits[i] =
+				subport_params->tc_credits_per_period[i];
 
-		subport->tc_time = port->time + subport->tc_period;
+		subport->tc_time = port->time + subport_params->tc_period;
 	}
 
 	/* Pipe TCs */
@@ -2008,6 +2216,8 @@ static inline uint64_t
 grinder_tc_ov_credits_update(struct rte_sched_port *port,
 	struct rte_sched_subport *subport)
 {
+	struct rte_sched_subport_profile *subport_params =
+						grinder->subport_params;
 	uint64_t tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
 	uint64_t tc_consumption = 0, tc_ov_consumption_max;
 	uint64_t tc_ov_wm = subport->tc_ov_wm;
@@ -2018,16 +2228,17 @@ grinder_tc_ov_credits_update(struct rte_sched_port *port,
 
 	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASS_BE; i++) {
 		tc_ov_consumption[i] =
-			subport->tc_credits_per_period[i] - subport->tc_credits[i];
+			subport_params->tc_credits_per_period[i] -
+						subport->tc_credits[i];
 		tc_consumption += tc_ov_consumption[i];
 	}
 
 	tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] =
-		subport->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
+	subport_params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
 		subport->tc_credits[RTE_SCHED_TRAFFIC_CLASS_BE];
 
 	tc_ov_consumption_max =
-		subport->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
+	subport_params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
 			tc_consumption;
 
 	if (tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] >
@@ -2053,14 +2264,18 @@ grinder_credits_update(struct rte_sched_port *port,
 	struct rte_sched_grinder *grinder = subport->grinder + pos;
 	struct rte_sched_pipe *pipe = grinder->pipe;
 	struct rte_sched_pipe_profile *params = grinder->pipe_params;
+	struct rte_sched_subport_profile *subport_params =
+						grinder->subport_params;
 	uint64_t n_periods;
 	uint32_t i;
 
 	/* Subport TB */
-	n_periods = (port->time - subport->tb_time) / subport->tb_period;
-	subport->tb_credits += n_periods * subport->tb_credits_per_period;
-	subport->tb_credits = RTE_MIN(subport->tb_credits, subport->tb_size);
-	subport->tb_time += n_periods * subport->tb_period;
+	n_periods = (port->time - subport->tb_time) / subport_params->tb_period;
+	subport->tb_credits += n_periods *
+				subport_params->tb_credits_per_period;
+	subport->tb_credits = RTE_MIN(subport->tb_credits,
+				subport_params->tb_size);
+	subport->tb_time += n_periods * subport_params->tb_period;
 
 	/* Pipe TB */
 	n_periods = (port->time - pipe->tb_time) / params->tb_period;
@@ -2073,9 +2288,10 @@ grinder_credits_update(struct rte_sched_port *port,
 		subport->tc_ov_wm = grinder_tc_ov_credits_update(port, subport);
 
 		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-			subport->tc_credits[i] = subport->tc_credits_per_period[i];
+			subport->tc_credits[i] =
+				subport_params->tc_credits_per_period[i];
 
-		subport->tc_time = port->time + subport->tc_period;
+		subport->tc_time = port->time + subport_params->tc_period;
 		subport->tc_ov_period_id++;
 	}
 
@@ -2598,6 +2814,8 @@ grinder_handle(struct rte_sched_port *port,
 		struct rte_sched_pipe *pipe = grinder->pipe;
 
 		grinder->pipe_params = subport->pipe_profiles + pipe->profile;
+		grinder->subport_params = port->subport_profiles +
+					  subport->profile;
 		grinder_prefetch_tc_queue_arrays(subport, pos);
 		grinder_credits_update(port, subport, pos);
 
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index 8a5a93c..7623919 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -149,18 +149,6 @@ struct rte_sched_pipe_params {
  * byte.
  */
 struct rte_sched_subport_params {
-	/** Token bucket rate (measured in bytes per second) */
-	uint64_t tb_rate;
-
-	/** Token bucket size (measured in credits) */
-	uint64_t tb_size;
-
-	/** Traffic class rates (measured in bytes per second) */
-	uint64_t tc_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
-
-	/** Enforcement period for rates (measured in milliseconds) */
-	uint64_t tc_period;
-
 	/** Number of subport pipes.
 	 * The subport can enable/allocate fewer pipes than the maximum
 	 * number set through struct port_params::n_max_pipes_per_subport,
@@ -192,6 +180,20 @@ struct rte_sched_subport_params {
 #endif
 };
 
+struct rte_sched_subport_profile_params {
+	/** Token bucket rate (measured in bytes per second) */
+	uint64_t tb_rate;
+
+	/** Token bucket size (measured in credits) */
+	uint64_t tb_size;
+
+	/** Traffic class rates (measured in bytes per second) */
+	uint64_t tc_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+
+	/** Enforcement period for rates (measured in milliseconds) */
+	uint64_t tc_period;
+};
+
 /** Subport statistics */
 struct rte_sched_subport_stats {
 	/** Number of packets successfully written */
@@ -254,6 +256,17 @@ struct rte_sched_port_params {
 	/** Number of subports */
 	uint32_t n_subports_per_port;
 
+	/** subport profile table.
+	 * Every pipe is configured using one of the profiles from this table.
+	 */
+	struct rte_sched_subport_profile_params *subport_profiles;
+
+	/** Profiles in the pipe profile table */
+	uint32_t n_subport_profiles;
+
+	/** Max allowed profiles in the pipe profile table */
+	uint32_t n_max_subport_profiles;
+
 	/** Maximum number of subport pipes.
 	 * This parameter is used to reserve a fixed number of bits
 	 * in struct rte_mbuf::sched.queue_id for the pipe_id for all
@@ -312,6 +325,29 @@ rte_sched_subport_pipe_profile_add(struct rte_sched_port *port,
 	uint32_t *pipe_profile_id);
 
 /**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Hierarchical scheduler subport bandwidth profile add
+ * Note that this function is safe to use in runtime for adding new
+ * subport bandwidth profile as it doesn't have any impact on hiearchical
+ * structure of the scheduler.
+ * @param port
+ *   Handle to port scheduler instance
+ * @param struct rte_sched_subport_profile
+ *   Subport bandwidth profile
+ * @param subport_profile_d
+ *   Subport profile id
+ * @return
+ *   0 upon success, error code otherwise
+ */
+__rte_experimental
+int
+rte_sched_port_subport_profile_add(struct rte_sched_port *port,
+	struct rte_sched_subport_profile_params *profile,
+	uint32_t *subport_profile_id);
+
+/**
  * Hierarchical scheduler subport configuration
  *
  * @param port
@@ -329,6 +365,28 @@ rte_sched_subport_config(struct rte_sched_port *port,
 	struct rte_sched_subport_params *params);
 
 /**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Hierarchical scheduler subport profile configuration
+ * Note that this function is safe to use in runtime for applying any specific
+ * subport bandwidth profile as it doesn't have any impact on hiearchical
+ * structure of the scheduler.
+ * @param port
+ *   Handle to port scheduler instance
+ * @param subport_id
+ *   Subport ID
+ * @param profile_d
+ *   Subport profile id
+ * @return
+ *   0 upon success, error code otherwise
+ */
+__rte_experimental
+int
+rte_sched_subport_profile_config(struct rte_sched_port *port,
+	uint32_t subport_id,
+	uint32_t profile_id);
+/**
  * Hierarchical scheduler pipe configuration
  *
  * @param port
diff --git a/lib/librte_sched/rte_sched_version.map b/lib/librte_sched/rte_sched_version.map
index cefd990..c02a223 100644
--- a/lib/librte_sched/rte_sched_version.map
+++ b/lib/librte_sched/rte_sched_version.map
@@ -28,4 +28,6 @@ EXPERIMENTAL {
 	global:
 
 	rte_sched_subport_pipe_profile_add;
+	rte_sched_port_subport_profile_add;
+	rte_sched_subport_profile_config;
 };
-- 
2.7.4


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

* [dpdk-dev] [RFC PATCH 2/2] example/qos_sched: subport bandwidth profile config
  2020-07-15 18:27 [dpdk-dev] [RFC PATCH 0/2] Enable dyynamic configuration of subport bandwidth profile Savinay Dharmappa
  2020-07-15 18:27 ` [dpdk-dev] [RFC PATCH 1/2] sched: add dynamic config " Savinay Dharmappa
@ 2020-07-15 18:27 ` Savinay Dharmappa
  2020-07-16  8:14   ` Singh, Jasvinder
  2020-09-02  9:07   ` [dpdk-dev] [PATCH v1 1/4] example/qos_sched: subport bandwidth dynmaic conf Savinay Dharmappa
  2020-07-16  8:14 ` [dpdk-dev] [RFC PATCH 0/2] Enable dyynamic configuration of subport bandwidth profile Singh, Jasvinder
  2 siblings, 2 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-07-15 18:27 UTC (permalink / raw)
  To: savinay.dharmappa, jasvinder.singh, dev

qos sched application uses the new apis introduced as part of dynamic
configuration of subport bandwidth to configure the deafult subport
bandwidth profile while buidling the hirerachical scheduler.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 examples/qos_sched/cfg_file.c  | 158 ++++++++++++++++++++++++-----------------
 examples/qos_sched/cfg_file.h  |   4 ++
 examples/qos_sched/init.c      |  24 +++++--
 examples/qos_sched/main.h      |   1 +
 examples/qos_sched/profile.cfg |   3 +
 5 files changed, 120 insertions(+), 70 deletions(-)

diff --git a/examples/qos_sched/cfg_file.c b/examples/qos_sched/cfg_file.c
index f078e4f..9e1341c 100644
--- a/examples/qos_sched/cfg_file.c
+++ b/examples/qos_sched/cfg_file.c
@@ -53,8 +53,11 @@ cfg_load_pipe(struct rte_cfgfile *cfg, struct rte_sched_pipe_params *pipe_params
 	if (!cfg || !pipe_params)
 		return -1;
 
-	profiles = rte_cfgfile_num_sections(cfg, "pipe profile", sizeof("pipe profile") - 1);
-	subport_params[0].n_pipe_profiles = profiles;
+	profiles = rte_cfgfile_num_sections(cfg, "pipe profile",
+					sizeof("pipe profile") - 1);
+	port_params.n_subport_profiles = profiles;
+
+	printf(" profiles = %d", profiles);
 
 	for (j = 0; j < profiles; j++) {
 		char pipe_name[32];
@@ -143,6 +146,93 @@ cfg_load_pipe(struct rte_cfgfile *cfg, struct rte_sched_pipe_params *pipe_params
 }
 
 int
+cfg_load_subport_profile(struct rte_cfgfile *cfg,
+	struct rte_sched_subport_profile_params *subport_profile)
+{
+	int i;
+	const char *entry;
+	int profiles;
+
+	if (!cfg || !subport_profile)
+		return -1;
+
+	profiles = rte_cfgfile_num_sections(cfg, "subport profile",
+					   sizeof("subport profile") - 1);
+	subport_params[0].n_pipe_profiles = profiles;
+
+	for (i = 0; i < profiles; i++) {
+		char sec_name[32];
+		snprintf(sec_name, sizeof(sec_name), "subport profile %d", i);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tb rate");
+		if (entry)
+			subport_profile[i].tb_rate = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tb size");
+		if (entry)
+			subport_profile[i].tb_size = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc period");
+		if (entry)
+			subport_profile[i].tc_period = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 0 rate");
+		if (entry)
+			subport_profile[i].tc_rate[0] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 1 rate");
+		if (entry)
+			subport_profile[i].tc_rate[1] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 2 rate");
+		if (entry)
+			subport_profile[i].tc_rate[2] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 3 rate");
+		if (entry)
+			subport_profile[i].tc_rate[3] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 4 rate");
+		if (entry)
+			subport_profile[i].tc_rate[4] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 5 rate");
+		if (entry)
+			subport_profile[i].tc_rate[5] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 6 rate");
+		if (entry)
+			subport_profile[i].tc_rate[6] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 7 rate");
+		if (entry)
+			subport_profile[i].tc_rate[7] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 8 rate");
+		if (entry)
+			subport_profile[i].tc_rate[8] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 9 rate");
+		if (entry)
+			subport_profile[i].tc_rate[9] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 10 rate");
+		if (entry)
+			subport_profile[i].tc_rate[10] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 11 rate");
+		if (entry)
+			subport_profile[i].tc_rate[11] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 12 rate");
+		if (entry)
+			subport_profile[i].tc_rate[12] = (uint64_t)atoi(entry);
+	}
+
+	return 0;
+}
+
+int
 cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subport_params)
 {
 	const char *entry;
@@ -267,70 +357,6 @@ cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subpo
 				}
 			}
 
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tb rate");
-			if (entry)
-				subport_params[i].tb_rate = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tb size");
-			if (entry)
-				subport_params[i].tb_size = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc period");
-			if (entry)
-				subport_params[i].tc_period = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 0 rate");
-			if (entry)
-				subport_params[i].tc_rate[0] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 1 rate");
-			if (entry)
-				subport_params[i].tc_rate[1] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 2 rate");
-			if (entry)
-				subport_params[i].tc_rate[2] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 3 rate");
-			if (entry)
-				subport_params[i].tc_rate[3] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 4 rate");
-			if (entry)
-				subport_params[i].tc_rate[4] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 5 rate");
-			if (entry)
-				subport_params[i].tc_rate[5] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 6 rate");
-			if (entry)
-				subport_params[i].tc_rate[6] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 7 rate");
-			if (entry)
-				subport_params[i].tc_rate[7] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 8 rate");
-			if (entry)
-				subport_params[i].tc_rate[8] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 9 rate");
-			if (entry)
-				subport_params[i].tc_rate[9] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 10 rate");
-			if (entry)
-				subport_params[i].tc_rate[10] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 11 rate");
-			if (entry)
-				subport_params[i].tc_rate[11] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 12 rate");
-			if (entry)
-				subport_params[i].tc_rate[12] = (uint64_t)atoi(entry);
-
 			int n_entries = rte_cfgfile_section_num_entries(cfg, sec_name);
 			struct rte_cfgfile_entry entries[n_entries];
 
diff --git a/examples/qos_sched/cfg_file.h b/examples/qos_sched/cfg_file.h
index 2eccf1c..0dc458a 100644
--- a/examples/qos_sched/cfg_file.h
+++ b/examples/qos_sched/cfg_file.h
@@ -14,4 +14,8 @@ int cfg_load_pipe(struct rte_cfgfile *cfg, struct rte_sched_pipe_params *pipe);
 
 int cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subport);
 
+int cfg_load_subport_profile(struct rte_cfgfile *cfg,
+			     struct rte_sched_subport_profile_params
+			     *subport_profile);
+
 #endif
diff --git a/examples/qos_sched/init.c b/examples/qos_sched/init.c
index 9626c15..541adb7 100644
--- a/examples/qos_sched/init.c
+++ b/examples/qos_sched/init.c
@@ -196,15 +196,20 @@ static struct rte_sched_pipe_params pipe_profiles[MAX_SCHED_PIPE_PROFILES] = {
 	},
 };
 
-struct rte_sched_subport_params subport_params[MAX_SCHED_SUBPORTS] = {
+static struct rte_sched_subport_profile_params
+		subport_profile[MAX_SCHED_SUBPORT_PROFILES] = {
 	{
 		.tb_rate = 1250000000,
 		.tb_size = 1000000,
-
 		.tc_rate = {1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000},
 		.tc_period = 10,
+	},
+};
+
+struct rte_sched_subport_params subport_params[MAX_SCHED_SUBPORTS] = {
+	{
 		.n_pipes_per_subport_enabled = 4096,
 		.qsize = {64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64},
 		.pipe_profiles = pipe_profiles,
@@ -289,6 +294,9 @@ struct rte_sched_port_params port_params = {
 	.mtu = 6 + 6 + 4 + 4 + 2 + 1500,
 	.frame_overhead = RTE_SCHED_FRAME_OVERHEAD_DEFAULT,
 	.n_subports_per_port = 1,
+	.n_subport_profiles = 1,
+	.subport_profiles = subport_profile,
+	.n_max_subport_profiles = MAX_SCHED_SUBPORT_PROFILES,
 	.n_pipes_per_subport = MAX_SCHED_PIPES,
 };
 
@@ -320,8 +328,15 @@ app_init_sched_port(uint32_t portid, uint32_t socketid)
 	for (subport = 0; subport < port_params.n_subports_per_port; subport ++) {
 		err = rte_sched_subport_config(port, subport, &subport_params[subport]);
 		if (err) {
-			rte_exit(EXIT_FAILURE, "Unable to config sched subport %u, err=%d\n",
-					subport, err);
+			rte_exit(EXIT_FAILURE, "Unable to config schedi "
+				"subport %u, err=%d\n", subport, err);
+		}
+
+		err = rte_sched_subport_profile_config(port, subport, 0);
+		if (err) {
+			rte_exit(EXIT_FAILURE, "failed to configure "
+				"profile err=%d\n", err);
+
 		}
 
 		uint32_t n_pipes_per_subport =
@@ -354,6 +369,7 @@ app_load_cfg_profile(const char *profile)
 
 	cfg_load_port(file, &port_params);
 	cfg_load_subport(file, subport_params);
+	cfg_load_subport_profile(file, subport_profile);
 	cfg_load_pipe(file, pipe_profiles);
 
 	rte_cfgfile_close(file);
diff --git a/examples/qos_sched/main.h b/examples/qos_sched/main.h
index 23bc418..0d6815a 100644
--- a/examples/qos_sched/main.h
+++ b/examples/qos_sched/main.h
@@ -51,6 +51,7 @@ extern "C" {
 #define MAX_SCHED_SUBPORTS		8
 #define MAX_SCHED_PIPES		4096
 #define MAX_SCHED_PIPE_PROFILES		256
+#define MAX_SCHED_SUBPORT_PROFILES	8
 
 #ifndef APP_COLLECT_STAT
 #define APP_COLLECT_STAT		1
diff --git a/examples/qos_sched/profile.cfg b/examples/qos_sched/profile.cfg
index 61b8b70..4486d27 100644
--- a/examples/qos_sched/profile.cfg
+++ b/examples/qos_sched/profile.cfg
@@ -26,6 +26,9 @@ number of subports per port = 1
 number of pipes per subport = 4096
 queue sizes = 64 64 64 64 64 64 64 64 64 64 64 64 64
 
+subport 0-8 = 0                ; These subports are configured with subport profile 0
+
+[subport profile 0]
 tb rate = 1250000000           ; Bytes per second
 tb size = 1000000              ; Bytes
 
-- 
2.7.4


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

* Re: [dpdk-dev] [RFC PATCH 0/2] Enable dyynamic configuration of subport bandwidth profile
  2020-07-15 18:27 [dpdk-dev] [RFC PATCH 0/2] Enable dyynamic configuration of subport bandwidth profile Savinay Dharmappa
  2020-07-15 18:27 ` [dpdk-dev] [RFC PATCH 1/2] sched: add dynamic config " Savinay Dharmappa
  2020-07-15 18:27 ` [dpdk-dev] [RFC PATCH 2/2] example/qos_sched: subport bandwidth profile config Savinay Dharmappa
@ 2020-07-16  8:14 ` Singh, Jasvinder
  2 siblings, 0 replies; 107+ messages in thread
From: Singh, Jasvinder @ 2020-07-16  8:14 UTC (permalink / raw)
  To: Dharmappa, Savinay, dev, Dumitrescu, Cristian



> -----Original Message-----
> From: Dharmappa, Savinay <savinay.dharmappa@intel.com>
> Sent: Wednesday, July 15, 2020 7:28 PM
> To: Dharmappa, Savinay <savinay.dharmappa@intel.com>; Singh, Jasvinder
> <jasvinder.singh@intel.com>; dev@dpdk.org
> Subject: [RFC PATCH 0/2] Enable dyynamic configuration of subport
> bandwidth profile
> 
> DPDK sched library allows runtime configuration of the pipe profiles to the
> pipes of the subport once scheduler hierarchy is constructed. However, to
> change the subport level bandwidth, existing hierarchy needs to be
> dismantled and whole process of building hierarchy under subport nodes
> needs to be repeated which might result in router downtime. Furthermore,
> due to lack of dynamic configuration of the subport bandwidth profile
> configuration (shaper and Traffic class rates), the user application is unable
> to dynamically re-distribute the excess-bandwidth of one subport among
> other subports in the scheduler hierarchy. Therefore, it is also not possible to
> adjust the subport bandwidth profile in sync with dynamic changes in pipe
> profiles of subscribers who want to consume higher bandwidth
> opportunistically.
> 
> This RFC proposes dynamic configuration of the subport bandwidth profile to
> overcome the runtime situation when group of subscribers are not using the
> allotted bandwidth and dynamic bandwidth re-distribution is needed the
> without making any structural changes in the hierarchy.
> 
> The implementation work includes refactoring the existing data structures
> defined for port and subport level, new APIs for adding subport level
> bandwidth profiles that can be used in runtime which causes API/ABI change.
> Therefore, deprecation notice will be sent out soon.
> 
> Savinay Dharmappa (2):
>   sched: add dynamic config of subport bandwidth profile
>   example/qos_sched: subport bandwidth dynmaic conf
> 
>  examples/qos_sched/cfg_file.c          | 158 ++++++-----
>  examples/qos_sched/cfg_file.h          |   4 +
>  examples/qos_sched/init.c              |  24 +-
>  examples/qos_sched/main.h              |   1 +
>  examples/qos_sched/profile.cfg         |   3 +
>  lib/librte_sched/rte_sched.c           | 486 ++++++++++++++++++++++++---------
>  lib/librte_sched/rte_sched.h           |  82 +++++-
>  lib/librte_sched/rte_sched_version.map |   2 +
>  8 files changed, 544 insertions(+), 216 deletions(-)
> 
> --
> 2.7.4

+ Cristian

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

* Re: [dpdk-dev] [RFC PATCH 1/2] sched: add dynamic config of subport bandwidth profile
  2020-07-15 18:27 ` [dpdk-dev] [RFC PATCH 1/2] sched: add dynamic config " Savinay Dharmappa
@ 2020-07-16  8:14   ` Singh, Jasvinder
  2020-07-20 11:20   ` Dumitrescu, Cristian
  2020-09-02  8:56   ` [dpdk-dev] [PATCH v1 1/4] " Savinay Dharmappa
  2 siblings, 0 replies; 107+ messages in thread
From: Singh, Jasvinder @ 2020-07-16  8:14 UTC (permalink / raw)
  To: Dharmappa, Savinay, dev, Dumitrescu, Cristian



> -----Original Message-----
> From: Dharmappa, Savinay <savinay.dharmappa@intel.com>
> Sent: Wednesday, July 15, 2020 7:28 PM
> To: Dharmappa, Savinay <savinay.dharmappa@intel.com>; Singh, Jasvinder
> <jasvinder.singh@intel.com>; dev@dpdk.org
> Subject: [RFC PATCH 1/2] sched: add dynamic config of subport bandwidth
> profile
> 
> This patch modifies the subport level data structures and add new API to
> allow dynamic configuration of the subport bandwidth profile.
> 
> Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
> Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> ---
>  lib/librte_sched/rte_sched.c           | 486 ++++++++++++++++++++++++---------
>  lib/librte_sched/rte_sched.h           |  82 +++++-
>  lib/librte_sched/rte_sched_version.map |   2 +
>  3 files changed, 424 insertions(+), 146 deletions(-)
> 
> diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c index
> c0983dd..5bb0d2b 100644
> --- a/lib/librte_sched/rte_sched.c
> +++ b/lib/librte_sched/rte_sched.c
> @@ -2,6 +2,7 @@
>   * Copyright(c) 2010-2014 Intel Corporation
>   */
> 
> +#include <stdint.h>
>  #include <stdio.h>
>  #include <string.h>
> 
> @@ -101,6 +102,16 @@ enum grinder_state {
>  	e_GRINDER_READ_MBUF
>  };
> 
> +struct rte_sched_subport_profile {
> +	/* Token bucket (TB) */
> +	uint64_t tb_period;
> +	uint64_t tb_credits_per_period;
> +	uint64_t tb_size;
> +
> +	uint64_t
> tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
> +	uint64_t tc_period;
> +};
> +
>  struct rte_sched_grinder {
>  	/* Pipe cache */
>  	uint16_t pcache_qmask[RTE_SCHED_GRINDER_PCACHE_SIZE];
> @@ -113,6 +124,7 @@ struct rte_sched_grinder {
>  	uint32_t productive;
>  	uint32_t pindex;
>  	struct rte_sched_subport *subport;
> +	struct rte_sched_subport_profile *subport_params;
>  	struct rte_sched_pipe *pipe;
>  	struct rte_sched_pipe_profile *pipe_params;
> 
> @@ -139,18 +151,13 @@ struct rte_sched_grinder {  };
> 
>  struct rte_sched_subport {
> -	/* Token bucket (TB) */
> +
>  	uint64_t tb_time; /* time of last update */
> -	uint64_t tb_period;
> -	uint64_t tb_credits_per_period;
> -	uint64_t tb_size;
>  	uint64_t tb_credits;
> 
>  	/* Traffic classes (TCs) */
>  	uint64_t tc_time; /* time of next update */
> -	uint64_t
> tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
>  	uint64_t tc_credits[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
> -	uint64_t tc_period;
> 
>  	/* TC oversubscription */
>  	uint64_t tc_ov_wm;
> @@ -164,6 +171,8 @@ struct rte_sched_subport {
>  	/* Statistics */
>  	struct rte_sched_subport_stats stats __rte_cache_aligned;
> 
> +	/* subport profile flag */
> +	uint32_t profile;
>  	/* Subport pipes */
>  	uint32_t n_pipes_per_subport_enabled;
>  	uint32_t n_pipe_profiles;
> @@ -212,6 +221,8 @@ struct rte_sched_port {
>  	uint16_t pipe_queue[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
>  	uint8_t pipe_tc[RTE_SCHED_QUEUES_PER_PIPE];
>  	uint8_t tc_queue[RTE_SCHED_QUEUES_PER_PIPE];
> +	uint32_t n_subport_profiles;
> +	uint32_t n_max_subport_profiles;
>  	uint64_t rate;
>  	uint32_t mtu;
>  	uint32_t frame_overhead;
> @@ -229,6 +240,7 @@ struct rte_sched_port {
>  	uint32_t subport_id;
> 
>  	/* Large data structures */
> +	struct rte_sched_subport_profile *subport_profiles;
>  	struct rte_sched_subport *subports[0] __rte_cache_aligned;  }
> __rte_cache_aligned;
> 
> @@ -375,8 +387,60 @@ pipe_profile_check(struct rte_sched_pipe_params
> *params,  }
> 
>  static int
> +subport_profile_check(struct rte_sched_subport_profile_params *params,
> +	uint64_t rate)
> +{
> +	uint32_t i;
> +
> +	/* Check user parameters */
> +	if (params == NULL) {
> +		RTE_LOG(ERR, SCHED,
> +			"%s: Incorrect value for parameter params\n",
> __func__);
> +		return -EINVAL;
> +	}
> +
> +	if (params->tb_rate == 0 || params->tb_rate > rate) {
> +		RTE_LOG(ERR, SCHED,
> +			"%s: Incorrect value for tb rate\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	if (params->tb_size == 0) {
> +		RTE_LOG(ERR, SCHED,
> +			"%s: Incorrect value for tb size\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
> +		uint64_t tc_rate = params->tc_rate[i];
> +
> +		if (tc_rate == 0 || (tc_rate > params->tb_rate)) {
> +			RTE_LOG(ERR, SCHED,
> +				"%s: Incorrect value for tc rate\n", __func__);
> +			return -EINVAL;
> +		}
> +	}
> +
> +	if (params->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
> +		RTE_LOG(ERR, SCHED,
> +			"%s: Incorrect tc rate(best effort)\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	if (params->tc_period == 0) {
> +		RTE_LOG(ERR, SCHED,
> +			"%s: Incorrect value for tc period\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
> +
> +static int
>  rte_sched_port_check_params(struct rte_sched_port_params *params)  {
> +	uint32_t i;
> +
>  	if (params == NULL) {
>  		RTE_LOG(ERR, SCHED,
>  			"%s: Incorrect value for parameter params\n",
> __func__); @@ -413,6 +477,29 @@ rte_sched_port_check_params(struct
> rte_sched_port_params *params)
>  		return -EINVAL;
>  	}
> 
> +	if (params->subport_profiles == NULL ||
> +		params->n_subport_profiles == 0 ||
> +		params->n_max_subport_profiles == 0 ||
> +		params->n_subport_profiles > params-
> >n_max_subport_profiles) {
> +		RTE_LOG(ERR, SCHED,
> +		"%s: Incorrect value for subport profiles\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	for (i = 0; i < params->n_subport_profiles; i++) {
> +		struct rte_sched_subport_profile_params *p =
> +						params->subport_profiles + i;
> +		int status;
> +
> +		status = subport_profile_check(p, params->rate);
> +		if (status != 0) {
> +			RTE_LOG(ERR, SCHED,
> +			"%s: subport profile check failed(%d)\n",
> +			__func__, status);
> +			return -EINVAL;
> +		}
> +	}
> +
>  	/* n_pipes_per_subport: non-zero, power of 2 */
>  	if (params->n_pipes_per_subport == 0 ||
>  	    !rte_is_power_of_2(params->n_pipes_per_subport)) { @@ -554,6
> +641,42 @@ rte_sched_port_log_pipe_profile(struct rte_sched_subport
> *subport, uint32_t i)
>  		p->wrr_cost[0], p->wrr_cost[1], p->wrr_cost[2], p-
> >wrr_cost[3]);  }
> 
> +static void
> +rte_sched_port_log_subport_profile(struct rte_sched_port *port,
> +uint32_t i) {
> +	struct rte_sched_subport_profile *p = port->subport_profiles + i;
> +
> +	RTE_LOG(DEBUG, SCHED, "Low level config for subport profile
> %u:\n"
> +	"Token bucket: period = %"PRIu64", credits per period = %"PRIu64",\
> +	size = %"PRIu64"\n"
> +	"Traffic classes: period = %"PRIu64",\n"
> +	"credits per period = [%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
> +	" %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64",
> %"PRIu64
> +	" %"PRIu64", %"PRIu64", %"PRIu64"]\n",
> +	i,
> +
> +	/* Token bucket */
> +	p->tb_period,
> +	p->tb_credits_per_period,
> +	p->tb_size,
> +
> +	/* Traffic classes */
> +	p->tc_period,
> +	p->tc_credits_per_period[0],
> +	p->tc_credits_per_period[1],
> +	p->tc_credits_per_period[2],
> +	p->tc_credits_per_period[3],
> +	p->tc_credits_per_period[4],
> +	p->tc_credits_per_period[5],
> +	p->tc_credits_per_period[6],
> +	p->tc_credits_per_period[7],
> +	p->tc_credits_per_period[8],
> +	p->tc_credits_per_period[9],
> +	p->tc_credits_per_period[10],
> +	p->tc_credits_per_period[11],
> +	p->tc_credits_per_period[12]);
> +}
> +
>  static inline uint64_t
>  rte_sched_time_ms_to_bytes(uint64_t time_ms, uint64_t rate)  { @@ -623,6
> +746,37 @@ rte_sched_pipe_profile_convert(struct rte_sched_subport
> *subport,  }
> 
>  static void
> +rte_sched_subport_profile_convert(struct
> rte_sched_subport_profile_params *src,
> +	struct rte_sched_subport_profile *dst,
> +	uint64_t rate)
> +{
> +	uint32_t i;
> +
> +	/* Token Bucket */
> +	if (src->tb_rate == rate) {
> +		dst->tb_credits_per_period = 1;
> +		dst->tb_period = 1;
> +	} else {
> +		double tb_rate = (double) src->tb_rate
> +				/ (double) rate;
> +		double d = RTE_SCHED_TB_RATE_CONFIG_ERR;
> +
> +		rte_approx_64(tb_rate, d, &dst->tb_credits_per_period,
> +			&dst->tb_period);
> +	}
> +
> +	dst->tb_size = src->tb_size;
> +
> +	/* Traffic Classes */
> +	dst->tc_period = rte_sched_time_ms_to_bytes(src->tc_period, rate);
> +
> +	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
> +		dst->tc_credits_per_period[i]
> +			= rte_sched_time_ms_to_bytes(src->tc_period,
> +				src->tc_rate[i]);
> +}
> +
> +static void
>  rte_sched_subport_config_pipe_profile_table(struct rte_sched_subport
> *subport,
>  	struct rte_sched_subport_params *params, uint32_t rate)  { @@ -
> 646,6 +800,24 @@ rte_sched_subport_config_pipe_profile_table(struct
> rte_sched_subport *subport,
>  	}
>  }
> 
> +static void
> +rte_sched_port_config_subport_profile_table(struct rte_sched_port *port,
> +	struct rte_sched_port_params *params,
> +	uint64_t rate)
> +{
> +	uint32_t i;
> +
> +	for (i = 0; i < port->n_subport_profiles; i++) {
> +		struct rte_sched_subport_profile_params *src
> +				= params->subport_profiles + i;
> +		struct rte_sched_subport_profile *dst
> +				= port->subport_profiles + i;
> +
> +		rte_sched_subport_profile_convert(src, dst, rate);
> +		rte_sched_port_log_subport_profile(port, i);
> +	}
> +}
> +
>  static int
>  rte_sched_subport_check_params(struct rte_sched_subport_params
> *params,
>  	uint32_t n_max_pipes_per_subport,
> @@ -660,18 +832,6 @@ rte_sched_subport_check_params(struct
> rte_sched_subport_params *params,
>  		return -EINVAL;
>  	}
> 
> -	if (params->tb_rate == 0 || params->tb_rate > rate) {
> -		RTE_LOG(ERR, SCHED,
> -			"%s: Incorrect value for tb rate\n", __func__);
> -		return -EINVAL;
> -	}
> -
> -	if (params->tb_size == 0) {
> -		RTE_LOG(ERR, SCHED,
> -			"%s: Incorrect value for tb size\n", __func__);
> -		return -EINVAL;
> -	}
> -
>  	/* qsize: if non-zero, power of 2,
>  	 * no bigger than 32K (due to 16-bit read/write pointers)
>  	 */
> @@ -685,32 +845,12 @@ rte_sched_subport_check_params(struct
> rte_sched_subport_params *params,
>  		}
>  	}
> 
> -	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
> -		uint64_t tc_rate = params->tc_rate[i];
> -		uint16_t qsize = params->qsize[i];
> -
> -		if ((qsize == 0 && tc_rate != 0) ||
> -			(qsize != 0 && tc_rate == 0) ||
> -			(tc_rate > params->tb_rate)) {
> -			RTE_LOG(ERR, SCHED,
> -				"%s: Incorrect value for tc rate\n", __func__);
> -			return -EINVAL;
> -		}
> -	}
> -
> -	if (params->qsize[RTE_SCHED_TRAFFIC_CLASS_BE] == 0 ||
> -		params->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
> +	if (params->qsize[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
>  		RTE_LOG(ERR, SCHED,
>  			"%s: Incorrect qsize or tc rate(best effort)\n",
> __func__);
>  		return -EINVAL;
>  	}
> 
> -	if (params->tc_period == 0) {
> -		RTE_LOG(ERR, SCHED,
> -			"%s: Incorrect value for tc period\n", __func__);
> -		return -EINVAL;
> -	}
> -
>  	/* n_pipes_per_subport: non-zero, power of 2 */
>  	if (params->n_pipes_per_subport_enabled == 0 ||
>  		params->n_pipes_per_subport_enabled >
> n_max_pipes_per_subport || @@ -792,7 +932,7 @@ struct rte_sched_port
> *  rte_sched_port_config(struct rte_sched_port_params *params)  {
>  	struct rte_sched_port *port = NULL;
> -	uint32_t size0, size1;
> +	uint32_t size0, size1, size2;
>  	uint32_t cycles_per_byte;
>  	uint32_t i, j;
>  	int status;
> @@ -807,10 +947,21 @@ rte_sched_port_config(struct
> rte_sched_port_params *params)
> 
>  	size0 = sizeof(struct rte_sched_port);
>  	size1 = params->n_subports_per_port * sizeof(struct
> rte_sched_subport *);
> +	size2 = params->n_max_subport_profiles *
> +		sizeof(struct rte_sched_subport_profile);
> 
>  	/* Allocate memory to store the data structures */
> -	port = rte_zmalloc_socket("qos_params", size0 + size1,
> RTE_CACHE_LINE_SIZE,
> -		params->socket);
> +	port = rte_zmalloc_socket("qos_params", size0 + size1,
> +				 RTE_CACHE_LINE_SIZE, params->socket);
> +	if (port == NULL) {
> +		RTE_LOG(ERR, SCHED, "%s: Memory allocation fails\n",
> __func__);
> +
> +		return NULL;
> +	}
> +
> +	/* Allocate memory to store the subport profile */
> +	port->subport_profiles  = rte_zmalloc_socket("subport_profile",
> size2,
> +					RTE_CACHE_LINE_SIZE, params-
> >socket);
>  	if (port == NULL) {
>  		RTE_LOG(ERR, SCHED, "%s: Memory allocation fails\n",
> __func__);
> 
> @@ -819,6 +970,8 @@ rte_sched_port_config(struct
> rte_sched_port_params *params)
> 
>  	/* User parameters */
>  	port->n_subports_per_port = params->n_subports_per_port;
> +	port->n_subport_profiles = params->n_subport_profiles;
> +	port->n_max_subport_profiles = params->n_max_subport_profiles;
>  	port->n_pipes_per_subport = params->n_pipes_per_subport;
>  	port->n_pipes_per_subport_log2 =
>  			__builtin_ctz(params->n_pipes_per_subport);
> @@ -849,6 +1002,9 @@ rte_sched_port_config(struct
> rte_sched_port_params *params)
>  	port->time_cpu_bytes = 0;
>  	port->time = 0;
> 
> +	/* Subport profile table */
> +	rte_sched_port_config_subport_profile_table(port, params, port-
> >rate);
> +
>  	cycles_per_byte = (rte_get_tsc_hz() << RTE_SCHED_TIME_SHIFT)
>  		/ params->rate;
>  	port->inv_cycles_per_byte = rte_reciprocal_value(cycles_per_byte);
> @@ -907,48 +1063,6 @@ rte_sched_port_free(struct rte_sched_port *port)
> }
> 
>  static void
> -rte_sched_port_log_subport_config(struct rte_sched_port *port, uint32_t i)
> -{
> -	struct rte_sched_subport *s = port->subports[i];
> -
> -	RTE_LOG(DEBUG, SCHED, "Low level config for subport %u:\n"
> -		"	Token bucket: period = %"PRIu64", credits per period
> = %"PRIu64
> -		", size = %"PRIu64"\n"
> -		"	Traffic classes: period = %"PRIu64"\n"
> -		"	credits per period = [%"PRIu64", %"PRIu64",
> %"PRIu64", %"PRIu64
> -		", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64",
> %"PRIu64
> -		", %"PRIu64", %"PRIu64", %"PRIu64"]\n"
> -		"	Best effort traffic class oversubscription: wm min =
> %"PRIu64
> -		", wm max = %"PRIu64"\n",
> -		i,
> -
> -		/* Token bucket */
> -		s->tb_period,
> -		s->tb_credits_per_period,
> -		s->tb_size,
> -
> -		/* Traffic classes */
> -		s->tc_period,
> -		s->tc_credits_per_period[0],
> -		s->tc_credits_per_period[1],
> -		s->tc_credits_per_period[2],
> -		s->tc_credits_per_period[3],
> -		s->tc_credits_per_period[4],
> -		s->tc_credits_per_period[5],
> -		s->tc_credits_per_period[6],
> -		s->tc_credits_per_period[7],
> -		s->tc_credits_per_period[8],
> -		s->tc_credits_per_period[9],
> -		s->tc_credits_per_period[10],
> -		s->tc_credits_per_period[11],
> -		s->tc_credits_per_period[12],
> -
> -		/* Best effort traffic class oversubscription */
> -		s->tc_ov_wm_min,
> -		s->tc_ov_wm_max);
> -}
> -
> -static void
>  rte_sched_free_memory(struct rte_sched_port *port, uint32_t n_subports)
> {
>  	uint32_t i;
> @@ -1021,33 +1135,7 @@ rte_sched_subport_config(struct rte_sched_port
> *port,
>  	/* Port */
>  	port->subports[subport_id] = s;
> 
> -	/* Token Bucket (TB) */
> -	if (params->tb_rate == port->rate) {
> -		s->tb_credits_per_period = 1;
> -		s->tb_period = 1;
> -	} else {
> -		double tb_rate = ((double) params->tb_rate) / ((double)
> port->rate);
> -		double d = RTE_SCHED_TB_RATE_CONFIG_ERR;
> -
> -		rte_approx_64(tb_rate, d, &s->tb_credits_per_period, &s-
> >tb_period);
> -	}
> -
> -	s->tb_size = params->tb_size;
>  	s->tb_time = port->time;
> -	s->tb_credits = s->tb_size / 2;
> -
> -	/* Traffic Classes (TCs) */
> -	s->tc_period = rte_sched_time_ms_to_bytes(params->tc_period,
> port->rate);
> -	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
> -		if (params->qsize[i])
> -			s->tc_credits_per_period[i]
> -				= rte_sched_time_ms_to_bytes(params-
> >tc_period,
> -					params->tc_rate[i]);
> -	}
> -	s->tc_time = port->time + s->tc_period;
> -	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
> -		if (params->qsize[i])
> -			s->tc_credits[i] = s->tc_credits_per_period[i];
> 
>  	/* compile time checks */
>  	RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS == 0); @@ -
> 1137,8 +1225,6 @@ rte_sched_subport_config(struct rte_sched_port *port,
> #ifdef RTE_SCHED_SUBPORT_TC_OV
>  	/* TC oversubscription */
>  	s->tc_ov_wm_min = port->mtu;
> -	s->tc_ov_wm_max = rte_sched_time_ms_to_bytes(params-
> >tc_period,
> -						     s->pipe_tc_be_rate_max);
>  	s->tc_ov_wm = s->tc_ov_wm_max;
>  	s->tc_ov_period_id = 0;
>  	s->tc_ov = 0;
> @@ -1146,7 +1232,54 @@ rte_sched_subport_config(struct rte_sched_port
> *port,
>  	s->tc_ov_rate = 0;
>  #endif
> 
> -	rte_sched_port_log_subport_config(port, subport_id);
> +	return 0;
> +}
> +
> +int
> +rte_sched_subport_profile_config(struct rte_sched_port *port,
> +	uint32_t subport_id,
> +	uint32_t profile_id)
> +{
> +	int i;
> +	struct rte_sched_subport_profile *params;
> +	uint32_t n_subports = subport_id + 1;
> +	struct rte_sched_subport *s;
> +
> +	if (port == NULL) {
> +		RTE_LOG(ERR, SCHED,
> +			"%s: Incorrect value for parameter port\n",
> __func__);
> +		return -EINVAL;
> +	}
> +
> +	if (subport_id >= port->n_subports_per_port) {
> +		RTE_LOG(ERR, SCHED,
> +			"%s: Incorrect value for parameter subport id\n",
> __func__);
> +
> +		rte_sched_free_memory(port, n_subports);
> +		return -EINVAL;
> +	}
> +
> +	params =  port->subport_profiles + profile_id;
> +
> +	s = port->subports[subport_id];
> +
> +	s->tb_credits = params->tb_size / 2;
> +
> +	s->tc_time = port->time + params->tc_period;
> +
> +	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
> +		if (s->qsize[i])
> +			s->tc_credits[i] = params->tc_credits_per_period[i];
> +		else
> +			params->tc_credits_per_period[i] = 0;
> +
> +#ifdef RTE_SCHED_SUBPORT_TC_OV
> +	s->tc_ov_wm_max = rte_sched_time_ms_to_bytes(params-
> >tc_period,
> +						     s->pipe_tc_be_rate_max);
> +#endif
> +	s->profile = profile_id;
> +
> +	rte_sched_port_log_subport_profile(port, profile_id);
> 
>  	return 0;
>  }
> @@ -1158,6 +1291,7 @@ rte_sched_pipe_config(struct rte_sched_port
> *port,
>  	int32_t pipe_profile)
>  {
>  	struct rte_sched_subport *s;
> +	struct rte_sched_subport_profile *sp;
>  	struct rte_sched_pipe *p;
>  	struct rte_sched_pipe_profile *params;
>  	uint32_t n_subports = subport_id + 1;
> @@ -1198,14 +1332,16 @@ rte_sched_pipe_config(struct rte_sched_port
> *port,
>  		return -EINVAL;
>  	}
> 
> +	sp = port->subport_profiles + s->profile;
> +
>  	/* Handle the case when pipe already has a valid configuration */
>  	p = s->pipe + pipe_id;
>  	if (p->tb_time) {
>  		params = s->pipe_profiles + p->profile;
> 
>  		double subport_tc_be_rate =
> -			(double) s-
> >tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
> -			/ (double) s->tc_period;
> +		(double) sp-
> >tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
> +		/ (double) sp->tc_period;
>  		double pipe_tc_be_rate =
>  			(double) params-
> >tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
>  			/ (double) params->tc_period;
> @@ -1247,8 +1383,8 @@ rte_sched_pipe_config(struct rte_sched_port
> *port,
>  	{
>  		/* Subport best effort tc oversubscription */
>  		double subport_tc_be_rate =
> -			(double) s-
> >tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
> -			/ (double) s->tc_period;
> +		(double) sp-
> >tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
> +			/ (double) sp->tc_period;
>  		double pipe_tc_be_rate =
>  			(double) params-
> >tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
>  			/ (double) params->tc_period;
> @@ -1260,8 +1396,9 @@ rte_sched_pipe_config(struct rte_sched_port
> *port,
> 
>  		if (s->tc_ov != tc_be_ov) {
>  			RTE_LOG(DEBUG, SCHED,
> -				"Subport %u Best effort TC oversubscription
> is ON (%.4lf < %.4lf)\n",
> -				subport_id, subport_tc_be_rate, s-
> >tc_ov_rate);
> +			"Subport %u Best effort TC oversubscription is ON \
> +			(%.4lf < %.4lf)\n",
> +			subport_id, subport_tc_be_rate, s->tc_ov_rate);
>  		}
>  		p->tc_ov_period_id = s->tc_ov_period_id;
>  		p->tc_ov_credits = s->tc_ov_wm;
> @@ -1335,6 +1472,72 @@ rte_sched_subport_pipe_profile_add(struct
> rte_sched_port *port,
>  	return 0;
>  }
> 
> +int
> +rte_sched_port_subport_profile_add(struct rte_sched_port *port,
> +	struct rte_sched_subport_profile_params *params,
> +	uint32_t *subport_profile_id)
> +{
> +	int status;
> +	uint32_t i;
> +	struct rte_sched_subport_profile *dst;
> +
> +	/* Port */
> +	if (port == NULL) {
> +		RTE_LOG(ERR, SCHED,
> +		"%s: Incorrect value for parameter port\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	if (params == NULL) {
> +		RTE_LOG(ERR, SCHED,
> +		"%s: Incorrect value for parameter profile\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	if (subport_profile_id == NULL) {
> +		RTE_LOG(ERR, SCHED,
> +		"%s: Incorrect value for parameter \
> +		subport_profile_id\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	dst = port->subport_profiles + port->n_subport_profiles;
> +
> +	/* Subport profiles exceeds the max limit */
> +	if (port->n_subport_profiles >= port->n_max_subport_profiles) {
> +		RTE_LOG(ERR, SCHED,
> +		"%s: Number of subport profiles exceeds \
> +		the max limit\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	status = subport_profile_check(params, port->rate);
> +	if (status != 0) {
> +		RTE_LOG(ERR, SCHED,
> +		"%s: subport profile check failed(%d)\n", __func__, status);
> +		return -EINVAL;
> +	}
> +
> +	rte_sched_subport_profile_convert(params, dst, port->rate);
> +
> +	/* Subport profile should not exists */
> +	for (i = 0; i < port->n_subport_profiles; i++)
> +		if (memcmp(port->subport_profiles + i,
> +		    params, sizeof(*params)) == 0) {
> +			RTE_LOG(ERR, SCHED,
> +			"%s: subport profile exists\n", __func__);
> +			return -EINVAL;
> +		}
> +
> +	/* Subport profile commit */
> +	*subport_profile_id = port->n_subport_profiles;
> +	port->n_subport_profiles++;
> +
> +	rte_sched_port_log_subport_profile(port, *subport_profile_id);
> +
> +	return 0;
> +}
> +
>  static inline uint32_t
>  rte_sched_port_qindex(struct rte_sched_port *port,
>  	uint32_t subport,
> @@ -1970,14 +2173,18 @@ grinder_credits_update(struct rte_sched_port
> *port,
>  	struct rte_sched_grinder *grinder = subport->grinder + pos;
>  	struct rte_sched_pipe *pipe = grinder->pipe;
>  	struct rte_sched_pipe_profile *params = grinder->pipe_params;
> +	struct rte_sched_subport_profile *subport_params =
> +						grinder->subport_params;
>  	uint64_t n_periods;
>  	uint32_t i;
> 
>  	/* Subport TB */
> -	n_periods = (port->time - subport->tb_time) / subport->tb_period;
> -	subport->tb_credits += n_periods * subport->tb_credits_per_period;
> -	subport->tb_credits = RTE_MIN(subport->tb_credits, subport-
> >tb_size);
> -	subport->tb_time += n_periods * subport->tb_period;
> +	n_periods = (port->time - subport->tb_time) / subport_params-
> >tb_period;
> +	subport->tb_credits += n_periods *
> +			       subport_params->tb_credits_per_period;
> +	subport->tb_credits = RTE_MIN(subport->tb_credits,
> +				      subport_params->tb_size);
> +	subport->tb_time += n_periods * subport_params->tb_period;
> 
>  	/* Pipe TB */
>  	n_periods = (port->time - pipe->tb_time) / params->tb_period; @@ -
> 1988,9 +2195,10 @@ grinder_credits_update(struct rte_sched_port *port,
>  	/* Subport TCs */
>  	if (unlikely(port->time >= subport->tc_time)) {
>  		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
> -			subport->tc_credits[i] = subport-
> >tc_credits_per_period[i];
> +			subport->tc_credits[i] =
> +				subport_params->tc_credits_per_period[i];
> 
> -		subport->tc_time = port->time + subport->tc_period;
> +		subport->tc_time = port->time + subport_params->tc_period;
>  	}
> 
>  	/* Pipe TCs */
> @@ -2008,6 +2216,8 @@ static inline uint64_t
> grinder_tc_ov_credits_update(struct rte_sched_port *port,
>  	struct rte_sched_subport *subport)
>  {
> +	struct rte_sched_subport_profile *subport_params =
> +						grinder->subport_params;
>  	uint64_t
> tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
>  	uint64_t tc_consumption = 0, tc_ov_consumption_max;
>  	uint64_t tc_ov_wm = subport->tc_ov_wm; @@ -2018,16 +2228,17
> @@ grinder_tc_ov_credits_update(struct rte_sched_port *port,
> 
>  	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASS_BE; i++) {
>  		tc_ov_consumption[i] =
> -			subport->tc_credits_per_period[i] - subport-
> >tc_credits[i];
> +			subport_params->tc_credits_per_period[i] -
> +						subport->tc_credits[i];
>  		tc_consumption += tc_ov_consumption[i];
>  	}
> 
>  	tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] =
> -		subport-
> >tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
> +	subport_params-
> >tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
>  		subport->tc_credits[RTE_SCHED_TRAFFIC_CLASS_BE];
> 
>  	tc_ov_consumption_max =
> -		subport-
> >tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
> +	subport_params-
> >tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
>  			tc_consumption;
> 
>  	if (tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] > @@ -
> 2053,14 +2264,18 @@ grinder_credits_update(struct rte_sched_port *port,
>  	struct rte_sched_grinder *grinder = subport->grinder + pos;
>  	struct rte_sched_pipe *pipe = grinder->pipe;
>  	struct rte_sched_pipe_profile *params = grinder->pipe_params;
> +	struct rte_sched_subport_profile *subport_params =
> +						grinder->subport_params;
>  	uint64_t n_periods;
>  	uint32_t i;
> 
>  	/* Subport TB */
> -	n_periods = (port->time - subport->tb_time) / subport->tb_period;
> -	subport->tb_credits += n_periods * subport->tb_credits_per_period;
> -	subport->tb_credits = RTE_MIN(subport->tb_credits, subport-
> >tb_size);
> -	subport->tb_time += n_periods * subport->tb_period;
> +	n_periods = (port->time - subport->tb_time) / subport_params-
> >tb_period;
> +	subport->tb_credits += n_periods *
> +				subport_params->tb_credits_per_period;
> +	subport->tb_credits = RTE_MIN(subport->tb_credits,
> +				subport_params->tb_size);
> +	subport->tb_time += n_periods * subport_params->tb_period;
> 
>  	/* Pipe TB */
>  	n_periods = (port->time - pipe->tb_time) / params->tb_period; @@ -
> 2073,9 +2288,10 @@ grinder_credits_update(struct rte_sched_port *port,
>  		subport->tc_ov_wm = grinder_tc_ov_credits_update(port,
> subport);
> 
>  		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
> -			subport->tc_credits[i] = subport-
> >tc_credits_per_period[i];
> +			subport->tc_credits[i] =
> +				subport_params->tc_credits_per_period[i];
> 
> -		subport->tc_time = port->time + subport->tc_period;
> +		subport->tc_time = port->time + subport_params->tc_period;
>  		subport->tc_ov_period_id++;
>  	}
> 
> @@ -2598,6 +2814,8 @@ grinder_handle(struct rte_sched_port *port,
>  		struct rte_sched_pipe *pipe = grinder->pipe;
> 
>  		grinder->pipe_params = subport->pipe_profiles + pipe-
> >profile;
> +		grinder->subport_params = port->subport_profiles +
> +					  subport->profile;
>  		grinder_prefetch_tc_queue_arrays(subport, pos);
>  		grinder_credits_update(port, subport, pos);
> 
> diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h index
> 8a5a93c..7623919 100644
> --- a/lib/librte_sched/rte_sched.h
> +++ b/lib/librte_sched/rte_sched.h
> @@ -149,18 +149,6 @@ struct rte_sched_pipe_params {
>   * byte.
>   */
>  struct rte_sched_subport_params {
> -	/** Token bucket rate (measured in bytes per second) */
> -	uint64_t tb_rate;
> -
> -	/** Token bucket size (measured in credits) */
> -	uint64_t tb_size;
> -
> -	/** Traffic class rates (measured in bytes per second) */
> -	uint64_t tc_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
> -
> -	/** Enforcement period for rates (measured in milliseconds) */
> -	uint64_t tc_period;
> -
>  	/** Number of subport pipes.
>  	 * The subport can enable/allocate fewer pipes than the maximum
>  	 * number set through struct
> port_params::n_max_pipes_per_subport,
> @@ -192,6 +180,20 @@ struct rte_sched_subport_params {  #endif  };
> 
> +struct rte_sched_subport_profile_params {
> +	/** Token bucket rate (measured in bytes per second) */
> +	uint64_t tb_rate;
> +
> +	/** Token bucket size (measured in credits) */
> +	uint64_t tb_size;
> +
> +	/** Traffic class rates (measured in bytes per second) */
> +	uint64_t tc_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
> +
> +	/** Enforcement period for rates (measured in milliseconds) */
> +	uint64_t tc_period;
> +};
> +
>  /** Subport statistics */
>  struct rte_sched_subport_stats {
>  	/** Number of packets successfully written */ @@ -254,6 +256,17
> @@ struct rte_sched_port_params {
>  	/** Number of subports */
>  	uint32_t n_subports_per_port;
> 
> +	/** subport profile table.
> +	 * Every pipe is configured using one of the profiles from this table.
> +	 */
> +	struct rte_sched_subport_profile_params *subport_profiles;
> +
> +	/** Profiles in the pipe profile table */
> +	uint32_t n_subport_profiles;
> +
> +	/** Max allowed profiles in the pipe profile table */
> +	uint32_t n_max_subport_profiles;
> +
>  	/** Maximum number of subport pipes.
>  	 * This parameter is used to reserve a fixed number of bits
>  	 * in struct rte_mbuf::sched.queue_id for the pipe_id for all @@ -
> 312,6 +325,29 @@ rte_sched_subport_pipe_profile_add(struct
> rte_sched_port *port,
>  	uint32_t *pipe_profile_id);
> 
>  /**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice.
> + *
> + * Hierarchical scheduler subport bandwidth profile add
> + * Note that this function is safe to use in runtime for adding new
> + * subport bandwidth profile as it doesn't have any impact on
> +hiearchical
> + * structure of the scheduler.
> + * @param port
> + *   Handle to port scheduler instance
> + * @param struct rte_sched_subport_profile
> + *   Subport bandwidth profile
> + * @param subport_profile_d
> + *   Subport profile id
> + * @return
> + *   0 upon success, error code otherwise
> + */
> +__rte_experimental
> +int
> +rte_sched_port_subport_profile_add(struct rte_sched_port *port,
> +	struct rte_sched_subport_profile_params *profile,
> +	uint32_t *subport_profile_id);
> +
> +/**
>   * Hierarchical scheduler subport configuration
>   *
>   * @param port
> @@ -329,6 +365,28 @@ rte_sched_subport_config(struct rte_sched_port
> *port,
>  	struct rte_sched_subport_params *params);
> 
>  /**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice.
> + *
> + * Hierarchical scheduler subport profile configuration
> + * Note that this function is safe to use in runtime for applying any
> +specific
> + * subport bandwidth profile as it doesn't have any impact on
> +hiearchical
> + * structure of the scheduler.
> + * @param port
> + *   Handle to port scheduler instance
> + * @param subport_id
> + *   Subport ID
> + * @param profile_d
> + *   Subport profile id
> + * @return
> + *   0 upon success, error code otherwise
> + */
> +__rte_experimental
> +int
> +rte_sched_subport_profile_config(struct rte_sched_port *port,
> +	uint32_t subport_id,
> +	uint32_t profile_id);
> +/**
>   * Hierarchical scheduler pipe configuration
>   *
>   * @param port
> diff --git a/lib/librte_sched/rte_sched_version.map
> b/lib/librte_sched/rte_sched_version.map
> index cefd990..c02a223 100644
> --- a/lib/librte_sched/rte_sched_version.map
> +++ b/lib/librte_sched/rte_sched_version.map
> @@ -28,4 +28,6 @@ EXPERIMENTAL {
>  	global:
> 
>  	rte_sched_subport_pipe_profile_add;
> +	rte_sched_port_subport_profile_add;
> +	rte_sched_subport_profile_config;
>  };
> --
> 2.7.4

+ Cristian

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

* Re: [dpdk-dev] [RFC PATCH 2/2] example/qos_sched: subport bandwidth profile config
  2020-07-15 18:27 ` [dpdk-dev] [RFC PATCH 2/2] example/qos_sched: subport bandwidth profile config Savinay Dharmappa
@ 2020-07-16  8:14   ` Singh, Jasvinder
  2020-09-02  9:07   ` [dpdk-dev] [PATCH v1 1/4] example/qos_sched: subport bandwidth dynmaic conf Savinay Dharmappa
  1 sibling, 0 replies; 107+ messages in thread
From: Singh, Jasvinder @ 2020-07-16  8:14 UTC (permalink / raw)
  To: Dharmappa, Savinay, dev, Dumitrescu, Cristian



> -----Original Message-----
> From: Dharmappa, Savinay <savinay.dharmappa@intel.com>
> Sent: Wednesday, July 15, 2020 7:28 PM
> To: Dharmappa, Savinay <savinay.dharmappa@intel.com>; Singh, Jasvinder
> <jasvinder.singh@intel.com>; dev@dpdk.org
> Subject: [RFC PATCH 2/2] example/qos_sched: subport bandwidth profile
> config
> 
> qos sched application uses the new apis introduced as part of dynamic
> configuration of subport bandwidth to configure the deafult subport
> bandwidth profile while buidling the hirerachical scheduler.
> 
> Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
> Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> ---
>  examples/qos_sched/cfg_file.c  | 158 ++++++++++++++++++++++++-------------
> ----
>  examples/qos_sched/cfg_file.h  |   4 ++
>  examples/qos_sched/init.c      |  24 +++++--
>  examples/qos_sched/main.h      |   1 +
>  examples/qos_sched/profile.cfg |   3 +
>  5 files changed, 120 insertions(+), 70 deletions(-)
> 
> diff --git a/examples/qos_sched/cfg_file.c b/examples/qos_sched/cfg_file.c
> index f078e4f..9e1341c 100644
> --- a/examples/qos_sched/cfg_file.c
> +++ b/examples/qos_sched/cfg_file.c
> @@ -53,8 +53,11 @@ cfg_load_pipe(struct rte_cfgfile *cfg, struct
> rte_sched_pipe_params *pipe_params
>  	if (!cfg || !pipe_params)
>  		return -1;
> 
> -	profiles = rte_cfgfile_num_sections(cfg, "pipe profile", sizeof("pipe
> profile") - 1);
> -	subport_params[0].n_pipe_profiles = profiles;
> +	profiles = rte_cfgfile_num_sections(cfg, "pipe profile",
> +					sizeof("pipe profile") - 1);
> +	port_params.n_subport_profiles = profiles;
> +
> +	printf(" profiles = %d", profiles);
> 
>  	for (j = 0; j < profiles; j++) {
>  		char pipe_name[32];
> @@ -143,6 +146,93 @@ cfg_load_pipe(struct rte_cfgfile *cfg, struct
> rte_sched_pipe_params *pipe_params  }
> 
>  int
> +cfg_load_subport_profile(struct rte_cfgfile *cfg,
> +	struct rte_sched_subport_profile_params *subport_profile) {
> +	int i;
> +	const char *entry;
> +	int profiles;
> +
> +	if (!cfg || !subport_profile)
> +		return -1;
> +
> +	profiles = rte_cfgfile_num_sections(cfg, "subport profile",
> +					   sizeof("subport profile") - 1);
> +	subport_params[0].n_pipe_profiles = profiles;
> +
> +	for (i = 0; i < profiles; i++) {
> +		char sec_name[32];
> +		snprintf(sec_name, sizeof(sec_name), "subport profile %d",
> i);
> +
> +		entry = rte_cfgfile_get_entry(cfg, sec_name, "tb rate");
> +		if (entry)
> +			subport_profile[i].tb_rate = (uint64_t)atoi(entry);
> +
> +		entry = rte_cfgfile_get_entry(cfg, sec_name, "tb size");
> +		if (entry)
> +			subport_profile[i].tb_size = (uint64_t)atoi(entry);
> +
> +		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc period");
> +		if (entry)
> +			subport_profile[i].tc_period = (uint64_t)atoi(entry);
> +
> +		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 0 rate");
> +		if (entry)
> +			subport_profile[i].tc_rate[0] = (uint64_t)atoi(entry);
> +
> +		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 1 rate");
> +		if (entry)
> +			subport_profile[i].tc_rate[1] = (uint64_t)atoi(entry);
> +
> +		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 2 rate");
> +		if (entry)
> +			subport_profile[i].tc_rate[2] = (uint64_t)atoi(entry);
> +
> +		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 3 rate");
> +		if (entry)
> +			subport_profile[i].tc_rate[3] = (uint64_t)atoi(entry);
> +
> +		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 4 rate");
> +		if (entry)
> +			subport_profile[i].tc_rate[4] = (uint64_t)atoi(entry);
> +
> +		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 5 rate");
> +		if (entry)
> +			subport_profile[i].tc_rate[5] = (uint64_t)atoi(entry);
> +
> +		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 6 rate");
> +		if (entry)
> +			subport_profile[i].tc_rate[6] = (uint64_t)atoi(entry);
> +
> +		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 7 rate");
> +		if (entry)
> +			subport_profile[i].tc_rate[7] = (uint64_t)atoi(entry);
> +
> +		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 8 rate");
> +		if (entry)
> +			subport_profile[i].tc_rate[8] = (uint64_t)atoi(entry);
> +
> +		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 9 rate");
> +		if (entry)
> +			subport_profile[i].tc_rate[9] = (uint64_t)atoi(entry);
> +
> +		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 10 rate");
> +		if (entry)
> +			subport_profile[i].tc_rate[10] = (uint64_t)atoi(entry);
> +
> +		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 11 rate");
> +		if (entry)
> +			subport_profile[i].tc_rate[11] = (uint64_t)atoi(entry);
> +
> +		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 12 rate");
> +		if (entry)
> +			subport_profile[i].tc_rate[12] = (uint64_t)atoi(entry);
> +	}
> +
> +	return 0;
> +}
> +
> +int
>  cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params
> *subport_params)  {
>  	const char *entry;
> @@ -267,70 +357,6 @@ cfg_load_subport(struct rte_cfgfile *cfg, struct
> rte_sched_subport_params *subpo
>  				}
>  			}
> 
> -			entry = rte_cfgfile_get_entry(cfg, sec_name, "tb
> rate");
> -			if (entry)
> -				subport_params[i].tb_rate =
> (uint64_t)atoi(entry);
> -
> -			entry = rte_cfgfile_get_entry(cfg, sec_name, "tb
> size");
> -			if (entry)
> -				subport_params[i].tb_size =
> (uint64_t)atoi(entry);
> -
> -			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc
> period");
> -			if (entry)
> -				subport_params[i].tc_period =
> (uint64_t)atoi(entry);
> -
> -			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 0
> rate");
> -			if (entry)
> -				subport_params[i].tc_rate[0] =
> (uint64_t)atoi(entry);
> -
> -			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 1
> rate");
> -			if (entry)
> -				subport_params[i].tc_rate[1] =
> (uint64_t)atoi(entry);
> -
> -			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 2
> rate");
> -			if (entry)
> -				subport_params[i].tc_rate[2] =
> (uint64_t)atoi(entry);
> -
> -			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 3
> rate");
> -			if (entry)
> -				subport_params[i].tc_rate[3] =
> (uint64_t)atoi(entry);
> -
> -			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 4
> rate");
> -			if (entry)
> -				subport_params[i].tc_rate[4] =
> (uint64_t)atoi(entry);
> -
> -			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 5
> rate");
> -			if (entry)
> -				subport_params[i].tc_rate[5] =
> (uint64_t)atoi(entry);
> -
> -			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 6
> rate");
> -			if (entry)
> -				subport_params[i].tc_rate[6] =
> (uint64_t)atoi(entry);
> -
> -			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 7
> rate");
> -			if (entry)
> -				subport_params[i].tc_rate[7] =
> (uint64_t)atoi(entry);
> -
> -			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 8
> rate");
> -			if (entry)
> -				subport_params[i].tc_rate[8] =
> (uint64_t)atoi(entry);
> -
> -			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 9
> rate");
> -			if (entry)
> -				subport_params[i].tc_rate[9] =
> (uint64_t)atoi(entry);
> -
> -			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 10
> rate");
> -			if (entry)
> -				subport_params[i].tc_rate[10] =
> (uint64_t)atoi(entry);
> -
> -			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 11
> rate");
> -			if (entry)
> -				subport_params[i].tc_rate[11] =
> (uint64_t)atoi(entry);
> -
> -			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 12
> rate");
> -			if (entry)
> -				subport_params[i].tc_rate[12] =
> (uint64_t)atoi(entry);
> -
>  			int n_entries = rte_cfgfile_section_num_entries(cfg,
> sec_name);
>  			struct rte_cfgfile_entry entries[n_entries];
> 
> diff --git a/examples/qos_sched/cfg_file.h b/examples/qos_sched/cfg_file.h
> index 2eccf1c..0dc458a 100644
> --- a/examples/qos_sched/cfg_file.h
> +++ b/examples/qos_sched/cfg_file.h
> @@ -14,4 +14,8 @@ int cfg_load_pipe(struct rte_cfgfile *cfg, struct
> rte_sched_pipe_params *pipe);
> 
>  int cfg_load_subport(struct rte_cfgfile *cfg, struct
> rte_sched_subport_params *subport);
> 
> +int cfg_load_subport_profile(struct rte_cfgfile *cfg,
> +			     struct rte_sched_subport_profile_params
> +			     *subport_profile);
> +
>  #endif
> diff --git a/examples/qos_sched/init.c b/examples/qos_sched/init.c index
> 9626c15..541adb7 100644
> --- a/examples/qos_sched/init.c
> +++ b/examples/qos_sched/init.c
> @@ -196,15 +196,20 @@ static struct rte_sched_pipe_params
> pipe_profiles[MAX_SCHED_PIPE_PROFILES] = {
>  	},
>  };
> 
> -struct rte_sched_subport_params
> subport_params[MAX_SCHED_SUBPORTS] = {
> +static struct rte_sched_subport_profile_params
> +		subport_profile[MAX_SCHED_SUBPORT_PROFILES] = {
>  	{
>  		.tb_rate = 1250000000,
>  		.tb_size = 1000000,
> -
>  		.tc_rate = {1250000000, 1250000000, 1250000000,
> 1250000000,
>  			1250000000, 1250000000, 1250000000, 1250000000,
> 1250000000,
>  			1250000000, 1250000000, 1250000000, 1250000000},
>  		.tc_period = 10,
> +	},
> +};
> +
> +struct rte_sched_subport_params
> subport_params[MAX_SCHED_SUBPORTS] = {
> +	{
>  		.n_pipes_per_subport_enabled = 4096,
>  		.qsize = {64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64},
>  		.pipe_profiles = pipe_profiles,
> @@ -289,6 +294,9 @@ struct rte_sched_port_params port_params = {
>  	.mtu = 6 + 6 + 4 + 4 + 2 + 1500,
>  	.frame_overhead = RTE_SCHED_FRAME_OVERHEAD_DEFAULT,
>  	.n_subports_per_port = 1,
> +	.n_subport_profiles = 1,
> +	.subport_profiles = subport_profile,
> +	.n_max_subport_profiles = MAX_SCHED_SUBPORT_PROFILES,
>  	.n_pipes_per_subport = MAX_SCHED_PIPES,  };
> 
> @@ -320,8 +328,15 @@ app_init_sched_port(uint32_t portid, uint32_t
> socketid)
>  	for (subport = 0; subport < port_params.n_subports_per_port;
> subport ++) {
>  		err = rte_sched_subport_config(port, subport,
> &subport_params[subport]);
>  		if (err) {
> -			rte_exit(EXIT_FAILURE, "Unable to config sched
> subport %u, err=%d\n",
> -					subport, err);
> +			rte_exit(EXIT_FAILURE, "Unable to config schedi "
> +				"subport %u, err=%d\n", subport, err);
> +		}
> +
> +		err = rte_sched_subport_profile_config(port, subport, 0);
> +		if (err) {
> +			rte_exit(EXIT_FAILURE, "failed to configure "
> +				"profile err=%d\n", err);
> +
>  		}
> 
>  		uint32_t n_pipes_per_subport =
> @@ -354,6 +369,7 @@ app_load_cfg_profile(const char *profile)
> 
>  	cfg_load_port(file, &port_params);
>  	cfg_load_subport(file, subport_params);
> +	cfg_load_subport_profile(file, subport_profile);
>  	cfg_load_pipe(file, pipe_profiles);
> 
>  	rte_cfgfile_close(file);
> diff --git a/examples/qos_sched/main.h b/examples/qos_sched/main.h
> index 23bc418..0d6815a 100644
> --- a/examples/qos_sched/main.h
> +++ b/examples/qos_sched/main.h
> @@ -51,6 +51,7 @@ extern "C" {
>  #define MAX_SCHED_SUBPORTS		8
>  #define MAX_SCHED_PIPES		4096
>  #define MAX_SCHED_PIPE_PROFILES		256
> +#define MAX_SCHED_SUBPORT_PROFILES	8
> 
>  #ifndef APP_COLLECT_STAT
>  #define APP_COLLECT_STAT		1
> diff --git a/examples/qos_sched/profile.cfg
> b/examples/qos_sched/profile.cfg index 61b8b70..4486d27 100644
> --- a/examples/qos_sched/profile.cfg
> +++ b/examples/qos_sched/profile.cfg
> @@ -26,6 +26,9 @@ number of subports per port = 1  number of pipes per
> subport = 4096  queue sizes = 64 64 64 64 64 64 64 64 64 64 64 64 64
> 
> +subport 0-8 = 0                ; These subports are configured with subport profile
> 0
> +
> +[subport profile 0]
>  tb rate = 1250000000           ; Bytes per second
>  tb size = 1000000              ; Bytes
> 
> --
> 2.7.4

+ Cristian

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

* Re: [dpdk-dev] [RFC PATCH 1/2] sched: add dynamic config of subport bandwidth profile
  2020-07-15 18:27 ` [dpdk-dev] [RFC PATCH 1/2] sched: add dynamic config " Savinay Dharmappa
  2020-07-16  8:14   ` Singh, Jasvinder
@ 2020-07-20 11:20   ` Dumitrescu, Cristian
  2020-07-20 11:21     ` Dumitrescu, Cristian
  2020-09-02  8:56   ` [dpdk-dev] [PATCH v1 1/4] " Savinay Dharmappa
  2 siblings, 1 reply; 107+ messages in thread
From: Dumitrescu, Cristian @ 2020-07-20 11:20 UTC (permalink / raw)
  To: Dharmappa, Savinay, Dharmappa, Savinay, Singh, Jasvinder, dev



> -----Original Message-----
> From: dev <dev-bounces@dpdk.org> On Behalf Of Savinay Dharmappa
> Sent: Wednesday, July 15, 2020 7:28 PM
> To: Dharmappa, Savinay <savinay.dharmappa@intel.com>; Singh, Jasvinder
> <jasvinder.singh@intel.com>; dev@dpdk.org
> Subject: [dpdk-dev] [RFC PATCH 1/2] sched: add dynamic config of subport
> bandwidth profile
> 
> This patch modifies the subport level data structures
> and add new API to allow dynamic configuration of the
> subport bandwidth profile.
> 
> Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
> Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> ---
>  lib/librte_sched/rte_sched.c           | 486 ++++++++++++++++++++++++------
> ---
>  lib/librte_sched/rte_sched.h           |  82 +++++-
>  lib/librte_sched/rte_sched_version.map |   2 +
>  3 files changed, 424 insertions(+), 146 deletions(-)
> 

Hi Savinay,

Your patch makes sense, but it is very hard to review, as you put a massive amount of changes (~500 LOCs) in a single patch file.

Can you please split your patch into a patchset with incremental changes that can be reviewed easier? Some suggestions: split the internal changes in multiple increments first before changing the API (like move the check code into separate functions in individual patches, etc), change the API afterwards.

Thanks,
Cristian

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

* Re: [dpdk-dev] [RFC PATCH 1/2] sched: add dynamic config of subport bandwidth profile
  2020-07-20 11:20   ` Dumitrescu, Cristian
@ 2020-07-20 11:21     ` Dumitrescu, Cristian
  0 siblings, 0 replies; 107+ messages in thread
From: Dumitrescu, Cristian @ 2020-07-20 11:21 UTC (permalink / raw)
  To: Dharmappa, Savinay, Dharmappa, Savinay, Singh, Jasvinder, dev



> -----Original Message-----
> From: Dumitrescu, Cristian
> Sent: Monday, July 20, 2020 12:21 PM
> To: Savinay Dharmappa <savinay.dharmappa@intel.com>; Dharmappa,
> Savinay <Savinay.Dharmappa@intel.com>; Singh, Jasvinder
> <jasvinder.singh@intel.com>; dev@dpdk.org
> Subject: RE: [dpdk-dev] [RFC PATCH 1/2] sched: add dynamic config of
> subport bandwidth profile
> 
> 
> 
> > -----Original Message-----
> > From: dev <dev-bounces@dpdk.org> On Behalf Of Savinay Dharmappa
> > Sent: Wednesday, July 15, 2020 7:28 PM
> > To: Dharmappa, Savinay <savinay.dharmappa@intel.com>; Singh, Jasvinder
> > <jasvinder.singh@intel.com>; dev@dpdk.org
> > Subject: [dpdk-dev] [RFC PATCH 1/2] sched: add dynamic config of subport
> > bandwidth profile
> >
> > This patch modifies the subport level data structures
> > and add new API to allow dynamic configuration of the
> > subport bandwidth profile.
> >
> > Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
> > Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> > ---
> >  lib/librte_sched/rte_sched.c           | 486 ++++++++++++++++++++++++----
> --
> > ---
> >  lib/librte_sched/rte_sched.h           |  82 +++++-
> >  lib/librte_sched/rte_sched_version.map |   2 +
> >  3 files changed, 424 insertions(+), 146 deletions(-)
> >
> 
> Hi Savinay,
> 
> Your patch makes sense, but it is very hard to review, as you put a massive
> amount of changes (~500 LOCs) in a single patch file.
> 
> Can you please split your patch into a patchset with incremental changes that
> can be reviewed easier? Some suggestions: split the internal changes in
> multiple increments first before changing the API (like move the check code
> into separate functions in individual patches, etc), change the API
> afterwards.
> 
> Thanks,
> Cristian

Also please send v1 (non-RFC) as part of the next iteration, thanks!

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

* [dpdk-dev] [PATCH v1 1/4] sched: add dynamic config of subport bandwidth profile
  2020-07-15 18:27 ` [dpdk-dev] [RFC PATCH 1/2] sched: add dynamic config " Savinay Dharmappa
  2020-07-16  8:14   ` Singh, Jasvinder
  2020-07-20 11:20   ` Dumitrescu, Cristian
@ 2020-09-02  8:56   ` Savinay Dharmappa
  2020-09-02  8:56     ` [dpdk-dev] [PATCH v1 2/4] " Savinay Dharmappa
                       ` (3 more replies)
  2 siblings, 4 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-02  8:56 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

This patch modifies the subport level data structures
and add internal functions to create subport profile
table.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c | 173 +++++++++++++++++++++++++++++++++++++++----
 lib/librte_sched/rte_sched.h |  37 ++++++---
 2 files changed, 185 insertions(+), 25 deletions(-)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index c0983dd..c82e09c 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -2,6 +2,7 @@
  * Copyright(c) 2010-2014 Intel Corporation
  */
 
+#include <stdint.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -101,6 +102,16 @@ enum grinder_state {
 	e_GRINDER_READ_MBUF
 };
 
+struct rte_sched_subport_profile {
+	/* Token bucket (TB) */
+	uint64_t tb_period;
+	uint64_t tb_credits_per_period;
+	uint64_t tb_size;
+
+	uint64_t tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+	uint64_t tc_period;
+};
+
 struct rte_sched_grinder {
 	/* Pipe cache */
 	uint16_t pcache_qmask[RTE_SCHED_GRINDER_PCACHE_SIZE];
@@ -139,18 +150,13 @@ struct rte_sched_grinder {
 };
 
 struct rte_sched_subport {
-	/* Token bucket (TB) */
+
 	uint64_t tb_time; /* time of last update */
-	uint64_t tb_period;
-	uint64_t tb_credits_per_period;
-	uint64_t tb_size;
 	uint64_t tb_credits;
 
 	/* Traffic classes (TCs) */
 	uint64_t tc_time; /* time of next update */
-	uint64_t tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
 	uint64_t tc_credits[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
-	uint64_t tc_period;
 
 	/* TC oversubscription */
 	uint64_t tc_ov_wm;
@@ -164,6 +170,8 @@ struct rte_sched_subport {
 	/* Statistics */
 	struct rte_sched_subport_stats stats __rte_cache_aligned;
 
+	/* subport profile flag */
+	uint32_t profile;
 	/* Subport pipes */
 	uint32_t n_pipes_per_subport_enabled;
 	uint32_t n_pipe_profiles;
@@ -212,6 +220,8 @@ struct rte_sched_port {
 	uint16_t pipe_queue[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
 	uint8_t pipe_tc[RTE_SCHED_QUEUES_PER_PIPE];
 	uint8_t tc_queue[RTE_SCHED_QUEUES_PER_PIPE];
+	uint32_t n_subport_profiles;
+	uint32_t n_max_subport_profiles;
 	uint64_t rate;
 	uint32_t mtu;
 	uint32_t frame_overhead;
@@ -229,6 +239,7 @@ struct rte_sched_port {
 	uint32_t subport_id;
 
 	/* Large data structures */
+	struct rte_sched_subport_profile *subport_profiles;
 	struct rte_sched_subport *subports[0] __rte_cache_aligned;
 } __rte_cache_aligned;
 
@@ -375,6 +386,56 @@ pipe_profile_check(struct rte_sched_pipe_params *params,
 }
 
 static int
+subport_profile_check(struct rte_sched_subport_profile_params *params,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	/* Check user parameters */
+	if (params == NULL) {
+		RTE_LOG(ERR, SCHED,
+			"%s: Incorrect value for parameter params\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tb_rate == 0 || params->tb_rate > rate) {
+		RTE_LOG(ERR, SCHED,
+			"%s: Incorrect value for tb rate\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tb_size == 0) {
+		RTE_LOG(ERR, SCHED,
+			"%s: Incorrect value for tb size\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
+		uint64_t tc_rate = params->tc_rate[i];
+
+		if (tc_rate == 0 || (tc_rate > params->tb_rate)) {
+			RTE_LOG(ERR, SCHED,
+				"%s: Incorrect value for tc rate\n", __func__);
+			return -EINVAL;
+		}
+	}
+
+	if (params->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
+		RTE_LOG(ERR, SCHED,
+			"%s: Incorrect tc rate(best effort)\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tc_period == 0) {
+		RTE_LOG(ERR, SCHED,
+			"%s: Incorrect value for tc period\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
 rte_sched_port_check_params(struct rte_sched_port_params *params)
 {
 	if (params == NULL) {
@@ -517,13 +578,14 @@ rte_sched_port_log_pipe_profile(struct rte_sched_subport *subport, uint32_t i)
 	struct rte_sched_pipe_profile *p = subport->pipe_profiles + i;
 
 	RTE_LOG(DEBUG, SCHED, "Low level config for pipe profile %u:\n"
-		"	Token bucket: period = %"PRIu64", credits per period = %"PRIu64", size = %"PRIu64"\n"
-		"	Traffic classes: period = %"PRIu64",\n"
-		"	credits per period = [%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
-		", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
-		", %"PRIu64", %"PRIu64", %"PRIu64"]\n"
-		"	Best-effort traffic class oversubscription: weight = %hhu\n"
-		"	WRR cost: [%hhu, %hhu, %hhu, %hhu]\n",
+	"Token bucket: period = %"PRIu64", credits per period = %"PRIu64""
+	"       size = %"PRIu64",\n"
+	"	Traffic classes: period = %"PRIu64",\n"
+	"	credits per period = [%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64""
+	", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64""
+	", %"PRIu64", %"PRIu64", %"PRIu64"]\n"
+	"	Best-effort traffic class oversubscription: weight = %hhu\n"
+	"	WRR cost: [%hhu, %hhu, %hhu, %hhu]\n",
 		i,
 
 		/* Token bucket */
@@ -554,6 +616,42 @@ rte_sched_port_log_pipe_profile(struct rte_sched_subport *subport, uint32_t i)
 		p->wrr_cost[0], p->wrr_cost[1], p->wrr_cost[2], p->wrr_cost[3]);
 }
 
+static void
+rte_sched_port_log_subport_profile(struct rte_sched_port *port, uint32_t i)
+{
+	struct rte_sched_subport_profile *p = port->subport_profiles + i;
+
+	RTE_LOG(DEBUG, SCHED, "Low level config for subport profile %u:\n"
+	"Token bucket: period = %"PRIu64", credits per period = %"PRIu64",\
+	size = %"PRIu64"\n"
+	"Traffic classes: period = %"PRIu64",\n"
+	"credits per period = [%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
+	" %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
+	" %"PRIu64", %"PRIu64", %"PRIu64"]\n",
+	i,
+
+	/* Token bucket */
+	p->tb_period,
+	p->tb_credits_per_period,
+	p->tb_size,
+
+	/* Traffic classes */
+	p->tc_period,
+	p->tc_credits_per_period[0],
+	p->tc_credits_per_period[1],
+	p->tc_credits_per_period[2],
+	p->tc_credits_per_period[3],
+	p->tc_credits_per_period[4],
+	p->tc_credits_per_period[5],
+	p->tc_credits_per_period[6],
+	p->tc_credits_per_period[7],
+	p->tc_credits_per_period[8],
+	p->tc_credits_per_period[9],
+	p->tc_credits_per_period[10],
+	p->tc_credits_per_period[11],
+	p->tc_credits_per_period[12]);
+}
+
 static inline uint64_t
 rte_sched_time_ms_to_bytes(uint64_t time_ms, uint64_t rate)
 {
@@ -623,6 +721,37 @@ rte_sched_pipe_profile_convert(struct rte_sched_subport *subport,
 }
 
 static void
+rte_sched_subport_profile_convert(struct rte_sched_subport_profile_params *src,
+	struct rte_sched_subport_profile *dst,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	/* Token Bucket */
+	if (src->tb_rate == rate) {
+		dst->tb_credits_per_period = 1;
+		dst->tb_period = 1;
+	} else {
+		double tb_rate = (double) src->tb_rate
+				/ (double) rate;
+		double d = RTE_SCHED_TB_RATE_CONFIG_ERR;
+
+		rte_approx_64(tb_rate, d, &dst->tb_credits_per_period,
+			&dst->tb_period);
+	}
+
+	dst->tb_size = src->tb_size;
+
+	/* Traffic Classes */
+	dst->tc_period = rte_sched_time_ms_to_bytes(src->tc_period, rate);
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		dst->tc_credits_per_period[i]
+			= rte_sched_time_ms_to_bytes(src->tc_period,
+				src->tc_rate[i]);
+}
+
+static void
 rte_sched_subport_config_pipe_profile_table(struct rte_sched_subport *subport,
 	struct rte_sched_subport_params *params, uint32_t rate)
 {
@@ -646,6 +775,24 @@ rte_sched_subport_config_pipe_profile_table(struct rte_sched_subport *subport,
 	}
 }
 
+static void
+rte_sched_port_config_subport_profile_table(struct rte_sched_port *port,
+	struct rte_sched_port_params *params,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	for (i = 0; i < port->n_subport_profiles; i++) {
+		struct rte_sched_subport_profile_params *src
+				= params->subport_profiles + i;
+		struct rte_sched_subport_profile *dst
+				= port->subport_profiles + i;
+
+		rte_sched_subport_profile_convert(src, dst, rate);
+		rte_sched_port_log_subport_profile(port, i);
+	}
+}
+
 static int
 rte_sched_subport_check_params(struct rte_sched_subport_params *params,
 	uint32_t n_max_pipes_per_subport,
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index 8a5a93c..e7514bb 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -149,18 +149,6 @@ struct rte_sched_pipe_params {
  * byte.
  */
 struct rte_sched_subport_params {
-	/** Token bucket rate (measured in bytes per second) */
-	uint64_t tb_rate;
-
-	/** Token bucket size (measured in credits) */
-	uint64_t tb_size;
-
-	/** Traffic class rates (measured in bytes per second) */
-	uint64_t tc_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
-
-	/** Enforcement period for rates (measured in milliseconds) */
-	uint64_t tc_period;
-
 	/** Number of subport pipes.
 	 * The subport can enable/allocate fewer pipes than the maximum
 	 * number set through struct port_params::n_max_pipes_per_subport,
@@ -192,6 +180,20 @@ struct rte_sched_subport_params {
 #endif
 };
 
+struct rte_sched_subport_profile_params {
+	/** Token bucket rate (measured in bytes per second) */
+	uint64_t tb_rate;
+
+	/** Token bucket size (measured in credits) */
+	uint64_t tb_size;
+
+	/** Traffic class rates (measured in bytes per second) */
+	uint64_t tc_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+
+	/** Enforcement period for rates (measured in milliseconds) */
+	uint64_t tc_period;
+};
+
 /** Subport statistics */
 struct rte_sched_subport_stats {
 	/** Number of packets successfully written */
@@ -254,6 +256,17 @@ struct rte_sched_port_params {
 	/** Number of subports */
 	uint32_t n_subports_per_port;
 
+	/** subport profile table.
+	 * Every pipe is configured using one of the profiles from this table.
+	 */
+	struct rte_sched_subport_profile_params *subport_profiles;
+
+	/** Profiles in the pipe profile table */
+	uint32_t n_subport_profiles;
+
+	/** Max allowed profiles in the pipe profile table */
+	uint32_t n_max_subport_profiles;
+
 	/** Maximum number of subport pipes.
 	 * This parameter is used to reserve a fixed number of bits
 	 * in struct rte_mbuf::sched.queue_id for the pipe_id for all
-- 
2.7.4


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

* [dpdk-dev] [PATCH v1 2/4] sched: add dynamic config of subport bandwidth profile
  2020-09-02  8:56   ` [dpdk-dev] [PATCH v1 1/4] " Savinay Dharmappa
@ 2020-09-02  8:56     ` Savinay Dharmappa
  2020-09-02  8:56     ` [dpdk-dev] [PATCH v1 3/4] " Savinay Dharmappa
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-02  8:56 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

This patch builds the subport profile table during port
configuration. Since the tb_period,tb_size,tc_period,
tb_credits_per_period and tc_credits_per_period are updated
in subport profile table, references to them are removed
from subport configuration.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c | 154 +++++++++++++------------------------------
 1 file changed, 47 insertions(+), 107 deletions(-)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index c82e09c..c1846d0 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -438,6 +438,8 @@ subport_profile_check(struct rte_sched_subport_profile_params *params,
 static int
 rte_sched_port_check_params(struct rte_sched_port_params *params)
 {
+	uint32_t i;
+
 	if (params == NULL) {
 		RTE_LOG(ERR, SCHED,
 			"%s: Incorrect value for parameter params\n", __func__);
@@ -474,6 +476,29 @@ rte_sched_port_check_params(struct rte_sched_port_params *params)
 		return -EINVAL;
 	}
 
+	if (params->subport_profiles == NULL ||
+		params->n_subport_profiles == 0 ||
+		params->n_max_subport_profiles == 0 ||
+		params->n_subport_profiles > params->n_max_subport_profiles) {
+		RTE_LOG(ERR, SCHED,
+		"%s: Incorrect value for subport profiles\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < params->n_subport_profiles; i++) {
+		struct rte_sched_subport_profile_params *p =
+						params->subport_profiles + i;
+		int status;
+
+		status = subport_profile_check(p, params->rate);
+		if (status != 0) {
+			RTE_LOG(ERR, SCHED,
+			"%s: subport profile check failed(%d)\n",
+			__func__, status);
+			return -EINVAL;
+		}
+	}
+
 	/* n_pipes_per_subport: non-zero, power of 2 */
 	if (params->n_pipes_per_subport == 0 ||
 	    !rte_is_power_of_2(params->n_pipes_per_subport)) {
@@ -807,18 +832,6 @@ rte_sched_subport_check_params(struct rte_sched_subport_params *params,
 		return -EINVAL;
 	}
 
-	if (params->tb_rate == 0 || params->tb_rate > rate) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect value for tb rate\n", __func__);
-		return -EINVAL;
-	}
-
-	if (params->tb_size == 0) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect value for tb size\n", __func__);
-		return -EINVAL;
-	}
-
 	/* qsize: if non-zero, power of 2,
 	 * no bigger than 32K (due to 16-bit read/write pointers)
 	 */
@@ -832,32 +845,12 @@ rte_sched_subport_check_params(struct rte_sched_subport_params *params,
 		}
 	}
 
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
-		uint64_t tc_rate = params->tc_rate[i];
-		uint16_t qsize = params->qsize[i];
-
-		if ((qsize == 0 && tc_rate != 0) ||
-			(qsize != 0 && tc_rate == 0) ||
-			(tc_rate > params->tb_rate)) {
-			RTE_LOG(ERR, SCHED,
-				"%s: Incorrect value for tc rate\n", __func__);
-			return -EINVAL;
-		}
-	}
-
-	if (params->qsize[RTE_SCHED_TRAFFIC_CLASS_BE] == 0 ||
-		params->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
+	if (params->qsize[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
 		RTE_LOG(ERR, SCHED,
 			"%s: Incorrect qsize or tc rate(best effort)\n", __func__);
 		return -EINVAL;
 	}
 
-	if (params->tc_period == 0) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect value for tc period\n", __func__);
-		return -EINVAL;
-	}
-
 	/* n_pipes_per_subport: non-zero, power of 2 */
 	if (params->n_pipes_per_subport_enabled == 0 ||
 		params->n_pipes_per_subport_enabled > n_max_pipes_per_subport ||
@@ -939,7 +932,7 @@ struct rte_sched_port *
 rte_sched_port_config(struct rte_sched_port_params *params)
 {
 	struct rte_sched_port *port = NULL;
-	uint32_t size0, size1;
+	uint32_t size0, size1, size2;
 	uint32_t cycles_per_byte;
 	uint32_t i, j;
 	int status;
@@ -954,10 +947,21 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 
 	size0 = sizeof(struct rte_sched_port);
 	size1 = params->n_subports_per_port * sizeof(struct rte_sched_subport *);
+	size2 = params->n_max_subport_profiles *
+		sizeof(struct rte_sched_subport_profile);
 
 	/* Allocate memory to store the data structures */
-	port = rte_zmalloc_socket("qos_params", size0 + size1, RTE_CACHE_LINE_SIZE,
-		params->socket);
+	port = rte_zmalloc_socket("qos_params", size0 + size1,
+				 RTE_CACHE_LINE_SIZE, params->socket);
+	if (port == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: Memory allocation fails\n", __func__);
+
+		return NULL;
+	}
+
+	/* Allocate memory to store the subport profile */
+	port->subport_profiles  = rte_zmalloc_socket("subport_profile", size2,
+					RTE_CACHE_LINE_SIZE, params->socket);
 	if (port == NULL) {
 		RTE_LOG(ERR, SCHED, "%s: Memory allocation fails\n", __func__);
 
@@ -966,6 +970,8 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 
 	/* User parameters */
 	port->n_subports_per_port = params->n_subports_per_port;
+	port->n_subport_profiles = params->n_subport_profiles;
+	port->n_max_subport_profiles = params->n_max_subport_profiles;
 	port->n_pipes_per_subport = params->n_pipes_per_subport;
 	port->n_pipes_per_subport_log2 =
 			__builtin_ctz(params->n_pipes_per_subport);
@@ -996,6 +1002,9 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 	port->time_cpu_bytes = 0;
 	port->time = 0;
 
+	/* Subport profile table */
+	rte_sched_port_config_subport_profile_table(port, params, port->rate);
+
 	cycles_per_byte = (rte_get_tsc_hz() << RTE_SCHED_TIME_SHIFT)
 		/ params->rate;
 	port->inv_cycles_per_byte = rte_reciprocal_value(cycles_per_byte);
@@ -1054,48 +1063,6 @@ rte_sched_port_free(struct rte_sched_port *port)
 }
 
 static void
-rte_sched_port_log_subport_config(struct rte_sched_port *port, uint32_t i)
-{
-	struct rte_sched_subport *s = port->subports[i];
-
-	RTE_LOG(DEBUG, SCHED, "Low level config for subport %u:\n"
-		"	Token bucket: period = %"PRIu64", credits per period = %"PRIu64
-		", size = %"PRIu64"\n"
-		"	Traffic classes: period = %"PRIu64"\n"
-		"	credits per period = [%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
-		", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
-		", %"PRIu64", %"PRIu64", %"PRIu64"]\n"
-		"	Best effort traffic class oversubscription: wm min = %"PRIu64
-		", wm max = %"PRIu64"\n",
-		i,
-
-		/* Token bucket */
-		s->tb_period,
-		s->tb_credits_per_period,
-		s->tb_size,
-
-		/* Traffic classes */
-		s->tc_period,
-		s->tc_credits_per_period[0],
-		s->tc_credits_per_period[1],
-		s->tc_credits_per_period[2],
-		s->tc_credits_per_period[3],
-		s->tc_credits_per_period[4],
-		s->tc_credits_per_period[5],
-		s->tc_credits_per_period[6],
-		s->tc_credits_per_period[7],
-		s->tc_credits_per_period[8],
-		s->tc_credits_per_period[9],
-		s->tc_credits_per_period[10],
-		s->tc_credits_per_period[11],
-		s->tc_credits_per_period[12],
-
-		/* Best effort traffic class oversubscription */
-		s->tc_ov_wm_min,
-		s->tc_ov_wm_max);
-}
-
-static void
 rte_sched_free_memory(struct rte_sched_port *port, uint32_t n_subports)
 {
 	uint32_t i;
@@ -1168,33 +1135,7 @@ rte_sched_subport_config(struct rte_sched_port *port,
 	/* Port */
 	port->subports[subport_id] = s;
 
-	/* Token Bucket (TB) */
-	if (params->tb_rate == port->rate) {
-		s->tb_credits_per_period = 1;
-		s->tb_period = 1;
-	} else {
-		double tb_rate = ((double) params->tb_rate) / ((double) port->rate);
-		double d = RTE_SCHED_TB_RATE_CONFIG_ERR;
-
-		rte_approx_64(tb_rate, d, &s->tb_credits_per_period, &s->tb_period);
-	}
-
-	s->tb_size = params->tb_size;
 	s->tb_time = port->time;
-	s->tb_credits = s->tb_size / 2;
-
-	/* Traffic Classes (TCs) */
-	s->tc_period = rte_sched_time_ms_to_bytes(params->tc_period, port->rate);
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
-		if (params->qsize[i])
-			s->tc_credits_per_period[i]
-				= rte_sched_time_ms_to_bytes(params->tc_period,
-					params->tc_rate[i]);
-	}
-	s->tc_time = port->time + s->tc_period;
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-		if (params->qsize[i])
-			s->tc_credits[i] = s->tc_credits_per_period[i];
 
 	/* compile time checks */
 	RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS == 0);
@@ -1284,8 +1225,6 @@ rte_sched_subport_config(struct rte_sched_port *port,
 #ifdef RTE_SCHED_SUBPORT_TC_OV
 	/* TC oversubscription */
 	s->tc_ov_wm_min = port->mtu;
-	s->tc_ov_wm_max = rte_sched_time_ms_to_bytes(params->tc_period,
-						     s->pipe_tc_be_rate_max);
 	s->tc_ov_wm = s->tc_ov_wm_max;
 	s->tc_ov_period_id = 0;
 	s->tc_ov = 0;
@@ -1293,7 +1232,8 @@ rte_sched_subport_config(struct rte_sched_port *port,
 	s->tc_ov_rate = 0;
 #endif
 
-	rte_sched_port_log_subport_config(port, subport_id);
+	return 0;
+}
 
 	return 0;
 }
-- 
2.7.4


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

* [dpdk-dev] [PATCH v1 3/4] sched: add dynamic config of subport bandwidth profile
  2020-09-02  8:56   ` [dpdk-dev] [PATCH v1 1/4] " Savinay Dharmappa
  2020-09-02  8:56     ` [dpdk-dev] [PATCH v1 2/4] " Savinay Dharmappa
@ 2020-09-02  8:56     ` Savinay Dharmappa
  2020-09-02  8:56     ` [dpdk-dev] [PATCH v1 4/4] " Savinay Dharmappa
  2020-09-10 18:48     ` [dpdk-dev] [PATCH v2 00/10] Enable dynamic config of subport bandwidth Savinay Dharmappa
  3 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-02  8:56 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

This patch add public APIs to add new subport profile
and to configure them.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c | 115 ++++++++++++++++++++++++++++++++++++++++++-
 lib/librte_sched/rte_sched.h |  45 +++++++++++++++++
 2 files changed, 158 insertions(+), 2 deletions(-)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index c1846d0..770c8bd 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -1212,8 +1212,8 @@ rte_sched_subport_config(struct rte_sched_port *port,
 	s->bmp = rte_bitmap_init(n_subport_pipe_queues, s->bmp_array,
 				bmp_mem_size);
 	if (s->bmp == NULL) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Subport bitmap init error\n", __func__);
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Subport bitmap init error\n", __func__);
 
 		rte_sched_free_memory(port, n_subports);
 		return -EINVAL;
@@ -1235,6 +1235,52 @@ rte_sched_subport_config(struct rte_sched_port *port,
 	return 0;
 }
 
+int
+rte_sched_subport_profile_config(struct rte_sched_port *port,
+	uint32_t subport_id,
+	uint32_t profile_id)
+{
+	int i;
+	struct rte_sched_subport_profile *params;
+	uint32_t n_subports = subport_id + 1;
+	struct rte_sched_subport *s;
+
+	if (port == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter port\n", __func__);
+		return -EINVAL;
+	}
+
+	if (subport_id >= port->n_subports_per_port) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter subport id\n", __func__);
+
+		rte_sched_free_memory(port, n_subports);
+		return -EINVAL;
+	}
+
+	params =  port->subport_profiles + profile_id;
+
+	s = port->subports[subport_id];
+
+	s->tb_credits = params->tb_size / 2;
+
+	s->tc_time = port->time + params->tc_period;
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		if (s->qsize[i])
+			s->tc_credits[i] = params->tc_credits_per_period[i];
+		else
+			params->tc_credits_per_period[i] = 0;
+
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+	s->tc_ov_wm_max = rte_sched_time_ms_to_bytes(params->tc_period,
+						     s->pipe_tc_be_rate_max);
+#endif
+	s->profile = profile_id;
+
+	rte_sched_port_log_subport_profile(port, profile_id);
+
 	return 0;
 }
 
@@ -1422,6 +1468,71 @@ rte_sched_subport_pipe_profile_add(struct rte_sched_port *port,
 	return 0;
 }
 
+int
+rte_sched_port_subport_profile_add(struct rte_sched_port *port,
+	struct rte_sched_subport_profile_params *params,
+	uint32_t *subport_profile_id)
+{
+	int status;
+	uint32_t i;
+	struct rte_sched_subport_profile *dst;
+
+	/* Port */
+	if (port == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter port\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter profile\n", __func__);
+		return -EINVAL;
+	}
+
+	if (subport_profile_id == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parametersubport_profile_id\n",
+		__func__);
+		return -EINVAL;
+	}
+
+	dst = port->subport_profiles + port->n_subport_profiles;
+
+	/* Subport profiles exceeds the max limit */
+	if (port->n_subport_profiles >= port->n_max_subport_profiles) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Number of subport profiles exceeds the max limit", __func__);
+		return -EINVAL;
+	}
+
+	status = subport_profile_check(params, port->rate);
+	if (status != 0) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"subport profile check failed(%d)\n", __func__, status);
+		return -EINVAL;
+	}
+
+	rte_sched_subport_profile_convert(params, dst, port->rate);
+
+	/* Subport profile should not exists */
+	for (i = 0; i < port->n_subport_profiles; i++)
+		if (memcmp(port->subport_profiles + i,
+		    params, sizeof(*params)) == 0) {
+			RTE_LOG(ERR, SCHED,
+			"%s: subport profile exists\n", __func__);
+			return -EINVAL;
+		}
+
+	/* Subport profile commit */
+	*subport_profile_id = port->n_subport_profiles;
+	port->n_subport_profiles++;
+
+	rte_sched_port_log_subport_profile(port, *subport_profile_id);
+
+	return 0;
+}
+
 static inline uint32_t
 rte_sched_port_qindex(struct rte_sched_port *port,
 	uint32_t subport,
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index e7514bb..7623919 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -325,6 +325,29 @@ rte_sched_subport_pipe_profile_add(struct rte_sched_port *port,
 	uint32_t *pipe_profile_id);
 
 /**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Hierarchical scheduler subport bandwidth profile add
+ * Note that this function is safe to use in runtime for adding new
+ * subport bandwidth profile as it doesn't have any impact on hiearchical
+ * structure of the scheduler.
+ * @param port
+ *   Handle to port scheduler instance
+ * @param struct rte_sched_subport_profile
+ *   Subport bandwidth profile
+ * @param subport_profile_d
+ *   Subport profile id
+ * @return
+ *   0 upon success, error code otherwise
+ */
+__rte_experimental
+int
+rte_sched_port_subport_profile_add(struct rte_sched_port *port,
+	struct rte_sched_subport_profile_params *profile,
+	uint32_t *subport_profile_id);
+
+/**
  * Hierarchical scheduler subport configuration
  *
  * @param port
@@ -342,6 +365,28 @@ rte_sched_subport_config(struct rte_sched_port *port,
 	struct rte_sched_subport_params *params);
 
 /**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Hierarchical scheduler subport profile configuration
+ * Note that this function is safe to use in runtime for applying any specific
+ * subport bandwidth profile as it doesn't have any impact on hiearchical
+ * structure of the scheduler.
+ * @param port
+ *   Handle to port scheduler instance
+ * @param subport_id
+ *   Subport ID
+ * @param profile_d
+ *   Subport profile id
+ * @return
+ *   0 upon success, error code otherwise
+ */
+__rte_experimental
+int
+rte_sched_subport_profile_config(struct rte_sched_port *port,
+	uint32_t subport_id,
+	uint32_t profile_id);
+/**
  * Hierarchical scheduler pipe configuration
  *
  * @param port
-- 
2.7.4


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

* [dpdk-dev] [PATCH v1 4/4] sched: add dynamic config of subport bandwidth profile
  2020-09-02  8:56   ` [dpdk-dev] [PATCH v1 1/4] " Savinay Dharmappa
  2020-09-02  8:56     ` [dpdk-dev] [PATCH v1 2/4] " Savinay Dharmappa
  2020-09-02  8:56     ` [dpdk-dev] [PATCH v1 3/4] " Savinay Dharmappa
@ 2020-09-02  8:56     ` Savinay Dharmappa
  2020-09-10 18:48     ` [dpdk-dev] [PATCH v2 00/10] Enable dynamic config of subport bandwidth Savinay Dharmappa
  3 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-02  8:56 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

This patch modifies the way credits are updated. Credits
are updated by fetching parameters from subport profile
table.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c           | 62 ++++++++++++++++++++++------------
 lib/librte_sched/rte_sched_version.map |  2 ++
 2 files changed, 43 insertions(+), 21 deletions(-)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index 770c8bd..cfbcf5c 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -124,6 +124,7 @@ struct rte_sched_grinder {
 	uint32_t productive;
 	uint32_t pindex;
 	struct rte_sched_subport *subport;
+	struct rte_sched_subport_profile *subport_params;
 	struct rte_sched_pipe *pipe;
 	struct rte_sched_pipe_profile *pipe_params;
 
@@ -1291,6 +1292,7 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 	int32_t pipe_profile)
 {
 	struct rte_sched_subport *s;
+	struct rte_sched_subport_profile *sp;
 	struct rte_sched_pipe *p;
 	struct rte_sched_pipe_profile *params;
 	uint32_t n_subports = subport_id + 1;
@@ -1331,14 +1333,16 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 		return -EINVAL;
 	}
 
+	sp = port->subport_profiles + s->profile;
+
 	/* Handle the case when pipe already has a valid configuration */
 	p = s->pipe + pipe_id;
 	if (p->tb_time) {
 		params = s->pipe_profiles + p->profile;
 
 		double subport_tc_be_rate =
-			(double) s->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
-			/ (double) s->tc_period;
+		(double) sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
+		/ (double) sp->tc_period;
 		double pipe_tc_be_rate =
 			(double) params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
 			/ (double) params->tc_period;
@@ -1380,8 +1384,8 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 	{
 		/* Subport best effort tc oversubscription */
 		double subport_tc_be_rate =
-			(double) s->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
-			/ (double) s->tc_period;
+		(double) sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
+			/ (double) sp->tc_period;
 		double pipe_tc_be_rate =
 			(double) params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
 			/ (double) params->tc_period;
@@ -1393,8 +1397,9 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 
 		if (s->tc_ov != tc_be_ov) {
 			RTE_LOG(DEBUG, SCHED,
-				"Subport %u Best effort TC oversubscription is ON (%.4lf < %.4lf)\n",
-				subport_id, subport_tc_be_rate, s->tc_ov_rate);
+			"Subport %u Best effort TC oversubscription is ON "
+			"(%.4lf < %.4lf)\n",
+			subport_id, subport_tc_be_rate, s->tc_ov_rate);
 		}
 		p->tc_ov_period_id = s->tc_ov_period_id;
 		p->tc_ov_credits = s->tc_ov_wm;
@@ -2168,14 +2173,18 @@ grinder_credits_update(struct rte_sched_port *port,
 	struct rte_sched_grinder *grinder = subport->grinder + pos;
 	struct rte_sched_pipe *pipe = grinder->pipe;
 	struct rte_sched_pipe_profile *params = grinder->pipe_params;
+	struct rte_sched_subport_profile *subport_params =
+						grinder->subport_params;
 	uint64_t n_periods;
 	uint32_t i;
 
 	/* Subport TB */
-	n_periods = (port->time - subport->tb_time) / subport->tb_period;
-	subport->tb_credits += n_periods * subport->tb_credits_per_period;
-	subport->tb_credits = RTE_MIN(subport->tb_credits, subport->tb_size);
-	subport->tb_time += n_periods * subport->tb_period;
+	n_periods = (port->time - subport->tb_time) / subport_params->tb_period;
+	subport->tb_credits += n_periods *
+			       subport_params->tb_credits_per_period;
+	subport->tb_credits = RTE_MIN(subport->tb_credits,
+				      subport_params->tb_size);
+	subport->tb_time += n_periods * subport_params->tb_period;
 
 	/* Pipe TB */
 	n_periods = (port->time - pipe->tb_time) / params->tb_period;
@@ -2186,9 +2195,10 @@ grinder_credits_update(struct rte_sched_port *port,
 	/* Subport TCs */
 	if (unlikely(port->time >= subport->tc_time)) {
 		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-			subport->tc_credits[i] = subport->tc_credits_per_period[i];
+			subport->tc_credits[i] =
+				subport_params->tc_credits_per_period[i];
 
-		subport->tc_time = port->time + subport->tc_period;
+		subport->tc_time = port->time + subport_params->tc_period;
 	}
 
 	/* Pipe TCs */
@@ -2206,6 +2216,8 @@ static inline uint64_t
 grinder_tc_ov_credits_update(struct rte_sched_port *port,
 	struct rte_sched_subport *subport)
 {
+	struct rte_sched_subport_profile *subport_params =
+						grinder->subport_params;
 	uint64_t tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
 	uint64_t tc_consumption = 0, tc_ov_consumption_max;
 	uint64_t tc_ov_wm = subport->tc_ov_wm;
@@ -2216,16 +2228,17 @@ grinder_tc_ov_credits_update(struct rte_sched_port *port,
 
 	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASS_BE; i++) {
 		tc_ov_consumption[i] =
-			subport->tc_credits_per_period[i] - subport->tc_credits[i];
+			subport_params->tc_credits_per_period[i] -
+						subport->tc_credits[i];
 		tc_consumption += tc_ov_consumption[i];
 	}
 
 	tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] =
-		subport->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
+	subport_params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
 		subport->tc_credits[RTE_SCHED_TRAFFIC_CLASS_BE];
 
 	tc_ov_consumption_max =
-		subport->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
+	subport_params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
 			tc_consumption;
 
 	if (tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] >
@@ -2251,14 +2264,18 @@ grinder_credits_update(struct rte_sched_port *port,
 	struct rte_sched_grinder *grinder = subport->grinder + pos;
 	struct rte_sched_pipe *pipe = grinder->pipe;
 	struct rte_sched_pipe_profile *params = grinder->pipe_params;
+	struct rte_sched_subport_profile *subport_params =
+						grinder->subport_params;
 	uint64_t n_periods;
 	uint32_t i;
 
 	/* Subport TB */
-	n_periods = (port->time - subport->tb_time) / subport->tb_period;
-	subport->tb_credits += n_periods * subport->tb_credits_per_period;
-	subport->tb_credits = RTE_MIN(subport->tb_credits, subport->tb_size);
-	subport->tb_time += n_periods * subport->tb_period;
+	n_periods = (port->time - subport->tb_time) / subport_params->tb_period;
+	subport->tb_credits += n_periods *
+				subport_params->tb_credits_per_period;
+	subport->tb_credits = RTE_MIN(subport->tb_credits,
+				subport_params->tb_size);
+	subport->tb_time += n_periods * subport_params->tb_period;
 
 	/* Pipe TB */
 	n_periods = (port->time - pipe->tb_time) / params->tb_period;
@@ -2271,9 +2288,10 @@ grinder_credits_update(struct rte_sched_port *port,
 		subport->tc_ov_wm = grinder_tc_ov_credits_update(port, subport);
 
 		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-			subport->tc_credits[i] = subport->tc_credits_per_period[i];
+			subport->tc_credits[i] =
+				subport_params->tc_credits_per_period[i];
 
-		subport->tc_time = port->time + subport->tc_period;
+		subport->tc_time = port->time + subport_params->tc_period;
 		subport->tc_ov_period_id++;
 	}
 
@@ -2796,6 +2814,8 @@ grinder_handle(struct rte_sched_port *port,
 		struct rte_sched_pipe *pipe = grinder->pipe;
 
 		grinder->pipe_params = subport->pipe_profiles + pipe->profile;
+		grinder->subport_params = port->subport_profiles +
+					  subport->profile;
 		grinder_prefetch_tc_queue_arrays(subport, pos);
 		grinder_credits_update(port, subport, pos);
 
diff --git a/lib/librte_sched/rte_sched_version.map b/lib/librte_sched/rte_sched_version.map
index cefd990..c02a223 100644
--- a/lib/librte_sched/rte_sched_version.map
+++ b/lib/librte_sched/rte_sched_version.map
@@ -28,4 +28,6 @@ EXPERIMENTAL {
 	global:
 
 	rte_sched_subport_pipe_profile_add;
+	rte_sched_port_subport_profile_add;
+	rte_sched_subport_profile_config;
 };
-- 
2.7.4


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

* [dpdk-dev] [PATCH v1 1/4] example/qos_sched: subport bandwidth dynmaic conf
  2020-07-15 18:27 ` [dpdk-dev] [RFC PATCH 2/2] example/qos_sched: subport bandwidth profile config Savinay Dharmappa
  2020-07-16  8:14   ` Singh, Jasvinder
@ 2020-09-02  9:07   ` Savinay Dharmappa
  2020-09-02  9:07     ` [dpdk-dev] [PATCH v1 2/4] example/ip_pipeline: " Savinay Dharmappa
                       ` (3 more replies)
  1 sibling, 4 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-02  9:07 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

qos sched application uses the new apis introduced as part of dynamic
configuration of subport bandwidth to configure the deafult subport
bandwidth profile while buidling the hirerachical scheduler.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 examples/qos_sched/cfg_file.c  | 158 ++++++++++++++++++++++++-----------------
 examples/qos_sched/cfg_file.h  |   4 ++
 examples/qos_sched/init.c      |  24 +++++--
 examples/qos_sched/main.h      |   1 +
 examples/qos_sched/profile.cfg |   3 +
 5 files changed, 120 insertions(+), 70 deletions(-)

diff --git a/examples/qos_sched/cfg_file.c b/examples/qos_sched/cfg_file.c
index f078e4f..9e1341c 100644
--- a/examples/qos_sched/cfg_file.c
+++ b/examples/qos_sched/cfg_file.c
@@ -53,8 +53,11 @@ cfg_load_pipe(struct rte_cfgfile *cfg, struct rte_sched_pipe_params *pipe_params
 	if (!cfg || !pipe_params)
 		return -1;
 
-	profiles = rte_cfgfile_num_sections(cfg, "pipe profile", sizeof("pipe profile") - 1);
-	subport_params[0].n_pipe_profiles = profiles;
+	profiles = rte_cfgfile_num_sections(cfg, "pipe profile",
+					sizeof("pipe profile") - 1);
+	port_params.n_subport_profiles = profiles;
+
+	printf(" profiles = %d", profiles);
 
 	for (j = 0; j < profiles; j++) {
 		char pipe_name[32];
@@ -143,6 +146,93 @@ cfg_load_pipe(struct rte_cfgfile *cfg, struct rte_sched_pipe_params *pipe_params
 }
 
 int
+cfg_load_subport_profile(struct rte_cfgfile *cfg,
+	struct rte_sched_subport_profile_params *subport_profile)
+{
+	int i;
+	const char *entry;
+	int profiles;
+
+	if (!cfg || !subport_profile)
+		return -1;
+
+	profiles = rte_cfgfile_num_sections(cfg, "subport profile",
+					   sizeof("subport profile") - 1);
+	subport_params[0].n_pipe_profiles = profiles;
+
+	for (i = 0; i < profiles; i++) {
+		char sec_name[32];
+		snprintf(sec_name, sizeof(sec_name), "subport profile %d", i);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tb rate");
+		if (entry)
+			subport_profile[i].tb_rate = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tb size");
+		if (entry)
+			subport_profile[i].tb_size = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc period");
+		if (entry)
+			subport_profile[i].tc_period = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 0 rate");
+		if (entry)
+			subport_profile[i].tc_rate[0] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 1 rate");
+		if (entry)
+			subport_profile[i].tc_rate[1] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 2 rate");
+		if (entry)
+			subport_profile[i].tc_rate[2] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 3 rate");
+		if (entry)
+			subport_profile[i].tc_rate[3] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 4 rate");
+		if (entry)
+			subport_profile[i].tc_rate[4] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 5 rate");
+		if (entry)
+			subport_profile[i].tc_rate[5] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 6 rate");
+		if (entry)
+			subport_profile[i].tc_rate[6] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 7 rate");
+		if (entry)
+			subport_profile[i].tc_rate[7] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 8 rate");
+		if (entry)
+			subport_profile[i].tc_rate[8] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 9 rate");
+		if (entry)
+			subport_profile[i].tc_rate[9] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 10 rate");
+		if (entry)
+			subport_profile[i].tc_rate[10] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 11 rate");
+		if (entry)
+			subport_profile[i].tc_rate[11] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 12 rate");
+		if (entry)
+			subport_profile[i].tc_rate[12] = (uint64_t)atoi(entry);
+	}
+
+	return 0;
+}
+
+int
 cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subport_params)
 {
 	const char *entry;
@@ -267,70 +357,6 @@ cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subpo
 				}
 			}
 
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tb rate");
-			if (entry)
-				subport_params[i].tb_rate = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tb size");
-			if (entry)
-				subport_params[i].tb_size = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc period");
-			if (entry)
-				subport_params[i].tc_period = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 0 rate");
-			if (entry)
-				subport_params[i].tc_rate[0] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 1 rate");
-			if (entry)
-				subport_params[i].tc_rate[1] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 2 rate");
-			if (entry)
-				subport_params[i].tc_rate[2] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 3 rate");
-			if (entry)
-				subport_params[i].tc_rate[3] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 4 rate");
-			if (entry)
-				subport_params[i].tc_rate[4] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 5 rate");
-			if (entry)
-				subport_params[i].tc_rate[5] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 6 rate");
-			if (entry)
-				subport_params[i].tc_rate[6] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 7 rate");
-			if (entry)
-				subport_params[i].tc_rate[7] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 8 rate");
-			if (entry)
-				subport_params[i].tc_rate[8] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 9 rate");
-			if (entry)
-				subport_params[i].tc_rate[9] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 10 rate");
-			if (entry)
-				subport_params[i].tc_rate[10] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 11 rate");
-			if (entry)
-				subport_params[i].tc_rate[11] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 12 rate");
-			if (entry)
-				subport_params[i].tc_rate[12] = (uint64_t)atoi(entry);
-
 			int n_entries = rte_cfgfile_section_num_entries(cfg, sec_name);
 			struct rte_cfgfile_entry entries[n_entries];
 
diff --git a/examples/qos_sched/cfg_file.h b/examples/qos_sched/cfg_file.h
index 2eccf1c..0dc458a 100644
--- a/examples/qos_sched/cfg_file.h
+++ b/examples/qos_sched/cfg_file.h
@@ -14,4 +14,8 @@ int cfg_load_pipe(struct rte_cfgfile *cfg, struct rte_sched_pipe_params *pipe);
 
 int cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subport);
 
+int cfg_load_subport_profile(struct rte_cfgfile *cfg,
+			     struct rte_sched_subport_profile_params
+			     *subport_profile);
+
 #endif
diff --git a/examples/qos_sched/init.c b/examples/qos_sched/init.c
index 9626c15..541adb7 100644
--- a/examples/qos_sched/init.c
+++ b/examples/qos_sched/init.c
@@ -196,15 +196,20 @@ static struct rte_sched_pipe_params pipe_profiles[MAX_SCHED_PIPE_PROFILES] = {
 	},
 };
 
-struct rte_sched_subport_params subport_params[MAX_SCHED_SUBPORTS] = {
+static struct rte_sched_subport_profile_params
+		subport_profile[MAX_SCHED_SUBPORT_PROFILES] = {
 	{
 		.tb_rate = 1250000000,
 		.tb_size = 1000000,
-
 		.tc_rate = {1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000},
 		.tc_period = 10,
+	},
+};
+
+struct rte_sched_subport_params subport_params[MAX_SCHED_SUBPORTS] = {
+	{
 		.n_pipes_per_subport_enabled = 4096,
 		.qsize = {64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64},
 		.pipe_profiles = pipe_profiles,
@@ -289,6 +294,9 @@ struct rte_sched_port_params port_params = {
 	.mtu = 6 + 6 + 4 + 4 + 2 + 1500,
 	.frame_overhead = RTE_SCHED_FRAME_OVERHEAD_DEFAULT,
 	.n_subports_per_port = 1,
+	.n_subport_profiles = 1,
+	.subport_profiles = subport_profile,
+	.n_max_subport_profiles = MAX_SCHED_SUBPORT_PROFILES,
 	.n_pipes_per_subport = MAX_SCHED_PIPES,
 };
 
@@ -320,8 +328,15 @@ app_init_sched_port(uint32_t portid, uint32_t socketid)
 	for (subport = 0; subport < port_params.n_subports_per_port; subport ++) {
 		err = rte_sched_subport_config(port, subport, &subport_params[subport]);
 		if (err) {
-			rte_exit(EXIT_FAILURE, "Unable to config sched subport %u, err=%d\n",
-					subport, err);
+			rte_exit(EXIT_FAILURE, "Unable to config schedi "
+				"subport %u, err=%d\n", subport, err);
+		}
+
+		err = rte_sched_subport_profile_config(port, subport, 0);
+		if (err) {
+			rte_exit(EXIT_FAILURE, "failed to configure "
+				"profile err=%d\n", err);
+
 		}
 
 		uint32_t n_pipes_per_subport =
@@ -354,6 +369,7 @@ app_load_cfg_profile(const char *profile)
 
 	cfg_load_port(file, &port_params);
 	cfg_load_subport(file, subport_params);
+	cfg_load_subport_profile(file, subport_profile);
 	cfg_load_pipe(file, pipe_profiles);
 
 	rte_cfgfile_close(file);
diff --git a/examples/qos_sched/main.h b/examples/qos_sched/main.h
index 23bc418..0d6815a 100644
--- a/examples/qos_sched/main.h
+++ b/examples/qos_sched/main.h
@@ -51,6 +51,7 @@ extern "C" {
 #define MAX_SCHED_SUBPORTS		8
 #define MAX_SCHED_PIPES		4096
 #define MAX_SCHED_PIPE_PROFILES		256
+#define MAX_SCHED_SUBPORT_PROFILES	8
 
 #ifndef APP_COLLECT_STAT
 #define APP_COLLECT_STAT		1
diff --git a/examples/qos_sched/profile.cfg b/examples/qos_sched/profile.cfg
index 61b8b70..4486d27 100644
--- a/examples/qos_sched/profile.cfg
+++ b/examples/qos_sched/profile.cfg
@@ -26,6 +26,9 @@ number of subports per port = 1
 number of pipes per subport = 4096
 queue sizes = 64 64 64 64 64 64 64 64 64 64 64 64 64
 
+subport 0-8 = 0                ; These subports are configured with subport profile 0
+
+[subport profile 0]
 tb rate = 1250000000           ; Bytes per second
 tb size = 1000000              ; Bytes
 
-- 
2.7.4


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

* [dpdk-dev] [PATCH v1 2/4] example/ip_pipeline: subport bandwidth dynmaic conf
  2020-09-02  9:07   ` [dpdk-dev] [PATCH v1 1/4] example/qos_sched: subport bandwidth dynmaic conf Savinay Dharmappa
@ 2020-09-02  9:07     ` Savinay Dharmappa
  2020-09-02  9:07     ` [dpdk-dev] [PATCH v1 3/4] drivers/softnic: subport bandwidth profile config Savinay Dharmappa
                       ` (2 subsequent siblings)
  3 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-02  9:07 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

ip_pipeline application uses the new apis introduced as part of dynamic
configuration of subport bandwidth to configure the deafult subport
bandwidth profile while buidling the hirerachical scheduler

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 examples/ip_pipeline/cli.c  | 10 ++++++----
 examples/ip_pipeline/tmgr.c | 28 +++++++++++++++++++++++++---
 examples/ip_pipeline/tmgr.h |  3 ++-
 3 files changed, 33 insertions(+), 8 deletions(-)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index d79699e..e192275 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -406,7 +406,8 @@ cmd_tmgr_subport_profile(char **tokens,
 	char *out,
 	size_t out_size)
 {
-	struct rte_sched_subport_params p;
+	struct rte_sched_subport_params params;
+	struct rte_sched_subport_profile_params p;
 	int status, i;
 
 	if (n_tokens != 35) {
@@ -440,7 +441,8 @@ cmd_tmgr_subport_profile(char **tokens,
 		return;
 	}
 
-	if (parser_read_uint32(&p.n_pipes_per_subport_enabled, tokens[20]) != 0) {
+	if (parser_read_uint32(&params.n_pipes_per_subport_enabled,
+		tokens[20]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport");
 		return;
 	}
@@ -451,12 +453,12 @@ cmd_tmgr_subport_profile(char **tokens,
 	}
 
 	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-		if (parser_read_uint16(&p.qsize[i], tokens[22 + i]) != 0) {
+		if (parser_read_uint16(&params.qsize[i], tokens[22 + i]) != 0) {
 			snprintf(out, out_size, MSG_ARG_INVALID, "qsize");
 			return;
 		}
 
-	status = tmgr_subport_profile_add(&p);
+	status = tmgr_subport_profile_add(&p, &params);
 	if (status != 0) {
 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
 		return;
diff --git a/examples/ip_pipeline/tmgr.c b/examples/ip_pipeline/tmgr.c
index 91ccbf6..c609102 100644
--- a/examples/ip_pipeline/tmgr.c
+++ b/examples/ip_pipeline/tmgr.c
@@ -11,6 +11,9 @@
 static struct rte_sched_subport_params
 	subport_profile[TMGR_SUBPORT_PROFILE_MAX];
 
+static struct rte_sched_subport_profile_params
+		profile_params[TMGR_SUBPORT_PROFILE_MAX];
+
 static uint32_t n_subport_profiles;
 
 static struct rte_sched_pipe_params
@@ -44,15 +47,20 @@ tmgr_port_find(const char *name)
 }
 
 int
-tmgr_subport_profile_add(struct rte_sched_subport_params *p)
+tmgr_subport_profile_add(struct rte_sched_subport_profile_params *p,
+			 struct rte_sched_subport_params *params)
 {
 	/* Check input params */
-	if (p == NULL ||
-		p->n_pipes_per_subport_enabled == 0)
+	if (p == NULL || params == NULL ||
+		params->n_pipes_per_subport_enabled == 0)
 		return -1;
 
 	/* Save profile */
 	memcpy(&subport_profile[n_subport_profiles],
+		params,
+		sizeof(*params));
+
+	memcpy(&profile_params[n_subport_profiles],
 		p,
 		sizeof(*p));
 
@@ -103,6 +111,9 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 	p.mtu = params->mtu;
 	p.frame_overhead = params->frame_overhead;
 	p.n_subports_per_port = params->n_subports_per_port;
+	p.n_subport_profiles = n_subport_profiles;
+	p.subport_profiles = profile_params;
+	p.n_max_subport_profiles = TMGR_SUBPORT_PROFILE_MAX;
 	p.n_pipes_per_subport = TMGR_PIPE_SUBPORT_MAX;
 
 	s = rte_sched_port_config(&p);
@@ -126,6 +137,13 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 			return NULL;
 		}
 
+		status = rte_sched_subport_profile_config(s, i, 0);
+
+		if (status) {
+			rte_sched_port_free(s);
+			return NULL;
+		}
+
 		for (j = 0; j < subport_profile[0].n_pipes_per_subport_enabled; j++) {
 			status = rte_sched_pipe_config(
 				s,
@@ -182,6 +200,10 @@ tmgr_subport_config(const char *port_name,
 		subport_id,
 		&subport_profile[subport_profile_id]);
 
+	if (!status)
+		status = rte_sched_subport_profile_config(port->s, subport_id,
+							subport_profile_id);
+
 	return status;
 }
 
diff --git a/examples/ip_pipeline/tmgr.h b/examples/ip_pipeline/tmgr.h
index ee50cf7..b19fb23 100644
--- a/examples/ip_pipeline/tmgr.h
+++ b/examples/ip_pipeline/tmgr.h
@@ -48,7 +48,8 @@ struct tmgr_port_params {
 };
 
 int
-tmgr_subport_profile_add(struct rte_sched_subport_params *p);
+tmgr_subport_profile_add(struct rte_sched_subport_profile_params *p,
+			 struct rte_sched_subport_params *params);
 
 int
 tmgr_pipe_profile_add(struct rte_sched_pipe_params *p);
-- 
2.7.4


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

* [dpdk-dev] [PATCH v1 3/4] drivers/softnic: subport bandwidth profile config
  2020-09-02  9:07   ` [dpdk-dev] [PATCH v1 1/4] example/qos_sched: subport bandwidth dynmaic conf Savinay Dharmappa
  2020-09-02  9:07     ` [dpdk-dev] [PATCH v1 2/4] example/ip_pipeline: " Savinay Dharmappa
@ 2020-09-02  9:07     ` Savinay Dharmappa
  2020-09-02  9:07     ` [dpdk-dev] [PATCH v1 4/4] app/test_sched: " Savinay Dharmappa
  2020-09-02 10:46     ` [dpdk-dev] [PATCH v1 1/4] example/qos_sched: subport bandwidth dynmaic conf Dharmappa, Savinay
  3 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-02  9:07 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

softnic driver uses the new apis introduced as part of dynamic
configuration of subport bandwidth to configure the deafult subport
bandwidth profile while buidling the hirerachical scheduler.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 drivers/net/softnic/rte_eth_softnic_internals.h |   9 +
 drivers/net/softnic/rte_eth_softnic_tm.c        | 222 +++++++++++++++++++-----
 2 files changed, 186 insertions(+), 45 deletions(-)

diff --git a/drivers/net/softnic/rte_eth_softnic_internals.h b/drivers/net/softnic/rte_eth_softnic_internals.h
index 6eec43b..cc50037 100644
--- a/drivers/net/softnic/rte_eth_softnic_internals.h
+++ b/drivers/net/softnic/rte_eth_softnic_internals.h
@@ -164,10 +164,19 @@ TAILQ_HEAD(softnic_link_list, softnic_link);
 #ifndef TM_MAX_PIPE_PROFILE
 #define TM_MAX_PIPE_PROFILE				256
 #endif
+
+#ifndef TM_MAX_SUBPORT_PROFILE
+#define TM_MAX_SUBPORT_PROFILE				256
+#endif
+
 struct tm_params {
 	struct rte_sched_port_params port_params;
 
 	struct rte_sched_subport_params subport_params[TM_MAX_SUBPORTS];
+	struct rte_sched_subport_profile_params
+				subport_profiles[TM_MAX_SUBPORT_PROFILE];
+	uint32_t n_subport_profiles;
+	uint32_t subport_to_profile[TM_MAX_SUBPORT_PROFILE];
 
 	struct rte_sched_pipe_params pipe_profiles[TM_MAX_PIPE_PROFILE];
 	uint32_t n_pipe_profiles;
diff --git a/drivers/net/softnic/rte_eth_softnic_tm.c b/drivers/net/softnic/rte_eth_softnic_tm.c
index 80a470c..881f025 100644
--- a/drivers/net/softnic/rte_eth_softnic_tm.c
+++ b/drivers/net/softnic/rte_eth_softnic_tm.c
@@ -98,6 +98,13 @@ softnic_tmgr_port_create(struct pmd_internals *p,
 			return NULL;
 		}
 
+		status = rte_sched_subport_profile_config(sched,
+			subport_id, t->subport_to_profile[subport_id]);
+		if (status) {
+			rte_sched_port_free(sched);
+			return NULL;
+		}
+
 		/* Pipe */
 		for (pipe_id = 0; pipe_id < n_pipes_per_subport; pipe_id++) {
 			int pos = subport_id * TM_MAX_PIPES_PER_SUBPORT + pipe_id;
@@ -1043,6 +1050,25 @@ tm_shared_shaper_get_tc(struct rte_eth_dev *dev,
 }
 
 static int
+subport_profile_exists(struct rte_eth_dev *dev,
+	struct rte_sched_subport_profile_params *sp,
+	uint32_t *subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+	uint32_t i;
+
+	for (i = 0; i < t->n_subport_profiles; i++)
+		if (memcmp(&t->subport_profiles[i], sp, sizeof(*sp)) == 0) {
+			if (subport_profile_id)
+				*subport_profile_id = i;
+			return 1;
+		}
+
+	return 0;
+}
+
+static int
 update_subport_tc_rate(struct rte_eth_dev *dev,
 	struct tm_node *nt,
 	struct tm_shared_shaper *ss,
@@ -1050,26 +1076,27 @@ update_subport_tc_rate(struct rte_eth_dev *dev,
 {
 	struct pmd_internals *p = dev->data->dev_private;
 	uint32_t tc_id = tm_node_tc_id(dev, nt);
-
 	struct tm_node *np = nt->parent_node;
-
 	struct tm_node *ns = np->parent_node;
 	uint32_t subport_id = tm_node_subport_id(dev, ns);
-
-	struct rte_sched_subport_params subport_params;
-
+	struct rte_sched_subport_profile_params subport_profile;
 	struct tm_shaper_profile *sp_old = tm_shaper_profile_search(dev,
 		ss->shaper_profile_id);
+	uint32_t subport_profile_id;
 
 	/* Derive new subport configuration. */
-	memcpy(&subport_params,
-		&p->soft.tm.params.subport_params[subport_id],
-		sizeof(subport_params));
-	subport_params.tc_rate[tc_id] = sp_new->params.peak.rate;
+	memcpy(&subport_profile,
+		&p->soft.tm.params.subport_profiles[subport_id],
+		sizeof(subport_profile));
+	subport_profile.tc_rate[tc_id] = sp_new->params.peak.rate;
+
+	if (subport_profile_exists(dev, &subport_profile,
+				  &subport_profile_id) == 0)
+		return -1;
 
 	/* Update the subport configuration. */
-	if (rte_sched_subport_config(SCHED(p),
-		subport_id, &subport_params))
+	if (rte_sched_subport_profile_config(SCHED(p),
+		subport_id, subport_profile_id))
 		return -1;
 
 	/* Commit changes. */
@@ -1078,9 +1105,9 @@ update_subport_tc_rate(struct rte_eth_dev *dev,
 	ss->shaper_profile_id = sp_new->shaper_profile_id;
 	sp_new->n_users++;
 
-	memcpy(&p->soft.tm.params.subport_params[subport_id],
-		&subport_params,
-		sizeof(subport_params));
+	memcpy(&p->soft.tm.params.subport_profiles[subport_id],
+		&subport_profile,
+		sizeof(subport_profile));
 
 	return 0;
 }
@@ -2190,6 +2217,108 @@ pipe_profiles_generate(struct rte_eth_dev *dev)
 	return 0;
 }
 
+static struct rte_sched_subport_profile_params *
+subport_profile_get(struct rte_eth_dev *dev, struct tm_node *np)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+	uint32_t subport_id = tm_node_subport_id(dev, np->parent_node);
+
+	return &t->subport_profiles[subport_id];
+}
+
+static void
+subport_profile_mark(struct rte_eth_dev *dev,
+	uint32_t subport_id,
+	uint32_t subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+
+	t->subport_to_profile[subport_id] = subport_profile_id;
+}
+
+static void
+subport_profile_install(struct rte_eth_dev *dev,
+	struct rte_sched_subport_profile_params *sp,
+	uint32_t subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+
+	memcpy(&t->subport_profiles[subport_profile_id], sp, sizeof(*sp));
+	t->n_subport_profiles++;
+}
+
+static int
+subport_profile_free_exists(struct rte_eth_dev *dev,
+	uint32_t *subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+
+	if (t->n_subport_profiles < TM_MAX_SUBPORT_PROFILE) {
+		*subport_profile_id = t->n_subport_profiles;
+		return 1;
+	}
+
+	return 0;
+}
+
+static void
+subport_profile_build(struct tm_node *np,
+	struct rte_sched_subport_profile_params *sp)
+{
+	memset(sp, 0, sizeof(*sp));
+
+	/* Pipe */
+	sp->tb_rate = np->shaper_profile->params.peak.rate;
+	sp->tb_size = np->shaper_profile->params.peak.size;
+
+	/* Traffic Class (TC) */
+	sp->tc_period = SUBPORT_TC_PERIOD;
+}
+
+static int
+subport_profiles_generate(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_hierarchy *h = &p->soft.tm.h;
+	struct tm_node_list *nl = &h->nodes;
+	struct tm_node *ns;
+	uint32_t subport_id;
+
+	/* Objective: Fill in the following fields in struct tm_params:
+	 *    - subport_profiles
+	 *    - n_subport_profiles
+	 *    - subport_to_profile
+	 */
+
+	subport_id = 0;
+	TAILQ_FOREACH(ns, nl, node) {
+		if (ns->level != TM_NODE_LEVEL_SUBPORT)
+			continue;
+
+		struct rte_sched_subport_profile_params sp;
+		uint32_t pos;
+
+		subport_profile_build(ns, &sp);
+
+		if (!subport_profile_exists(dev, &sp, &pos)) {
+			if (!subport_profile_free_exists(dev, &pos))
+				return -1;
+
+			subport_profile_install(dev, &sp, pos);
+		}
+
+		subport_profile_mark(dev, subport_id, pos);
+
+		subport_id++;
+	}
+
+	return 0;
+}
+
 static struct tm_wred_profile *
 tm_tc_wred_profile_get(struct rte_eth_dev *dev, uint32_t tc_id)
 {
@@ -2447,6 +2576,15 @@ hierarchy_commit_check(struct rte_eth_dev *dev, struct rte_tm_error *error)
 				rte_strerror(EINVAL));
 	}
 
+	/* Not too many subport profiles. */
+	if (subport_profiles_generate(dev))
+		return -rte_tm_error_set(error,
+			EINVAL,
+			RTE_TM_ERROR_TYPE_UNSPECIFIED,
+			NULL,
+			rte_strerror(EINVAL));
+
+
 	/* Not too many pipe profiles. */
 	if (pipe_profiles_generate(dev))
 		return -rte_tm_error_set(error,
@@ -2528,6 +2666,8 @@ hierarchy_blueprints_create(struct rte_eth_dev *dev)
 		.frame_overhead =
 			root->shaper_profile->params.pkt_length_adjust,
 		.n_subports_per_port = root->n_children,
+		.n_subport_profiles = t->n_subport_profiles,
+		.subport_profiles = t->subport_profiles,
 		.n_pipes_per_subport = TM_MAX_PIPES_PER_SUBPORT,
 	};
 
@@ -2548,28 +2688,11 @@ hierarchy_blueprints_create(struct rte_eth_dev *dev)
 				ss->shaper_profile_id) :
 				n->shaper_profile;
 			tc_rate[i] = sp->params.peak.rate;
+			t->subport_profiles[subport_id].tc_rate[i] = tc_rate[i];
 		}
 
 		t->subport_params[subport_id] =
 			(struct rte_sched_subport_params) {
-				.tb_rate = n->shaper_profile->params.peak.rate,
-				.tb_size = n->shaper_profile->params.peak.size,
-
-				.tc_rate = {tc_rate[0],
-					tc_rate[1],
-					tc_rate[2],
-					tc_rate[3],
-					tc_rate[4],
-					tc_rate[5],
-					tc_rate[6],
-					tc_rate[7],
-					tc_rate[8],
-					tc_rate[9],
-					tc_rate[10],
-					tc_rate[11],
-					tc_rate[12],
-				},
-				.tc_period = SUBPORT_TC_PERIOD,
 				.n_pipes_per_subport_enabled =
 					h->n_tm_nodes[TM_NODE_LEVEL_PIPE] /
 					h->n_tm_nodes[TM_NODE_LEVEL_SUBPORT],
@@ -2829,30 +2952,39 @@ update_subport_rate(struct rte_eth_dev *dev,
 	struct pmd_internals *p = dev->data->dev_private;
 	uint32_t subport_id = tm_node_subport_id(dev, ns);
 
-	struct rte_sched_subport_params subport_params;
+	struct rte_sched_subport_profile_params *profile0 =
+					subport_profile_get(dev, ns);
+	struct rte_sched_subport_profile_params profile1;
+	uint32_t subport_profile_id;
 
-	/* Derive new subport configuration. */
-	memcpy(&subport_params,
-		&p->soft.tm.params.subport_params[subport_id],
-		sizeof(subport_params));
-	subport_params.tb_rate = sp->params.peak.rate;
-	subport_params.tb_size = sp->params.peak.size;
+	/* Derive new pipe profile. */
+	memcpy(&profile1, profile0, sizeof(profile1));
+	profile1.tb_rate = sp->params.peak.rate;
+	profile1.tb_size = sp->params.peak.size;
+
+	/* Since implementation does not allow adding more subport profiles
+	 * after port configuration, the pipe configuration can be successfully
+	 * updated only if the new profile is also part of the existing set of
+	 * pipe profiles.
+	 */
+	if (subport_profile_exists(dev, &profile1, &subport_profile_id) == 0)
+		return -1;
 
 	/* Update the subport configuration. */
-	if (rte_sched_subport_config(SCHED(p), subport_id,
-		&subport_params))
+	if (rte_sched_subport_profile_config(SCHED(p), subport_id,
+		subport_profile_id))
 		return -1;
 
+	subport_profile_mark(dev, subport_id, subport_profile_id);
 	/* Commit changes. */
 	ns->shaper_profile->n_users--;
-
 	ns->shaper_profile = sp;
 	ns->params.shaper_profile_id = sp->shaper_profile_id;
 	sp->n_users++;
 
-	memcpy(&p->soft.tm.params.subport_params[subport_id],
-		&subport_params,
-		sizeof(subport_params));
+	memcpy(&p->soft.tm.params.subport_profiles[subport_id],
+		&profile1,
+		sizeof(profile1));
 
 	return 0;
 }
-- 
2.7.4


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

* [dpdk-dev] [PATCH v1 4/4] app/test_sched: subport bandwidth profile config
  2020-09-02  9:07   ` [dpdk-dev] [PATCH v1 1/4] example/qos_sched: subport bandwidth dynmaic conf Savinay Dharmappa
  2020-09-02  9:07     ` [dpdk-dev] [PATCH v1 2/4] example/ip_pipeline: " Savinay Dharmappa
  2020-09-02  9:07     ` [dpdk-dev] [PATCH v1 3/4] drivers/softnic: subport bandwidth profile config Savinay Dharmappa
@ 2020-09-02  9:07     ` Savinay Dharmappa
  2020-09-02 10:46     ` [dpdk-dev] [PATCH v1 1/4] example/qos_sched: subport bandwidth dynmaic conf Dharmappa, Savinay
  3 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-02  9:07 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

test_sched application uses the new apis introduced as part of dynamic
configuration of subport bandwidth to configure the deafult subport
bandwidth profile while buidling the hirerachical scheduler

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 app/test/test_sched.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/app/test/test_sched.c b/app/test/test_sched.c
index fc31080..99d7f87 100644
--- a/app/test/test_sched.c
+++ b/app/test/test_sched.c
@@ -36,15 +36,20 @@ static struct rte_sched_pipe_params pipe_profile[] = {
 	},
 };
 
-static struct rte_sched_subport_params subport_param[] = {
+static struct rte_sched_subport_profile_params
+		subport_profile[] = {
 	{
 		.tb_rate = 1250000000,
 		.tb_size = 1000000,
-
 		.tc_rate = {1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000},
 		.tc_period = 10,
+	},
+};
+
+static struct rte_sched_subport_params subport_param[] = {
+	{
 		.n_pipes_per_subport_enabled = 1024,
 		.qsize = {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32},
 		.pipe_profiles = pipe_profile,
@@ -59,6 +64,8 @@ static struct rte_sched_port_params port_param = {
 	.mtu = 1522,
 	.frame_overhead = RTE_SCHED_FRAME_OVERHEAD_DEFAULT,
 	.n_subports_per_port = 1,
+	.n_subport_profiles = 1,
+	.subport_profiles = subport_profile,
 	.n_pipes_per_subport = 1024,
 };
 
@@ -66,6 +73,7 @@ static struct rte_sched_port_params port_param = {
 #define MBUF_DATA_SZ     (2048 + RTE_PKTMBUF_HEADROOM)
 #define MEMPOOL_CACHE_SZ 0
 #define SOCKET           0
+#define DEFAULT_PROFILE  0
 
 
 static struct rte_mempool *
@@ -141,6 +149,10 @@ test_sched(void)
 	err = rte_sched_subport_config(port, SUBPORT, subport_param);
 	TEST_ASSERT_SUCCESS(err, "Error config sched, err=%d\n", err);
 
+	err = rte_sched_subport_profile_config(port, SUBPORT,
+						DEFAULT_PROFILE);
+	TEST_ASSERT_SUCCESS(err, "Error config sched, err=%d\n", err);
+
 	for (pipe = 0; pipe < subport_param[0].n_pipes_per_subport_enabled; pipe++) {
 		err = rte_sched_pipe_config(port, SUBPORT, pipe, 0);
 		TEST_ASSERT_SUCCESS(err, "Error config sched pipe %u, err=%d\n", pipe, err);
-- 
2.7.4


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

* Re: [dpdk-dev] [PATCH v1 1/4] example/qos_sched: subport bandwidth dynmaic conf
  2020-09-02  9:07   ` [dpdk-dev] [PATCH v1 1/4] example/qos_sched: subport bandwidth dynmaic conf Savinay Dharmappa
                       ` (2 preceding siblings ...)
  2020-09-02  9:07     ` [dpdk-dev] [PATCH v1 4/4] app/test_sched: " Savinay Dharmappa
@ 2020-09-02 10:46     ` Dharmappa, Savinay
  3 siblings, 0 replies; 107+ messages in thread
From: Dharmappa, Savinay @ 2020-09-02 10:46 UTC (permalink / raw)
  To: Dumitrescu, Cristian, Singh, Jasvinder, dev

Self NACK the patch. As I would like to merge the application series changes of patch with previous sent library changes patches series and have single patch series.

Regards
savinay

-----Original Message-----
From: Dharmappa, Savinay <savinay.dharmappa@intel.com> 
Sent: Wednesday, September 2, 2020 2:37 PM
To: Dumitrescu, Cristian <cristian.dumitrescu@intel.com>; Singh, Jasvinder <jasvinder.singh@intel.com>; dev@dpdk.org
Cc: Dharmappa, Savinay <savinay.dharmappa@intel.com>
Subject: [PATCH v1 1/4] example/qos_sched: subport bandwidth dynmaic conf

qos sched application uses the new apis introduced as part of dynamic configuration of subport bandwidth to configure the deafult subport bandwidth profile while buidling the hirerachical scheduler.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 examples/qos_sched/cfg_file.c  | 158 ++++++++++++++++++++++++-----------------
 examples/qos_sched/cfg_file.h  |   4 ++
 examples/qos_sched/init.c      |  24 +++++--
 examples/qos_sched/main.h      |   1 +
 examples/qos_sched/profile.cfg |   3 +
 5 files changed, 120 insertions(+), 70 deletions(-)

diff --git a/examples/qos_sched/cfg_file.c b/examples/qos_sched/cfg_file.c index f078e4f..9e1341c 100644
--- a/examples/qos_sched/cfg_file.c
+++ b/examples/qos_sched/cfg_file.c
@@ -53,8 +53,11 @@ cfg_load_pipe(struct rte_cfgfile *cfg, struct rte_sched_pipe_params *pipe_params
 	if (!cfg || !pipe_params)
 		return -1;
 
-	profiles = rte_cfgfile_num_sections(cfg, "pipe profile", sizeof("pipe profile") - 1);
-	subport_params[0].n_pipe_profiles = profiles;
+	profiles = rte_cfgfile_num_sections(cfg, "pipe profile",
+					sizeof("pipe profile") - 1);
+	port_params.n_subport_profiles = profiles;
+
+	printf(" profiles = %d", profiles);
 
 	for (j = 0; j < profiles; j++) {
 		char pipe_name[32];
@@ -143,6 +146,93 @@ cfg_load_pipe(struct rte_cfgfile *cfg, struct rte_sched_pipe_params *pipe_params  }
 
 int
+cfg_load_subport_profile(struct rte_cfgfile *cfg,
+	struct rte_sched_subport_profile_params *subport_profile) {
+	int i;
+	const char *entry;
+	int profiles;
+
+	if (!cfg || !subport_profile)
+		return -1;
+
+	profiles = rte_cfgfile_num_sections(cfg, "subport profile",
+					   sizeof("subport profile") - 1);
+	subport_params[0].n_pipe_profiles = profiles;
+
+	for (i = 0; i < profiles; i++) {
+		char sec_name[32];
+		snprintf(sec_name, sizeof(sec_name), "subport profile %d", i);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tb rate");
+		if (entry)
+			subport_profile[i].tb_rate = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tb size");
+		if (entry)
+			subport_profile[i].tb_size = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc period");
+		if (entry)
+			subport_profile[i].tc_period = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 0 rate");
+		if (entry)
+			subport_profile[i].tc_rate[0] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 1 rate");
+		if (entry)
+			subport_profile[i].tc_rate[1] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 2 rate");
+		if (entry)
+			subport_profile[i].tc_rate[2] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 3 rate");
+		if (entry)
+			subport_profile[i].tc_rate[3] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 4 rate");
+		if (entry)
+			subport_profile[i].tc_rate[4] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 5 rate");
+		if (entry)
+			subport_profile[i].tc_rate[5] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 6 rate");
+		if (entry)
+			subport_profile[i].tc_rate[6] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 7 rate");
+		if (entry)
+			subport_profile[i].tc_rate[7] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 8 rate");
+		if (entry)
+			subport_profile[i].tc_rate[8] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 9 rate");
+		if (entry)
+			subport_profile[i].tc_rate[9] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 10 rate");
+		if (entry)
+			subport_profile[i].tc_rate[10] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 11 rate");
+		if (entry)
+			subport_profile[i].tc_rate[11] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 12 rate");
+		if (entry)
+			subport_profile[i].tc_rate[12] = (uint64_t)atoi(entry);
+	}
+
+	return 0;
+}
+
+int
 cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subport_params)  {
 	const char *entry;
@@ -267,70 +357,6 @@ cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subpo
 				}
 			}
 
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tb rate");
-			if (entry)
-				subport_params[i].tb_rate = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tb size");
-			if (entry)
-				subport_params[i].tb_size = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc period");
-			if (entry)
-				subport_params[i].tc_period = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 0 rate");
-			if (entry)
-				subport_params[i].tc_rate[0] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 1 rate");
-			if (entry)
-				subport_params[i].tc_rate[1] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 2 rate");
-			if (entry)
-				subport_params[i].tc_rate[2] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 3 rate");
-			if (entry)
-				subport_params[i].tc_rate[3] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 4 rate");
-			if (entry)
-				subport_params[i].tc_rate[4] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 5 rate");
-			if (entry)
-				subport_params[i].tc_rate[5] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 6 rate");
-			if (entry)
-				subport_params[i].tc_rate[6] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 7 rate");
-			if (entry)
-				subport_params[i].tc_rate[7] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 8 rate");
-			if (entry)
-				subport_params[i].tc_rate[8] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 9 rate");
-			if (entry)
-				subport_params[i].tc_rate[9] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 10 rate");
-			if (entry)
-				subport_params[i].tc_rate[10] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 11 rate");
-			if (entry)
-				subport_params[i].tc_rate[11] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 12 rate");
-			if (entry)
-				subport_params[i].tc_rate[12] = (uint64_t)atoi(entry);
-
 			int n_entries = rte_cfgfile_section_num_entries(cfg, sec_name);
 			struct rte_cfgfile_entry entries[n_entries];
 
diff --git a/examples/qos_sched/cfg_file.h b/examples/qos_sched/cfg_file.h index 2eccf1c..0dc458a 100644
--- a/examples/qos_sched/cfg_file.h
+++ b/examples/qos_sched/cfg_file.h
@@ -14,4 +14,8 @@ int cfg_load_pipe(struct rte_cfgfile *cfg, struct rte_sched_pipe_params *pipe);
 
 int cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subport);
 
+int cfg_load_subport_profile(struct rte_cfgfile *cfg,
+			     struct rte_sched_subport_profile_params
+			     *subport_profile);
+
 #endif
diff --git a/examples/qos_sched/init.c b/examples/qos_sched/init.c index 9626c15..541adb7 100644
--- a/examples/qos_sched/init.c
+++ b/examples/qos_sched/init.c
@@ -196,15 +196,20 @@ static struct rte_sched_pipe_params pipe_profiles[MAX_SCHED_PIPE_PROFILES] = {
 	},
 };
 
-struct rte_sched_subport_params subport_params[MAX_SCHED_SUBPORTS] = {
+static struct rte_sched_subport_profile_params
+		subport_profile[MAX_SCHED_SUBPORT_PROFILES] = {
 	{
 		.tb_rate = 1250000000,
 		.tb_size = 1000000,
-
 		.tc_rate = {1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000},
 		.tc_period = 10,
+	},
+};
+
+struct rte_sched_subport_params subport_params[MAX_SCHED_SUBPORTS] = {
+	{
 		.n_pipes_per_subport_enabled = 4096,
 		.qsize = {64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64},
 		.pipe_profiles = pipe_profiles,
@@ -289,6 +294,9 @@ struct rte_sched_port_params port_params = {
 	.mtu = 6 + 6 + 4 + 4 + 2 + 1500,
 	.frame_overhead = RTE_SCHED_FRAME_OVERHEAD_DEFAULT,
 	.n_subports_per_port = 1,
+	.n_subport_profiles = 1,
+	.subport_profiles = subport_profile,
+	.n_max_subport_profiles = MAX_SCHED_SUBPORT_PROFILES,
 	.n_pipes_per_subport = MAX_SCHED_PIPES,  };
 
@@ -320,8 +328,15 @@ app_init_sched_port(uint32_t portid, uint32_t socketid)
 	for (subport = 0; subport < port_params.n_subports_per_port; subport ++) {
 		err = rte_sched_subport_config(port, subport, &subport_params[subport]);
 		if (err) {
-			rte_exit(EXIT_FAILURE, "Unable to config sched subport %u, err=%d\n",
-					subport, err);
+			rte_exit(EXIT_FAILURE, "Unable to config schedi "
+				"subport %u, err=%d\n", subport, err);
+		}
+
+		err = rte_sched_subport_profile_config(port, subport, 0);
+		if (err) {
+			rte_exit(EXIT_FAILURE, "failed to configure "
+				"profile err=%d\n", err);
+
 		}
 
 		uint32_t n_pipes_per_subport =
@@ -354,6 +369,7 @@ app_load_cfg_profile(const char *profile)
 
 	cfg_load_port(file, &port_params);
 	cfg_load_subport(file, subport_params);
+	cfg_load_subport_profile(file, subport_profile);
 	cfg_load_pipe(file, pipe_profiles);
 
 	rte_cfgfile_close(file);
diff --git a/examples/qos_sched/main.h b/examples/qos_sched/main.h index 23bc418..0d6815a 100644
--- a/examples/qos_sched/main.h
+++ b/examples/qos_sched/main.h
@@ -51,6 +51,7 @@ extern "C" {
 #define MAX_SCHED_SUBPORTS		8
 #define MAX_SCHED_PIPES		4096
 #define MAX_SCHED_PIPE_PROFILES		256
+#define MAX_SCHED_SUBPORT_PROFILES	8
 
 #ifndef APP_COLLECT_STAT
 #define APP_COLLECT_STAT		1
diff --git a/examples/qos_sched/profile.cfg b/examples/qos_sched/profile.cfg index 61b8b70..4486d27 100644
--- a/examples/qos_sched/profile.cfg
+++ b/examples/qos_sched/profile.cfg
@@ -26,6 +26,9 @@ number of subports per port = 1  number of pipes per subport = 4096  queue sizes = 64 64 64 64 64 64 64 64 64 64 64 64 64
 
+subport 0-8 = 0                ; These subports are configured with subport profile 0
+
+[subport profile 0]
 tb rate = 1250000000           ; Bytes per second
 tb size = 1000000              ; Bytes
 
--
2.7.4


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

* [dpdk-dev] [PATCH v2 00/10] Enable dynamic config of subport bandwidth
  2020-09-02  8:56   ` [dpdk-dev] [PATCH v1 1/4] " Savinay Dharmappa
                       ` (2 preceding siblings ...)
  2020-09-02  8:56     ` [dpdk-dev] [PATCH v1 4/4] " Savinay Dharmappa
@ 2020-09-10 18:48     ` Savinay Dharmappa
  2020-09-10 18:48       ` [dpdk-dev] [PATCH v2 01/10] sched: add support profile data structure Savinay Dharmappa
                         ` (10 more replies)
  3 siblings, 11 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-10 18:48 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

DPDK sched library allows runtime configuration of the pipe profiles to the
pipes of the subport once scheduler hierarchy is constructed. However, to
change the subport level bandwidth, existing hierarchy needs to be
dismantled and whole process of building hierarchy under subport nodes
needs to be repeated which might result in router downtime. Furthermore,
due to lack of dynamic configuration of the subport bandwidth profile
configuration (shaper and Traffic class rates), the user application
is unable to dynamically re-distribute the excess-bandwidth of one subport
among other subports in the scheduler hierarchy. Therefore, it is also not
possible to adjust the subport bandwidth profile in sync with dynamic
changes in pipe profiles of subscribers who want to consume higher
bandwidth opportunistically. 

This patch series implements dynamic configuration of the subport bandwidth
profile to overcome the runtime situation when group of subscribers are not
using the allotted bandwidth and dynamic bandwidth re-distribution is
needed the without making any structural changes in the hierarchy.

The implementation work includes refactoring the existing data structures
defined for port and subport level, new APIs for adding subport level
bandwidth profiles that can be used in runtime.

Savinay Dharmappa (10):
  sched: add data structure to support dynamic conf of subport bandwidth
  sched: create subport profile table
  sched: Add public APIs to support dynamic conf of subport profile
  sched: modify the way credits are updated
  sched: Modify subport best effort tc oversubscription
  example/qos_sched: add dynamic config of subport
  example/ip_pipeline: add dynamic config of subport
  drivers/softnic: add dynamic config of subport
  app/test_sched: add dynamic config of subport
  sched: remove the redundant code

 app/test/test_sched.c                           |  18 +-
 doc/guides/rel_notes/deprecation.rst            |   6 -
 doc/guides/rel_notes/release_20_11.rst          |   4 +
 drivers/net/softnic/rte_eth_softnic_internals.h |   9 +
 drivers/net/softnic/rte_eth_softnic_tm.c        | 223 ++++++++---
 examples/ip_pipeline/cli.c                      |  10 +-
 examples/ip_pipeline/tmgr.c                     |  28 +-
 examples/ip_pipeline/tmgr.h                     |   3 +-
 examples/qos_sched/cfg_file.c                   | 158 ++++----
 examples/qos_sched/cfg_file.h                   |   4 +
 examples/qos_sched/init.c                       |  24 +-
 examples/qos_sched/main.h                       |   1 +
 examples/qos_sched/profile.cfg                  |   3 +
 lib/librte_sched/rte_sched.c                    | 484 +++++++++++++++++-------
 lib/librte_sched/rte_sched.h                    |  82 +++-
 lib/librte_sched/rte_sched_version.map          |   2 +
 16 files changed, 780 insertions(+), 279 deletions(-)

-- 
2.7.4


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

* [dpdk-dev] [PATCH v2 01/10] sched: add support profile data structure
  2020-09-10 18:48     ` [dpdk-dev] [PATCH v2 00/10] Enable dynamic config of subport bandwidth Savinay Dharmappa
@ 2020-09-10 18:48       ` Savinay Dharmappa
  2020-09-10 18:48       ` [dpdk-dev] [PATCH v2 02/10] sched: add subport profile table Savinay Dharmappa
                         ` (9 subsequent siblings)
  10 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-10 18:48 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Add subport profile data structure to support dynamic configuration
of subport bandwidth

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c | 11 +++++++++++
 lib/librte_sched/rte_sched.h | 25 +++++++++++++++++++++++++
 2 files changed, 36 insertions(+)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index 0fa0741..474422b 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -2,6 +2,7 @@
  * Copyright(c) 2010-2014 Intel Corporation
  */
 
+#include <stdint.h>
 #include <stdio.h>
 #include <string.h>
 
@@ -101,6 +102,16 @@ enum grinder_state {
 	e_GRINDER_READ_MBUF
 };
 
+struct rte_sched_subport_profile {
+	/* Token bucket (TB) */
+	uint64_t tb_period;
+	uint64_t tb_credits_per_period;
+	uint64_t tb_size;
+
+	uint64_t tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+	uint64_t tc_period;
+};
+
 struct rte_sched_grinder {
 	/* Pipe cache */
 	uint16_t pcache_qmask[RTE_SCHED_GRINDER_PCACHE_SIZE];
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index 8a5a93c..39339b7 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -192,6 +192,20 @@ struct rte_sched_subport_params {
 #endif
 };
 
+struct rte_sched_subport_profile_params {
+	/** Token bucket rate (measured in bytes per second) */
+	uint64_t tb_rate;
+
+	/** Token bucket size (measured in credits) */
+	uint64_t tb_size;
+
+	/** Traffic class rates (measured in bytes per second) */
+	uint64_t tc_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+
+	/** Enforcement period for rates (measured in milliseconds) */
+	uint64_t tc_period;
+};
+
 /** Subport statistics */
 struct rte_sched_subport_stats {
 	/** Number of packets successfully written */
@@ -254,6 +268,17 @@ struct rte_sched_port_params {
 	/** Number of subports */
 	uint32_t n_subports_per_port;
 
+	/** subport profile table.
+	 * Every pipe is configured using one of the profiles from this table.
+	 */
+	struct rte_sched_subport_profile_params *subport_profiles;
+
+	/** Profiles in the pipe profile table */
+	uint32_t n_subport_profiles;
+
+	/** Max allowed profiles in the pipe profile table */
+	uint32_t n_max_subport_profiles;
+
 	/** Maximum number of subport pipes.
 	 * This parameter is used to reserve a fixed number of bits
 	 * in struct rte_mbuf::sched.queue_id for the pipe_id for all
-- 
2.7.4


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

* [dpdk-dev] [PATCH v2 02/10] sched: add subport profile table
  2020-09-10 18:48     ` [dpdk-dev] [PATCH v2 00/10] Enable dynamic config of subport bandwidth Savinay Dharmappa
  2020-09-10 18:48       ` [dpdk-dev] [PATCH v2 01/10] sched: add support profile data structure Savinay Dharmappa
@ 2020-09-10 18:48       ` Savinay Dharmappa
  2020-09-10 18:48       ` [dpdk-dev] [PATCH v2 03/10] sched: add subport profile add and config api Savinay Dharmappa
                         ` (8 subsequent siblings)
  10 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-10 18:48 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Add subport profile table to internal port data structure and
update the port config function.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c | 185 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 182 insertions(+), 3 deletions(-)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index 474422b..ec6e6bf 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -223,6 +223,8 @@ struct rte_sched_port {
 	uint16_t pipe_queue[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
 	uint8_t pipe_tc[RTE_SCHED_QUEUES_PER_PIPE];
 	uint8_t tc_queue[RTE_SCHED_QUEUES_PER_PIPE];
+	uint32_t n_subport_profiles;
+	uint32_t n_max_subport_profiles;
 	uint64_t rate;
 	uint32_t mtu;
 	uint32_t frame_overhead;
@@ -241,6 +243,7 @@ struct rte_sched_port {
 	uint32_t subport_id;
 
 	/* Large data structures */
+	struct rte_sched_subport_profile *subport_profiles;
 	struct rte_sched_subport *subports[0] __rte_cache_aligned;
 } __rte_cache_aligned;
 
@@ -387,8 +390,60 @@ pipe_profile_check(struct rte_sched_pipe_params *params,
 }
 
 static int
+subport_profile_check(struct rte_sched_subport_profile_params *params,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	/* Check user parameters */
+	if (params == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter params\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tb_rate == 0 || params->tb_rate > rate) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for tb rate\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tb_size == 0) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for tb size\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
+		uint64_t tc_rate = params->tc_rate[i];
+
+		if (tc_rate == 0 || (tc_rate > params->tb_rate)) {
+			RTE_LOG(ERR, SCHED, "%s: "
+			"Incorrect value for tc rate\n", __func__);
+			return -EINVAL;
+		}
+	}
+
+	if (params->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect tc rate(best effort)\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tc_period == 0) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for tc period\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
 rte_sched_port_check_params(struct rte_sched_port_params *params)
 {
+	uint32_t i;
+
 	if (params == NULL) {
 		RTE_LOG(ERR, SCHED,
 			"%s: Incorrect value for parameter params\n", __func__);
@@ -425,6 +480,29 @@ rte_sched_port_check_params(struct rte_sched_port_params *params)
 		return -EINVAL;
 	}
 
+	if (params->subport_profiles == NULL ||
+		params->n_subport_profiles == 0 ||
+		params->n_max_subport_profiles == 0 ||
+		params->n_subport_profiles > params->n_max_subport_profiles) {
+		RTE_LOG(ERR, SCHED,
+		"%s: Incorrect value for subport profiles\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < params->n_subport_profiles; i++) {
+		struct rte_sched_subport_profile_params *p =
+						params->subport_profiles + i;
+		int status;
+
+		status = subport_profile_check(p, params->rate);
+		if (status != 0) {
+			RTE_LOG(ERR, SCHED,
+			"%s: subport profile check failed(%d)\n",
+			__func__, status);
+			return -EINVAL;
+		}
+	}
+
 	/* n_pipes_per_subport: non-zero, power of 2 */
 	if (params->n_pipes_per_subport == 0 ||
 	    !rte_is_power_of_2(params->n_pipes_per_subport)) {
@@ -566,6 +644,42 @@ rte_sched_port_log_pipe_profile(struct rte_sched_subport *subport, uint32_t i)
 		p->wrr_cost[0], p->wrr_cost[1], p->wrr_cost[2], p->wrr_cost[3]);
 }
 
+static void
+rte_sched_port_log_subport_profile(struct rte_sched_port *port, uint32_t i)
+{
+	struct rte_sched_subport_profile *p = port->subport_profiles + i;
+
+	RTE_LOG(DEBUG, SCHED, "Low level config for subport profile %u:\n"
+	"Token bucket: period = %"PRIu64", credits per period = %"PRIu64","
+	"size = %"PRIu64"\n"
+	"Traffic classes: period = %"PRIu64",\n"
+	"credits per period = [%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
+	" %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
+	" %"PRIu64", %"PRIu64", %"PRIu64"]\n",
+	i,
+
+	/* Token bucket */
+	p->tb_period,
+	p->tb_credits_per_period,
+	p->tb_size,
+
+	/* Traffic classes */
+	p->tc_period,
+	p->tc_credits_per_period[0],
+	p->tc_credits_per_period[1],
+	p->tc_credits_per_period[2],
+	p->tc_credits_per_period[3],
+	p->tc_credits_per_period[4],
+	p->tc_credits_per_period[5],
+	p->tc_credits_per_period[6],
+	p->tc_credits_per_period[7],
+	p->tc_credits_per_period[8],
+	p->tc_credits_per_period[9],
+	p->tc_credits_per_period[10],
+	p->tc_credits_per_period[11],
+	p->tc_credits_per_period[12]);
+}
+
 static inline uint64_t
 rte_sched_time_ms_to_bytes(uint64_t time_ms, uint64_t rate)
 {
@@ -635,6 +749,37 @@ rte_sched_pipe_profile_convert(struct rte_sched_subport *subport,
 }
 
 static void
+rte_sched_subport_profile_convert(struct rte_sched_subport_profile_params *src,
+	struct rte_sched_subport_profile *dst,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	/* Token Bucket */
+	if (src->tb_rate == rate) {
+		dst->tb_credits_per_period = 1;
+		dst->tb_period = 1;
+	} else {
+		double tb_rate = (double) src->tb_rate
+				/ (double) rate;
+		double d = RTE_SCHED_TB_RATE_CONFIG_ERR;
+
+		rte_approx_64(tb_rate, d, &dst->tb_credits_per_period,
+			&dst->tb_period);
+	}
+
+	dst->tb_size = src->tb_size;
+
+	/* Traffic Classes */
+	dst->tc_period = rte_sched_time_ms_to_bytes(src->tc_period, rate);
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		dst->tc_credits_per_period[i]
+			= rte_sched_time_ms_to_bytes(src->tc_period,
+				src->tc_rate[i]);
+}
+
+static void
 rte_sched_subport_config_pipe_profile_table(struct rte_sched_subport *subport,
 	struct rte_sched_subport_params *params, uint64_t rate)
 {
@@ -658,6 +803,24 @@ rte_sched_subport_config_pipe_profile_table(struct rte_sched_subport *subport,
 	}
 }
 
+static void
+rte_sched_port_config_subport_profile_table(struct rte_sched_port *port,
+	struct rte_sched_port_params *params,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	for (i = 0; i < port->n_subport_profiles; i++) {
+		struct rte_sched_subport_profile_params *src
+				= params->subport_profiles + i;
+		struct rte_sched_subport_profile *dst
+				= port->subport_profiles + i;
+
+		rte_sched_subport_profile_convert(src, dst, rate);
+		rte_sched_port_log_subport_profile(port, i);
+	}
+}
+
 static int
 rte_sched_subport_check_params(struct rte_sched_subport_params *params,
 	uint32_t n_max_pipes_per_subport,
@@ -804,7 +967,7 @@ struct rte_sched_port *
 rte_sched_port_config(struct rte_sched_port_params *params)
 {
 	struct rte_sched_port *port = NULL;
-	uint32_t size0, size1;
+	uint32_t size0, size1, size2;
 	uint32_t cycles_per_byte;
 	uint32_t i, j;
 	int status;
@@ -819,10 +982,21 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 
 	size0 = sizeof(struct rte_sched_port);
 	size1 = params->n_subports_per_port * sizeof(struct rte_sched_subport *);
+	size2 = params->n_max_subport_profiles *
+		sizeof(struct rte_sched_subport_profile);
 
 	/* Allocate memory to store the data structures */
-	port = rte_zmalloc_socket("qos_params", size0 + size1, RTE_CACHE_LINE_SIZE,
-		params->socket);
+	port = rte_zmalloc_socket("qos_params", size0 + size1,
+				 RTE_CACHE_LINE_SIZE, params->socket);
+	if (port == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: Memory allocation fails\n", __func__);
+
+		return NULL;
+	}
+
+	/* Allocate memory to store the subport profile */
+	port->subport_profiles  = rte_zmalloc_socket("subport_profile", size2,
+					RTE_CACHE_LINE_SIZE, params->socket);
 	if (port == NULL) {
 		RTE_LOG(ERR, SCHED, "%s: Memory allocation fails\n", __func__);
 
@@ -831,6 +1005,8 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 
 	/* User parameters */
 	port->n_subports_per_port = params->n_subports_per_port;
+	port->n_subport_profiles = params->n_subport_profiles;
+	port->n_max_subport_profiles = params->n_max_subport_profiles;
 	port->n_pipes_per_subport = params->n_pipes_per_subport;
 	port->n_pipes_per_subport_log2 =
 			__builtin_ctz(params->n_pipes_per_subport);
@@ -861,6 +1037,9 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 	port->time_cpu_bytes = 0;
 	port->time = 0;
 
+	/* Subport profile table */
+	rte_sched_port_config_subport_profile_table(port, params, port->rate);
+
 	cycles_per_byte = (rte_get_tsc_hz() << RTE_SCHED_TIME_SHIFT)
 		/ params->rate;
 	port->inv_cycles_per_byte = rte_reciprocal_value(cycles_per_byte);
-- 
2.7.4


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

* [dpdk-dev] [PATCH v2 03/10] sched: add subport profile add and config api
  2020-09-10 18:48     ` [dpdk-dev] [PATCH v2 00/10] Enable dynamic config of subport bandwidth Savinay Dharmappa
  2020-09-10 18:48       ` [dpdk-dev] [PATCH v2 01/10] sched: add support profile data structure Savinay Dharmappa
  2020-09-10 18:48       ` [dpdk-dev] [PATCH v2 02/10] sched: add subport profile table Savinay Dharmappa
@ 2020-09-10 18:48       ` Savinay Dharmappa
  2020-09-14 14:05         ` Singh, Jasvinder
  2020-09-10 18:48       ` [dpdk-dev] [PATCH v2 04/10] sched: update the grinder credit update function Savinay Dharmappa
                         ` (7 subsequent siblings)
  10 siblings, 1 reply; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-10 18:48 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Add apis to add new subport profile and configure it.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c           | 118 +++++++++++++++++++++++++++++++++
 lib/librte_sched/rte_sched.h           |  45 +++++++++++++
 lib/librte_sched/rte_sched_version.map |   2 +
 3 files changed, 165 insertions(+)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index ec6e6bf..ba5700a 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -175,6 +175,8 @@ struct rte_sched_subport {
 	/* Statistics */
 	struct rte_sched_subport_stats stats __rte_cache_aligned;
 
+	/* subport profile flag */
+	uint32_t profile;
 	/* Subport pipes */
 	uint32_t n_pipes_per_subport_enabled;
 	uint32_t n_pipe_profiles;
@@ -1344,6 +1346,56 @@ rte_sched_subport_config(struct rte_sched_port *port,
 }
 
 int
+rte_sched_subport_profile_config(struct rte_sched_port *port,
+	uint32_t subport_id,
+	uint32_t profile_id)
+{
+	int i;
+	struct rte_sched_subport_profile *params;
+	uint32_t n_subports = subport_id + 1;
+	struct rte_sched_subport *s;
+
+	if (port == NULL) {
+		RTE_LOG(ERR, SCHED,
+			"%s: Incorrect value for parameter port\n", __func__);
+		return -EINVAL;
+	}
+
+	if (subport_id >= port->n_subports_per_port) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter subport id\n", __func__);
+
+		rte_sched_free_memory(port, n_subports);
+		return -EINVAL;
+	}
+
+	params =  port->subport_profiles + profile_id;
+
+	s = port->subports[subport_id];
+
+	s->tb_credits = params->tb_size / 2;
+
+	s->tc_time = port->time + params->tc_period;
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		if (s->qsize[i])
+			s->tc_credits[i] =
+				params->tc_credits_per_period[i];
+		else
+			params->tc_credits_per_period[i] = 0;
+
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+	s->tc_ov_wm_max = rte_sched_time_ms_to_bytes(params->tc_period,
+						     s->pipe_tc_be_rate_max);
+#endif
+	s->profile = profile_id;
+
+	rte_sched_port_log_subport_profile(port, profile_id);
+
+	return 0;
+}
+
+int
 rte_sched_pipe_config(struct rte_sched_port *port,
 	uint32_t subport_id,
 	uint32_t pipe_id,
@@ -1527,6 +1579,72 @@ rte_sched_subport_pipe_profile_add(struct rte_sched_port *port,
 	return 0;
 }
 
+int
+rte_sched_port_subport_profile_add(struct rte_sched_port *port,
+	struct rte_sched_subport_profile_params *params,
+	uint32_t *subport_profile_id)
+{
+	int status;
+	uint32_t i;
+	struct rte_sched_subport_profile *dst;
+
+	/* Port */
+	if (port == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter port\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter profile\n", __func__);
+		return -EINVAL;
+	}
+
+	if (subport_profile_id == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter subport_profile_id\n",
+		__func__);
+		return -EINVAL;
+	}
+
+	dst = port->subport_profiles + port->n_subport_profiles;
+
+	/* Subport profiles exceeds the max limit */
+	if (port->n_subport_profiles >= port->n_max_subport_profiles) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Number of subport profiles exceeds the max limit\n",
+		 __func__);
+		return -EINVAL;
+	}
+
+	status = subport_profile_check(params, port->rate);
+	if (status != 0) {
+		RTE_LOG(ERR, SCHED,
+		"%s: subport profile check failed(%d)\n", __func__, status);
+		return -EINVAL;
+	}
+
+	rte_sched_subport_profile_convert(params, dst, port->rate);
+
+	/* Subport profile should not exists */
+	for (i = 0; i < port->n_subport_profiles; i++)
+		if (memcmp(port->subport_profiles + i,
+		    params, sizeof(*params)) == 0) {
+			RTE_LOG(ERR, SCHED,
+			"%s: subport profile exists\n", __func__);
+			return -EINVAL;
+		}
+
+	/* Subport profile commit */
+	*subport_profile_id = port->n_subport_profiles;
+	port->n_subport_profiles++;
+
+	rte_sched_port_log_subport_profile(port, *subport_profile_id);
+
+	return 0;
+}
+
 static inline uint32_t
 rte_sched_port_qindex(struct rte_sched_port *port,
 	uint32_t subport,
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index 39339b7..a7c2638 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -337,6 +337,29 @@ rte_sched_subport_pipe_profile_add(struct rte_sched_port *port,
 	uint32_t *pipe_profile_id);
 
 /**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Hierarchical scheduler subport bandwidth profile add
+ * Note that this function is safe to use in runtime for adding new
+ * subport bandwidth profile as it doesn't have any impact on hiearchical
+ * structure of the scheduler.
+ * @param port
+ *   Handle to port scheduler instance
+ * @param struct rte_sched_subport_profile
+ *   Subport bandwidth profile
+ * @param subport_profile_d
+ *   Subport profile id
+ * @return
+ *   0 upon success, error code otherwise
+ */
+__rte_experimental
+int
+rte_sched_port_subport_profile_add(struct rte_sched_port *port,
+	struct rte_sched_subport_profile_params *profile,
+	uint32_t *subport_profile_id);
+
+/**
  * Hierarchical scheduler subport configuration
  *
  * @param port
@@ -354,6 +377,28 @@ rte_sched_subport_config(struct rte_sched_port *port,
 	struct rte_sched_subport_params *params);
 
 /**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Hierarchical scheduler subport profile configuration
+ * Note that this function is safe to use in runtime for applying any specific
+ * subport bandwidth profile as it doesn't have any impact on hiearchical
+ * structure of the scheduler.
+ * @param port
+ *   Handle to port scheduler instance
+ * @param subport_id
+ *   Subport ID
+ * @param profile_d
+ *   Subport profile id
+ * @return
+ *   0 upon success, error code otherwise
+ */
+__rte_experimental
+int
+rte_sched_subport_profile_config(struct rte_sched_port *port,
+	uint32_t subport_id,
+	uint32_t profile_id);
+/**
  * Hierarchical scheduler pipe configuration
  *
  * @param port
diff --git a/lib/librte_sched/rte_sched_version.map b/lib/librte_sched/rte_sched_version.map
index 3faef6f..e64335f 100644
--- a/lib/librte_sched/rte_sched_version.map
+++ b/lib/librte_sched/rte_sched_version.map
@@ -28,4 +28,6 @@ EXPERIMENTAL {
 	global:
 
 	rte_sched_subport_pipe_profile_add;
+	rte_sched_port_subport_profile_add;
+	rte_sched_subport_profile_config;
 };
-- 
2.7.4


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

* [dpdk-dev] [PATCH v2 04/10] sched: update the grinder credit update function
  2020-09-10 18:48     ` [dpdk-dev] [PATCH v2 00/10] Enable dynamic config of subport bandwidth Savinay Dharmappa
                         ` (2 preceding siblings ...)
  2020-09-10 18:48       ` [dpdk-dev] [PATCH v2 03/10] sched: add subport profile add and config api Savinay Dharmappa
@ 2020-09-10 18:48       ` Savinay Dharmappa
  2020-09-10 18:48       ` [dpdk-dev] [PATCH v2 05/10] sched: update the pipe config api implementation Savinay Dharmappa
                         ` (6 subsequent siblings)
  10 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-10 18:48 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Credits are updated by fetching subport profile parameters from
subport profile table.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c | 49 ++++++++++++++++++++++++++++----------------
 1 file changed, 31 insertions(+), 18 deletions(-)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index ba5700a..8e66d08 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -124,6 +124,7 @@ struct rte_sched_grinder {
 	uint32_t productive;
 	uint32_t pindex;
 	struct rte_sched_subport *subport;
+	struct rte_sched_subport_profile *subport_params;
 	struct rte_sched_pipe *pipe;
 	struct rte_sched_pipe_profile *pipe_params;
 
@@ -2280,14 +2281,16 @@ grinder_credits_update(struct rte_sched_port *port,
 	struct rte_sched_grinder *grinder = subport->grinder + pos;
 	struct rte_sched_pipe *pipe = grinder->pipe;
 	struct rte_sched_pipe_profile *params = grinder->pipe_params;
+	struct rte_sched_subport_profile *sp_params = grinder->subport_params;
 	uint64_t n_periods;
 	uint32_t i;
 
 	/* Subport TB */
-	n_periods = (port->time - subport->tb_time) / subport->tb_period;
-	subport->tb_credits += n_periods * subport->tb_credits_per_period;
-	subport->tb_credits = RTE_MIN(subport->tb_credits, subport->tb_size);
-	subport->tb_time += n_periods * subport->tb_period;
+	n_periods = (port->time - subport->tb_time) / sp_params->sp_tb_period;
+	subport->tb_credits += n_periods * sp_params->sp_tb_credits_per_period;
+	subport->tb_credits = RTE_MIN(subport->tb_credits,
+				sp_params->sp_tb_size);
+	subport->tb_time += n_periods * sp_params->sp_tb_period;
 
 	/* Pipe TB */
 	n_periods = (port->time - pipe->tb_time) / params->tb_period;
@@ -2298,9 +2301,10 @@ grinder_credits_update(struct rte_sched_port *port,
 	/* Subport TCs */
 	if (unlikely(port->time >= subport->tc_time)) {
 		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-			subport->tc_credits[i] = subport->tc_credits_per_period[i];
+			subport->tc_credits[i] =
+					sp_params->sp_tc_credits_per_period[i];
 
-		subport->tc_time = port->time + subport->tc_period;
+		subport->tc_time = port->time + sp_params->sp_tc_period;
 	}
 
 	/* Pipe TCs */
@@ -2316,8 +2320,10 @@ grinder_credits_update(struct rte_sched_port *port,
 
 static inline uint64_t
 grinder_tc_ov_credits_update(struct rte_sched_port *port,
-	struct rte_sched_subport *subport)
+	struct rte_sched_subport *subport, uint32_t pos)
 {
+	struct rte_sched_grinder *grinder = subport->grinder + pos;
+	struct rte_sched_subport_profile *sp_params = grinder->subport_params;
 	uint64_t tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
 	uint64_t tc_consumption = 0, tc_ov_consumption_max;
 	uint64_t tc_ov_wm = subport->tc_ov_wm;
@@ -2327,17 +2333,17 @@ grinder_tc_ov_credits_update(struct rte_sched_port *port,
 		return subport->tc_ov_wm_max;
 
 	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASS_BE; i++) {
-		tc_ov_consumption[i] =
-			subport->tc_credits_per_period[i] - subport->tc_credits[i];
+		tc_ov_consumption[i] = sp_params->sp_tc_credits_per_period[i]
+					-  subport->tc_credits[i];
 		tc_consumption += tc_ov_consumption[i];
 	}
 
 	tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] =
-		subport->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
+	sp_params->sp_tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
 		subport->tc_credits[RTE_SCHED_TRAFFIC_CLASS_BE];
 
 	tc_ov_consumption_max =
-		subport->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
+	sp_params->sp_tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
 			tc_consumption;
 
 	if (tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] >
@@ -2363,14 +2369,16 @@ grinder_credits_update(struct rte_sched_port *port,
 	struct rte_sched_grinder *grinder = subport->grinder + pos;
 	struct rte_sched_pipe *pipe = grinder->pipe;
 	struct rte_sched_pipe_profile *params = grinder->pipe_params;
+	struct rte_sched_subport_profile *sp_params = grinder->subport_params;
 	uint64_t n_periods;
 	uint32_t i;
 
 	/* Subport TB */
-	n_periods = (port->time - subport->tb_time) / subport->tb_period;
-	subport->tb_credits += n_periods * subport->tb_credits_per_period;
-	subport->tb_credits = RTE_MIN(subport->tb_credits, subport->tb_size);
-	subport->tb_time += n_periods * subport->tb_period;
+	n_periods = (port->time - subport->tb_time) / sp_params->sp_tb_period;
+	subport->tb_credits += n_periods * sp_params->sp_tb_credits_per_period;
+	subport->tb_credits = RTE_MIN(subport->tb_credits,
+				sp_params->sp_tb_size);
+	subport->tb_time += n_periods * sp_params->sp_tb_period;
 
 	/* Pipe TB */
 	n_periods = (port->time - pipe->tb_time) / params->tb_period;
@@ -2380,12 +2388,14 @@ grinder_credits_update(struct rte_sched_port *port,
 
 	/* Subport TCs */
 	if (unlikely(port->time >= subport->tc_time)) {
-		subport->tc_ov_wm = grinder_tc_ov_credits_update(port, subport);
+		subport->tc_ov_wm =
+			grinder_tc_ov_credits_update(port, subport, pos);
 
 		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-			subport->tc_credits[i] = subport->tc_credits_per_period[i];
+			subport->tc_credits[i] =
+				sp_params->sp_tc_credits_per_period[i];
 
-		subport->tc_time = port->time + subport->tc_period;
+		subport->tc_time = port->time + sp_params->sp_tc_period;
 		subport->tc_ov_period_id++;
 	}
 
@@ -2908,6 +2918,9 @@ grinder_handle(struct rte_sched_port *port,
 		struct rte_sched_pipe *pipe = grinder->pipe;
 
 		grinder->pipe_params = subport->pipe_profiles + pipe->profile;
+		grinder->subport_params = port->subport_profiles +
+						subport->profile;
+
 		grinder_prefetch_tc_queue_arrays(subport, pos);
 		grinder_credits_update(port, subport, pos);
 
-- 
2.7.4


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

* [dpdk-dev] [PATCH v2 05/10] sched: update the pipe config api implementation
  2020-09-10 18:48     ` [dpdk-dev] [PATCH v2 00/10] Enable dynamic config of subport bandwidth Savinay Dharmappa
                         ` (3 preceding siblings ...)
  2020-09-10 18:48       ` [dpdk-dev] [PATCH v2 04/10] sched: update the grinder credit update function Savinay Dharmappa
@ 2020-09-10 18:48       ` Savinay Dharmappa
  2020-09-14 14:26         ` Singh, Jasvinder
  2020-09-10 18:48       ` [dpdk-dev] [PATCH v2 06/10] example/qos_sched: add dynamic config of subport Savinay Dharmappa
                         ` (5 subsequent siblings)
  10 siblings, 1 reply; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-10 18:48 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Subport profile parameters are fetched from subport profile
table to calculate the subport best effort tc rate.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c | 40 +++++++++++++++++++++-------------------
 1 file changed, 21 insertions(+), 19 deletions(-)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index 8e66d08..9ff67e0 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -1403,6 +1403,7 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 	int32_t pipe_profile)
 {
 	struct rte_sched_subport *s;
+	struct rte_sched_subport_profile *sp;
 	struct rte_sched_pipe *p;
 	struct rte_sched_pipe_profile *params;
 	uint32_t n_subports = subport_id + 1;
@@ -1443,14 +1444,15 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 		return -EINVAL;
 	}
 
+	sp = port->subport_profiles + s->profile;
 	/* Handle the case when pipe already has a valid configuration */
 	p = s->pipe + pipe_id;
 	if (p->tb_time) {
 		params = s->pipe_profiles + p->profile;
 
 		double subport_tc_be_rate =
-			(double) s->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
-			/ (double) s->tc_period;
+		(double)sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
+			/ (double) sp->tc_period;
 		double pipe_tc_be_rate =
 			(double) params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
 			/ (double) params->tc_period;
@@ -1492,8 +1494,8 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 	{
 		/* Subport best effort tc oversubscription */
 		double subport_tc_be_rate =
-			(double) s->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
-			/ (double) s->tc_period;
+		(double)sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
+			/ (double) sp->tc_period;
 		double pipe_tc_be_rate =
 			(double) params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
 			/ (double) params->tc_period;
@@ -2286,11 +2288,11 @@ grinder_credits_update(struct rte_sched_port *port,
 	uint32_t i;
 
 	/* Subport TB */
-	n_periods = (port->time - subport->tb_time) / sp_params->sp_tb_period;
-	subport->tb_credits += n_periods * sp_params->sp_tb_credits_per_period;
+	n_periods = (port->time - subport->tb_time) / sp_params->tb_period;
+	subport->tb_credits += n_periods * sp_params->tb_credits_per_period;
 	subport->tb_credits = RTE_MIN(subport->tb_credits,
-				sp_params->sp_tb_size);
-	subport->tb_time += n_periods * sp_params->sp_tb_period;
+				sp_params->tb_size);
+	subport->tb_time += n_periods * sp_params->tb_period;
 
 	/* Pipe TB */
 	n_periods = (port->time - pipe->tb_time) / params->tb_period;
@@ -2302,9 +2304,9 @@ grinder_credits_update(struct rte_sched_port *port,
 	if (unlikely(port->time >= subport->tc_time)) {
 		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
 			subport->tc_credits[i] =
-					sp_params->sp_tc_credits_per_period[i];
+					sp_params->tc_credits_per_period[i];
 
-		subport->tc_time = port->time + sp_params->sp_tc_period;
+		subport->tc_time = port->time + sp_params->tc_period;
 	}
 
 	/* Pipe TCs */
@@ -2333,17 +2335,17 @@ grinder_tc_ov_credits_update(struct rte_sched_port *port,
 		return subport->tc_ov_wm_max;
 
 	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASS_BE; i++) {
-		tc_ov_consumption[i] = sp_params->sp_tc_credits_per_period[i]
+		tc_ov_consumption[i] = sp_params->tc_credits_per_period[i]
 					-  subport->tc_credits[i];
 		tc_consumption += tc_ov_consumption[i];
 	}
 
 	tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] =
-	sp_params->sp_tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
+	sp_params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
 		subport->tc_credits[RTE_SCHED_TRAFFIC_CLASS_BE];
 
 	tc_ov_consumption_max =
-	sp_params->sp_tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
+	sp_params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
 			tc_consumption;
 
 	if (tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] >
@@ -2374,11 +2376,11 @@ grinder_credits_update(struct rte_sched_port *port,
 	uint32_t i;
 
 	/* Subport TB */
-	n_periods = (port->time - subport->tb_time) / sp_params->sp_tb_period;
-	subport->tb_credits += n_periods * sp_params->sp_tb_credits_per_period;
+	n_periods = (port->time - subport->tb_time) / sp_params->tb_period;
+	subport->tb_credits += n_periods * sp_params->tb_credits_per_period;
 	subport->tb_credits = RTE_MIN(subport->tb_credits,
-				sp_params->sp_tb_size);
-	subport->tb_time += n_periods * sp_params->sp_tb_period;
+				sp_params->tb_size);
+	subport->tb_time += n_periods * sp_params->tb_period;
 
 	/* Pipe TB */
 	n_periods = (port->time - pipe->tb_time) / params->tb_period;
@@ -2393,9 +2395,9 @@ grinder_credits_update(struct rte_sched_port *port,
 
 		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
 			subport->tc_credits[i] =
-				sp_params->sp_tc_credits_per_period[i];
+				sp_params->tc_credits_per_period[i];
 
-		subport->tc_time = port->time + sp_params->sp_tc_period;
+		subport->tc_time = port->time + sp_params->tc_period;
 		subport->tc_ov_period_id++;
 	}
 
-- 
2.7.4


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

* [dpdk-dev] [PATCH v2 06/10] example/qos_sched: add dynamic config of subport
  2020-09-10 18:48     ` [dpdk-dev] [PATCH v2 00/10] Enable dynamic config of subport bandwidth Savinay Dharmappa
                         ` (4 preceding siblings ...)
  2020-09-10 18:48       ` [dpdk-dev] [PATCH v2 05/10] sched: update the pipe config api implementation Savinay Dharmappa
@ 2020-09-10 18:48       ` Savinay Dharmappa
  2020-09-10 18:48       ` [dpdk-dev] [PATCH v2 07/10] example/ip_pipeline: " Savinay Dharmappa
                         ` (4 subsequent siblings)
  10 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-10 18:48 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Modify the qos_sched application to build the hierarchical scheduler
with default subport bandwidth profile. It also allows to configure
a subport with different subport bandwidth profile dynamically.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 examples/qos_sched/cfg_file.c  | 158 ++++++++++++++++++++++++-----------------
 examples/qos_sched/cfg_file.h  |   4 ++
 examples/qos_sched/init.c      |  24 +++++--
 examples/qos_sched/main.h      |   1 +
 examples/qos_sched/profile.cfg |   3 +
 5 files changed, 120 insertions(+), 70 deletions(-)

diff --git a/examples/qos_sched/cfg_file.c b/examples/qos_sched/cfg_file.c
index f078e4f..9e1341c 100644
--- a/examples/qos_sched/cfg_file.c
+++ b/examples/qos_sched/cfg_file.c
@@ -53,8 +53,11 @@ cfg_load_pipe(struct rte_cfgfile *cfg, struct rte_sched_pipe_params *pipe_params
 	if (!cfg || !pipe_params)
 		return -1;
 
-	profiles = rte_cfgfile_num_sections(cfg, "pipe profile", sizeof("pipe profile") - 1);
-	subport_params[0].n_pipe_profiles = profiles;
+	profiles = rte_cfgfile_num_sections(cfg, "pipe profile",
+					sizeof("pipe profile") - 1);
+	port_params.n_subport_profiles = profiles;
+
+	printf(" profiles = %d", profiles);
 
 	for (j = 0; j < profiles; j++) {
 		char pipe_name[32];
@@ -143,6 +146,93 @@ cfg_load_pipe(struct rte_cfgfile *cfg, struct rte_sched_pipe_params *pipe_params
 }
 
 int
+cfg_load_subport_profile(struct rte_cfgfile *cfg,
+	struct rte_sched_subport_profile_params *subport_profile)
+{
+	int i;
+	const char *entry;
+	int profiles;
+
+	if (!cfg || !subport_profile)
+		return -1;
+
+	profiles = rte_cfgfile_num_sections(cfg, "subport profile",
+					   sizeof("subport profile") - 1);
+	subport_params[0].n_pipe_profiles = profiles;
+
+	for (i = 0; i < profiles; i++) {
+		char sec_name[32];
+		snprintf(sec_name, sizeof(sec_name), "subport profile %d", i);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tb rate");
+		if (entry)
+			subport_profile[i].tb_rate = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tb size");
+		if (entry)
+			subport_profile[i].tb_size = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc period");
+		if (entry)
+			subport_profile[i].tc_period = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 0 rate");
+		if (entry)
+			subport_profile[i].tc_rate[0] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 1 rate");
+		if (entry)
+			subport_profile[i].tc_rate[1] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 2 rate");
+		if (entry)
+			subport_profile[i].tc_rate[2] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 3 rate");
+		if (entry)
+			subport_profile[i].tc_rate[3] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 4 rate");
+		if (entry)
+			subport_profile[i].tc_rate[4] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 5 rate");
+		if (entry)
+			subport_profile[i].tc_rate[5] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 6 rate");
+		if (entry)
+			subport_profile[i].tc_rate[6] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 7 rate");
+		if (entry)
+			subport_profile[i].tc_rate[7] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 8 rate");
+		if (entry)
+			subport_profile[i].tc_rate[8] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 9 rate");
+		if (entry)
+			subport_profile[i].tc_rate[9] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 10 rate");
+		if (entry)
+			subport_profile[i].tc_rate[10] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 11 rate");
+		if (entry)
+			subport_profile[i].tc_rate[11] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 12 rate");
+		if (entry)
+			subport_profile[i].tc_rate[12] = (uint64_t)atoi(entry);
+	}
+
+	return 0;
+}
+
+int
 cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subport_params)
 {
 	const char *entry;
@@ -267,70 +357,6 @@ cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subpo
 				}
 			}
 
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tb rate");
-			if (entry)
-				subport_params[i].tb_rate = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tb size");
-			if (entry)
-				subport_params[i].tb_size = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc period");
-			if (entry)
-				subport_params[i].tc_period = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 0 rate");
-			if (entry)
-				subport_params[i].tc_rate[0] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 1 rate");
-			if (entry)
-				subport_params[i].tc_rate[1] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 2 rate");
-			if (entry)
-				subport_params[i].tc_rate[2] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 3 rate");
-			if (entry)
-				subport_params[i].tc_rate[3] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 4 rate");
-			if (entry)
-				subport_params[i].tc_rate[4] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 5 rate");
-			if (entry)
-				subport_params[i].tc_rate[5] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 6 rate");
-			if (entry)
-				subport_params[i].tc_rate[6] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 7 rate");
-			if (entry)
-				subport_params[i].tc_rate[7] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 8 rate");
-			if (entry)
-				subport_params[i].tc_rate[8] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 9 rate");
-			if (entry)
-				subport_params[i].tc_rate[9] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 10 rate");
-			if (entry)
-				subport_params[i].tc_rate[10] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 11 rate");
-			if (entry)
-				subport_params[i].tc_rate[11] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 12 rate");
-			if (entry)
-				subport_params[i].tc_rate[12] = (uint64_t)atoi(entry);
-
 			int n_entries = rte_cfgfile_section_num_entries(cfg, sec_name);
 			struct rte_cfgfile_entry entries[n_entries];
 
diff --git a/examples/qos_sched/cfg_file.h b/examples/qos_sched/cfg_file.h
index 2eccf1c..0dc458a 100644
--- a/examples/qos_sched/cfg_file.h
+++ b/examples/qos_sched/cfg_file.h
@@ -14,4 +14,8 @@ int cfg_load_pipe(struct rte_cfgfile *cfg, struct rte_sched_pipe_params *pipe);
 
 int cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subport);
 
+int cfg_load_subport_profile(struct rte_cfgfile *cfg,
+			     struct rte_sched_subport_profile_params
+			     *subport_profile);
+
 #endif
diff --git a/examples/qos_sched/init.c b/examples/qos_sched/init.c
index 9626c15..541adb7 100644
--- a/examples/qos_sched/init.c
+++ b/examples/qos_sched/init.c
@@ -196,15 +196,20 @@ static struct rte_sched_pipe_params pipe_profiles[MAX_SCHED_PIPE_PROFILES] = {
 	},
 };
 
-struct rte_sched_subport_params subport_params[MAX_SCHED_SUBPORTS] = {
+static struct rte_sched_subport_profile_params
+		subport_profile[MAX_SCHED_SUBPORT_PROFILES] = {
 	{
 		.tb_rate = 1250000000,
 		.tb_size = 1000000,
-
 		.tc_rate = {1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000},
 		.tc_period = 10,
+	},
+};
+
+struct rte_sched_subport_params subport_params[MAX_SCHED_SUBPORTS] = {
+	{
 		.n_pipes_per_subport_enabled = 4096,
 		.qsize = {64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64},
 		.pipe_profiles = pipe_profiles,
@@ -289,6 +294,9 @@ struct rte_sched_port_params port_params = {
 	.mtu = 6 + 6 + 4 + 4 + 2 + 1500,
 	.frame_overhead = RTE_SCHED_FRAME_OVERHEAD_DEFAULT,
 	.n_subports_per_port = 1,
+	.n_subport_profiles = 1,
+	.subport_profiles = subport_profile,
+	.n_max_subport_profiles = MAX_SCHED_SUBPORT_PROFILES,
 	.n_pipes_per_subport = MAX_SCHED_PIPES,
 };
 
@@ -320,8 +328,15 @@ app_init_sched_port(uint32_t portid, uint32_t socketid)
 	for (subport = 0; subport < port_params.n_subports_per_port; subport ++) {
 		err = rte_sched_subport_config(port, subport, &subport_params[subport]);
 		if (err) {
-			rte_exit(EXIT_FAILURE, "Unable to config sched subport %u, err=%d\n",
-					subport, err);
+			rte_exit(EXIT_FAILURE, "Unable to config schedi "
+				"subport %u, err=%d\n", subport, err);
+		}
+
+		err = rte_sched_subport_profile_config(port, subport, 0);
+		if (err) {
+			rte_exit(EXIT_FAILURE, "failed to configure "
+				"profile err=%d\n", err);
+
 		}
 
 		uint32_t n_pipes_per_subport =
@@ -354,6 +369,7 @@ app_load_cfg_profile(const char *profile)
 
 	cfg_load_port(file, &port_params);
 	cfg_load_subport(file, subport_params);
+	cfg_load_subport_profile(file, subport_profile);
 	cfg_load_pipe(file, pipe_profiles);
 
 	rte_cfgfile_close(file);
diff --git a/examples/qos_sched/main.h b/examples/qos_sched/main.h
index 23bc418..0d6815a 100644
--- a/examples/qos_sched/main.h
+++ b/examples/qos_sched/main.h
@@ -51,6 +51,7 @@ extern "C" {
 #define MAX_SCHED_SUBPORTS		8
 #define MAX_SCHED_PIPES		4096
 #define MAX_SCHED_PIPE_PROFILES		256
+#define MAX_SCHED_SUBPORT_PROFILES	8
 
 #ifndef APP_COLLECT_STAT
 #define APP_COLLECT_STAT		1
diff --git a/examples/qos_sched/profile.cfg b/examples/qos_sched/profile.cfg
index 61b8b70..4486d27 100644
--- a/examples/qos_sched/profile.cfg
+++ b/examples/qos_sched/profile.cfg
@@ -26,6 +26,9 @@ number of subports per port = 1
 number of pipes per subport = 4096
 queue sizes = 64 64 64 64 64 64 64 64 64 64 64 64 64
 
+subport 0-8 = 0                ; These subports are configured with subport profile 0
+
+[subport profile 0]
 tb rate = 1250000000           ; Bytes per second
 tb size = 1000000              ; Bytes
 
-- 
2.7.4


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

* [dpdk-dev] [PATCH v2 07/10] example/ip_pipeline: add dynamic config of subport
  2020-09-10 18:48     ` [dpdk-dev] [PATCH v2 00/10] Enable dynamic config of subport bandwidth Savinay Dharmappa
                         ` (5 preceding siblings ...)
  2020-09-10 18:48       ` [dpdk-dev] [PATCH v2 06/10] example/qos_sched: add dynamic config of subport Savinay Dharmappa
@ 2020-09-10 18:48       ` Savinay Dharmappa
  2020-09-10 18:48       ` [dpdk-dev] [PATCH v2 08/10] drivers/softnic: " Savinay Dharmappa
                         ` (3 subsequent siblings)
  10 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-10 18:48 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Modify the ip_pipeline application to build the hierarchical scheduler
with default subport bandwidth profile. It also allows to configure
a subport with different subport bandwidth profile dynamically

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 examples/ip_pipeline/cli.c  | 10 ++++++----
 examples/ip_pipeline/tmgr.c | 28 +++++++++++++++++++++++++---
 examples/ip_pipeline/tmgr.h |  3 ++-
 3 files changed, 33 insertions(+), 8 deletions(-)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index d79699e..e192275 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -406,7 +406,8 @@ cmd_tmgr_subport_profile(char **tokens,
 	char *out,
 	size_t out_size)
 {
-	struct rte_sched_subport_params p;
+	struct rte_sched_subport_params params;
+	struct rte_sched_subport_profile_params p;
 	int status, i;
 
 	if (n_tokens != 35) {
@@ -440,7 +441,8 @@ cmd_tmgr_subport_profile(char **tokens,
 		return;
 	}
 
-	if (parser_read_uint32(&p.n_pipes_per_subport_enabled, tokens[20]) != 0) {
+	if (parser_read_uint32(&params.n_pipes_per_subport_enabled,
+		tokens[20]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport");
 		return;
 	}
@@ -451,12 +453,12 @@ cmd_tmgr_subport_profile(char **tokens,
 	}
 
 	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-		if (parser_read_uint16(&p.qsize[i], tokens[22 + i]) != 0) {
+		if (parser_read_uint16(&params.qsize[i], tokens[22 + i]) != 0) {
 			snprintf(out, out_size, MSG_ARG_INVALID, "qsize");
 			return;
 		}
 
-	status = tmgr_subport_profile_add(&p);
+	status = tmgr_subport_profile_add(&p, &params);
 	if (status != 0) {
 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
 		return;
diff --git a/examples/ip_pipeline/tmgr.c b/examples/ip_pipeline/tmgr.c
index 91ccbf6..c609102 100644
--- a/examples/ip_pipeline/tmgr.c
+++ b/examples/ip_pipeline/tmgr.c
@@ -11,6 +11,9 @@
 static struct rte_sched_subport_params
 	subport_profile[TMGR_SUBPORT_PROFILE_MAX];
 
+static struct rte_sched_subport_profile_params
+		profile_params[TMGR_SUBPORT_PROFILE_MAX];
+
 static uint32_t n_subport_profiles;
 
 static struct rte_sched_pipe_params
@@ -44,15 +47,20 @@ tmgr_port_find(const char *name)
 }
 
 int
-tmgr_subport_profile_add(struct rte_sched_subport_params *p)
+tmgr_subport_profile_add(struct rte_sched_subport_profile_params *p,
+			 struct rte_sched_subport_params *params)
 {
 	/* Check input params */
-	if (p == NULL ||
-		p->n_pipes_per_subport_enabled == 0)
+	if (p == NULL || params == NULL ||
+		params->n_pipes_per_subport_enabled == 0)
 		return -1;
 
 	/* Save profile */
 	memcpy(&subport_profile[n_subport_profiles],
+		params,
+		sizeof(*params));
+
+	memcpy(&profile_params[n_subport_profiles],
 		p,
 		sizeof(*p));
 
@@ -103,6 +111,9 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 	p.mtu = params->mtu;
 	p.frame_overhead = params->frame_overhead;
 	p.n_subports_per_port = params->n_subports_per_port;
+	p.n_subport_profiles = n_subport_profiles;
+	p.subport_profiles = profile_params;
+	p.n_max_subport_profiles = TMGR_SUBPORT_PROFILE_MAX;
 	p.n_pipes_per_subport = TMGR_PIPE_SUBPORT_MAX;
 
 	s = rte_sched_port_config(&p);
@@ -126,6 +137,13 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 			return NULL;
 		}
 
+		status = rte_sched_subport_profile_config(s, i, 0);
+
+		if (status) {
+			rte_sched_port_free(s);
+			return NULL;
+		}
+
 		for (j = 0; j < subport_profile[0].n_pipes_per_subport_enabled; j++) {
 			status = rte_sched_pipe_config(
 				s,
@@ -182,6 +200,10 @@ tmgr_subport_config(const char *port_name,
 		subport_id,
 		&subport_profile[subport_profile_id]);
 
+	if (!status)
+		status = rte_sched_subport_profile_config(port->s, subport_id,
+							subport_profile_id);
+
 	return status;
 }
 
diff --git a/examples/ip_pipeline/tmgr.h b/examples/ip_pipeline/tmgr.h
index ee50cf7..b19fb23 100644
--- a/examples/ip_pipeline/tmgr.h
+++ b/examples/ip_pipeline/tmgr.h
@@ -48,7 +48,8 @@ struct tmgr_port_params {
 };
 
 int
-tmgr_subport_profile_add(struct rte_sched_subport_params *p);
+tmgr_subport_profile_add(struct rte_sched_subport_profile_params *p,
+			 struct rte_sched_subport_params *params);
 
 int
 tmgr_pipe_profile_add(struct rte_sched_pipe_params *p);
-- 
2.7.4


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

* [dpdk-dev] [PATCH v2 08/10] drivers/softnic: add dynamic config of subport
  2020-09-10 18:48     ` [dpdk-dev] [PATCH v2 00/10] Enable dynamic config of subport bandwidth Savinay Dharmappa
                         ` (6 preceding siblings ...)
  2020-09-10 18:48       ` [dpdk-dev] [PATCH v2 07/10] example/ip_pipeline: " Savinay Dharmappa
@ 2020-09-10 18:48       ` Savinay Dharmappa
  2020-09-10 18:48       ` [dpdk-dev] [PATCH v2 09/10] app/test_sched: " Savinay Dharmappa
                         ` (2 subsequent siblings)
  10 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-10 18:48 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Modify the softnic drivers to build the hierarchical scheduler
with default subport bandwidth profile. It also allows to configure
a subport with different subport bandwidth profile dynamically.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 drivers/net/softnic/rte_eth_softnic_internals.h |   9 +
 drivers/net/softnic/rte_eth_softnic_tm.c        | 223 +++++++++++++++++++-----
 2 files changed, 187 insertions(+), 45 deletions(-)

diff --git a/drivers/net/softnic/rte_eth_softnic_internals.h b/drivers/net/softnic/rte_eth_softnic_internals.h
index 6eec43b..cc50037 100644
--- a/drivers/net/softnic/rte_eth_softnic_internals.h
+++ b/drivers/net/softnic/rte_eth_softnic_internals.h
@@ -164,10 +164,19 @@ TAILQ_HEAD(softnic_link_list, softnic_link);
 #ifndef TM_MAX_PIPE_PROFILE
 #define TM_MAX_PIPE_PROFILE				256
 #endif
+
+#ifndef TM_MAX_SUBPORT_PROFILE
+#define TM_MAX_SUBPORT_PROFILE				256
+#endif
+
 struct tm_params {
 	struct rte_sched_port_params port_params;
 
 	struct rte_sched_subport_params subport_params[TM_MAX_SUBPORTS];
+	struct rte_sched_subport_profile_params
+				subport_profiles[TM_MAX_SUBPORT_PROFILE];
+	uint32_t n_subport_profiles;
+	uint32_t subport_to_profile[TM_MAX_SUBPORT_PROFILE];
 
 	struct rte_sched_pipe_params pipe_profiles[TM_MAX_PIPE_PROFILE];
 	uint32_t n_pipe_profiles;
diff --git a/drivers/net/softnic/rte_eth_softnic_tm.c b/drivers/net/softnic/rte_eth_softnic_tm.c
index 80a470c..a223655 100644
--- a/drivers/net/softnic/rte_eth_softnic_tm.c
+++ b/drivers/net/softnic/rte_eth_softnic_tm.c
@@ -98,6 +98,13 @@ softnic_tmgr_port_create(struct pmd_internals *p,
 			return NULL;
 		}
 
+		status = rte_sched_subport_profile_config(sched,
+			subport_id, t->subport_to_profile[subport_id]);
+		if (status) {
+			rte_sched_port_free(sched);
+			return NULL;
+		}
+
 		/* Pipe */
 		for (pipe_id = 0; pipe_id < n_pipes_per_subport; pipe_id++) {
 			int pos = subport_id * TM_MAX_PIPES_PER_SUBPORT + pipe_id;
@@ -1043,6 +1050,25 @@ tm_shared_shaper_get_tc(struct rte_eth_dev *dev,
 }
 
 static int
+subport_profile_exists(struct rte_eth_dev *dev,
+	struct rte_sched_subport_profile_params *sp,
+	uint32_t *subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+	uint32_t i;
+
+	for (i = 0; i < t->n_subport_profiles; i++)
+		if (memcmp(&t->subport_profiles[i], sp, sizeof(*sp)) == 0) {
+			if (subport_profile_id)
+				*subport_profile_id = i;
+			return 1;
+		}
+
+	return 0;
+}
+
+static int
 update_subport_tc_rate(struct rte_eth_dev *dev,
 	struct tm_node *nt,
 	struct tm_shared_shaper *ss,
@@ -1050,26 +1076,27 @@ update_subport_tc_rate(struct rte_eth_dev *dev,
 {
 	struct pmd_internals *p = dev->data->dev_private;
 	uint32_t tc_id = tm_node_tc_id(dev, nt);
-
 	struct tm_node *np = nt->parent_node;
-
 	struct tm_node *ns = np->parent_node;
 	uint32_t subport_id = tm_node_subport_id(dev, ns);
-
-	struct rte_sched_subport_params subport_params;
-
+	struct rte_sched_subport_profile_params subport_profile;
 	struct tm_shaper_profile *sp_old = tm_shaper_profile_search(dev,
 		ss->shaper_profile_id);
+	uint32_t subport_profile_id;
 
 	/* Derive new subport configuration. */
-	memcpy(&subport_params,
-		&p->soft.tm.params.subport_params[subport_id],
-		sizeof(subport_params));
-	subport_params.tc_rate[tc_id] = sp_new->params.peak.rate;
+	memcpy(&subport_profile,
+		&p->soft.tm.params.subport_profiles[subport_id],
+		sizeof(subport_profile));
+	subport_profile.tc_rate[tc_id] = sp_new->params.peak.rate;
+
+	if (subport_profile_exists(dev, &subport_profile,
+				  &subport_profile_id) == 0)
+		return -1;
 
 	/* Update the subport configuration. */
-	if (rte_sched_subport_config(SCHED(p),
-		subport_id, &subport_params))
+	if (rte_sched_subport_profile_config(SCHED(p),
+		subport_id, subport_profile_id))
 		return -1;
 
 	/* Commit changes. */
@@ -1078,9 +1105,9 @@ update_subport_tc_rate(struct rte_eth_dev *dev,
 	ss->shaper_profile_id = sp_new->shaper_profile_id;
 	sp_new->n_users++;
 
-	memcpy(&p->soft.tm.params.subport_params[subport_id],
-		&subport_params,
-		sizeof(subport_params));
+	memcpy(&p->soft.tm.params.subport_profiles[subport_id],
+		&subport_profile,
+		sizeof(subport_profile));
 
 	return 0;
 }
@@ -2190,6 +2217,108 @@ pipe_profiles_generate(struct rte_eth_dev *dev)
 	return 0;
 }
 
+static struct rte_sched_subport_profile_params *
+subport_profile_get(struct rte_eth_dev *dev, struct tm_node *np)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+	uint32_t subport_id = tm_node_subport_id(dev, np->parent_node);
+
+	return &t->subport_profiles[subport_id];
+}
+
+static void
+subport_profile_mark(struct rte_eth_dev *dev,
+	uint32_t subport_id,
+	uint32_t subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+
+	t->subport_to_profile[subport_id] = subport_profile_id;
+}
+
+static void
+subport_profile_install(struct rte_eth_dev *dev,
+	struct rte_sched_subport_profile_params *sp,
+	uint32_t subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+
+	memcpy(&t->subport_profiles[subport_profile_id], sp, sizeof(*sp));
+	t->n_subport_profiles++;
+}
+
+static int
+subport_profile_free_exists(struct rte_eth_dev *dev,
+	uint32_t *subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+
+	if (t->n_subport_profiles < TM_MAX_SUBPORT_PROFILE) {
+		*subport_profile_id = t->n_subport_profiles;
+		return 1;
+	}
+
+	return 0;
+}
+
+static void
+subport_profile_build(struct tm_node *np,
+	struct rte_sched_subport_profile_params *sp)
+{
+	memset(sp, 0, sizeof(*sp));
+
+	/* Pipe */
+	sp->tb_rate = np->shaper_profile->params.peak.rate;
+	sp->tb_size = np->shaper_profile->params.peak.size;
+
+	/* Traffic Class (TC) */
+	sp->tc_period = SUBPORT_TC_PERIOD;
+}
+
+static int
+subport_profiles_generate(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_hierarchy *h = &p->soft.tm.h;
+	struct tm_node_list *nl = &h->nodes;
+	struct tm_node *ns;
+	uint32_t subport_id;
+
+	/* Objective: Fill in the following fields in struct tm_params:
+	 *    - subport_profiles
+	 *    - n_subport_profiles
+	 *    - subport_to_profile
+	 */
+
+	subport_id = 0;
+	TAILQ_FOREACH(ns, nl, node) {
+		if (ns->level != TM_NODE_LEVEL_SUBPORT)
+			continue;
+
+		struct rte_sched_subport_profile_params sp;
+		uint32_t pos;
+
+		subport_profile_build(ns, &sp);
+
+		if (!subport_profile_exists(dev, &sp, &pos)) {
+			if (!subport_profile_free_exists(dev, &pos))
+				return -1;
+
+			subport_profile_install(dev, &sp, pos);
+		}
+
+		subport_profile_mark(dev, subport_id, pos);
+
+		subport_id++;
+	}
+
+	return 0;
+}
+
 static struct tm_wred_profile *
 tm_tc_wred_profile_get(struct rte_eth_dev *dev, uint32_t tc_id)
 {
@@ -2447,6 +2576,15 @@ hierarchy_commit_check(struct rte_eth_dev *dev, struct rte_tm_error *error)
 				rte_strerror(EINVAL));
 	}
 
+	/* Not too many subport profiles. */
+	if (subport_profiles_generate(dev))
+		return -rte_tm_error_set(error,
+			EINVAL,
+			RTE_TM_ERROR_TYPE_UNSPECIFIED,
+			NULL,
+			rte_strerror(EINVAL));
+
+
 	/* Not too many pipe profiles. */
 	if (pipe_profiles_generate(dev))
 		return -rte_tm_error_set(error,
@@ -2528,6 +2666,9 @@ hierarchy_blueprints_create(struct rte_eth_dev *dev)
 		.frame_overhead =
 			root->shaper_profile->params.pkt_length_adjust,
 		.n_subports_per_port = root->n_children,
+		.n_subport_profiles = t->n_subport_profiles,
+		.subport_profiles = t->subport_profiles,
+		.n_max_subport_profiles = TM_MAX_SUBPORT_PROFILE,
 		.n_pipes_per_subport = TM_MAX_PIPES_PER_SUBPORT,
 	};
 
@@ -2548,28 +2689,11 @@ hierarchy_blueprints_create(struct rte_eth_dev *dev)
 				ss->shaper_profile_id) :
 				n->shaper_profile;
 			tc_rate[i] = sp->params.peak.rate;
+			t->subport_profiles[subport_id].tc_rate[i] = tc_rate[i];
 		}
 
 		t->subport_params[subport_id] =
 			(struct rte_sched_subport_params) {
-				.tb_rate = n->shaper_profile->params.peak.rate,
-				.tb_size = n->shaper_profile->params.peak.size,
-
-				.tc_rate = {tc_rate[0],
-					tc_rate[1],
-					tc_rate[2],
-					tc_rate[3],
-					tc_rate[4],
-					tc_rate[5],
-					tc_rate[6],
-					tc_rate[7],
-					tc_rate[8],
-					tc_rate[9],
-					tc_rate[10],
-					tc_rate[11],
-					tc_rate[12],
-				},
-				.tc_period = SUBPORT_TC_PERIOD,
 				.n_pipes_per_subport_enabled =
 					h->n_tm_nodes[TM_NODE_LEVEL_PIPE] /
 					h->n_tm_nodes[TM_NODE_LEVEL_SUBPORT],
@@ -2829,30 +2953,39 @@ update_subport_rate(struct rte_eth_dev *dev,
 	struct pmd_internals *p = dev->data->dev_private;
 	uint32_t subport_id = tm_node_subport_id(dev, ns);
 
-	struct rte_sched_subport_params subport_params;
+	struct rte_sched_subport_profile_params *profile0 =
+					subport_profile_get(dev, ns);
+	struct rte_sched_subport_profile_params profile1;
+	uint32_t subport_profile_id;
 
-	/* Derive new subport configuration. */
-	memcpy(&subport_params,
-		&p->soft.tm.params.subport_params[subport_id],
-		sizeof(subport_params));
-	subport_params.tb_rate = sp->params.peak.rate;
-	subport_params.tb_size = sp->params.peak.size;
+	/* Derive new pipe profile. */
+	memcpy(&profile1, profile0, sizeof(profile1));
+	profile1.tb_rate = sp->params.peak.rate;
+	profile1.tb_size = sp->params.peak.size;
+
+	/* Since implementation does not allow adding more subport profiles
+	 * after port configuration, the pipe configuration can be successfully
+	 * updated only if the new profile is also part of the existing set of
+	 * pipe profiles.
+	 */
+	if (subport_profile_exists(dev, &profile1, &subport_profile_id) == 0)
+		return -1;
 
 	/* Update the subport configuration. */
-	if (rte_sched_subport_config(SCHED(p), subport_id,
-		&subport_params))
+	if (rte_sched_subport_profile_config(SCHED(p), subport_id,
+		subport_profile_id))
 		return -1;
 
+	subport_profile_mark(dev, subport_id, subport_profile_id);
 	/* Commit changes. */
 	ns->shaper_profile->n_users--;
-
 	ns->shaper_profile = sp;
 	ns->params.shaper_profile_id = sp->shaper_profile_id;
 	sp->n_users++;
 
-	memcpy(&p->soft.tm.params.subport_params[subport_id],
-		&subport_params,
-		sizeof(subport_params));
+	memcpy(&p->soft.tm.params.subport_profiles[subport_id],
+		&profile1,
+		sizeof(profile1));
 
 	return 0;
 }
-- 
2.7.4


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

* [dpdk-dev] [PATCH v2 09/10] app/test_sched: add dynamic config of subport
  2020-09-10 18:48     ` [dpdk-dev] [PATCH v2 00/10] Enable dynamic config of subport bandwidth Savinay Dharmappa
                         ` (7 preceding siblings ...)
  2020-09-10 18:48       ` [dpdk-dev] [PATCH v2 08/10] drivers/softnic: " Savinay Dharmappa
@ 2020-09-10 18:48       ` Savinay Dharmappa
  2020-09-10 18:48       ` [dpdk-dev] [PATCH v2 10/10] sched: remove the redundant code Savinay Dharmappa
  2020-09-16 16:43       ` [dpdk-dev] [PATCH v3 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
  10 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-10 18:48 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Modify the test_sched application to build the hierarchical scheduler
with default subport bandwidth profile. It also allows to configure
a subport with different subport bandwidth profile dynamically

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 app/test/test_sched.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/app/test/test_sched.c b/app/test/test_sched.c
index fc31080..8d1eb25 100644
--- a/app/test/test_sched.c
+++ b/app/test/test_sched.c
@@ -21,6 +21,7 @@
 #define PIPE            1
 #define TC              2
 #define QUEUE           0
+#define MAX_SCHED_SUBPORT_PROFILES  8
 
 static struct rte_sched_pipe_params pipe_profile[] = {
 	{ /* Profile #0 */
@@ -36,15 +37,20 @@ static struct rte_sched_pipe_params pipe_profile[] = {
 	},
 };
 
-static struct rte_sched_subport_params subport_param[] = {
+static struct rte_sched_subport_profile_params
+		subport_profile[] = {
 	{
 		.tb_rate = 1250000000,
 		.tb_size = 1000000,
-
 		.tc_rate = {1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000},
 		.tc_period = 10,
+	},
+};
+
+static struct rte_sched_subport_params subport_param[] = {
+	{
 		.n_pipes_per_subport_enabled = 1024,
 		.qsize = {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32},
 		.pipe_profiles = pipe_profile,
@@ -59,6 +65,9 @@ static struct rte_sched_port_params port_param = {
 	.mtu = 1522,
 	.frame_overhead = RTE_SCHED_FRAME_OVERHEAD_DEFAULT,
 	.n_subports_per_port = 1,
+	.n_subport_profiles = 1,
+	.subport_profiles = subport_profile,
+	.n_max_subport_profiles = MAX_SCHED_SUBPORT_PROFILES,
 	.n_pipes_per_subport = 1024,
 };
 
@@ -66,6 +75,7 @@ static struct rte_sched_port_params port_param = {
 #define MBUF_DATA_SZ     (2048 + RTE_PKTMBUF_HEADROOM)
 #define MEMPOOL_CACHE_SZ 0
 #define SOCKET           0
+#define DEFAULT_PROFILE  0
 
 
 static struct rte_mempool *
@@ -141,6 +151,10 @@ test_sched(void)
 	err = rte_sched_subport_config(port, SUBPORT, subport_param);
 	TEST_ASSERT_SUCCESS(err, "Error config sched, err=%d\n", err);
 
+	err = rte_sched_subport_profile_config(port, SUBPORT,
+						DEFAULT_PROFILE);
+	TEST_ASSERT_SUCCESS(err, "Error config sched, err=%d\n", err);
+
 	for (pipe = 0; pipe < subport_param[0].n_pipes_per_subport_enabled; pipe++) {
 		err = rte_sched_pipe_config(port, SUBPORT, pipe, 0);
 		TEST_ASSERT_SUCCESS(err, "Error config sched pipe %u, err=%d\n", pipe, err);
-- 
2.7.4


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

* [dpdk-dev] [PATCH v2 10/10] sched: remove the redundant code
  2020-09-10 18:48     ` [dpdk-dev] [PATCH v2 00/10] Enable dynamic config of subport bandwidth Savinay Dharmappa
                         ` (8 preceding siblings ...)
  2020-09-10 18:48       ` [dpdk-dev] [PATCH v2 09/10] app/test_sched: " Savinay Dharmappa
@ 2020-09-10 18:48       ` Savinay Dharmappa
  2020-09-16 16:43       ` [dpdk-dev] [PATCH v3 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
  10 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-10 18:48 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Remove redundant data structure fields references from
functions and subport level data structures. It also
update the release and deprecation note.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 doc/guides/rel_notes/deprecation.rst   |   6 --
 doc/guides/rel_notes/release_20_11.rst |   4 ++
 lib/librte_sched/rte_sched.c           | 115 +--------------------------------
 lib/librte_sched/rte_sched.h           |  12 ----
 4 files changed, 6 insertions(+), 131 deletions(-)

diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 279eccb..3926c3c 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -311,12 +311,6 @@ Deprecation Notices
   in "rte_sched.h". These changes are aligned to improvements suggested in the
   RFC https://mails.dpdk.org/archives/dev/2018-November/120035.html.
 
-* sched: To allow dynamic configuration of the subport bandwidth profile,
-  changes will be made to data structures ``rte_sched_subport_params``,
-  ``rte_sched_port_params`` and new data structure, API functions will be
-  defined in ``rte_sched.h``. These changes are aligned as suggested in the
-  RFC https://mails.dpdk.org/archives/dev/2020-July/175161.html
-
 * metrics: The function ``rte_metrics_init`` will have a non-void return
   in order to notify errors instead of calling ``rte_exit``.
 
diff --git a/doc/guides/rel_notes/release_20_11.rst b/doc/guides/rel_notes/release_20_11.rst
index df227a1..51c4568 100644
--- a/doc/guides/rel_notes/release_20_11.rst
+++ b/doc/guides/rel_notes/release_20_11.rst
@@ -84,6 +84,10 @@ API Changes
    Also, make sure to start the actual text at the margin.
    =======================================================
 
+* sched: The subport bandwidth configuration parameters such as tb_rate,
+  tc_rate, tc_period etc., are moved from subport level data structure to
+  new a data structure. This allows to configure a subport with different
+  subport bandwidth configuration dynamically.
 
 ABI Changes
 -----------
diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index 9ff67e0..6edc622 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -153,16 +153,11 @@ struct rte_sched_grinder {
 struct rte_sched_subport {
 	/* Token bucket (TB) */
 	uint64_t tb_time; /* time of last update */
-	uint64_t tb_period;
-	uint64_t tb_credits_per_period;
-	uint64_t tb_size;
 	uint64_t tb_credits;
 
 	/* Traffic classes (TCs) */
 	uint64_t tc_time; /* time of next update */
-	uint64_t tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
 	uint64_t tc_credits[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
-	uint64_t tc_period;
 
 	/* TC oversubscription */
 	uint64_t tc_ov_wm;
@@ -838,18 +833,6 @@ rte_sched_subport_check_params(struct rte_sched_subport_params *params,
 		return -EINVAL;
 	}
 
-	if (params->tb_rate == 0 || params->tb_rate > rate) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect value for tb rate\n", __func__);
-		return -EINVAL;
-	}
-
-	if (params->tb_size == 0) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect value for tb size\n", __func__);
-		return -EINVAL;
-	}
-
 	/* qsize: if non-zero, power of 2,
 	 * no bigger than 32K (due to 16-bit read/write pointers)
 	 */
@@ -863,29 +846,8 @@ rte_sched_subport_check_params(struct rte_sched_subport_params *params,
 		}
 	}
 
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
-		uint64_t tc_rate = params->tc_rate[i];
-		uint16_t qsize = params->qsize[i];
-
-		if ((qsize == 0 && tc_rate != 0) ||
-			(qsize != 0 && tc_rate == 0) ||
-			(tc_rate > params->tb_rate)) {
-			RTE_LOG(ERR, SCHED,
-				"%s: Incorrect value for tc rate\n", __func__);
-			return -EINVAL;
-		}
-	}
-
-	if (params->qsize[RTE_SCHED_TRAFFIC_CLASS_BE] == 0 ||
-		params->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect qsize or tc rate(best effort)\n", __func__);
-		return -EINVAL;
-	}
-
-	if (params->tc_period == 0) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect value for tc period\n", __func__);
+	if (params->qsize[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
+		RTE_LOG(ERR, SCHED, "%s: Incorrect qsize\n", __func__);
 		return -EINVAL;
 	}
 
@@ -1102,48 +1064,6 @@ rte_sched_port_free(struct rte_sched_port *port)
 }
 
 static void
-rte_sched_port_log_subport_config(struct rte_sched_port *port, uint32_t i)
-{
-	struct rte_sched_subport *s = port->subports[i];
-
-	RTE_LOG(DEBUG, SCHED, "Low level config for subport %u:\n"
-		"	Token bucket: period = %"PRIu64", credits per period = %"PRIu64
-		", size = %"PRIu64"\n"
-		"	Traffic classes: period = %"PRIu64"\n"
-		"	credits per period = [%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
-		", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
-		", %"PRIu64", %"PRIu64", %"PRIu64"]\n"
-		"	Best effort traffic class oversubscription: wm min = %"PRIu64
-		", wm max = %"PRIu64"\n",
-		i,
-
-		/* Token bucket */
-		s->tb_period,
-		s->tb_credits_per_period,
-		s->tb_size,
-
-		/* Traffic classes */
-		s->tc_period,
-		s->tc_credits_per_period[0],
-		s->tc_credits_per_period[1],
-		s->tc_credits_per_period[2],
-		s->tc_credits_per_period[3],
-		s->tc_credits_per_period[4],
-		s->tc_credits_per_period[5],
-		s->tc_credits_per_period[6],
-		s->tc_credits_per_period[7],
-		s->tc_credits_per_period[8],
-		s->tc_credits_per_period[9],
-		s->tc_credits_per_period[10],
-		s->tc_credits_per_period[11],
-		s->tc_credits_per_period[12],
-
-		/* Best effort traffic class oversubscription */
-		s->tc_ov_wm_min,
-		s->tc_ov_wm_max);
-}
-
-static void
 rte_sched_free_memory(struct rte_sched_port *port, uint32_t n_subports)
 {
 	uint32_t i;
@@ -1216,33 +1136,7 @@ rte_sched_subport_config(struct rte_sched_port *port,
 	/* Port */
 	port->subports[subport_id] = s;
 
-	/* Token Bucket (TB) */
-	if (params->tb_rate == port->rate) {
-		s->tb_credits_per_period = 1;
-		s->tb_period = 1;
-	} else {
-		double tb_rate = ((double) params->tb_rate) / ((double) port->rate);
-		double d = RTE_SCHED_TB_RATE_CONFIG_ERR;
-
-		rte_approx_64(tb_rate, d, &s->tb_credits_per_period, &s->tb_period);
-	}
-
-	s->tb_size = params->tb_size;
 	s->tb_time = port->time;
-	s->tb_credits = s->tb_size / 2;
-
-	/* Traffic Classes (TCs) */
-	s->tc_period = rte_sched_time_ms_to_bytes(params->tc_period, port->rate);
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
-		if (params->qsize[i])
-			s->tc_credits_per_period[i]
-				= rte_sched_time_ms_to_bytes(params->tc_period,
-					params->tc_rate[i]);
-	}
-	s->tc_time = port->time + s->tc_period;
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-		if (params->qsize[i])
-			s->tc_credits[i] = s->tc_credits_per_period[i];
 
 	/* compile time checks */
 	RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS == 0);
@@ -1332,17 +1226,12 @@ rte_sched_subport_config(struct rte_sched_port *port,
 #ifdef RTE_SCHED_SUBPORT_TC_OV
 	/* TC oversubscription */
 	s->tc_ov_wm_min = port->mtu;
-	s->tc_ov_wm_max = rte_sched_time_ms_to_bytes(params->tc_period,
-						     s->pipe_tc_be_rate_max);
 	s->tc_ov_wm = s->tc_ov_wm_max;
 	s->tc_ov_period_id = 0;
 	s->tc_ov = 0;
 	s->tc_ov_n = 0;
 	s->tc_ov_rate = 0;
 #endif
-
-	rte_sched_port_log_subport_config(port, subport_id);
-
 	return 0;
 }
 
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index a7c2638..7623919 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -149,18 +149,6 @@ struct rte_sched_pipe_params {
  * byte.
  */
 struct rte_sched_subport_params {
-	/** Token bucket rate (measured in bytes per second) */
-	uint64_t tb_rate;
-
-	/** Token bucket size (measured in credits) */
-	uint64_t tb_size;
-
-	/** Traffic class rates (measured in bytes per second) */
-	uint64_t tc_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
-
-	/** Enforcement period for rates (measured in milliseconds) */
-	uint64_t tc_period;
-
 	/** Number of subport pipes.
 	 * The subport can enable/allocate fewer pipes than the maximum
 	 * number set through struct port_params::n_max_pipes_per_subport,
-- 
2.7.4


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

* Re: [dpdk-dev] [PATCH v2 03/10] sched: add subport profile add and config api
  2020-09-10 18:48       ` [dpdk-dev] [PATCH v2 03/10] sched: add subport profile add and config api Savinay Dharmappa
@ 2020-09-14 14:05         ` Singh, Jasvinder
  0 siblings, 0 replies; 107+ messages in thread
From: Singh, Jasvinder @ 2020-09-14 14:05 UTC (permalink / raw)
  To: Dharmappa, Savinay, Dumitrescu, Cristian, dev



> -----Original Message-----
> From: Dharmappa, Savinay <savinay.dharmappa@intel.com>
> Sent: Thursday, September 10, 2020 7:49 PM
> To: Singh, Jasvinder <jasvinder.singh@intel.com>; Dumitrescu, Cristian
> <cristian.dumitrescu@intel.com>; dev@dpdk.org
> Cc: Dharmappa, Savinay <savinay.dharmappa@intel.com>
> Subject: [PATCH v2 03/10] sched: add subport profile add and config api
> 
> Add apis to add new subport profile and configure it.
> 
> Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
> Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> ---
>  lib/librte_sched/rte_sched.c           | 118
> +++++++++++++++++++++++++++++++++
>  lib/librte_sched/rte_sched.h           |  45 +++++++++++++
>  lib/librte_sched/rte_sched_version.map |   2 +
>  3 files changed, 165 insertions(+)
> 
> diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c index
> ec6e6bf..ba5700a 100644
> --- a/lib/librte_sched/rte_sched.c
> +++ b/lib/librte_sched/rte_sched.c
> @@ -175,6 +175,8 @@ struct rte_sched_subport {
>  	/* Statistics */
>  	struct rte_sched_subport_stats stats __rte_cache_aligned;
> 
> +	/* subport profile flag */
> +	uint32_t profile;
>  	/* Subport pipes */
>  	uint32_t n_pipes_per_subport_enabled;
>  	uint32_t n_pipe_profiles;
> @@ -1344,6 +1346,56 @@ rte_sched_subport_config(struct rte_sched_port
> *port,  }
> 
>  int
> +rte_sched_subport_profile_config(struct rte_sched_port *port,
> +	uint32_t subport_id,
> +	uint32_t profile_id)
> +{
> +	int i;
> +	struct rte_sched_subport_profile *params;
> +	uint32_t n_subports = subport_id + 1;
> +	struct rte_sched_subport *s;
> +
> +	if (port == NULL) {
> +		RTE_LOG(ERR, SCHED,
> +			"%s: Incorrect value for parameter port\n",
> __func__);
> +		return -EINVAL;
> +	}
> +
> +	if (subport_id >= port->n_subports_per_port) {
> +		RTE_LOG(ERR, SCHED, "%s: "
> +		"Incorrect value for parameter subport id\n", __func__);
> +
> +		rte_sched_free_memory(port, n_subports);
> +		return -EINVAL;
> +	}
> +
> +	params =  port->subport_profiles + profile_id;
> +
> +	s = port->subports[subport_id];
> +
> +	s->tb_credits = params->tb_size / 2;
> +
> +	s->tc_time = port->time + params->tc_period;
> +
> +	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
> +		if (s->qsize[i])
> +			s->tc_credits[i] =
> +				params->tc_credits_per_period[i];
> +		else
> +			params->tc_credits_per_period[i] = 0;
> +
> +#ifdef RTE_SCHED_SUBPORT_TC_OV
> +	s->tc_ov_wm_max = rte_sched_time_ms_to_bytes(params-
> >tc_period,
> +						     s->pipe_tc_be_rate_max);
> +#endif
> +	s->profile = profile_id;
> +
> +	rte_sched_port_log_subport_profile(port, profile_id);
> +
> +	return 0;
> +}
> +
> +int
>  rte_sched_pipe_config(struct rte_sched_port *port,
>  	uint32_t subport_id,
>  	uint32_t pipe_id,
> @@ -1527,6 +1579,72 @@ rte_sched_subport_pipe_profile_add(struct
> rte_sched_port *port,
>  	return 0;
>  }
> 
> +int
> +rte_sched_port_subport_profile_add(struct rte_sched_port *port,
> +	struct rte_sched_subport_profile_params *params,
> +	uint32_t *subport_profile_id)
> +{
> +	int status;
> +	uint32_t i;
> +	struct rte_sched_subport_profile *dst;
> +
> +	/* Port */
> +	if (port == NULL) {
> +		RTE_LOG(ERR, SCHED, "%s: "
> +		"Incorrect value for parameter port\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	if (params == NULL) {
> +		RTE_LOG(ERR, SCHED, "%s: "
> +		"Incorrect value for parameter profile\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	if (subport_profile_id == NULL) {
> +		RTE_LOG(ERR, SCHED, "%s: "
> +		"Incorrect value for parameter subport_profile_id\n",
> +		__func__);
> +		return -EINVAL;
> +	}
> +
> +	dst = port->subport_profiles + port->n_subport_profiles;
> +
> +	/* Subport profiles exceeds the max limit */
> +	if (port->n_subport_profiles >= port->n_max_subport_profiles) {
> +		RTE_LOG(ERR, SCHED, "%s: "
> +		"Number of subport profiles exceeds the max limit\n",
> +		 __func__);
> +		return -EINVAL;
> +	}
> +
> +	status = subport_profile_check(params, port->rate);
> +	if (status != 0) {
> +		RTE_LOG(ERR, SCHED,
> +		"%s: subport profile check failed(%d)\n", __func__, status);
> +		return -EINVAL;
> +	}
> +
> +	rte_sched_subport_profile_convert(params, dst, port->rate);
> +
> +	/* Subport profile should not exists */
> +	for (i = 0; i < port->n_subport_profiles; i++)
> +		if (memcmp(port->subport_profiles + i,
> +		    params, sizeof(*params)) == 0) {
> +			RTE_LOG(ERR, SCHED,
> +			"%s: subport profile exists\n", __func__);
> +			return -EINVAL;
> +		}
> +

Savinay, Comparing port->subport_profiles with params is wrong as they are different structures, need to compare port->subport_profiles with dst. 


> +	/* Subport profile commit */
> +	*subport_profile_id = port->n_subport_profiles;
> +	port->n_subport_profiles++;
> +
> +	rte_sched_port_log_subport_profile(port, *subport_profile_id);
> +
> +	return 0;
> +}
> +
>  static inline uint32_t
>  rte_sched_port_qindex(struct rte_sched_port *port,
>  	uint32_t subport,
> diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h index
> 39339b7..a7c2638 100644
> --- a/lib/librte_sched/rte_sched.h
> +++ b/lib/librte_sched/rte_sched.h
> @@ -337,6 +337,29 @@ rte_sched_subport_pipe_profile_add(struct
> rte_sched_port *port,
>  	uint32_t *pipe_profile_id);
> 
>  /**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice.
> + *
> + * Hierarchical scheduler subport bandwidth profile add
> + * Note that this function is safe to use in runtime for adding new
> + * subport bandwidth profile as it doesn't have any impact on
> +hiearchical
> + * structure of the scheduler.
> + * @param port
> + *   Handle to port scheduler instance
> + * @param struct rte_sched_subport_profile
> + *   Subport bandwidth profile
> + * @param subport_profile_d
> + *   Subport profile id
> + * @return
> + *   0 upon success, error code otherwise
> + */
> +__rte_experimental
> +int
> +rte_sched_port_subport_profile_add(struct rte_sched_port *port,
> +	struct rte_sched_subport_profile_params *profile,
> +	uint32_t *subport_profile_id);
> +
> +/**
>   * Hierarchical scheduler subport configuration
>   *
>   * @param port
> @@ -354,6 +377,28 @@ rte_sched_subport_config(struct rte_sched_port
> *port,
>  	struct rte_sched_subport_params *params);
> 
>  /**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice.
> + *
> + * Hierarchical scheduler subport profile configuration
> + * Note that this function is safe to use in runtime for applying any
> +specific
> + * subport bandwidth profile as it doesn't have any impact on
> +hiearchical
> + * structure of the scheduler.
> + * @param port
> + *   Handle to port scheduler instance
> + * @param subport_id
> + *   Subport ID
> + * @param profile_d
> + *   Subport profile id
> + * @return
> + *   0 upon success, error code otherwise
> + */
> +__rte_experimental
> +int
> +rte_sched_subport_profile_config(struct rte_sched_port *port,
> +	uint32_t subport_id,
> +	uint32_t profile_id);
> +/**
>   * Hierarchical scheduler pipe configuration
>   *
>   * @param port
> diff --git a/lib/librte_sched/rte_sched_version.map
> b/lib/librte_sched/rte_sched_version.map
> index 3faef6f..e64335f 100644
> --- a/lib/librte_sched/rte_sched_version.map
> +++ b/lib/librte_sched/rte_sched_version.map
> @@ -28,4 +28,6 @@ EXPERIMENTAL {
>  	global:
> 
>  	rte_sched_subport_pipe_profile_add;
> +	rte_sched_port_subport_profile_add;
> +	rte_sched_subport_profile_config;
>  };
> --
> 2.7.4


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

* Re: [dpdk-dev] [PATCH v2 05/10] sched: update the pipe config api implementation
  2020-09-10 18:48       ` [dpdk-dev] [PATCH v2 05/10] sched: update the pipe config api implementation Savinay Dharmappa
@ 2020-09-14 14:26         ` Singh, Jasvinder
  0 siblings, 0 replies; 107+ messages in thread
From: Singh, Jasvinder @ 2020-09-14 14:26 UTC (permalink / raw)
  To: Dharmappa, Savinay, Dumitrescu, Cristian, dev



> -----Original Message-----
> From: Dharmappa, Savinay <savinay.dharmappa@intel.com>
> Sent: Thursday, September 10, 2020 7:49 PM
> To: Singh, Jasvinder <jasvinder.singh@intel.com>; Dumitrescu, Cristian
> <cristian.dumitrescu@intel.com>; dev@dpdk.org
> Cc: Dharmappa, Savinay <savinay.dharmappa@intel.com>
> Subject: [PATCH v2 05/10] sched: update the pipe config api implementation
> 
> Subport profile parameters are fetched from subport profile table to
> calculate the subport best effort tc rate.
> 
> Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
> Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> ---
>  lib/librte_sched/rte_sched.c | 40 +++++++++++++++++++++-------------------
>  1 file changed, 21 insertions(+), 19 deletions(-)
> 
> diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c index
> 8e66d08..9ff67e0 100644
> --- a/lib/librte_sched/rte_sched.c
> +++ b/lib/librte_sched/rte_sched.c
> @@ -1403,6 +1403,7 @@ rte_sched_pipe_config(struct rte_sched_port
> *port,
>  	int32_t pipe_profile)
>  {
>  	struct rte_sched_subport *s;
> +	struct rte_sched_subport_profile *sp;
>  	struct rte_sched_pipe *p;
>  	struct rte_sched_pipe_profile *params;
>  	uint32_t n_subports = subport_id + 1;
> @@ -1443,14 +1444,15 @@ rte_sched_pipe_config(struct rte_sched_port
> *port,
>  		return -EINVAL;
>  	}
> 
> +	sp = port->subport_profiles + s->profile;
>  	/* Handle the case when pipe already has a valid configuration */
>  	p = s->pipe + pipe_id;
>  	if (p->tb_time) {
>  		params = s->pipe_profiles + p->profile;
> 
>  		double subport_tc_be_rate =
> -			(double) s-
> >tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
> -			/ (double) s->tc_period;
> +		(double)sp-
> >tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
> +			/ (double) sp->tc_period;
>  		double pipe_tc_be_rate =
>  			(double) params-
> >tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
>  			/ (double) params->tc_period;
> @@ -1492,8 +1494,8 @@ rte_sched_pipe_config(struct rte_sched_port
> *port,
>  	{
>  		/* Subport best effort tc oversubscription */
>  		double subport_tc_be_rate =
> -			(double) s-
> >tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
> -			/ (double) s->tc_period;
> +		(double)sp-
> >tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
> +			/ (double) sp->tc_period;
>  		double pipe_tc_be_rate =
>  			(double) params-
> >tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
>  			/ (double) params->tc_period;
> @@ -2286,11 +2288,11 @@ grinder_credits_update(struct rte_sched_port
> *port,
>  	uint32_t i;
> 
>  	/* Subport TB */
> -	n_periods = (port->time - subport->tb_time) / sp_params-
> >sp_tb_period;
> -	subport->tb_credits += n_periods * sp_params-
> >sp_tb_credits_per_period;
> +	n_periods = (port->time - subport->tb_time) / sp_params-
> >tb_period;
> +	subport->tb_credits += n_periods * sp_params-
> >tb_credits_per_period;
>  	subport->tb_credits = RTE_MIN(subport->tb_credits,
> -				sp_params->sp_tb_size);
> -	subport->tb_time += n_periods * sp_params->sp_tb_period;
> +				sp_params->tb_size);
> +	subport->tb_time += n_periods * sp_params->tb_period;
> 
>  	/* Pipe TB */
>  	n_periods = (port->time - pipe->tb_time) / params->tb_period; @@ -
> 2302,9 +2304,9 @@ grinder_credits_update(struct rte_sched_port *port,
>  	if (unlikely(port->time >= subport->tc_time)) {
>  		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
>  			subport->tc_credits[i] =
> -					sp_params-
> >sp_tc_credits_per_period[i];
> +					sp_params->tc_credits_per_period[i];
> 
> -		subport->tc_time = port->time + sp_params->sp_tc_period;
> +		subport->tc_time = port->time + sp_params->tc_period;
>  	}
> 
>  	/* Pipe TCs */
> @@ -2333,17 +2335,17 @@ grinder_tc_ov_credits_update(struct
> rte_sched_port *port,
>  		return subport->tc_ov_wm_max;
> 
>  	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASS_BE; i++) {
> -		tc_ov_consumption[i] = sp_params-
> >sp_tc_credits_per_period[i]
> +		tc_ov_consumption[i] = sp_params->tc_credits_per_period[i]
>  					-  subport->tc_credits[i];
>  		tc_consumption += tc_ov_consumption[i];
>  	}
> 
>  	tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] =
> -	sp_params-
> >sp_tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
> +	sp_params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
> -
>  		subport->tc_credits[RTE_SCHED_TRAFFIC_CLASS_BE];
> 
>  	tc_ov_consumption_max =
> -	sp_params-
> >sp_tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
> +	sp_params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
> -
>  			tc_consumption;
> 
>  	if (tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] > @@ -
> 2374,11 +2376,11 @@ grinder_credits_update(struct rte_sched_port *port,
>  	uint32_t i;
> 
>  	/* Subport TB */
> -	n_periods = (port->time - subport->tb_time) / sp_params-
> >sp_tb_period;
> -	subport->tb_credits += n_periods * sp_params-
> >sp_tb_credits_per_period;
> +	n_periods = (port->time - subport->tb_time) / sp_params-
> >tb_period;
> +	subport->tb_credits += n_periods * sp_params-
> >tb_credits_per_period;
>  	subport->tb_credits = RTE_MIN(subport->tb_credits,
> -				sp_params->sp_tb_size);
> -	subport->tb_time += n_periods * sp_params->sp_tb_period;
> +				sp_params->tb_size);
> +	subport->tb_time += n_periods * sp_params->tb_period;
> 
>  	/* Pipe TB */
>  	n_periods = (port->time - pipe->tb_time) / params->tb_period; @@ -
> 2393,9 +2395,9 @@ grinder_credits_update(struct rte_sched_port *port,
> 
>  		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
>  			subport->tc_credits[i] =
> -				sp_params->sp_tc_credits_per_period[i];
> +				sp_params->tc_credits_per_period[i];
> 
> -		subport->tc_time = port->time + sp_params->sp_tc_period;
> +		subport->tc_time = port->time + sp_params->tc_period;
>  		subport->tc_ov_period_id++;
>  	}
> 
> --
> 2.7.4

Looks like the above changes have already been done in the last patch of this series. Please check.

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

* [dpdk-dev] [PATCH v3 0/9] Enable dynamic config of subport bandwidth
  2020-09-10 18:48     ` [dpdk-dev] [PATCH v2 00/10] Enable dynamic config of subport bandwidth Savinay Dharmappa
                         ` (9 preceding siblings ...)
  2020-09-10 18:48       ` [dpdk-dev] [PATCH v2 10/10] sched: remove the redundant code Savinay Dharmappa
@ 2020-09-16 16:43       ` Savinay Dharmappa
  2020-09-16 16:43         ` [dpdk-dev] [PATCH v3 1/9] sched: add support profile data structure Savinay Dharmappa
                           ` (9 more replies)
  10 siblings, 10 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-16 16:43 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

DPDK sched library allows runtime configuration of the pipe profiles to the
pipes of the subport once scheduler hierarchy is constructed. However, to
change the subport level bandwidth, existing hierarchy needs to be
dismantled and whole process of building hierarchy under subport nodes
needs to be repeated which might result in router downtime. Furthermore,
due to lack of dynamic configuration of the subport bandwidth profile
configuration (shaper and Traffic class rates), the user application
is unable to dynamically re-distribute the excess-bandwidth of one subport
among other subports in the scheduler hierarchy. Therefore, it is also not
possible to adjust the subport bandwidth profile in sync with dynamic
changes in pipe profiles of subscribers who want to consume higher
bandwidth opportunistically.

This patch series implements dynamic configuration of the subport bandwidth
profile to overcome the runtime situation when group of subscribers are not
using the allotted bandwidth and dynamic bandwidth re-distribution is
needed the without making any structural changes in the hierarchy.

The implementation work includes refactoring the existing data structures
defined for port and subport level, new APIs for adding subport level
bandwidth profiles that can be used in runtime.

Savinay Dharmappa (9):
  sched: add support profile data structure
  sched: add subport profile table
  sched: add subport profile add and config api
  sched: update grinder credit and pipe config function
  example/qos_sched: add dynamic config of subport
  example/ip_pipeline: add dynamic config of subport
  drivers/softnic: add dynamic config of subport
  app/test_sched: add dynamic config of subport
  sched: remove the redundant code

 app/test/test_sched.c                           |  18 +-
 doc/guides/rel_notes/deprecation.rst            |   6 -
 doc/guides/rel_notes/release_20_11.rst          |   4 +
 drivers/net/softnic/rte_eth_softnic_internals.h |   9 +
 drivers/net/softnic/rte_eth_softnic_tm.c        | 223 ++++++++---
 examples/ip_pipeline/cli.c                      |  14 +-
 examples/ip_pipeline/tmgr.c                     |  26 +-
 examples/ip_pipeline/tmgr.h                     |   3 +-
 examples/qos_sched/cfg_file.c                   | 151 ++++----
 examples/qos_sched/cfg_file.h                   |   4 +
 examples/qos_sched/init.c                       |  24 +-
 examples/qos_sched/main.h                       |   1 +
 examples/qos_sched/profile.cfg                  |   3 +
 lib/librte_sched/rte_sched.c                    | 479 +++++++++++++++++-------
 lib/librte_sched/rte_sched.h                    |  82 +++-
 lib/librte_sched/rte_sched_version.map          |   2 +
 16 files changed, 771 insertions(+), 278 deletions(-)

-- 
2.7.4


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

* [dpdk-dev] [PATCH v3 1/9] sched: add support profile data structure
  2020-09-16 16:43       ` [dpdk-dev] [PATCH v3 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
@ 2020-09-16 16:43         ` Savinay Dharmappa
  2020-09-16 16:43         ` [dpdk-dev] [PATCH v3 2/9] sched: add subport profile table Savinay Dharmappa
                           ` (8 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-16 16:43 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Add subport profile data structure to support dynamic configuration
of subport bandwidth

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c | 10 ++++++++++
 lib/librte_sched/rte_sched.h | 25 +++++++++++++++++++++++++
 2 files changed, 35 insertions(+)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index 0fa0741..dc5beb2 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -101,6 +101,16 @@ enum grinder_state {
 	e_GRINDER_READ_MBUF
 };
 
+struct rte_sched_subport_profile {
+	/* Token bucket (TB) */
+	uint64_t tb_period;
+	uint64_t tb_credits_per_period;
+	uint64_t tb_size;
+
+	uint64_t tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+	uint64_t tc_period;
+};
+
 struct rte_sched_grinder {
 	/* Pipe cache */
 	uint16_t pcache_qmask[RTE_SCHED_GRINDER_PCACHE_SIZE];
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index 8a5a93c..39339b7 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -192,6 +192,20 @@ struct rte_sched_subport_params {
 #endif
 };
 
+struct rte_sched_subport_profile_params {
+	/** Token bucket rate (measured in bytes per second) */
+	uint64_t tb_rate;
+
+	/** Token bucket size (measured in credits) */
+	uint64_t tb_size;
+
+	/** Traffic class rates (measured in bytes per second) */
+	uint64_t tc_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+
+	/** Enforcement period for rates (measured in milliseconds) */
+	uint64_t tc_period;
+};
+
 /** Subport statistics */
 struct rte_sched_subport_stats {
 	/** Number of packets successfully written */
@@ -254,6 +268,17 @@ struct rte_sched_port_params {
 	/** Number of subports */
 	uint32_t n_subports_per_port;
 
+	/** subport profile table.
+	 * Every pipe is configured using one of the profiles from this table.
+	 */
+	struct rte_sched_subport_profile_params *subport_profiles;
+
+	/** Profiles in the pipe profile table */
+	uint32_t n_subport_profiles;
+
+	/** Max allowed profiles in the pipe profile table */
+	uint32_t n_max_subport_profiles;
+
 	/** Maximum number of subport pipes.
 	 * This parameter is used to reserve a fixed number of bits
 	 * in struct rte_mbuf::sched.queue_id for the pipe_id for all
-- 
2.7.4


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

* [dpdk-dev] [PATCH v3 2/9] sched: add subport profile table
  2020-09-16 16:43       ` [dpdk-dev] [PATCH v3 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
  2020-09-16 16:43         ` [dpdk-dev] [PATCH v3 1/9] sched: add support profile data structure Savinay Dharmappa
@ 2020-09-16 16:43         ` Savinay Dharmappa
  2020-09-16 16:43         ` [dpdk-dev] [PATCH v3 3/9] sched: add subport profile add and config api Savinay Dharmappa
                           ` (7 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-16 16:43 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Add subport profile table to internal port data structure and
update the port config function.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c | 185 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 182 insertions(+), 3 deletions(-)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index dc5beb2..5fa7865 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -222,6 +222,8 @@ struct rte_sched_port {
 	uint16_t pipe_queue[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
 	uint8_t pipe_tc[RTE_SCHED_QUEUES_PER_PIPE];
 	uint8_t tc_queue[RTE_SCHED_QUEUES_PER_PIPE];
+	uint32_t n_subport_profiles;
+	uint32_t n_max_subport_profiles;
 	uint64_t rate;
 	uint32_t mtu;
 	uint32_t frame_overhead;
@@ -240,6 +242,7 @@ struct rte_sched_port {
 	uint32_t subport_id;
 
 	/* Large data structures */
+	struct rte_sched_subport_profile *subport_profiles;
 	struct rte_sched_subport *subports[0] __rte_cache_aligned;
 } __rte_cache_aligned;
 
@@ -386,8 +389,60 @@ pipe_profile_check(struct rte_sched_pipe_params *params,
 }
 
 static int
+subport_profile_check(struct rte_sched_subport_profile_params *params,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	/* Check user parameters */
+	if (params == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter params\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tb_rate == 0 || params->tb_rate > rate) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for tb rate\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tb_size == 0) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for tb size\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
+		uint64_t tc_rate = params->tc_rate[i];
+
+		if (tc_rate == 0 || (tc_rate > params->tb_rate)) {
+			RTE_LOG(ERR, SCHED, "%s: "
+			"Incorrect value for tc rate\n", __func__);
+			return -EINVAL;
+		}
+	}
+
+	if (params->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect tc rate(best effort)\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tc_period == 0) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for tc period\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
 rte_sched_port_check_params(struct rte_sched_port_params *params)
 {
+	uint32_t i;
+
 	if (params == NULL) {
 		RTE_LOG(ERR, SCHED,
 			"%s: Incorrect value for parameter params\n", __func__);
@@ -424,6 +479,29 @@ rte_sched_port_check_params(struct rte_sched_port_params *params)
 		return -EINVAL;
 	}
 
+	if (params->subport_profiles == NULL ||
+		params->n_subport_profiles == 0 ||
+		params->n_max_subport_profiles == 0 ||
+		params->n_subport_profiles > params->n_max_subport_profiles) {
+		RTE_LOG(ERR, SCHED,
+		"%s: Incorrect value for subport profiles\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < params->n_subport_profiles; i++) {
+		struct rte_sched_subport_profile_params *p =
+						params->subport_profiles + i;
+		int status;
+
+		status = subport_profile_check(p, params->rate);
+		if (status != 0) {
+			RTE_LOG(ERR, SCHED,
+			"%s: subport profile check failed(%d)\n",
+			__func__, status);
+			return -EINVAL;
+		}
+	}
+
 	/* n_pipes_per_subport: non-zero, power of 2 */
 	if (params->n_pipes_per_subport == 0 ||
 	    !rte_is_power_of_2(params->n_pipes_per_subport)) {
@@ -565,6 +643,42 @@ rte_sched_port_log_pipe_profile(struct rte_sched_subport *subport, uint32_t i)
 		p->wrr_cost[0], p->wrr_cost[1], p->wrr_cost[2], p->wrr_cost[3]);
 }
 
+static void
+rte_sched_port_log_subport_profile(struct rte_sched_port *port, uint32_t i)
+{
+	struct rte_sched_subport_profile *p = port->subport_profiles + i;
+
+	RTE_LOG(DEBUG, SCHED, "Low level config for subport profile %u:\n"
+	"Token bucket: period = %"PRIu64", credits per period = %"PRIu64","
+	"size = %"PRIu64"\n"
+	"Traffic classes: period = %"PRIu64",\n"
+	"credits per period = [%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
+	" %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
+	" %"PRIu64", %"PRIu64", %"PRIu64"]\n",
+	i,
+
+	/* Token bucket */
+	p->tb_period,
+	p->tb_credits_per_period,
+	p->tb_size,
+
+	/* Traffic classes */
+	p->tc_period,
+	p->tc_credits_per_period[0],
+	p->tc_credits_per_period[1],
+	p->tc_credits_per_period[2],
+	p->tc_credits_per_period[3],
+	p->tc_credits_per_period[4],
+	p->tc_credits_per_period[5],
+	p->tc_credits_per_period[6],
+	p->tc_credits_per_period[7],
+	p->tc_credits_per_period[8],
+	p->tc_credits_per_period[9],
+	p->tc_credits_per_period[10],
+	p->tc_credits_per_period[11],
+	p->tc_credits_per_period[12]);
+}
+
 static inline uint64_t
 rte_sched_time_ms_to_bytes(uint64_t time_ms, uint64_t rate)
 {
@@ -634,6 +748,37 @@ rte_sched_pipe_profile_convert(struct rte_sched_subport *subport,
 }
 
 static void
+rte_sched_subport_profile_convert(struct rte_sched_subport_profile_params *src,
+	struct rte_sched_subport_profile *dst,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	/* Token Bucket */
+	if (src->tb_rate == rate) {
+		dst->tb_credits_per_period = 1;
+		dst->tb_period = 1;
+	} else {
+		double tb_rate = (double) src->tb_rate
+				/ (double) rate;
+		double d = RTE_SCHED_TB_RATE_CONFIG_ERR;
+
+		rte_approx_64(tb_rate, d, &dst->tb_credits_per_period,
+			&dst->tb_period);
+	}
+
+	dst->tb_size = src->tb_size;
+
+	/* Traffic Classes */
+	dst->tc_period = rte_sched_time_ms_to_bytes(src->tc_period, rate);
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		dst->tc_credits_per_period[i]
+			= rte_sched_time_ms_to_bytes(src->tc_period,
+				src->tc_rate[i]);
+}
+
+static void
 rte_sched_subport_config_pipe_profile_table(struct rte_sched_subport *subport,
 	struct rte_sched_subport_params *params, uint64_t rate)
 {
@@ -657,6 +802,24 @@ rte_sched_subport_config_pipe_profile_table(struct rte_sched_subport *subport,
 	}
 }
 
+static void
+rte_sched_port_config_subport_profile_table(struct rte_sched_port *port,
+	struct rte_sched_port_params *params,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	for (i = 0; i < port->n_subport_profiles; i++) {
+		struct rte_sched_subport_profile_params *src
+				= params->subport_profiles + i;
+		struct rte_sched_subport_profile *dst
+				= port->subport_profiles + i;
+
+		rte_sched_subport_profile_convert(src, dst, rate);
+		rte_sched_port_log_subport_profile(port, i);
+	}
+}
+
 static int
 rte_sched_subport_check_params(struct rte_sched_subport_params *params,
 	uint32_t n_max_pipes_per_subport,
@@ -803,7 +966,7 @@ struct rte_sched_port *
 rte_sched_port_config(struct rte_sched_port_params *params)
 {
 	struct rte_sched_port *port = NULL;
-	uint32_t size0, size1;
+	uint32_t size0, size1, size2;
 	uint32_t cycles_per_byte;
 	uint32_t i, j;
 	int status;
@@ -818,10 +981,21 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 
 	size0 = sizeof(struct rte_sched_port);
 	size1 = params->n_subports_per_port * sizeof(struct rte_sched_subport *);
+	size2 = params->n_max_subport_profiles *
+		sizeof(struct rte_sched_subport_profile);
 
 	/* Allocate memory to store the data structures */
-	port = rte_zmalloc_socket("qos_params", size0 + size1, RTE_CACHE_LINE_SIZE,
-		params->socket);
+	port = rte_zmalloc_socket("qos_params", size0 + size1,
+				 RTE_CACHE_LINE_SIZE, params->socket);
+	if (port == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: Memory allocation fails\n", __func__);
+
+		return NULL;
+	}
+
+	/* Allocate memory to store the subport profile */
+	port->subport_profiles  = rte_zmalloc_socket("subport_profile", size2,
+					RTE_CACHE_LINE_SIZE, params->socket);
 	if (port == NULL) {
 		RTE_LOG(ERR, SCHED, "%s: Memory allocation fails\n", __func__);
 
@@ -830,6 +1004,8 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 
 	/* User parameters */
 	port->n_subports_per_port = params->n_subports_per_port;
+	port->n_subport_profiles = params->n_subport_profiles;
+	port->n_max_subport_profiles = params->n_max_subport_profiles;
 	port->n_pipes_per_subport = params->n_pipes_per_subport;
 	port->n_pipes_per_subport_log2 =
 			__builtin_ctz(params->n_pipes_per_subport);
@@ -860,6 +1036,9 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 	port->time_cpu_bytes = 0;
 	port->time = 0;
 
+	/* Subport profile table */
+	rte_sched_port_config_subport_profile_table(port, params, port->rate);
+
 	cycles_per_byte = (rte_get_tsc_hz() << RTE_SCHED_TIME_SHIFT)
 		/ params->rate;
 	port->inv_cycles_per_byte = rte_reciprocal_value(cycles_per_byte);
-- 
2.7.4


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

* [dpdk-dev] [PATCH v3 3/9] sched: add subport profile add and config api
  2020-09-16 16:43       ` [dpdk-dev] [PATCH v3 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
  2020-09-16 16:43         ` [dpdk-dev] [PATCH v3 1/9] sched: add support profile data structure Savinay Dharmappa
  2020-09-16 16:43         ` [dpdk-dev] [PATCH v3 2/9] sched: add subport profile table Savinay Dharmappa
@ 2020-09-16 16:43         ` Savinay Dharmappa
  2020-09-16 16:43         ` [dpdk-dev] [PATCH v3 4/9] sched: update grinder credit and pipe config function Savinay Dharmappa
                           ` (6 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-16 16:43 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Add apis to add new subport profile and configure it.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c           | 118 +++++++++++++++++++++++++++++++++
 lib/librte_sched/rte_sched.h           |  45 +++++++++++++
 lib/librte_sched/rte_sched_version.map |   2 +
 3 files changed, 165 insertions(+)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index 5fa7865..23aaec4 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -174,6 +174,8 @@ struct rte_sched_subport {
 	/* Statistics */
 	struct rte_sched_subport_stats stats __rte_cache_aligned;
 
+	/* subport profile */
+	uint32_t profile;
 	/* Subport pipes */
 	uint32_t n_pipes_per_subport_enabled;
 	uint32_t n_pipe_profiles;
@@ -1343,6 +1345,56 @@ rte_sched_subport_config(struct rte_sched_port *port,
 }
 
 int
+rte_sched_subport_profile_config(struct rte_sched_port *port,
+	uint32_t subport_id,
+	uint32_t profile_id)
+{
+	int i;
+	struct rte_sched_subport_profile *params;
+	uint32_t n_subports = subport_id + 1;
+	struct rte_sched_subport *s;
+
+	if (port == NULL) {
+		RTE_LOG(ERR, SCHED,
+			"%s: Incorrect value for parameter port\n", __func__);
+		return -EINVAL;
+	}
+
+	if (subport_id >= port->n_subports_per_port) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter subport id\n", __func__);
+
+		rte_sched_free_memory(port, n_subports);
+		return -EINVAL;
+	}
+
+	params =  port->subport_profiles + profile_id;
+
+	s = port->subports[subport_id];
+
+	s->tb_credits = params->tb_size / 2;
+
+	s->tc_time = port->time + params->tc_period;
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		if (s->qsize[i])
+			s->tc_credits[i] =
+				params->tc_credits_per_period[i];
+		else
+			params->tc_credits_per_period[i] = 0;
+
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+	s->tc_ov_wm_max = rte_sched_time_ms_to_bytes(params->tc_period,
+						     s->pipe_tc_be_rate_max);
+#endif
+	s->profile = profile_id;
+
+	rte_sched_port_log_subport_profile(port, profile_id);
+
+	return 0;
+}
+
+int
 rte_sched_pipe_config(struct rte_sched_port *port,
 	uint32_t subport_id,
 	uint32_t pipe_id,
@@ -1526,6 +1578,72 @@ rte_sched_subport_pipe_profile_add(struct rte_sched_port *port,
 	return 0;
 }
 
+int
+rte_sched_port_subport_profile_add(struct rte_sched_port *port,
+	struct rte_sched_subport_profile_params *params,
+	uint32_t *subport_profile_id)
+{
+	int status;
+	uint32_t i;
+	struct rte_sched_subport_profile *dst;
+
+	/* Port */
+	if (port == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter port\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter profile\n", __func__);
+		return -EINVAL;
+	}
+
+	if (subport_profile_id == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter subport_profile_id\n",
+		__func__);
+		return -EINVAL;
+	}
+
+	dst = port->subport_profiles + port->n_subport_profiles;
+
+	/* Subport profiles exceeds the max limit */
+	if (port->n_subport_profiles >= port->n_max_subport_profiles) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Number of subport profiles exceeds the max limit\n",
+		 __func__);
+		return -EINVAL;
+	}
+
+	status = subport_profile_check(params, port->rate);
+	if (status != 0) {
+		RTE_LOG(ERR, SCHED,
+		"%s: subport profile check failed(%d)\n", __func__, status);
+		return -EINVAL;
+	}
+
+	rte_sched_subport_profile_convert(params, dst, port->rate);
+
+	/* Subport profile should not exists */
+	for (i = 0; i < port->n_subport_profiles; i++)
+		if (memcmp(port->subport_profiles + i,
+		    dst, sizeof(*dst)) == 0) {
+			RTE_LOG(ERR, SCHED,
+			"%s: subport profile exists\n", __func__);
+			return -EINVAL;
+		}
+
+	/* Subport profile commit */
+	*subport_profile_id = port->n_subport_profiles;
+	port->n_subport_profiles++;
+
+	rte_sched_port_log_subport_profile(port, *subport_profile_id);
+
+	return 0;
+}
+
 static inline uint32_t
 rte_sched_port_qindex(struct rte_sched_port *port,
 	uint32_t subport,
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index 39339b7..a7c2638 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -337,6 +337,29 @@ rte_sched_subport_pipe_profile_add(struct rte_sched_port *port,
 	uint32_t *pipe_profile_id);
 
 /**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Hierarchical scheduler subport bandwidth profile add
+ * Note that this function is safe to use in runtime for adding new
+ * subport bandwidth profile as it doesn't have any impact on hiearchical
+ * structure of the scheduler.
+ * @param port
+ *   Handle to port scheduler instance
+ * @param struct rte_sched_subport_profile
+ *   Subport bandwidth profile
+ * @param subport_profile_d
+ *   Subport profile id
+ * @return
+ *   0 upon success, error code otherwise
+ */
+__rte_experimental
+int
+rte_sched_port_subport_profile_add(struct rte_sched_port *port,
+	struct rte_sched_subport_profile_params *profile,
+	uint32_t *subport_profile_id);
+
+/**
  * Hierarchical scheduler subport configuration
  *
  * @param port
@@ -354,6 +377,28 @@ rte_sched_subport_config(struct rte_sched_port *port,
 	struct rte_sched_subport_params *params);
 
 /**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Hierarchical scheduler subport profile configuration
+ * Note that this function is safe to use in runtime for applying any specific
+ * subport bandwidth profile as it doesn't have any impact on hiearchical
+ * structure of the scheduler.
+ * @param port
+ *   Handle to port scheduler instance
+ * @param subport_id
+ *   Subport ID
+ * @param profile_d
+ *   Subport profile id
+ * @return
+ *   0 upon success, error code otherwise
+ */
+__rte_experimental
+int
+rte_sched_subport_profile_config(struct rte_sched_port *port,
+	uint32_t subport_id,
+	uint32_t profile_id);
+/**
  * Hierarchical scheduler pipe configuration
  *
  * @param port
diff --git a/lib/librte_sched/rte_sched_version.map b/lib/librte_sched/rte_sched_version.map
index 3faef6f..e64335f 100644
--- a/lib/librte_sched/rte_sched_version.map
+++ b/lib/librte_sched/rte_sched_version.map
@@ -28,4 +28,6 @@ EXPERIMENTAL {
 	global:
 
 	rte_sched_subport_pipe_profile_add;
+	rte_sched_port_subport_profile_add;
+	rte_sched_subport_profile_config;
 };
-- 
2.7.4


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

* [dpdk-dev] [PATCH v3 4/9] sched: update grinder credit and pipe config function
  2020-09-16 16:43       ` [dpdk-dev] [PATCH v3 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
                           ` (2 preceding siblings ...)
  2020-09-16 16:43         ` [dpdk-dev] [PATCH v3 3/9] sched: add subport profile add and config api Savinay Dharmappa
@ 2020-09-16 16:43         ` Savinay Dharmappa
  2020-09-16 16:43         ` [dpdk-dev] [PATCH v3 5/9] example/qos_sched: add dynamic config of subport Savinay Dharmappa
                           ` (5 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-16 16:43 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Credits are updated by fetching subport profile parameters from
subport profile table. Similarly subport best effort tc is
calculated in pipe config.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c | 55 ++++++++++++++++++++++++++------------------
 1 file changed, 33 insertions(+), 22 deletions(-)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index 23aaec4..3f61afa 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -123,6 +123,7 @@ struct rte_sched_grinder {
 	uint32_t productive;
 	uint32_t pindex;
 	struct rte_sched_subport *subport;
+	struct rte_sched_subport_profile *subport_params;
 	struct rte_sched_pipe *pipe;
 	struct rte_sched_pipe_profile *pipe_params;
 
@@ -1401,6 +1402,7 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 	int32_t pipe_profile)
 {
 	struct rte_sched_subport *s;
+	struct rte_sched_subport_profile *sp;
 	struct rte_sched_pipe *p;
 	struct rte_sched_pipe_profile *params;
 	uint32_t n_subports = subport_id + 1;
@@ -1441,14 +1443,15 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 		return -EINVAL;
 	}
 
+	sp = port->subport_profiles + s->profile;
 	/* Handle the case when pipe already has a valid configuration */
 	p = s->pipe + pipe_id;
 	if (p->tb_time) {
 		params = s->pipe_profiles + p->profile;
 
 		double subport_tc_be_rate =
-			(double) s->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
-			/ (double) s->tc_period;
+		(double)sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
+			/ (double) sp->tc_period;
 		double pipe_tc_be_rate =
 			(double) params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
 			/ (double) params->tc_period;
@@ -1490,8 +1493,8 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 	{
 		/* Subport best effort tc oversubscription */
 		double subport_tc_be_rate =
-			(double) s->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
-			/ (double) s->tc_period;
+		(double)sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
+			/ (double) sp->tc_period;
 		double pipe_tc_be_rate =
 			(double) params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
 			/ (double) params->tc_period;
@@ -2279,14 +2282,15 @@ grinder_credits_update(struct rte_sched_port *port,
 	struct rte_sched_grinder *grinder = subport->grinder + pos;
 	struct rte_sched_pipe *pipe = grinder->pipe;
 	struct rte_sched_pipe_profile *params = grinder->pipe_params;
+	struct rte_sched_subport_profile *sp = grinder->subport_params;
 	uint64_t n_periods;
 	uint32_t i;
 
 	/* Subport TB */
-	n_periods = (port->time - subport->tb_time) / subport->tb_period;
-	subport->tb_credits += n_periods * subport->tb_credits_per_period;
-	subport->tb_credits = RTE_MIN(subport->tb_credits, subport->tb_size);
-	subport->tb_time += n_periods * subport->tb_period;
+	n_periods = (port->time - subport->tb_time) / sp->tb_period;
+	subport->tb_credits += n_periods * sp->tb_credits_per_period;
+	subport->tb_credits = RTE_MIN(subport->tb_credits, sp->tb_size);
+	subport->tb_time += n_periods * sp->tb_period;
 
 	/* Pipe TB */
 	n_periods = (port->time - pipe->tb_time) / params->tb_period;
@@ -2297,9 +2301,9 @@ grinder_credits_update(struct rte_sched_port *port,
 	/* Subport TCs */
 	if (unlikely(port->time >= subport->tc_time)) {
 		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-			subport->tc_credits[i] = subport->tc_credits_per_period[i];
+			subport->tc_credits[i] = sp->tc_credits_per_period[i];
 
-		subport->tc_time = port->time + subport->tc_period;
+		subport->tc_time = port->time + sp->tc_period;
 	}
 
 	/* Pipe TCs */
@@ -2315,8 +2319,10 @@ grinder_credits_update(struct rte_sched_port *port,
 
 static inline uint64_t
 grinder_tc_ov_credits_update(struct rte_sched_port *port,
-	struct rte_sched_subport *subport)
+	struct rte_sched_subport *subport, uint32_t pos)
 {
+	struct rte_sched_grinder *grinder = subport->grinder + pos;
+	struct rte_sched_subport_profile *sp = grinder->subport_params;
 	uint64_t tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
 	uint64_t tc_consumption = 0, tc_ov_consumption_max;
 	uint64_t tc_ov_wm = subport->tc_ov_wm;
@@ -2326,17 +2332,17 @@ grinder_tc_ov_credits_update(struct rte_sched_port *port,
 		return subport->tc_ov_wm_max;
 
 	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASS_BE; i++) {
-		tc_ov_consumption[i] =
-			subport->tc_credits_per_period[i] - subport->tc_credits[i];
+		tc_ov_consumption[i] = sp->tc_credits_per_period[i]
+					-  subport->tc_credits[i];
 		tc_consumption += tc_ov_consumption[i];
 	}
 
 	tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] =
-		subport->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
+	sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
 		subport->tc_credits[RTE_SCHED_TRAFFIC_CLASS_BE];
 
 	tc_ov_consumption_max =
-		subport->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
+	sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
 			tc_consumption;
 
 	if (tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] >
@@ -2362,14 +2368,15 @@ grinder_credits_update(struct rte_sched_port *port,
 	struct rte_sched_grinder *grinder = subport->grinder + pos;
 	struct rte_sched_pipe *pipe = grinder->pipe;
 	struct rte_sched_pipe_profile *params = grinder->pipe_params;
+	struct rte_sched_subport_profile *sp = grinder->subport_params;
 	uint64_t n_periods;
 	uint32_t i;
 
 	/* Subport TB */
-	n_periods = (port->time - subport->tb_time) / subport->tb_period;
-	subport->tb_credits += n_periods * subport->tb_credits_per_period;
-	subport->tb_credits = RTE_MIN(subport->tb_credits, subport->tb_size);
-	subport->tb_time += n_periods * subport->tb_period;
+	n_periods = (port->time - subport->tb_time) / sp->tb_period;
+	subport->tb_credits += n_periods * sp->tb_credits_per_period;
+	subport->tb_credits = RTE_MIN(subport->tb_credits, sp->tb_size);
+	subport->tb_time += n_periods * sp->tb_period;
 
 	/* Pipe TB */
 	n_periods = (port->time - pipe->tb_time) / params->tb_period;
@@ -2379,12 +2386,13 @@ grinder_credits_update(struct rte_sched_port *port,
 
 	/* Subport TCs */
 	if (unlikely(port->time >= subport->tc_time)) {
-		subport->tc_ov_wm = grinder_tc_ov_credits_update(port, subport);
+		subport->tc_ov_wm =
+			grinder_tc_ov_credits_update(port, subport, pos);
 
 		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-			subport->tc_credits[i] = subport->tc_credits_per_period[i];
+			subport->tc_credits[i] = sp->tc_credits_per_period[i];
 
-		subport->tc_time = port->time + subport->tc_period;
+		subport->tc_time = port->time + sp->tc_period;
 		subport->tc_ov_period_id++;
 	}
 
@@ -2907,6 +2915,9 @@ grinder_handle(struct rte_sched_port *port,
 		struct rte_sched_pipe *pipe = grinder->pipe;
 
 		grinder->pipe_params = subport->pipe_profiles + pipe->profile;
+		grinder->subport_params = port->subport_profiles +
+						subport->profile;
+
 		grinder_prefetch_tc_queue_arrays(subport, pos);
 		grinder_credits_update(port, subport, pos);
 
-- 
2.7.4


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

* [dpdk-dev] [PATCH v3 5/9] example/qos_sched: add dynamic config of subport
  2020-09-16 16:43       ` [dpdk-dev] [PATCH v3 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
                           ` (3 preceding siblings ...)
  2020-09-16 16:43         ` [dpdk-dev] [PATCH v3 4/9] sched: update grinder credit and pipe config function Savinay Dharmappa
@ 2020-09-16 16:43         ` Savinay Dharmappa
  2020-09-16 16:43         ` [dpdk-dev] [PATCH v3 6/9] example/ip_pipeline: " Savinay Dharmappa
                           ` (4 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-16 16:43 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Modify the qos_sched application to build the hierarchical scheduler
with default subport bandwidth profile. It also allows to configure
a subport with different subport bandwidth profile dynamically.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 examples/qos_sched/cfg_file.c  | 151 ++++++++++++++++++++++++-----------------
 examples/qos_sched/cfg_file.h  |   4 ++
 examples/qos_sched/init.c      |  24 +++++--
 examples/qos_sched/main.h      |   1 +
 examples/qos_sched/profile.cfg |   3 +
 5 files changed, 115 insertions(+), 68 deletions(-)

diff --git a/examples/qos_sched/cfg_file.c b/examples/qos_sched/cfg_file.c
index f078e4f..cd167bd 100644
--- a/examples/qos_sched/cfg_file.c
+++ b/examples/qos_sched/cfg_file.c
@@ -143,6 +143,93 @@ cfg_load_pipe(struct rte_cfgfile *cfg, struct rte_sched_pipe_params *pipe_params
 }
 
 int
+cfg_load_subport_profile(struct rte_cfgfile *cfg,
+	struct rte_sched_subport_profile_params *subport_profile)
+{
+	int i;
+	const char *entry;
+	int profiles;
+
+	if (!cfg || !subport_profile)
+		return -1;
+
+	profiles = rte_cfgfile_num_sections(cfg, "subport profile",
+					   sizeof("subport profile") - 1);
+	subport_params[0].n_pipe_profiles = profiles;
+
+	for (i = 0; i < profiles; i++) {
+		char sec_name[32];
+		snprintf(sec_name, sizeof(sec_name), "subport profile %d", i);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tb rate");
+		if (entry)
+			subport_profile[i].tb_rate = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tb size");
+		if (entry)
+			subport_profile[i].tb_size = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc period");
+		if (entry)
+			subport_profile[i].tc_period = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 0 rate");
+		if (entry)
+			subport_profile[i].tc_rate[0] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 1 rate");
+		if (entry)
+			subport_profile[i].tc_rate[1] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 2 rate");
+		if (entry)
+			subport_profile[i].tc_rate[2] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 3 rate");
+		if (entry)
+			subport_profile[i].tc_rate[3] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 4 rate");
+		if (entry)
+			subport_profile[i].tc_rate[4] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 5 rate");
+		if (entry)
+			subport_profile[i].tc_rate[5] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 6 rate");
+		if (entry)
+			subport_profile[i].tc_rate[6] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 7 rate");
+		if (entry)
+			subport_profile[i].tc_rate[7] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 8 rate");
+		if (entry)
+			subport_profile[i].tc_rate[8] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 9 rate");
+		if (entry)
+			subport_profile[i].tc_rate[9] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 10 rate");
+		if (entry)
+			subport_profile[i].tc_rate[10] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 11 rate");
+		if (entry)
+			subport_profile[i].tc_rate[11] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 12 rate");
+		if (entry)
+			subport_profile[i].tc_rate[12] = (uint64_t)atoi(entry);
+	}
+
+	return 0;
+}
+
+int
 cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subport_params)
 {
 	const char *entry;
@@ -267,70 +354,6 @@ cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subpo
 				}
 			}
 
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tb rate");
-			if (entry)
-				subport_params[i].tb_rate = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tb size");
-			if (entry)
-				subport_params[i].tb_size = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc period");
-			if (entry)
-				subport_params[i].tc_period = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 0 rate");
-			if (entry)
-				subport_params[i].tc_rate[0] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 1 rate");
-			if (entry)
-				subport_params[i].tc_rate[1] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 2 rate");
-			if (entry)
-				subport_params[i].tc_rate[2] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 3 rate");
-			if (entry)
-				subport_params[i].tc_rate[3] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 4 rate");
-			if (entry)
-				subport_params[i].tc_rate[4] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 5 rate");
-			if (entry)
-				subport_params[i].tc_rate[5] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 6 rate");
-			if (entry)
-				subport_params[i].tc_rate[6] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 7 rate");
-			if (entry)
-				subport_params[i].tc_rate[7] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 8 rate");
-			if (entry)
-				subport_params[i].tc_rate[8] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 9 rate");
-			if (entry)
-				subport_params[i].tc_rate[9] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 10 rate");
-			if (entry)
-				subport_params[i].tc_rate[10] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 11 rate");
-			if (entry)
-				subport_params[i].tc_rate[11] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 12 rate");
-			if (entry)
-				subport_params[i].tc_rate[12] = (uint64_t)atoi(entry);
-
 			int n_entries = rte_cfgfile_section_num_entries(cfg, sec_name);
 			struct rte_cfgfile_entry entries[n_entries];
 
diff --git a/examples/qos_sched/cfg_file.h b/examples/qos_sched/cfg_file.h
index 2eccf1c..0dc458a 100644
--- a/examples/qos_sched/cfg_file.h
+++ b/examples/qos_sched/cfg_file.h
@@ -14,4 +14,8 @@ int cfg_load_pipe(struct rte_cfgfile *cfg, struct rte_sched_pipe_params *pipe);
 
 int cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subport);
 
+int cfg_load_subport_profile(struct rte_cfgfile *cfg,
+			     struct rte_sched_subport_profile_params
+			     *subport_profile);
+
 #endif
diff --git a/examples/qos_sched/init.c b/examples/qos_sched/init.c
index 9626c15..541adb7 100644
--- a/examples/qos_sched/init.c
+++ b/examples/qos_sched/init.c
@@ -196,15 +196,20 @@ static struct rte_sched_pipe_params pipe_profiles[MAX_SCHED_PIPE_PROFILES] = {
 	},
 };
 
-struct rte_sched_subport_params subport_params[MAX_SCHED_SUBPORTS] = {
+static struct rte_sched_subport_profile_params
+		subport_profile[MAX_SCHED_SUBPORT_PROFILES] = {
 	{
 		.tb_rate = 1250000000,
 		.tb_size = 1000000,
-
 		.tc_rate = {1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000},
 		.tc_period = 10,
+	},
+};
+
+struct rte_sched_subport_params subport_params[MAX_SCHED_SUBPORTS] = {
+	{
 		.n_pipes_per_subport_enabled = 4096,
 		.qsize = {64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64},
 		.pipe_profiles = pipe_profiles,
@@ -289,6 +294,9 @@ struct rte_sched_port_params port_params = {
 	.mtu = 6 + 6 + 4 + 4 + 2 + 1500,
 	.frame_overhead = RTE_SCHED_FRAME_OVERHEAD_DEFAULT,
 	.n_subports_per_port = 1,
+	.n_subport_profiles = 1,
+	.subport_profiles = subport_profile,
+	.n_max_subport_profiles = MAX_SCHED_SUBPORT_PROFILES,
 	.n_pipes_per_subport = MAX_SCHED_PIPES,
 };
 
@@ -320,8 +328,15 @@ app_init_sched_port(uint32_t portid, uint32_t socketid)
 	for (subport = 0; subport < port_params.n_subports_per_port; subport ++) {
 		err = rte_sched_subport_config(port, subport, &subport_params[subport]);
 		if (err) {
-			rte_exit(EXIT_FAILURE, "Unable to config sched subport %u, err=%d\n",
-					subport, err);
+			rte_exit(EXIT_FAILURE, "Unable to config schedi "
+				"subport %u, err=%d\n", subport, err);
+		}
+
+		err = rte_sched_subport_profile_config(port, subport, 0);
+		if (err) {
+			rte_exit(EXIT_FAILURE, "failed to configure "
+				"profile err=%d\n", err);
+
 		}
 
 		uint32_t n_pipes_per_subport =
@@ -354,6 +369,7 @@ app_load_cfg_profile(const char *profile)
 
 	cfg_load_port(file, &port_params);
 	cfg_load_subport(file, subport_params);
+	cfg_load_subport_profile(file, subport_profile);
 	cfg_load_pipe(file, pipe_profiles);
 
 	rte_cfgfile_close(file);
diff --git a/examples/qos_sched/main.h b/examples/qos_sched/main.h
index 23bc418..0d6815a 100644
--- a/examples/qos_sched/main.h
+++ b/examples/qos_sched/main.h
@@ -51,6 +51,7 @@ extern "C" {
 #define MAX_SCHED_SUBPORTS		8
 #define MAX_SCHED_PIPES		4096
 #define MAX_SCHED_PIPE_PROFILES		256
+#define MAX_SCHED_SUBPORT_PROFILES	8
 
 #ifndef APP_COLLECT_STAT
 #define APP_COLLECT_STAT		1
diff --git a/examples/qos_sched/profile.cfg b/examples/qos_sched/profile.cfg
index 61b8b70..4486d27 100644
--- a/examples/qos_sched/profile.cfg
+++ b/examples/qos_sched/profile.cfg
@@ -26,6 +26,9 @@ number of subports per port = 1
 number of pipes per subport = 4096
 queue sizes = 64 64 64 64 64 64 64 64 64 64 64 64 64
 
+subport 0-8 = 0                ; These subports are configured with subport profile 0
+
+[subport profile 0]
 tb rate = 1250000000           ; Bytes per second
 tb size = 1000000              ; Bytes
 
-- 
2.7.4


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

* [dpdk-dev] [PATCH v3 6/9] example/ip_pipeline: add dynamic config of subport
  2020-09-16 16:43       ` [dpdk-dev] [PATCH v3 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
                           ` (4 preceding siblings ...)
  2020-09-16 16:43         ` [dpdk-dev] [PATCH v3 5/9] example/qos_sched: add dynamic config of subport Savinay Dharmappa
@ 2020-09-16 16:43         ` Savinay Dharmappa
  2020-09-16 16:43         ` [dpdk-dev] [PATCH v3 7/9] drivers/softnic: " Savinay Dharmappa
                           ` (3 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-16 16:43 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Modify the ip_pipeline application to build the hierarchical scheduler
with default subport bandwidth profile. It also allows to configure
a subport with different subport bandwidth profile dynamically

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 examples/ip_pipeline/cli.c  | 14 ++++++++------
 examples/ip_pipeline/tmgr.c | 26 ++++++++++++++++++++++++--
 examples/ip_pipeline/tmgr.h |  3 ++-
 3 files changed, 34 insertions(+), 9 deletions(-)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index d79699e..7eccde3 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -407,6 +407,7 @@ cmd_tmgr_subport_profile(char **tokens,
 	size_t out_size)
 {
 	struct rte_sched_subport_params p;
+	struct rte_sched_subport_profile_params pp;
 	int status, i;
 
 	if (n_tokens != 35) {
@@ -414,23 +415,23 @@ cmd_tmgr_subport_profile(char **tokens,
 		return;
 	}
 
-	if (parser_read_uint64(&p.tb_rate, tokens[3]) != 0) {
+	if (parser_read_uint64(&pp.tb_rate, tokens[3]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
 		return;
 	}
 
-	if (parser_read_uint64(&p.tb_size, tokens[4]) != 0) {
+	if (parser_read_uint64(&pp.tb_size, tokens[4]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
 		return;
 	}
 
 	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-		if (parser_read_uint64(&p.tc_rate[i], tokens[5 + i]) != 0) {
+		if (parser_read_uint64(&pp.tc_rate[i], tokens[5 + i]) != 0) {
 			snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
 			return;
 		}
 
-	if (parser_read_uint64(&p.tc_period, tokens[18]) != 0) {
+	if (parser_read_uint64(&pp.tc_period, tokens[18]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
 		return;
 	}
@@ -440,7 +441,8 @@ cmd_tmgr_subport_profile(char **tokens,
 		return;
 	}
 
-	if (parser_read_uint32(&p.n_pipes_per_subport_enabled, tokens[20]) != 0) {
+	if (parser_read_uint32(&p.n_pipes_per_subport_enabled,
+		tokens[20]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport");
 		return;
 	}
@@ -456,7 +458,7 @@ cmd_tmgr_subport_profile(char **tokens,
 			return;
 		}
 
-	status = tmgr_subport_profile_add(&p);
+	status = tmgr_subport_profile_add(&p, &pp);
 	if (status != 0) {
 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
 		return;
diff --git a/examples/ip_pipeline/tmgr.c b/examples/ip_pipeline/tmgr.c
index 91ccbf6..5c3df92 100644
--- a/examples/ip_pipeline/tmgr.c
+++ b/examples/ip_pipeline/tmgr.c
@@ -11,6 +11,9 @@
 static struct rte_sched_subport_params
 	subport_profile[TMGR_SUBPORT_PROFILE_MAX];
 
+static struct rte_sched_subport_profile_params
+		profile_params[TMGR_SUBPORT_PROFILE_MAX];
+
 static uint32_t n_subport_profiles;
 
 static struct rte_sched_pipe_params
@@ -44,10 +47,11 @@ tmgr_port_find(const char *name)
 }
 
 int
-tmgr_subport_profile_add(struct rte_sched_subport_params *p)
+tmgr_subport_profile_add(struct rte_sched_subport_params *p,
+			 struct rte_sched_subport_profile_params *pp)
 {
 	/* Check input params */
-	if (p == NULL ||
+	if (p == NULL || pp == NULL ||
 		p->n_pipes_per_subport_enabled == 0)
 		return -1;
 
@@ -56,6 +60,10 @@ tmgr_subport_profile_add(struct rte_sched_subport_params *p)
 		p,
 		sizeof(*p));
 
+	memcpy(&profile_params[n_subport_profiles],
+		pp,
+		sizeof(*pp));
+
 	n_subport_profiles++;
 
 	return 0;
@@ -103,6 +111,9 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 	p.mtu = params->mtu;
 	p.frame_overhead = params->frame_overhead;
 	p.n_subports_per_port = params->n_subports_per_port;
+	p.n_subport_profiles = n_subport_profiles;
+	p.subport_profiles = profile_params;
+	p.n_max_subport_profiles = TMGR_SUBPORT_PROFILE_MAX;
 	p.n_pipes_per_subport = TMGR_PIPE_SUBPORT_MAX;
 
 	s = rte_sched_port_config(&p);
@@ -126,6 +137,13 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 			return NULL;
 		}
 
+		status = rte_sched_subport_profile_config(s, i, 0);
+
+		if (status) {
+			rte_sched_port_free(s);
+			return NULL;
+		}
+
 		for (j = 0; j < subport_profile[0].n_pipes_per_subport_enabled; j++) {
 			status = rte_sched_pipe_config(
 				s,
@@ -182,6 +200,10 @@ tmgr_subport_config(const char *port_name,
 		subport_id,
 		&subport_profile[subport_profile_id]);
 
+	if (!status)
+		status = rte_sched_subport_profile_config(port->s, subport_id,
+							subport_profile_id);
+
 	return status;
 }
 
diff --git a/examples/ip_pipeline/tmgr.h b/examples/ip_pipeline/tmgr.h
index ee50cf7..8c14523 100644
--- a/examples/ip_pipeline/tmgr.h
+++ b/examples/ip_pipeline/tmgr.h
@@ -48,7 +48,8 @@ struct tmgr_port_params {
 };
 
 int
-tmgr_subport_profile_add(struct rte_sched_subport_params *p);
+tmgr_subport_profile_add(struct rte_sched_subport_params *p,
+			 struct rte_sched_subport_profile_params *pp);
 
 int
 tmgr_pipe_profile_add(struct rte_sched_pipe_params *p);
-- 
2.7.4


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

* [dpdk-dev] [PATCH v3 7/9] drivers/softnic: add dynamic config of subport
  2020-09-16 16:43       ` [dpdk-dev] [PATCH v3 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
                           ` (5 preceding siblings ...)
  2020-09-16 16:43         ` [dpdk-dev] [PATCH v3 6/9] example/ip_pipeline: " Savinay Dharmappa
@ 2020-09-16 16:43         ` Savinay Dharmappa
  2020-09-16 16:43         ` [dpdk-dev] [PATCH v3 8/9] app/test_sched: " Savinay Dharmappa
                           ` (2 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-16 16:43 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Modify the softnic drivers to build the hierarchical scheduler
with default subport bandwidth profile. It also allows to configure
a subport with different subport bandwidth profile dynamically.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 drivers/net/softnic/rte_eth_softnic_internals.h |   9 +
 drivers/net/softnic/rte_eth_softnic_tm.c        | 223 +++++++++++++++++++-----
 2 files changed, 187 insertions(+), 45 deletions(-)

diff --git a/drivers/net/softnic/rte_eth_softnic_internals.h b/drivers/net/softnic/rte_eth_softnic_internals.h
index 6eec43b..cc50037 100644
--- a/drivers/net/softnic/rte_eth_softnic_internals.h
+++ b/drivers/net/softnic/rte_eth_softnic_internals.h
@@ -164,10 +164,19 @@ TAILQ_HEAD(softnic_link_list, softnic_link);
 #ifndef TM_MAX_PIPE_PROFILE
 #define TM_MAX_PIPE_PROFILE				256
 #endif
+
+#ifndef TM_MAX_SUBPORT_PROFILE
+#define TM_MAX_SUBPORT_PROFILE				256
+#endif
+
 struct tm_params {
 	struct rte_sched_port_params port_params;
 
 	struct rte_sched_subport_params subport_params[TM_MAX_SUBPORTS];
+	struct rte_sched_subport_profile_params
+				subport_profiles[TM_MAX_SUBPORT_PROFILE];
+	uint32_t n_subport_profiles;
+	uint32_t subport_to_profile[TM_MAX_SUBPORT_PROFILE];
 
 	struct rte_sched_pipe_params pipe_profiles[TM_MAX_PIPE_PROFILE];
 	uint32_t n_pipe_profiles;
diff --git a/drivers/net/softnic/rte_eth_softnic_tm.c b/drivers/net/softnic/rte_eth_softnic_tm.c
index 80a470c..a223655 100644
--- a/drivers/net/softnic/rte_eth_softnic_tm.c
+++ b/drivers/net/softnic/rte_eth_softnic_tm.c
@@ -98,6 +98,13 @@ softnic_tmgr_port_create(struct pmd_internals *p,
 			return NULL;
 		}
 
+		status = rte_sched_subport_profile_config(sched,
+			subport_id, t->subport_to_profile[subport_id]);
+		if (status) {
+			rte_sched_port_free(sched);
+			return NULL;
+		}
+
 		/* Pipe */
 		for (pipe_id = 0; pipe_id < n_pipes_per_subport; pipe_id++) {
 			int pos = subport_id * TM_MAX_PIPES_PER_SUBPORT + pipe_id;
@@ -1043,6 +1050,25 @@ tm_shared_shaper_get_tc(struct rte_eth_dev *dev,
 }
 
 static int
+subport_profile_exists(struct rte_eth_dev *dev,
+	struct rte_sched_subport_profile_params *sp,
+	uint32_t *subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+	uint32_t i;
+
+	for (i = 0; i < t->n_subport_profiles; i++)
+		if (memcmp(&t->subport_profiles[i], sp, sizeof(*sp)) == 0) {
+			if (subport_profile_id)
+				*subport_profile_id = i;
+			return 1;
+		}
+
+	return 0;
+}
+
+static int
 update_subport_tc_rate(struct rte_eth_dev *dev,
 	struct tm_node *nt,
 	struct tm_shared_shaper *ss,
@@ -1050,26 +1076,27 @@ update_subport_tc_rate(struct rte_eth_dev *dev,
 {
 	struct pmd_internals *p = dev->data->dev_private;
 	uint32_t tc_id = tm_node_tc_id(dev, nt);
-
 	struct tm_node *np = nt->parent_node;
-
 	struct tm_node *ns = np->parent_node;
 	uint32_t subport_id = tm_node_subport_id(dev, ns);
-
-	struct rte_sched_subport_params subport_params;
-
+	struct rte_sched_subport_profile_params subport_profile;
 	struct tm_shaper_profile *sp_old = tm_shaper_profile_search(dev,
 		ss->shaper_profile_id);
+	uint32_t subport_profile_id;
 
 	/* Derive new subport configuration. */
-	memcpy(&subport_params,
-		&p->soft.tm.params.subport_params[subport_id],
-		sizeof(subport_params));
-	subport_params.tc_rate[tc_id] = sp_new->params.peak.rate;
+	memcpy(&subport_profile,
+		&p->soft.tm.params.subport_profiles[subport_id],
+		sizeof(subport_profile));
+	subport_profile.tc_rate[tc_id] = sp_new->params.peak.rate;
+
+	if (subport_profile_exists(dev, &subport_profile,
+				  &subport_profile_id) == 0)
+		return -1;
 
 	/* Update the subport configuration. */
-	if (rte_sched_subport_config(SCHED(p),
-		subport_id, &subport_params))
+	if (rte_sched_subport_profile_config(SCHED(p),
+		subport_id, subport_profile_id))
 		return -1;
 
 	/* Commit changes. */
@@ -1078,9 +1105,9 @@ update_subport_tc_rate(struct rte_eth_dev *dev,
 	ss->shaper_profile_id = sp_new->shaper_profile_id;
 	sp_new->n_users++;
 
-	memcpy(&p->soft.tm.params.subport_params[subport_id],
-		&subport_params,
-		sizeof(subport_params));
+	memcpy(&p->soft.tm.params.subport_profiles[subport_id],
+		&subport_profile,
+		sizeof(subport_profile));
 
 	return 0;
 }
@@ -2190,6 +2217,108 @@ pipe_profiles_generate(struct rte_eth_dev *dev)
 	return 0;
 }
 
+static struct rte_sched_subport_profile_params *
+subport_profile_get(struct rte_eth_dev *dev, struct tm_node *np)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+	uint32_t subport_id = tm_node_subport_id(dev, np->parent_node);
+
+	return &t->subport_profiles[subport_id];
+}
+
+static void
+subport_profile_mark(struct rte_eth_dev *dev,
+	uint32_t subport_id,
+	uint32_t subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+
+	t->subport_to_profile[subport_id] = subport_profile_id;
+}
+
+static void
+subport_profile_install(struct rte_eth_dev *dev,
+	struct rte_sched_subport_profile_params *sp,
+	uint32_t subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+
+	memcpy(&t->subport_profiles[subport_profile_id], sp, sizeof(*sp));
+	t->n_subport_profiles++;
+}
+
+static int
+subport_profile_free_exists(struct rte_eth_dev *dev,
+	uint32_t *subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+
+	if (t->n_subport_profiles < TM_MAX_SUBPORT_PROFILE) {
+		*subport_profile_id = t->n_subport_profiles;
+		return 1;
+	}
+
+	return 0;
+}
+
+static void
+subport_profile_build(struct tm_node *np,
+	struct rte_sched_subport_profile_params *sp)
+{
+	memset(sp, 0, sizeof(*sp));
+
+	/* Pipe */
+	sp->tb_rate = np->shaper_profile->params.peak.rate;
+	sp->tb_size = np->shaper_profile->params.peak.size;
+
+	/* Traffic Class (TC) */
+	sp->tc_period = SUBPORT_TC_PERIOD;
+}
+
+static int
+subport_profiles_generate(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_hierarchy *h = &p->soft.tm.h;
+	struct tm_node_list *nl = &h->nodes;
+	struct tm_node *ns;
+	uint32_t subport_id;
+
+	/* Objective: Fill in the following fields in struct tm_params:
+	 *    - subport_profiles
+	 *    - n_subport_profiles
+	 *    - subport_to_profile
+	 */
+
+	subport_id = 0;
+	TAILQ_FOREACH(ns, nl, node) {
+		if (ns->level != TM_NODE_LEVEL_SUBPORT)
+			continue;
+
+		struct rte_sched_subport_profile_params sp;
+		uint32_t pos;
+
+		subport_profile_build(ns, &sp);
+
+		if (!subport_profile_exists(dev, &sp, &pos)) {
+			if (!subport_profile_free_exists(dev, &pos))
+				return -1;
+
+			subport_profile_install(dev, &sp, pos);
+		}
+
+		subport_profile_mark(dev, subport_id, pos);
+
+		subport_id++;
+	}
+
+	return 0;
+}
+
 static struct tm_wred_profile *
 tm_tc_wred_profile_get(struct rte_eth_dev *dev, uint32_t tc_id)
 {
@@ -2447,6 +2576,15 @@ hierarchy_commit_check(struct rte_eth_dev *dev, struct rte_tm_error *error)
 				rte_strerror(EINVAL));
 	}
 
+	/* Not too many subport profiles. */
+	if (subport_profiles_generate(dev))
+		return -rte_tm_error_set(error,
+			EINVAL,
+			RTE_TM_ERROR_TYPE_UNSPECIFIED,
+			NULL,
+			rte_strerror(EINVAL));
+
+
 	/* Not too many pipe profiles. */
 	if (pipe_profiles_generate(dev))
 		return -rte_tm_error_set(error,
@@ -2528,6 +2666,9 @@ hierarchy_blueprints_create(struct rte_eth_dev *dev)
 		.frame_overhead =
 			root->shaper_profile->params.pkt_length_adjust,
 		.n_subports_per_port = root->n_children,
+		.n_subport_profiles = t->n_subport_profiles,
+		.subport_profiles = t->subport_profiles,
+		.n_max_subport_profiles = TM_MAX_SUBPORT_PROFILE,
 		.n_pipes_per_subport = TM_MAX_PIPES_PER_SUBPORT,
 	};
 
@@ -2548,28 +2689,11 @@ hierarchy_blueprints_create(struct rte_eth_dev *dev)
 				ss->shaper_profile_id) :
 				n->shaper_profile;
 			tc_rate[i] = sp->params.peak.rate;
+			t->subport_profiles[subport_id].tc_rate[i] = tc_rate[i];
 		}
 
 		t->subport_params[subport_id] =
 			(struct rte_sched_subport_params) {
-				.tb_rate = n->shaper_profile->params.peak.rate,
-				.tb_size = n->shaper_profile->params.peak.size,
-
-				.tc_rate = {tc_rate[0],
-					tc_rate[1],
-					tc_rate[2],
-					tc_rate[3],
-					tc_rate[4],
-					tc_rate[5],
-					tc_rate[6],
-					tc_rate[7],
-					tc_rate[8],
-					tc_rate[9],
-					tc_rate[10],
-					tc_rate[11],
-					tc_rate[12],
-				},
-				.tc_period = SUBPORT_TC_PERIOD,
 				.n_pipes_per_subport_enabled =
 					h->n_tm_nodes[TM_NODE_LEVEL_PIPE] /
 					h->n_tm_nodes[TM_NODE_LEVEL_SUBPORT],
@@ -2829,30 +2953,39 @@ update_subport_rate(struct rte_eth_dev *dev,
 	struct pmd_internals *p = dev->data->dev_private;
 	uint32_t subport_id = tm_node_subport_id(dev, ns);
 
-	struct rte_sched_subport_params subport_params;
+	struct rte_sched_subport_profile_params *profile0 =
+					subport_profile_get(dev, ns);
+	struct rte_sched_subport_profile_params profile1;
+	uint32_t subport_profile_id;
 
-	/* Derive new subport configuration. */
-	memcpy(&subport_params,
-		&p->soft.tm.params.subport_params[subport_id],
-		sizeof(subport_params));
-	subport_params.tb_rate = sp->params.peak.rate;
-	subport_params.tb_size = sp->params.peak.size;
+	/* Derive new pipe profile. */
+	memcpy(&profile1, profile0, sizeof(profile1));
+	profile1.tb_rate = sp->params.peak.rate;
+	profile1.tb_size = sp->params.peak.size;
+
+	/* Since implementation does not allow adding more subport profiles
+	 * after port configuration, the pipe configuration can be successfully
+	 * updated only if the new profile is also part of the existing set of
+	 * pipe profiles.
+	 */
+	if (subport_profile_exists(dev, &profile1, &subport_profile_id) == 0)
+		return -1;
 
 	/* Update the subport configuration. */
-	if (rte_sched_subport_config(SCHED(p), subport_id,
-		&subport_params))
+	if (rte_sched_subport_profile_config(SCHED(p), subport_id,
+		subport_profile_id))
 		return -1;
 
+	subport_profile_mark(dev, subport_id, subport_profile_id);
 	/* Commit changes. */
 	ns->shaper_profile->n_users--;
-
 	ns->shaper_profile = sp;
 	ns->params.shaper_profile_id = sp->shaper_profile_id;
 	sp->n_users++;
 
-	memcpy(&p->soft.tm.params.subport_params[subport_id],
-		&subport_params,
-		sizeof(subport_params));
+	memcpy(&p->soft.tm.params.subport_profiles[subport_id],
+		&profile1,
+		sizeof(profile1));
 
 	return 0;
 }
-- 
2.7.4


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

* [dpdk-dev] [PATCH v3 8/9] app/test_sched: add dynamic config of subport
  2020-09-16 16:43       ` [dpdk-dev] [PATCH v3 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
                           ` (6 preceding siblings ...)
  2020-09-16 16:43         ` [dpdk-dev] [PATCH v3 7/9] drivers/softnic: " Savinay Dharmappa
@ 2020-09-16 16:43         ` Savinay Dharmappa
  2020-09-16 16:43         ` [dpdk-dev] [PATCH v3 9/9] sched: remove the redundant code Savinay Dharmappa
  2020-09-17  8:42         ` [dpdk-dev] [PATCH v4 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-16 16:43 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Modify the test_sched application to build the hierarchical scheduler
with default subport bandwidth profile. It also allows to configure
a subport with different subport bandwidth profile dynamically

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 app/test/test_sched.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/app/test/test_sched.c b/app/test/test_sched.c
index fc31080..8d1eb25 100644
--- a/app/test/test_sched.c
+++ b/app/test/test_sched.c
@@ -21,6 +21,7 @@
 #define PIPE            1
 #define TC              2
 #define QUEUE           0
+#define MAX_SCHED_SUBPORT_PROFILES  8
 
 static struct rte_sched_pipe_params pipe_profile[] = {
 	{ /* Profile #0 */
@@ -36,15 +37,20 @@ static struct rte_sched_pipe_params pipe_profile[] = {
 	},
 };
 
-static struct rte_sched_subport_params subport_param[] = {
+static struct rte_sched_subport_profile_params
+		subport_profile[] = {
 	{
 		.tb_rate = 1250000000,
 		.tb_size = 1000000,
-
 		.tc_rate = {1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000},
 		.tc_period = 10,
+	},
+};
+
+static struct rte_sched_subport_params subport_param[] = {
+	{
 		.n_pipes_per_subport_enabled = 1024,
 		.qsize = {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32},
 		.pipe_profiles = pipe_profile,
@@ -59,6 +65,9 @@ static struct rte_sched_port_params port_param = {
 	.mtu = 1522,
 	.frame_overhead = RTE_SCHED_FRAME_OVERHEAD_DEFAULT,
 	.n_subports_per_port = 1,
+	.n_subport_profiles = 1,
+	.subport_profiles = subport_profile,
+	.n_max_subport_profiles = MAX_SCHED_SUBPORT_PROFILES,
 	.n_pipes_per_subport = 1024,
 };
 
@@ -66,6 +75,7 @@ static struct rte_sched_port_params port_param = {
 #define MBUF_DATA_SZ     (2048 + RTE_PKTMBUF_HEADROOM)
 #define MEMPOOL_CACHE_SZ 0
 #define SOCKET           0
+#define DEFAULT_PROFILE  0
 
 
 static struct rte_mempool *
@@ -141,6 +151,10 @@ test_sched(void)
 	err = rte_sched_subport_config(port, SUBPORT, subport_param);
 	TEST_ASSERT_SUCCESS(err, "Error config sched, err=%d\n", err);
 
+	err = rte_sched_subport_profile_config(port, SUBPORT,
+						DEFAULT_PROFILE);
+	TEST_ASSERT_SUCCESS(err, "Error config sched, err=%d\n", err);
+
 	for (pipe = 0; pipe < subport_param[0].n_pipes_per_subport_enabled; pipe++) {
 		err = rte_sched_pipe_config(port, SUBPORT, pipe, 0);
 		TEST_ASSERT_SUCCESS(err, "Error config sched pipe %u, err=%d\n", pipe, err);
-- 
2.7.4


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

* [dpdk-dev] [PATCH v3 9/9] sched: remove the redundant code
  2020-09-16 16:43       ` [dpdk-dev] [PATCH v3 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
                           ` (7 preceding siblings ...)
  2020-09-16 16:43         ` [dpdk-dev] [PATCH v3 8/9] app/test_sched: " Savinay Dharmappa
@ 2020-09-16 16:43         ` Savinay Dharmappa
  2020-09-17  8:42         ` [dpdk-dev] [PATCH v4 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-16 16:43 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Remove redundant data structure fields references from
functions and subport level data structures. It also
update the release and deprecation note.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 doc/guides/rel_notes/deprecation.rst   |   6 --
 doc/guides/rel_notes/release_20_11.rst |   4 ++
 lib/librte_sched/rte_sched.c           | 115 +--------------------------------
 lib/librte_sched/rte_sched.h           |  12 ----
 4 files changed, 6 insertions(+), 131 deletions(-)

diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 345c38d..261f133 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -318,12 +318,6 @@ Deprecation Notices
   in "rte_sched.h". These changes are aligned to improvements suggested in the
   RFC https://mails.dpdk.org/archives/dev/2018-November/120035.html.
 
-* sched: To allow dynamic configuration of the subport bandwidth profile,
-  changes will be made to data structures ``rte_sched_subport_params``,
-  ``rte_sched_port_params`` and new data structure, API functions will be
-  defined in ``rte_sched.h``. These changes are aligned as suggested in the
-  RFC https://mails.dpdk.org/archives/dev/2020-July/175161.html
-
 * metrics: The function ``rte_metrics_init`` will have a non-void return
   in order to notify errors instead of calling ``rte_exit``.
 
diff --git a/doc/guides/rel_notes/release_20_11.rst b/doc/guides/rel_notes/release_20_11.rst
index df227a1..51c4568 100644
--- a/doc/guides/rel_notes/release_20_11.rst
+++ b/doc/guides/rel_notes/release_20_11.rst
@@ -84,6 +84,10 @@ API Changes
    Also, make sure to start the actual text at the margin.
    =======================================================
 
+* sched: The subport bandwidth configuration parameters such as tb_rate,
+  tc_rate, tc_period etc., are moved from subport level data structure to
+  new a data structure. This allows to configure a subport with different
+  subport bandwidth configuration dynamically.
 
 ABI Changes
 -----------
diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index 3f61afa..6b6892d 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -152,16 +152,11 @@ struct rte_sched_grinder {
 struct rte_sched_subport {
 	/* Token bucket (TB) */
 	uint64_t tb_time; /* time of last update */
-	uint64_t tb_period;
-	uint64_t tb_credits_per_period;
-	uint64_t tb_size;
 	uint64_t tb_credits;
 
 	/* Traffic classes (TCs) */
 	uint64_t tc_time; /* time of next update */
-	uint64_t tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
 	uint64_t tc_credits[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
-	uint64_t tc_period;
 
 	/* TC oversubscription */
 	uint64_t tc_ov_wm;
@@ -837,18 +832,6 @@ rte_sched_subport_check_params(struct rte_sched_subport_params *params,
 		return -EINVAL;
 	}
 
-	if (params->tb_rate == 0 || params->tb_rate > rate) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect value for tb rate\n", __func__);
-		return -EINVAL;
-	}
-
-	if (params->tb_size == 0) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect value for tb size\n", __func__);
-		return -EINVAL;
-	}
-
 	/* qsize: if non-zero, power of 2,
 	 * no bigger than 32K (due to 16-bit read/write pointers)
 	 */
@@ -862,29 +845,8 @@ rte_sched_subport_check_params(struct rte_sched_subport_params *params,
 		}
 	}
 
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
-		uint64_t tc_rate = params->tc_rate[i];
-		uint16_t qsize = params->qsize[i];
-
-		if ((qsize == 0 && tc_rate != 0) ||
-			(qsize != 0 && tc_rate == 0) ||
-			(tc_rate > params->tb_rate)) {
-			RTE_LOG(ERR, SCHED,
-				"%s: Incorrect value for tc rate\n", __func__);
-			return -EINVAL;
-		}
-	}
-
-	if (params->qsize[RTE_SCHED_TRAFFIC_CLASS_BE] == 0 ||
-		params->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect qsize or tc rate(best effort)\n", __func__);
-		return -EINVAL;
-	}
-
-	if (params->tc_period == 0) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect value for tc period\n", __func__);
+	if (params->qsize[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
+		RTE_LOG(ERR, SCHED, "%s: Incorrect qsize\n", __func__);
 		return -EINVAL;
 	}
 
@@ -1101,48 +1063,6 @@ rte_sched_port_free(struct rte_sched_port *port)
 }
 
 static void
-rte_sched_port_log_subport_config(struct rte_sched_port *port, uint32_t i)
-{
-	struct rte_sched_subport *s = port->subports[i];
-
-	RTE_LOG(DEBUG, SCHED, "Low level config for subport %u:\n"
-		"	Token bucket: period = %"PRIu64", credits per period = %"PRIu64
-		", size = %"PRIu64"\n"
-		"	Traffic classes: period = %"PRIu64"\n"
-		"	credits per period = [%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
-		", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
-		", %"PRIu64", %"PRIu64", %"PRIu64"]\n"
-		"	Best effort traffic class oversubscription: wm min = %"PRIu64
-		", wm max = %"PRIu64"\n",
-		i,
-
-		/* Token bucket */
-		s->tb_period,
-		s->tb_credits_per_period,
-		s->tb_size,
-
-		/* Traffic classes */
-		s->tc_period,
-		s->tc_credits_per_period[0],
-		s->tc_credits_per_period[1],
-		s->tc_credits_per_period[2],
-		s->tc_credits_per_period[3],
-		s->tc_credits_per_period[4],
-		s->tc_credits_per_period[5],
-		s->tc_credits_per_period[6],
-		s->tc_credits_per_period[7],
-		s->tc_credits_per_period[8],
-		s->tc_credits_per_period[9],
-		s->tc_credits_per_period[10],
-		s->tc_credits_per_period[11],
-		s->tc_credits_per_period[12],
-
-		/* Best effort traffic class oversubscription */
-		s->tc_ov_wm_min,
-		s->tc_ov_wm_max);
-}
-
-static void
 rte_sched_free_memory(struct rte_sched_port *port, uint32_t n_subports)
 {
 	uint32_t i;
@@ -1215,33 +1135,7 @@ rte_sched_subport_config(struct rte_sched_port *port,
 	/* Port */
 	port->subports[subport_id] = s;
 
-	/* Token Bucket (TB) */
-	if (params->tb_rate == port->rate) {
-		s->tb_credits_per_period = 1;
-		s->tb_period = 1;
-	} else {
-		double tb_rate = ((double) params->tb_rate) / ((double) port->rate);
-		double d = RTE_SCHED_TB_RATE_CONFIG_ERR;
-
-		rte_approx_64(tb_rate, d, &s->tb_credits_per_period, &s->tb_period);
-	}
-
-	s->tb_size = params->tb_size;
 	s->tb_time = port->time;
-	s->tb_credits = s->tb_size / 2;
-
-	/* Traffic Classes (TCs) */
-	s->tc_period = rte_sched_time_ms_to_bytes(params->tc_period, port->rate);
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
-		if (params->qsize[i])
-			s->tc_credits_per_period[i]
-				= rte_sched_time_ms_to_bytes(params->tc_period,
-					params->tc_rate[i]);
-	}
-	s->tc_time = port->time + s->tc_period;
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-		if (params->qsize[i])
-			s->tc_credits[i] = s->tc_credits_per_period[i];
 
 	/* compile time checks */
 	RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS == 0);
@@ -1331,17 +1225,12 @@ rte_sched_subport_config(struct rte_sched_port *port,
 #ifdef RTE_SCHED_SUBPORT_TC_OV
 	/* TC oversubscription */
 	s->tc_ov_wm_min = port->mtu;
-	s->tc_ov_wm_max = rte_sched_time_ms_to_bytes(params->tc_period,
-						     s->pipe_tc_be_rate_max);
 	s->tc_ov_wm = s->tc_ov_wm_max;
 	s->tc_ov_period_id = 0;
 	s->tc_ov = 0;
 	s->tc_ov_n = 0;
 	s->tc_ov_rate = 0;
 #endif
-
-	rte_sched_port_log_subport_config(port, subport_id);
-
 	return 0;
 }
 
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index a7c2638..7623919 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -149,18 +149,6 @@ struct rte_sched_pipe_params {
  * byte.
  */
 struct rte_sched_subport_params {
-	/** Token bucket rate (measured in bytes per second) */
-	uint64_t tb_rate;
-
-	/** Token bucket size (measured in credits) */
-	uint64_t tb_size;
-
-	/** Traffic class rates (measured in bytes per second) */
-	uint64_t tc_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
-
-	/** Enforcement period for rates (measured in milliseconds) */
-	uint64_t tc_period;
-
 	/** Number of subport pipes.
 	 * The subport can enable/allocate fewer pipes than the maximum
 	 * number set through struct port_params::n_max_pipes_per_subport,
-- 
2.7.4


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

* [dpdk-dev] [PATCH v4 0/9] Enable dynamic config of subport bandwidth
  2020-09-16 16:43       ` [dpdk-dev] [PATCH v3 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
                           ` (8 preceding siblings ...)
  2020-09-16 16:43         ` [dpdk-dev] [PATCH v3 9/9] sched: remove the redundant code Savinay Dharmappa
@ 2020-09-17  8:42         ` Savinay Dharmappa
  2020-09-17  8:42           ` [dpdk-dev] [PATCH v4 1/9] sched: add support profile data structure Savinay Dharmappa
                             ` (9 more replies)
  9 siblings, 10 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-17  8:42 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

DPDK sched library allows runtime configuration of the pipe profiles to the
pipes of the subport once scheduler hierarchy is constructed. However, to
change the subport level bandwidth, existing hierarchy needs to be
dismantled and whole process of building hierarchy under subport nodes
needs to be repeated which might result in router downtime. Furthermore,
due to lack of dynamic configuration of the subport bandwidth profile
configuration (shaper and Traffic class rates), the user application
is unable to dynamically re-distribute the excess-bandwidth of one subport
among other subports in the scheduler hierarchy. Therefore, it is also not
possible to adjust the subport bandwidth profile in sync with dynamic
changes in pipe profiles of subscribers who want to consume higher
bandwidth opportunistically.

This patch series implements dynamic configuration of the subport bandwidth
profile to overcome the runtime situation when group of subscribers are not
using the allotted bandwidth and dynamic bandwidth re-distribution is
needed the without making any structural changes in the hierarchy.

The implementation work includes refactoring the existing data structures
defined for port and subport level, new APIs for adding subport level
bandwidth profiles that can be used in runtime.

Savinay Dharmappa (9):
  sched: add support profile data structure
  sched: add subport profile table
  sched: add subport profile add and config api
  sched: update grinder credit and pipe config function
  example/qos_sched: add dynamic config of subport
  example/ip_pipeline: add dynamic config of subport
  drivers/softnic: add dynamic config of subport
  app/test_sched: add dynamic config of subport
  sched: remove the redundant code

 app/test/test_sched.c                           |  18 +-
 doc/guides/rel_notes/deprecation.rst            |   6 -
 doc/guides/rel_notes/release_20_11.rst          |   4 +
 drivers/net/softnic/rte_eth_softnic_internals.h |   9 +
 drivers/net/softnic/rte_eth_softnic_tm.c        | 223 ++++++++---
 examples/ip_pipeline/cli.c                      |  14 +-
 examples/ip_pipeline/tmgr.c                     |  26 +-
 examples/ip_pipeline/tmgr.h                     |   3 +-
 examples/qos_sched/cfg_file.c                   | 151 ++++----
 examples/qos_sched/cfg_file.h                   |   4 +
 examples/qos_sched/init.c                       |  24 +-
 examples/qos_sched/main.h                       |   1 +
 examples/qos_sched/profile.cfg                  |   3 +
 lib/librte_sched/rte_sched.c                    | 479 +++++++++++++++++-------
 lib/librte_sched/rte_sched.h                    |  82 +++-
 lib/librte_sched/rte_sched_version.map          |   2 +
 16 files changed, 771 insertions(+), 278 deletions(-)

-- 
2.7.4


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

* [dpdk-dev] [PATCH v4 1/9] sched: add support profile data structure
  2020-09-17  8:42         ` [dpdk-dev] [PATCH v4 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
@ 2020-09-17  8:42           ` Savinay Dharmappa
  2020-09-17  8:42           ` [dpdk-dev] [PATCH v4 2/9] sched: add subport profile table Savinay Dharmappa
                             ` (8 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-17  8:42 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Add subport profile data structure to support dynamic configuration
of subport bandwidth

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c | 10 ++++++++++
 lib/librte_sched/rte_sched.h | 25 +++++++++++++++++++++++++
 2 files changed, 35 insertions(+)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index 0fa0741..dc5beb2 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -101,6 +101,16 @@ enum grinder_state {
 	e_GRINDER_READ_MBUF
 };
 
+struct rte_sched_subport_profile {
+	/* Token bucket (TB) */
+	uint64_t tb_period;
+	uint64_t tb_credits_per_period;
+	uint64_t tb_size;
+
+	uint64_t tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+	uint64_t tc_period;
+};
+
 struct rte_sched_grinder {
 	/* Pipe cache */
 	uint16_t pcache_qmask[RTE_SCHED_GRINDER_PCACHE_SIZE];
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index 8a5a93c..39339b7 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -192,6 +192,20 @@ struct rte_sched_subport_params {
 #endif
 };
 
+struct rte_sched_subport_profile_params {
+	/** Token bucket rate (measured in bytes per second) */
+	uint64_t tb_rate;
+
+	/** Token bucket size (measured in credits) */
+	uint64_t tb_size;
+
+	/** Traffic class rates (measured in bytes per second) */
+	uint64_t tc_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+
+	/** Enforcement period for rates (measured in milliseconds) */
+	uint64_t tc_period;
+};
+
 /** Subport statistics */
 struct rte_sched_subport_stats {
 	/** Number of packets successfully written */
@@ -254,6 +268,17 @@ struct rte_sched_port_params {
 	/** Number of subports */
 	uint32_t n_subports_per_port;
 
+	/** subport profile table.
+	 * Every pipe is configured using one of the profiles from this table.
+	 */
+	struct rte_sched_subport_profile_params *subport_profiles;
+
+	/** Profiles in the pipe profile table */
+	uint32_t n_subport_profiles;
+
+	/** Max allowed profiles in the pipe profile table */
+	uint32_t n_max_subport_profiles;
+
 	/** Maximum number of subport pipes.
 	 * This parameter is used to reserve a fixed number of bits
 	 * in struct rte_mbuf::sched.queue_id for the pipe_id for all
-- 
2.7.4


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

* [dpdk-dev] [PATCH v4 2/9] sched: add subport profile table
  2020-09-17  8:42         ` [dpdk-dev] [PATCH v4 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
  2020-09-17  8:42           ` [dpdk-dev] [PATCH v4 1/9] sched: add support profile data structure Savinay Dharmappa
@ 2020-09-17  8:42           ` Savinay Dharmappa
  2020-09-17  8:42           ` [dpdk-dev] [PATCH v4 3/9] sched: add subport profile add and config api Savinay Dharmappa
                             ` (7 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-17  8:42 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Add subport profile table to internal port data structure and
update the port config function.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c | 185 ++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 182 insertions(+), 3 deletions(-)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index dc5beb2..5fa7865 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -222,6 +222,8 @@ struct rte_sched_port {
 	uint16_t pipe_queue[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
 	uint8_t pipe_tc[RTE_SCHED_QUEUES_PER_PIPE];
 	uint8_t tc_queue[RTE_SCHED_QUEUES_PER_PIPE];
+	uint32_t n_subport_profiles;
+	uint32_t n_max_subport_profiles;
 	uint64_t rate;
 	uint32_t mtu;
 	uint32_t frame_overhead;
@@ -240,6 +242,7 @@ struct rte_sched_port {
 	uint32_t subport_id;
 
 	/* Large data structures */
+	struct rte_sched_subport_profile *subport_profiles;
 	struct rte_sched_subport *subports[0] __rte_cache_aligned;
 } __rte_cache_aligned;
 
@@ -386,8 +389,60 @@ pipe_profile_check(struct rte_sched_pipe_params *params,
 }
 
 static int
+subport_profile_check(struct rte_sched_subport_profile_params *params,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	/* Check user parameters */
+	if (params == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter params\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tb_rate == 0 || params->tb_rate > rate) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for tb rate\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tb_size == 0) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for tb size\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
+		uint64_t tc_rate = params->tc_rate[i];
+
+		if (tc_rate == 0 || (tc_rate > params->tb_rate)) {
+			RTE_LOG(ERR, SCHED, "%s: "
+			"Incorrect value for tc rate\n", __func__);
+			return -EINVAL;
+		}
+	}
+
+	if (params->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect tc rate(best effort)\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tc_period == 0) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for tc period\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static int
 rte_sched_port_check_params(struct rte_sched_port_params *params)
 {
+	uint32_t i;
+
 	if (params == NULL) {
 		RTE_LOG(ERR, SCHED,
 			"%s: Incorrect value for parameter params\n", __func__);
@@ -424,6 +479,29 @@ rte_sched_port_check_params(struct rte_sched_port_params *params)
 		return -EINVAL;
 	}
 
+	if (params->subport_profiles == NULL ||
+		params->n_subport_profiles == 0 ||
+		params->n_max_subport_profiles == 0 ||
+		params->n_subport_profiles > params->n_max_subport_profiles) {
+		RTE_LOG(ERR, SCHED,
+		"%s: Incorrect value for subport profiles\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < params->n_subport_profiles; i++) {
+		struct rte_sched_subport_profile_params *p =
+						params->subport_profiles + i;
+		int status;
+
+		status = subport_profile_check(p, params->rate);
+		if (status != 0) {
+			RTE_LOG(ERR, SCHED,
+			"%s: subport profile check failed(%d)\n",
+			__func__, status);
+			return -EINVAL;
+		}
+	}
+
 	/* n_pipes_per_subport: non-zero, power of 2 */
 	if (params->n_pipes_per_subport == 0 ||
 	    !rte_is_power_of_2(params->n_pipes_per_subport)) {
@@ -565,6 +643,42 @@ rte_sched_port_log_pipe_profile(struct rte_sched_subport *subport, uint32_t i)
 		p->wrr_cost[0], p->wrr_cost[1], p->wrr_cost[2], p->wrr_cost[3]);
 }
 
+static void
+rte_sched_port_log_subport_profile(struct rte_sched_port *port, uint32_t i)
+{
+	struct rte_sched_subport_profile *p = port->subport_profiles + i;
+
+	RTE_LOG(DEBUG, SCHED, "Low level config for subport profile %u:\n"
+	"Token bucket: period = %"PRIu64", credits per period = %"PRIu64","
+	"size = %"PRIu64"\n"
+	"Traffic classes: period = %"PRIu64",\n"
+	"credits per period = [%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
+	" %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
+	" %"PRIu64", %"PRIu64", %"PRIu64"]\n",
+	i,
+
+	/* Token bucket */
+	p->tb_period,
+	p->tb_credits_per_period,
+	p->tb_size,
+
+	/* Traffic classes */
+	p->tc_period,
+	p->tc_credits_per_period[0],
+	p->tc_credits_per_period[1],
+	p->tc_credits_per_period[2],
+	p->tc_credits_per_period[3],
+	p->tc_credits_per_period[4],
+	p->tc_credits_per_period[5],
+	p->tc_credits_per_period[6],
+	p->tc_credits_per_period[7],
+	p->tc_credits_per_period[8],
+	p->tc_credits_per_period[9],
+	p->tc_credits_per_period[10],
+	p->tc_credits_per_period[11],
+	p->tc_credits_per_period[12]);
+}
+
 static inline uint64_t
 rte_sched_time_ms_to_bytes(uint64_t time_ms, uint64_t rate)
 {
@@ -634,6 +748,37 @@ rte_sched_pipe_profile_convert(struct rte_sched_subport *subport,
 }
 
 static void
+rte_sched_subport_profile_convert(struct rte_sched_subport_profile_params *src,
+	struct rte_sched_subport_profile *dst,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	/* Token Bucket */
+	if (src->tb_rate == rate) {
+		dst->tb_credits_per_period = 1;
+		dst->tb_period = 1;
+	} else {
+		double tb_rate = (double) src->tb_rate
+				/ (double) rate;
+		double d = RTE_SCHED_TB_RATE_CONFIG_ERR;
+
+		rte_approx_64(tb_rate, d, &dst->tb_credits_per_period,
+			&dst->tb_period);
+	}
+
+	dst->tb_size = src->tb_size;
+
+	/* Traffic Classes */
+	dst->tc_period = rte_sched_time_ms_to_bytes(src->tc_period, rate);
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		dst->tc_credits_per_period[i]
+			= rte_sched_time_ms_to_bytes(src->tc_period,
+				src->tc_rate[i]);
+}
+
+static void
 rte_sched_subport_config_pipe_profile_table(struct rte_sched_subport *subport,
 	struct rte_sched_subport_params *params, uint64_t rate)
 {
@@ -657,6 +802,24 @@ rte_sched_subport_config_pipe_profile_table(struct rte_sched_subport *subport,
 	}
 }
 
+static void
+rte_sched_port_config_subport_profile_table(struct rte_sched_port *port,
+	struct rte_sched_port_params *params,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	for (i = 0; i < port->n_subport_profiles; i++) {
+		struct rte_sched_subport_profile_params *src
+				= params->subport_profiles + i;
+		struct rte_sched_subport_profile *dst
+				= port->subport_profiles + i;
+
+		rte_sched_subport_profile_convert(src, dst, rate);
+		rte_sched_port_log_subport_profile(port, i);
+	}
+}
+
 static int
 rte_sched_subport_check_params(struct rte_sched_subport_params *params,
 	uint32_t n_max_pipes_per_subport,
@@ -803,7 +966,7 @@ struct rte_sched_port *
 rte_sched_port_config(struct rte_sched_port_params *params)
 {
 	struct rte_sched_port *port = NULL;
-	uint32_t size0, size1;
+	uint32_t size0, size1, size2;
 	uint32_t cycles_per_byte;
 	uint32_t i, j;
 	int status;
@@ -818,10 +981,21 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 
 	size0 = sizeof(struct rte_sched_port);
 	size1 = params->n_subports_per_port * sizeof(struct rte_sched_subport *);
+	size2 = params->n_max_subport_profiles *
+		sizeof(struct rte_sched_subport_profile);
 
 	/* Allocate memory to store the data structures */
-	port = rte_zmalloc_socket("qos_params", size0 + size1, RTE_CACHE_LINE_SIZE,
-		params->socket);
+	port = rte_zmalloc_socket("qos_params", size0 + size1,
+				 RTE_CACHE_LINE_SIZE, params->socket);
+	if (port == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: Memory allocation fails\n", __func__);
+
+		return NULL;
+	}
+
+	/* Allocate memory to store the subport profile */
+	port->subport_profiles  = rte_zmalloc_socket("subport_profile", size2,
+					RTE_CACHE_LINE_SIZE, params->socket);
 	if (port == NULL) {
 		RTE_LOG(ERR, SCHED, "%s: Memory allocation fails\n", __func__);
 
@@ -830,6 +1004,8 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 
 	/* User parameters */
 	port->n_subports_per_port = params->n_subports_per_port;
+	port->n_subport_profiles = params->n_subport_profiles;
+	port->n_max_subport_profiles = params->n_max_subport_profiles;
 	port->n_pipes_per_subport = params->n_pipes_per_subport;
 	port->n_pipes_per_subport_log2 =
 			__builtin_ctz(params->n_pipes_per_subport);
@@ -860,6 +1036,9 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 	port->time_cpu_bytes = 0;
 	port->time = 0;
 
+	/* Subport profile table */
+	rte_sched_port_config_subport_profile_table(port, params, port->rate);
+
 	cycles_per_byte = (rte_get_tsc_hz() << RTE_SCHED_TIME_SHIFT)
 		/ params->rate;
 	port->inv_cycles_per_byte = rte_reciprocal_value(cycles_per_byte);
-- 
2.7.4


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

* [dpdk-dev] [PATCH v4 3/9] sched: add subport profile add and config api
  2020-09-17  8:42         ` [dpdk-dev] [PATCH v4 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
  2020-09-17  8:42           ` [dpdk-dev] [PATCH v4 1/9] sched: add support profile data structure Savinay Dharmappa
  2020-09-17  8:42           ` [dpdk-dev] [PATCH v4 2/9] sched: add subport profile table Savinay Dharmappa
@ 2020-09-17  8:42           ` Savinay Dharmappa
  2020-09-29 21:19             ` Dumitrescu, Cristian
  2020-09-17  8:42           ` [dpdk-dev] [PATCH v4 4/9] sched: update grinder credit and pipe config function Savinay Dharmappa
                             ` (6 subsequent siblings)
  9 siblings, 1 reply; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-17  8:42 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Add apis to add new subport profile and configure it.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c           | 118 +++++++++++++++++++++++++++++++++
 lib/librte_sched/rte_sched.h           |  45 +++++++++++++
 lib/librte_sched/rte_sched_version.map |   2 +
 3 files changed, 165 insertions(+)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index 5fa7865..23aaec4 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -174,6 +174,8 @@ struct rte_sched_subport {
 	/* Statistics */
 	struct rte_sched_subport_stats stats __rte_cache_aligned;
 
+	/* subport profile */
+	uint32_t profile;
 	/* Subport pipes */
 	uint32_t n_pipes_per_subport_enabled;
 	uint32_t n_pipe_profiles;
@@ -1343,6 +1345,56 @@ rte_sched_subport_config(struct rte_sched_port *port,
 }
 
 int
+rte_sched_subport_profile_config(struct rte_sched_port *port,
+	uint32_t subport_id,
+	uint32_t profile_id)
+{
+	int i;
+	struct rte_sched_subport_profile *params;
+	uint32_t n_subports = subport_id + 1;
+	struct rte_sched_subport *s;
+
+	if (port == NULL) {
+		RTE_LOG(ERR, SCHED,
+			"%s: Incorrect value for parameter port\n", __func__);
+		return -EINVAL;
+	}
+
+	if (subport_id >= port->n_subports_per_port) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter subport id\n", __func__);
+
+		rte_sched_free_memory(port, n_subports);
+		return -EINVAL;
+	}
+
+	params =  port->subport_profiles + profile_id;
+
+	s = port->subports[subport_id];
+
+	s->tb_credits = params->tb_size / 2;
+
+	s->tc_time = port->time + params->tc_period;
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		if (s->qsize[i])
+			s->tc_credits[i] =
+				params->tc_credits_per_period[i];
+		else
+			params->tc_credits_per_period[i] = 0;
+
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+	s->tc_ov_wm_max = rte_sched_time_ms_to_bytes(params->tc_period,
+						     s->pipe_tc_be_rate_max);
+#endif
+	s->profile = profile_id;
+
+	rte_sched_port_log_subport_profile(port, profile_id);
+
+	return 0;
+}
+
+int
 rte_sched_pipe_config(struct rte_sched_port *port,
 	uint32_t subport_id,
 	uint32_t pipe_id,
@@ -1526,6 +1578,72 @@ rte_sched_subport_pipe_profile_add(struct rte_sched_port *port,
 	return 0;
 }
 
+int
+rte_sched_port_subport_profile_add(struct rte_sched_port *port,
+	struct rte_sched_subport_profile_params *params,
+	uint32_t *subport_profile_id)
+{
+	int status;
+	uint32_t i;
+	struct rte_sched_subport_profile *dst;
+
+	/* Port */
+	if (port == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter port\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter profile\n", __func__);
+		return -EINVAL;
+	}
+
+	if (subport_profile_id == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter subport_profile_id\n",
+		__func__);
+		return -EINVAL;
+	}
+
+	dst = port->subport_profiles + port->n_subport_profiles;
+
+	/* Subport profiles exceeds the max limit */
+	if (port->n_subport_profiles >= port->n_max_subport_profiles) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Number of subport profiles exceeds the max limit\n",
+		 __func__);
+		return -EINVAL;
+	}
+
+	status = subport_profile_check(params, port->rate);
+	if (status != 0) {
+		RTE_LOG(ERR, SCHED,
+		"%s: subport profile check failed(%d)\n", __func__, status);
+		return -EINVAL;
+	}
+
+	rte_sched_subport_profile_convert(params, dst, port->rate);
+
+	/* Subport profile should not exists */
+	for (i = 0; i < port->n_subport_profiles; i++)
+		if (memcmp(port->subport_profiles + i,
+		    dst, sizeof(*dst)) == 0) {
+			RTE_LOG(ERR, SCHED,
+			"%s: subport profile exists\n", __func__);
+			return -EINVAL;
+		}
+
+	/* Subport profile commit */
+	*subport_profile_id = port->n_subport_profiles;
+	port->n_subport_profiles++;
+
+	rte_sched_port_log_subport_profile(port, *subport_profile_id);
+
+	return 0;
+}
+
 static inline uint32_t
 rte_sched_port_qindex(struct rte_sched_port *port,
 	uint32_t subport,
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index 39339b7..a7c2638 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -337,6 +337,29 @@ rte_sched_subport_pipe_profile_add(struct rte_sched_port *port,
 	uint32_t *pipe_profile_id);
 
 /**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Hierarchical scheduler subport bandwidth profile add
+ * Note that this function is safe to use in runtime for adding new
+ * subport bandwidth profile as it doesn't have any impact on hiearchical
+ * structure of the scheduler.
+ * @param port
+ *   Handle to port scheduler instance
+ * @param struct rte_sched_subport_profile
+ *   Subport bandwidth profile
+ * @param subport_profile_d
+ *   Subport profile id
+ * @return
+ *   0 upon success, error code otherwise
+ */
+__rte_experimental
+int
+rte_sched_port_subport_profile_add(struct rte_sched_port *port,
+	struct rte_sched_subport_profile_params *profile,
+	uint32_t *subport_profile_id);
+
+/**
  * Hierarchical scheduler subport configuration
  *
  * @param port
@@ -354,6 +377,28 @@ rte_sched_subport_config(struct rte_sched_port *port,
 	struct rte_sched_subport_params *params);
 
 /**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Hierarchical scheduler subport profile configuration
+ * Note that this function is safe to use in runtime for applying any specific
+ * subport bandwidth profile as it doesn't have any impact on hiearchical
+ * structure of the scheduler.
+ * @param port
+ *   Handle to port scheduler instance
+ * @param subport_id
+ *   Subport ID
+ * @param profile_d
+ *   Subport profile id
+ * @return
+ *   0 upon success, error code otherwise
+ */
+__rte_experimental
+int
+rte_sched_subport_profile_config(struct rte_sched_port *port,
+	uint32_t subport_id,
+	uint32_t profile_id);
+/**
  * Hierarchical scheduler pipe configuration
  *
  * @param port
diff --git a/lib/librte_sched/rte_sched_version.map b/lib/librte_sched/rte_sched_version.map
index 3faef6f..e64335f 100644
--- a/lib/librte_sched/rte_sched_version.map
+++ b/lib/librte_sched/rte_sched_version.map
@@ -28,4 +28,6 @@ EXPERIMENTAL {
 	global:
 
 	rte_sched_subport_pipe_profile_add;
+	rte_sched_port_subport_profile_add;
+	rte_sched_subport_profile_config;
 };
-- 
2.7.4


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

* [dpdk-dev] [PATCH v4 4/9] sched: update grinder credit and pipe config function
  2020-09-17  8:42         ` [dpdk-dev] [PATCH v4 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
                             ` (2 preceding siblings ...)
  2020-09-17  8:42           ` [dpdk-dev] [PATCH v4 3/9] sched: add subport profile add and config api Savinay Dharmappa
@ 2020-09-17  8:42           ` Savinay Dharmappa
  2020-09-17  8:42           ` [dpdk-dev] [PATCH v4 5/9] example/qos_sched: add dynamic config of subport Savinay Dharmappa
                             ` (5 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-17  8:42 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Credits are updated by fetching subport profile parameters from
subport profile table. Similarly subport best effort tc is
calculated in pipe config.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c | 55 ++++++++++++++++++++++++++------------------
 1 file changed, 33 insertions(+), 22 deletions(-)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index 23aaec4..3f61afa 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -123,6 +123,7 @@ struct rte_sched_grinder {
 	uint32_t productive;
 	uint32_t pindex;
 	struct rte_sched_subport *subport;
+	struct rte_sched_subport_profile *subport_params;
 	struct rte_sched_pipe *pipe;
 	struct rte_sched_pipe_profile *pipe_params;
 
@@ -1401,6 +1402,7 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 	int32_t pipe_profile)
 {
 	struct rte_sched_subport *s;
+	struct rte_sched_subport_profile *sp;
 	struct rte_sched_pipe *p;
 	struct rte_sched_pipe_profile *params;
 	uint32_t n_subports = subport_id + 1;
@@ -1441,14 +1443,15 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 		return -EINVAL;
 	}
 
+	sp = port->subport_profiles + s->profile;
 	/* Handle the case when pipe already has a valid configuration */
 	p = s->pipe + pipe_id;
 	if (p->tb_time) {
 		params = s->pipe_profiles + p->profile;
 
 		double subport_tc_be_rate =
-			(double) s->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
-			/ (double) s->tc_period;
+		(double)sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
+			/ (double) sp->tc_period;
 		double pipe_tc_be_rate =
 			(double) params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
 			/ (double) params->tc_period;
@@ -1490,8 +1493,8 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 	{
 		/* Subport best effort tc oversubscription */
 		double subport_tc_be_rate =
-			(double) s->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
-			/ (double) s->tc_period;
+		(double)sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
+			/ (double) sp->tc_period;
 		double pipe_tc_be_rate =
 			(double) params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
 			/ (double) params->tc_period;
@@ -2279,14 +2282,15 @@ grinder_credits_update(struct rte_sched_port *port,
 	struct rte_sched_grinder *grinder = subport->grinder + pos;
 	struct rte_sched_pipe *pipe = grinder->pipe;
 	struct rte_sched_pipe_profile *params = grinder->pipe_params;
+	struct rte_sched_subport_profile *sp = grinder->subport_params;
 	uint64_t n_periods;
 	uint32_t i;
 
 	/* Subport TB */
-	n_periods = (port->time - subport->tb_time) / subport->tb_period;
-	subport->tb_credits += n_periods * subport->tb_credits_per_period;
-	subport->tb_credits = RTE_MIN(subport->tb_credits, subport->tb_size);
-	subport->tb_time += n_periods * subport->tb_period;
+	n_periods = (port->time - subport->tb_time) / sp->tb_period;
+	subport->tb_credits += n_periods * sp->tb_credits_per_period;
+	subport->tb_credits = RTE_MIN(subport->tb_credits, sp->tb_size);
+	subport->tb_time += n_periods * sp->tb_period;
 
 	/* Pipe TB */
 	n_periods = (port->time - pipe->tb_time) / params->tb_period;
@@ -2297,9 +2301,9 @@ grinder_credits_update(struct rte_sched_port *port,
 	/* Subport TCs */
 	if (unlikely(port->time >= subport->tc_time)) {
 		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-			subport->tc_credits[i] = subport->tc_credits_per_period[i];
+			subport->tc_credits[i] = sp->tc_credits_per_period[i];
 
-		subport->tc_time = port->time + subport->tc_period;
+		subport->tc_time = port->time + sp->tc_period;
 	}
 
 	/* Pipe TCs */
@@ -2315,8 +2319,10 @@ grinder_credits_update(struct rte_sched_port *port,
 
 static inline uint64_t
 grinder_tc_ov_credits_update(struct rte_sched_port *port,
-	struct rte_sched_subport *subport)
+	struct rte_sched_subport *subport, uint32_t pos)
 {
+	struct rte_sched_grinder *grinder = subport->grinder + pos;
+	struct rte_sched_subport_profile *sp = grinder->subport_params;
 	uint64_t tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
 	uint64_t tc_consumption = 0, tc_ov_consumption_max;
 	uint64_t tc_ov_wm = subport->tc_ov_wm;
@@ -2326,17 +2332,17 @@ grinder_tc_ov_credits_update(struct rte_sched_port *port,
 		return subport->tc_ov_wm_max;
 
 	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASS_BE; i++) {
-		tc_ov_consumption[i] =
-			subport->tc_credits_per_period[i] - subport->tc_credits[i];
+		tc_ov_consumption[i] = sp->tc_credits_per_period[i]
+					-  subport->tc_credits[i];
 		tc_consumption += tc_ov_consumption[i];
 	}
 
 	tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] =
-		subport->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
+	sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
 		subport->tc_credits[RTE_SCHED_TRAFFIC_CLASS_BE];
 
 	tc_ov_consumption_max =
-		subport->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
+	sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
 			tc_consumption;
 
 	if (tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] >
@@ -2362,14 +2368,15 @@ grinder_credits_update(struct rte_sched_port *port,
 	struct rte_sched_grinder *grinder = subport->grinder + pos;
 	struct rte_sched_pipe *pipe = grinder->pipe;
 	struct rte_sched_pipe_profile *params = grinder->pipe_params;
+	struct rte_sched_subport_profile *sp = grinder->subport_params;
 	uint64_t n_periods;
 	uint32_t i;
 
 	/* Subport TB */
-	n_periods = (port->time - subport->tb_time) / subport->tb_period;
-	subport->tb_credits += n_periods * subport->tb_credits_per_period;
-	subport->tb_credits = RTE_MIN(subport->tb_credits, subport->tb_size);
-	subport->tb_time += n_periods * subport->tb_period;
+	n_periods = (port->time - subport->tb_time) / sp->tb_period;
+	subport->tb_credits += n_periods * sp->tb_credits_per_period;
+	subport->tb_credits = RTE_MIN(subport->tb_credits, sp->tb_size);
+	subport->tb_time += n_periods * sp->tb_period;
 
 	/* Pipe TB */
 	n_periods = (port->time - pipe->tb_time) / params->tb_period;
@@ -2379,12 +2386,13 @@ grinder_credits_update(struct rte_sched_port *port,
 
 	/* Subport TCs */
 	if (unlikely(port->time >= subport->tc_time)) {
-		subport->tc_ov_wm = grinder_tc_ov_credits_update(port, subport);
+		subport->tc_ov_wm =
+			grinder_tc_ov_credits_update(port, subport, pos);
 
 		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-			subport->tc_credits[i] = subport->tc_credits_per_period[i];
+			subport->tc_credits[i] = sp->tc_credits_per_period[i];
 
-		subport->tc_time = port->time + subport->tc_period;
+		subport->tc_time = port->time + sp->tc_period;
 		subport->tc_ov_period_id++;
 	}
 
@@ -2907,6 +2915,9 @@ grinder_handle(struct rte_sched_port *port,
 		struct rte_sched_pipe *pipe = grinder->pipe;
 
 		grinder->pipe_params = subport->pipe_profiles + pipe->profile;
+		grinder->subport_params = port->subport_profiles +
+						subport->profile;
+
 		grinder_prefetch_tc_queue_arrays(subport, pos);
 		grinder_credits_update(port, subport, pos);
 
-- 
2.7.4


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

* [dpdk-dev] [PATCH v4 5/9] example/qos_sched: add dynamic config of subport
  2020-09-17  8:42         ` [dpdk-dev] [PATCH v4 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
                             ` (3 preceding siblings ...)
  2020-09-17  8:42           ` [dpdk-dev] [PATCH v4 4/9] sched: update grinder credit and pipe config function Savinay Dharmappa
@ 2020-09-17  8:42           ` Savinay Dharmappa
  2020-09-17  8:42           ` [dpdk-dev] [PATCH v4 6/9] example/ip_pipeline: " Savinay Dharmappa
                             ` (4 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-17  8:42 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Modify the qos_sched application to build the hierarchical scheduler
with default subport bandwidth profile. It also allows to configure
a subport with different subport bandwidth profile dynamically.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 examples/qos_sched/cfg_file.c  | 151 ++++++++++++++++++++++++-----------------
 examples/qos_sched/cfg_file.h  |   4 ++
 examples/qos_sched/init.c      |  24 +++++--
 examples/qos_sched/main.h      |   1 +
 examples/qos_sched/profile.cfg |   3 +
 5 files changed, 115 insertions(+), 68 deletions(-)

diff --git a/examples/qos_sched/cfg_file.c b/examples/qos_sched/cfg_file.c
index f078e4f..cd167bd 100644
--- a/examples/qos_sched/cfg_file.c
+++ b/examples/qos_sched/cfg_file.c
@@ -143,6 +143,93 @@ cfg_load_pipe(struct rte_cfgfile *cfg, struct rte_sched_pipe_params *pipe_params
 }
 
 int
+cfg_load_subport_profile(struct rte_cfgfile *cfg,
+	struct rte_sched_subport_profile_params *subport_profile)
+{
+	int i;
+	const char *entry;
+	int profiles;
+
+	if (!cfg || !subport_profile)
+		return -1;
+
+	profiles = rte_cfgfile_num_sections(cfg, "subport profile",
+					   sizeof("subport profile") - 1);
+	subport_params[0].n_pipe_profiles = profiles;
+
+	for (i = 0; i < profiles; i++) {
+		char sec_name[32];
+		snprintf(sec_name, sizeof(sec_name), "subport profile %d", i);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tb rate");
+		if (entry)
+			subport_profile[i].tb_rate = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tb size");
+		if (entry)
+			subport_profile[i].tb_size = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc period");
+		if (entry)
+			subport_profile[i].tc_period = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 0 rate");
+		if (entry)
+			subport_profile[i].tc_rate[0] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 1 rate");
+		if (entry)
+			subport_profile[i].tc_rate[1] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 2 rate");
+		if (entry)
+			subport_profile[i].tc_rate[2] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 3 rate");
+		if (entry)
+			subport_profile[i].tc_rate[3] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 4 rate");
+		if (entry)
+			subport_profile[i].tc_rate[4] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 5 rate");
+		if (entry)
+			subport_profile[i].tc_rate[5] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 6 rate");
+		if (entry)
+			subport_profile[i].tc_rate[6] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 7 rate");
+		if (entry)
+			subport_profile[i].tc_rate[7] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 8 rate");
+		if (entry)
+			subport_profile[i].tc_rate[8] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 9 rate");
+		if (entry)
+			subport_profile[i].tc_rate[9] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 10 rate");
+		if (entry)
+			subport_profile[i].tc_rate[10] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 11 rate");
+		if (entry)
+			subport_profile[i].tc_rate[11] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 12 rate");
+		if (entry)
+			subport_profile[i].tc_rate[12] = (uint64_t)atoi(entry);
+	}
+
+	return 0;
+}
+
+int
 cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subport_params)
 {
 	const char *entry;
@@ -267,70 +354,6 @@ cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subpo
 				}
 			}
 
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tb rate");
-			if (entry)
-				subport_params[i].tb_rate = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tb size");
-			if (entry)
-				subport_params[i].tb_size = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc period");
-			if (entry)
-				subport_params[i].tc_period = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 0 rate");
-			if (entry)
-				subport_params[i].tc_rate[0] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 1 rate");
-			if (entry)
-				subport_params[i].tc_rate[1] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 2 rate");
-			if (entry)
-				subport_params[i].tc_rate[2] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 3 rate");
-			if (entry)
-				subport_params[i].tc_rate[3] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 4 rate");
-			if (entry)
-				subport_params[i].tc_rate[4] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 5 rate");
-			if (entry)
-				subport_params[i].tc_rate[5] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 6 rate");
-			if (entry)
-				subport_params[i].tc_rate[6] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 7 rate");
-			if (entry)
-				subport_params[i].tc_rate[7] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 8 rate");
-			if (entry)
-				subport_params[i].tc_rate[8] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 9 rate");
-			if (entry)
-				subport_params[i].tc_rate[9] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 10 rate");
-			if (entry)
-				subport_params[i].tc_rate[10] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 11 rate");
-			if (entry)
-				subport_params[i].tc_rate[11] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 12 rate");
-			if (entry)
-				subport_params[i].tc_rate[12] = (uint64_t)atoi(entry);
-
 			int n_entries = rte_cfgfile_section_num_entries(cfg, sec_name);
 			struct rte_cfgfile_entry entries[n_entries];
 
diff --git a/examples/qos_sched/cfg_file.h b/examples/qos_sched/cfg_file.h
index 2eccf1c..0dc458a 100644
--- a/examples/qos_sched/cfg_file.h
+++ b/examples/qos_sched/cfg_file.h
@@ -14,4 +14,8 @@ int cfg_load_pipe(struct rte_cfgfile *cfg, struct rte_sched_pipe_params *pipe);
 
 int cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subport);
 
+int cfg_load_subport_profile(struct rte_cfgfile *cfg,
+			     struct rte_sched_subport_profile_params
+			     *subport_profile);
+
 #endif
diff --git a/examples/qos_sched/init.c b/examples/qos_sched/init.c
index 9626c15..541adb7 100644
--- a/examples/qos_sched/init.c
+++ b/examples/qos_sched/init.c
@@ -196,15 +196,20 @@ static struct rte_sched_pipe_params pipe_profiles[MAX_SCHED_PIPE_PROFILES] = {
 	},
 };
 
-struct rte_sched_subport_params subport_params[MAX_SCHED_SUBPORTS] = {
+static struct rte_sched_subport_profile_params
+		subport_profile[MAX_SCHED_SUBPORT_PROFILES] = {
 	{
 		.tb_rate = 1250000000,
 		.tb_size = 1000000,
-
 		.tc_rate = {1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000},
 		.tc_period = 10,
+	},
+};
+
+struct rte_sched_subport_params subport_params[MAX_SCHED_SUBPORTS] = {
+	{
 		.n_pipes_per_subport_enabled = 4096,
 		.qsize = {64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64},
 		.pipe_profiles = pipe_profiles,
@@ -289,6 +294,9 @@ struct rte_sched_port_params port_params = {
 	.mtu = 6 + 6 + 4 + 4 + 2 + 1500,
 	.frame_overhead = RTE_SCHED_FRAME_OVERHEAD_DEFAULT,
 	.n_subports_per_port = 1,
+	.n_subport_profiles = 1,
+	.subport_profiles = subport_profile,
+	.n_max_subport_profiles = MAX_SCHED_SUBPORT_PROFILES,
 	.n_pipes_per_subport = MAX_SCHED_PIPES,
 };
 
@@ -320,8 +328,15 @@ app_init_sched_port(uint32_t portid, uint32_t socketid)
 	for (subport = 0; subport < port_params.n_subports_per_port; subport ++) {
 		err = rte_sched_subport_config(port, subport, &subport_params[subport]);
 		if (err) {
-			rte_exit(EXIT_FAILURE, "Unable to config sched subport %u, err=%d\n",
-					subport, err);
+			rte_exit(EXIT_FAILURE, "Unable to config schedi "
+				"subport %u, err=%d\n", subport, err);
+		}
+
+		err = rte_sched_subport_profile_config(port, subport, 0);
+		if (err) {
+			rte_exit(EXIT_FAILURE, "failed to configure "
+				"profile err=%d\n", err);
+
 		}
 
 		uint32_t n_pipes_per_subport =
@@ -354,6 +369,7 @@ app_load_cfg_profile(const char *profile)
 
 	cfg_load_port(file, &port_params);
 	cfg_load_subport(file, subport_params);
+	cfg_load_subport_profile(file, subport_profile);
 	cfg_load_pipe(file, pipe_profiles);
 
 	rte_cfgfile_close(file);
diff --git a/examples/qos_sched/main.h b/examples/qos_sched/main.h
index 23bc418..0d6815a 100644
--- a/examples/qos_sched/main.h
+++ b/examples/qos_sched/main.h
@@ -51,6 +51,7 @@ extern "C" {
 #define MAX_SCHED_SUBPORTS		8
 #define MAX_SCHED_PIPES		4096
 #define MAX_SCHED_PIPE_PROFILES		256
+#define MAX_SCHED_SUBPORT_PROFILES	8
 
 #ifndef APP_COLLECT_STAT
 #define APP_COLLECT_STAT		1
diff --git a/examples/qos_sched/profile.cfg b/examples/qos_sched/profile.cfg
index 61b8b70..4486d27 100644
--- a/examples/qos_sched/profile.cfg
+++ b/examples/qos_sched/profile.cfg
@@ -26,6 +26,9 @@ number of subports per port = 1
 number of pipes per subport = 4096
 queue sizes = 64 64 64 64 64 64 64 64 64 64 64 64 64
 
+subport 0-8 = 0                ; These subports are configured with subport profile 0
+
+[subport profile 0]
 tb rate = 1250000000           ; Bytes per second
 tb size = 1000000              ; Bytes
 
-- 
2.7.4


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

* [dpdk-dev] [PATCH v4 6/9] example/ip_pipeline: add dynamic config of subport
  2020-09-17  8:42         ` [dpdk-dev] [PATCH v4 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
                             ` (4 preceding siblings ...)
  2020-09-17  8:42           ` [dpdk-dev] [PATCH v4 5/9] example/qos_sched: add dynamic config of subport Savinay Dharmappa
@ 2020-09-17  8:42           ` Savinay Dharmappa
  2020-09-29 21:23             ` Dumitrescu, Cristian
  2020-09-17  8:42           ` [dpdk-dev] [PATCH v4 7/9] drivers/softnic: " Savinay Dharmappa
                             ` (3 subsequent siblings)
  9 siblings, 1 reply; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-17  8:42 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Modify the ip_pipeline application to build the hierarchical scheduler
with default subport bandwidth profile. It also allows to configure
a subport with different subport bandwidth profile dynamically

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 examples/ip_pipeline/cli.c  | 14 ++++++++------
 examples/ip_pipeline/tmgr.c | 26 ++++++++++++++++++++++++--
 examples/ip_pipeline/tmgr.h |  3 ++-
 3 files changed, 34 insertions(+), 9 deletions(-)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index d79699e..7eccde3 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -407,6 +407,7 @@ cmd_tmgr_subport_profile(char **tokens,
 	size_t out_size)
 {
 	struct rte_sched_subport_params p;
+	struct rte_sched_subport_profile_params pp;
 	int status, i;
 
 	if (n_tokens != 35) {
@@ -414,23 +415,23 @@ cmd_tmgr_subport_profile(char **tokens,
 		return;
 	}
 
-	if (parser_read_uint64(&p.tb_rate, tokens[3]) != 0) {
+	if (parser_read_uint64(&pp.tb_rate, tokens[3]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
 		return;
 	}
 
-	if (parser_read_uint64(&p.tb_size, tokens[4]) != 0) {
+	if (parser_read_uint64(&pp.tb_size, tokens[4]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
 		return;
 	}
 
 	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-		if (parser_read_uint64(&p.tc_rate[i], tokens[5 + i]) != 0) {
+		if (parser_read_uint64(&pp.tc_rate[i], tokens[5 + i]) != 0) {
 			snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
 			return;
 		}
 
-	if (parser_read_uint64(&p.tc_period, tokens[18]) != 0) {
+	if (parser_read_uint64(&pp.tc_period, tokens[18]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
 		return;
 	}
@@ -440,7 +441,8 @@ cmd_tmgr_subport_profile(char **tokens,
 		return;
 	}
 
-	if (parser_read_uint32(&p.n_pipes_per_subport_enabled, tokens[20]) != 0) {
+	if (parser_read_uint32(&p.n_pipes_per_subport_enabled,
+		tokens[20]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport");
 		return;
 	}
@@ -456,7 +458,7 @@ cmd_tmgr_subport_profile(char **tokens,
 			return;
 		}
 
-	status = tmgr_subport_profile_add(&p);
+	status = tmgr_subport_profile_add(&p, &pp);
 	if (status != 0) {
 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
 		return;
diff --git a/examples/ip_pipeline/tmgr.c b/examples/ip_pipeline/tmgr.c
index 91ccbf6..5c3df92 100644
--- a/examples/ip_pipeline/tmgr.c
+++ b/examples/ip_pipeline/tmgr.c
@@ -11,6 +11,9 @@
 static struct rte_sched_subport_params
 	subport_profile[TMGR_SUBPORT_PROFILE_MAX];
 
+static struct rte_sched_subport_profile_params
+		profile_params[TMGR_SUBPORT_PROFILE_MAX];
+
 static uint32_t n_subport_profiles;
 
 static struct rte_sched_pipe_params
@@ -44,10 +47,11 @@ tmgr_port_find(const char *name)
 }
 
 int
-tmgr_subport_profile_add(struct rte_sched_subport_params *p)
+tmgr_subport_profile_add(struct rte_sched_subport_params *p,
+			 struct rte_sched_subport_profile_params *pp)
 {
 	/* Check input params */
-	if (p == NULL ||
+	if (p == NULL || pp == NULL ||
 		p->n_pipes_per_subport_enabled == 0)
 		return -1;
 
@@ -56,6 +60,10 @@ tmgr_subport_profile_add(struct rte_sched_subport_params *p)
 		p,
 		sizeof(*p));
 
+	memcpy(&profile_params[n_subport_profiles],
+		pp,
+		sizeof(*pp));
+
 	n_subport_profiles++;
 
 	return 0;
@@ -103,6 +111,9 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 	p.mtu = params->mtu;
 	p.frame_overhead = params->frame_overhead;
 	p.n_subports_per_port = params->n_subports_per_port;
+	p.n_subport_profiles = n_subport_profiles;
+	p.subport_profiles = profile_params;
+	p.n_max_subport_profiles = TMGR_SUBPORT_PROFILE_MAX;
 	p.n_pipes_per_subport = TMGR_PIPE_SUBPORT_MAX;
 
 	s = rte_sched_port_config(&p);
@@ -126,6 +137,13 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 			return NULL;
 		}
 
+		status = rte_sched_subport_profile_config(s, i, 0);
+
+		if (status) {
+			rte_sched_port_free(s);
+			return NULL;
+		}
+
 		for (j = 0; j < subport_profile[0].n_pipes_per_subport_enabled; j++) {
 			status = rte_sched_pipe_config(
 				s,
@@ -182,6 +200,10 @@ tmgr_subport_config(const char *port_name,
 		subport_id,
 		&subport_profile[subport_profile_id]);
 
+	if (!status)
+		status = rte_sched_subport_profile_config(port->s, subport_id,
+							subport_profile_id);
+
 	return status;
 }
 
diff --git a/examples/ip_pipeline/tmgr.h b/examples/ip_pipeline/tmgr.h
index ee50cf7..8c14523 100644
--- a/examples/ip_pipeline/tmgr.h
+++ b/examples/ip_pipeline/tmgr.h
@@ -48,7 +48,8 @@ struct tmgr_port_params {
 };
 
 int
-tmgr_subport_profile_add(struct rte_sched_subport_params *p);
+tmgr_subport_profile_add(struct rte_sched_subport_params *p,
+			 struct rte_sched_subport_profile_params *pp);
 
 int
 tmgr_pipe_profile_add(struct rte_sched_pipe_params *p);
-- 
2.7.4


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

* [dpdk-dev] [PATCH v4 7/9] drivers/softnic: add dynamic config of subport
  2020-09-17  8:42         ` [dpdk-dev] [PATCH v4 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
                             ` (5 preceding siblings ...)
  2020-09-17  8:42           ` [dpdk-dev] [PATCH v4 6/9] example/ip_pipeline: " Savinay Dharmappa
@ 2020-09-17  8:42           ` Savinay Dharmappa
  2020-09-17  8:42           ` [dpdk-dev] [PATCH v4 8/9] app/test_sched: " Savinay Dharmappa
                             ` (2 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-17  8:42 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Modify the softnic drivers to build the hierarchical scheduler
with default subport bandwidth profile. It also allows to configure
a subport with different subport bandwidth profile dynamically.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 drivers/net/softnic/rte_eth_softnic_internals.h |   9 +
 drivers/net/softnic/rte_eth_softnic_tm.c        | 223 +++++++++++++++++++-----
 2 files changed, 187 insertions(+), 45 deletions(-)

diff --git a/drivers/net/softnic/rte_eth_softnic_internals.h b/drivers/net/softnic/rte_eth_softnic_internals.h
index 6eec43b..cc50037 100644
--- a/drivers/net/softnic/rte_eth_softnic_internals.h
+++ b/drivers/net/softnic/rte_eth_softnic_internals.h
@@ -164,10 +164,19 @@ TAILQ_HEAD(softnic_link_list, softnic_link);
 #ifndef TM_MAX_PIPE_PROFILE
 #define TM_MAX_PIPE_PROFILE				256
 #endif
+
+#ifndef TM_MAX_SUBPORT_PROFILE
+#define TM_MAX_SUBPORT_PROFILE				256
+#endif
+
 struct tm_params {
 	struct rte_sched_port_params port_params;
 
 	struct rte_sched_subport_params subport_params[TM_MAX_SUBPORTS];
+	struct rte_sched_subport_profile_params
+				subport_profiles[TM_MAX_SUBPORT_PROFILE];
+	uint32_t n_subport_profiles;
+	uint32_t subport_to_profile[TM_MAX_SUBPORT_PROFILE];
 
 	struct rte_sched_pipe_params pipe_profiles[TM_MAX_PIPE_PROFILE];
 	uint32_t n_pipe_profiles;
diff --git a/drivers/net/softnic/rte_eth_softnic_tm.c b/drivers/net/softnic/rte_eth_softnic_tm.c
index 80a470c..a223655 100644
--- a/drivers/net/softnic/rte_eth_softnic_tm.c
+++ b/drivers/net/softnic/rte_eth_softnic_tm.c
@@ -98,6 +98,13 @@ softnic_tmgr_port_create(struct pmd_internals *p,
 			return NULL;
 		}
 
+		status = rte_sched_subport_profile_config(sched,
+			subport_id, t->subport_to_profile[subport_id]);
+		if (status) {
+			rte_sched_port_free(sched);
+			return NULL;
+		}
+
 		/* Pipe */
 		for (pipe_id = 0; pipe_id < n_pipes_per_subport; pipe_id++) {
 			int pos = subport_id * TM_MAX_PIPES_PER_SUBPORT + pipe_id;
@@ -1043,6 +1050,25 @@ tm_shared_shaper_get_tc(struct rte_eth_dev *dev,
 }
 
 static int
+subport_profile_exists(struct rte_eth_dev *dev,
+	struct rte_sched_subport_profile_params *sp,
+	uint32_t *subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+	uint32_t i;
+
+	for (i = 0; i < t->n_subport_profiles; i++)
+		if (memcmp(&t->subport_profiles[i], sp, sizeof(*sp)) == 0) {
+			if (subport_profile_id)
+				*subport_profile_id = i;
+			return 1;
+		}
+
+	return 0;
+}
+
+static int
 update_subport_tc_rate(struct rte_eth_dev *dev,
 	struct tm_node *nt,
 	struct tm_shared_shaper *ss,
@@ -1050,26 +1076,27 @@ update_subport_tc_rate(struct rte_eth_dev *dev,
 {
 	struct pmd_internals *p = dev->data->dev_private;
 	uint32_t tc_id = tm_node_tc_id(dev, nt);
-
 	struct tm_node *np = nt->parent_node;
-
 	struct tm_node *ns = np->parent_node;
 	uint32_t subport_id = tm_node_subport_id(dev, ns);
-
-	struct rte_sched_subport_params subport_params;
-
+	struct rte_sched_subport_profile_params subport_profile;
 	struct tm_shaper_profile *sp_old = tm_shaper_profile_search(dev,
 		ss->shaper_profile_id);
+	uint32_t subport_profile_id;
 
 	/* Derive new subport configuration. */
-	memcpy(&subport_params,
-		&p->soft.tm.params.subport_params[subport_id],
-		sizeof(subport_params));
-	subport_params.tc_rate[tc_id] = sp_new->params.peak.rate;
+	memcpy(&subport_profile,
+		&p->soft.tm.params.subport_profiles[subport_id],
+		sizeof(subport_profile));
+	subport_profile.tc_rate[tc_id] = sp_new->params.peak.rate;
+
+	if (subport_profile_exists(dev, &subport_profile,
+				  &subport_profile_id) == 0)
+		return -1;
 
 	/* Update the subport configuration. */
-	if (rte_sched_subport_config(SCHED(p),
-		subport_id, &subport_params))
+	if (rte_sched_subport_profile_config(SCHED(p),
+		subport_id, subport_profile_id))
 		return -1;
 
 	/* Commit changes. */
@@ -1078,9 +1105,9 @@ update_subport_tc_rate(struct rte_eth_dev *dev,
 	ss->shaper_profile_id = sp_new->shaper_profile_id;
 	sp_new->n_users++;
 
-	memcpy(&p->soft.tm.params.subport_params[subport_id],
-		&subport_params,
-		sizeof(subport_params));
+	memcpy(&p->soft.tm.params.subport_profiles[subport_id],
+		&subport_profile,
+		sizeof(subport_profile));
 
 	return 0;
 }
@@ -2190,6 +2217,108 @@ pipe_profiles_generate(struct rte_eth_dev *dev)
 	return 0;
 }
 
+static struct rte_sched_subport_profile_params *
+subport_profile_get(struct rte_eth_dev *dev, struct tm_node *np)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+	uint32_t subport_id = tm_node_subport_id(dev, np->parent_node);
+
+	return &t->subport_profiles[subport_id];
+}
+
+static void
+subport_profile_mark(struct rte_eth_dev *dev,
+	uint32_t subport_id,
+	uint32_t subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+
+	t->subport_to_profile[subport_id] = subport_profile_id;
+}
+
+static void
+subport_profile_install(struct rte_eth_dev *dev,
+	struct rte_sched_subport_profile_params *sp,
+	uint32_t subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+
+	memcpy(&t->subport_profiles[subport_profile_id], sp, sizeof(*sp));
+	t->n_subport_profiles++;
+}
+
+static int
+subport_profile_free_exists(struct rte_eth_dev *dev,
+	uint32_t *subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+
+	if (t->n_subport_profiles < TM_MAX_SUBPORT_PROFILE) {
+		*subport_profile_id = t->n_subport_profiles;
+		return 1;
+	}
+
+	return 0;
+}
+
+static void
+subport_profile_build(struct tm_node *np,
+	struct rte_sched_subport_profile_params *sp)
+{
+	memset(sp, 0, sizeof(*sp));
+
+	/* Pipe */
+	sp->tb_rate = np->shaper_profile->params.peak.rate;
+	sp->tb_size = np->shaper_profile->params.peak.size;
+
+	/* Traffic Class (TC) */
+	sp->tc_period = SUBPORT_TC_PERIOD;
+}
+
+static int
+subport_profiles_generate(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_hierarchy *h = &p->soft.tm.h;
+	struct tm_node_list *nl = &h->nodes;
+	struct tm_node *ns;
+	uint32_t subport_id;
+
+	/* Objective: Fill in the following fields in struct tm_params:
+	 *    - subport_profiles
+	 *    - n_subport_profiles
+	 *    - subport_to_profile
+	 */
+
+	subport_id = 0;
+	TAILQ_FOREACH(ns, nl, node) {
+		if (ns->level != TM_NODE_LEVEL_SUBPORT)
+			continue;
+
+		struct rte_sched_subport_profile_params sp;
+		uint32_t pos;
+
+		subport_profile_build(ns, &sp);
+
+		if (!subport_profile_exists(dev, &sp, &pos)) {
+			if (!subport_profile_free_exists(dev, &pos))
+				return -1;
+
+			subport_profile_install(dev, &sp, pos);
+		}
+
+		subport_profile_mark(dev, subport_id, pos);
+
+		subport_id++;
+	}
+
+	return 0;
+}
+
 static struct tm_wred_profile *
 tm_tc_wred_profile_get(struct rte_eth_dev *dev, uint32_t tc_id)
 {
@@ -2447,6 +2576,15 @@ hierarchy_commit_check(struct rte_eth_dev *dev, struct rte_tm_error *error)
 				rte_strerror(EINVAL));
 	}
 
+	/* Not too many subport profiles. */
+	if (subport_profiles_generate(dev))
+		return -rte_tm_error_set(error,
+			EINVAL,
+			RTE_TM_ERROR_TYPE_UNSPECIFIED,
+			NULL,
+			rte_strerror(EINVAL));
+
+
 	/* Not too many pipe profiles. */
 	if (pipe_profiles_generate(dev))
 		return -rte_tm_error_set(error,
@@ -2528,6 +2666,9 @@ hierarchy_blueprints_create(struct rte_eth_dev *dev)
 		.frame_overhead =
 			root->shaper_profile->params.pkt_length_adjust,
 		.n_subports_per_port = root->n_children,
+		.n_subport_profiles = t->n_subport_profiles,
+		.subport_profiles = t->subport_profiles,
+		.n_max_subport_profiles = TM_MAX_SUBPORT_PROFILE,
 		.n_pipes_per_subport = TM_MAX_PIPES_PER_SUBPORT,
 	};
 
@@ -2548,28 +2689,11 @@ hierarchy_blueprints_create(struct rte_eth_dev *dev)
 				ss->shaper_profile_id) :
 				n->shaper_profile;
 			tc_rate[i] = sp->params.peak.rate;
+			t->subport_profiles[subport_id].tc_rate[i] = tc_rate[i];
 		}
 
 		t->subport_params[subport_id] =
 			(struct rte_sched_subport_params) {
-				.tb_rate = n->shaper_profile->params.peak.rate,
-				.tb_size = n->shaper_profile->params.peak.size,
-
-				.tc_rate = {tc_rate[0],
-					tc_rate[1],
-					tc_rate[2],
-					tc_rate[3],
-					tc_rate[4],
-					tc_rate[5],
-					tc_rate[6],
-					tc_rate[7],
-					tc_rate[8],
-					tc_rate[9],
-					tc_rate[10],
-					tc_rate[11],
-					tc_rate[12],
-				},
-				.tc_period = SUBPORT_TC_PERIOD,
 				.n_pipes_per_subport_enabled =
 					h->n_tm_nodes[TM_NODE_LEVEL_PIPE] /
 					h->n_tm_nodes[TM_NODE_LEVEL_SUBPORT],
@@ -2829,30 +2953,39 @@ update_subport_rate(struct rte_eth_dev *dev,
 	struct pmd_internals *p = dev->data->dev_private;
 	uint32_t subport_id = tm_node_subport_id(dev, ns);
 
-	struct rte_sched_subport_params subport_params;
+	struct rte_sched_subport_profile_params *profile0 =
+					subport_profile_get(dev, ns);
+	struct rte_sched_subport_profile_params profile1;
+	uint32_t subport_profile_id;
 
-	/* Derive new subport configuration. */
-	memcpy(&subport_params,
-		&p->soft.tm.params.subport_params[subport_id],
-		sizeof(subport_params));
-	subport_params.tb_rate = sp->params.peak.rate;
-	subport_params.tb_size = sp->params.peak.size;
+	/* Derive new pipe profile. */
+	memcpy(&profile1, profile0, sizeof(profile1));
+	profile1.tb_rate = sp->params.peak.rate;
+	profile1.tb_size = sp->params.peak.size;
+
+	/* Since implementation does not allow adding more subport profiles
+	 * after port configuration, the pipe configuration can be successfully
+	 * updated only if the new profile is also part of the existing set of
+	 * pipe profiles.
+	 */
+	if (subport_profile_exists(dev, &profile1, &subport_profile_id) == 0)
+		return -1;
 
 	/* Update the subport configuration. */
-	if (rte_sched_subport_config(SCHED(p), subport_id,
-		&subport_params))
+	if (rte_sched_subport_profile_config(SCHED(p), subport_id,
+		subport_profile_id))
 		return -1;
 
+	subport_profile_mark(dev, subport_id, subport_profile_id);
 	/* Commit changes. */
 	ns->shaper_profile->n_users--;
-
 	ns->shaper_profile = sp;
 	ns->params.shaper_profile_id = sp->shaper_profile_id;
 	sp->n_users++;
 
-	memcpy(&p->soft.tm.params.subport_params[subport_id],
-		&subport_params,
-		sizeof(subport_params));
+	memcpy(&p->soft.tm.params.subport_profiles[subport_id],
+		&profile1,
+		sizeof(profile1));
 
 	return 0;
 }
-- 
2.7.4


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

* [dpdk-dev] [PATCH v4 8/9] app/test_sched: add dynamic config of subport
  2020-09-17  8:42         ` [dpdk-dev] [PATCH v4 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
                             ` (6 preceding siblings ...)
  2020-09-17  8:42           ` [dpdk-dev] [PATCH v4 7/9] drivers/softnic: " Savinay Dharmappa
@ 2020-09-17  8:42           ` Savinay Dharmappa
  2020-09-17  8:42           ` [dpdk-dev] [PATCH v4 9/9] sched: remove the redundant code Savinay Dharmappa
  2020-09-30 19:24           ` [dpdk-dev] [PATCH v5 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-17  8:42 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Modify the test_sched application to build the hierarchical scheduler
with default subport bandwidth profile. It also allows to configure
a subport with different subport bandwidth profile dynamically

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 app/test/test_sched.c | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)

diff --git a/app/test/test_sched.c b/app/test/test_sched.c
index fc31080..8d1eb25 100644
--- a/app/test/test_sched.c
+++ b/app/test/test_sched.c
@@ -21,6 +21,7 @@
 #define PIPE            1
 #define TC              2
 #define QUEUE           0
+#define MAX_SCHED_SUBPORT_PROFILES  8
 
 static struct rte_sched_pipe_params pipe_profile[] = {
 	{ /* Profile #0 */
@@ -36,15 +37,20 @@ static struct rte_sched_pipe_params pipe_profile[] = {
 	},
 };
 
-static struct rte_sched_subport_params subport_param[] = {
+static struct rte_sched_subport_profile_params
+		subport_profile[] = {
 	{
 		.tb_rate = 1250000000,
 		.tb_size = 1000000,
-
 		.tc_rate = {1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000},
 		.tc_period = 10,
+	},
+};
+
+static struct rte_sched_subport_params subport_param[] = {
+	{
 		.n_pipes_per_subport_enabled = 1024,
 		.qsize = {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32},
 		.pipe_profiles = pipe_profile,
@@ -59,6 +65,9 @@ static struct rte_sched_port_params port_param = {
 	.mtu = 1522,
 	.frame_overhead = RTE_SCHED_FRAME_OVERHEAD_DEFAULT,
 	.n_subports_per_port = 1,
+	.n_subport_profiles = 1,
+	.subport_profiles = subport_profile,
+	.n_max_subport_profiles = MAX_SCHED_SUBPORT_PROFILES,
 	.n_pipes_per_subport = 1024,
 };
 
@@ -66,6 +75,7 @@ static struct rte_sched_port_params port_param = {
 #define MBUF_DATA_SZ     (2048 + RTE_PKTMBUF_HEADROOM)
 #define MEMPOOL_CACHE_SZ 0
 #define SOCKET           0
+#define DEFAULT_PROFILE  0
 
 
 static struct rte_mempool *
@@ -141,6 +151,10 @@ test_sched(void)
 	err = rte_sched_subport_config(port, SUBPORT, subport_param);
 	TEST_ASSERT_SUCCESS(err, "Error config sched, err=%d\n", err);
 
+	err = rte_sched_subport_profile_config(port, SUBPORT,
+						DEFAULT_PROFILE);
+	TEST_ASSERT_SUCCESS(err, "Error config sched, err=%d\n", err);
+
 	for (pipe = 0; pipe < subport_param[0].n_pipes_per_subport_enabled; pipe++) {
 		err = rte_sched_pipe_config(port, SUBPORT, pipe, 0);
 		TEST_ASSERT_SUCCESS(err, "Error config sched pipe %u, err=%d\n", pipe, err);
-- 
2.7.4


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

* [dpdk-dev] [PATCH v4 9/9] sched: remove the redundant code
  2020-09-17  8:42         ` [dpdk-dev] [PATCH v4 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
                             ` (7 preceding siblings ...)
  2020-09-17  8:42           ` [dpdk-dev] [PATCH v4 8/9] app/test_sched: " Savinay Dharmappa
@ 2020-09-17  8:42           ` Savinay Dharmappa
  2020-09-30 19:24           ` [dpdk-dev] [PATCH v5 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-17  8:42 UTC (permalink / raw)
  To: jasvinder.singh, cristian.dumitrescu, dev; +Cc: savinay.dharmappa

Remove redundant data structure fields references from
functions and subport level data structures. It also
update the release and deprecation note.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 doc/guides/rel_notes/deprecation.rst   |   6 --
 doc/guides/rel_notes/release_20_11.rst |   4 ++
 lib/librte_sched/rte_sched.c           | 115 +--------------------------------
 lib/librte_sched/rte_sched.h           |  12 ----
 4 files changed, 6 insertions(+), 131 deletions(-)

diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 1f888fa..72eb190 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -294,12 +294,6 @@ Deprecation Notices
   in "rte_sched.h". These changes are aligned to improvements suggested in the
   RFC https://mails.dpdk.org/archives/dev/2018-November/120035.html.
 
-* sched: To allow dynamic configuration of the subport bandwidth profile,
-  changes will be made to data structures ``rte_sched_subport_params``,
-  ``rte_sched_port_params`` and new data structure, API functions will be
-  defined in ``rte_sched.h``. These changes are aligned as suggested in the
-  RFC https://mails.dpdk.org/archives/dev/2020-July/175161.html
-
 * metrics: The function ``rte_metrics_init`` will have a non-void return
   in order to notify errors instead of calling ``rte_exit``.
 
diff --git a/doc/guides/rel_notes/release_20_11.rst b/doc/guides/rel_notes/release_20_11.rst
index cc72609..9b05913 100644
--- a/doc/guides/rel_notes/release_20_11.rst
+++ b/doc/guides/rel_notes/release_20_11.rst
@@ -68,6 +68,10 @@ Removed Items
    Also, make sure to start the actual text at the margin.
    =======================================================
 
+* sched: The subport bandwidth configuration parameters such as tb_rate,
+  tc_rate, tc_period etc., are moved from subport level data structure to
+  new a data structure. This allows to configure a subport with different
+  subport bandwidth configuration dynamically.
 
 API Changes
 -----------
diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index 3f61afa..6b6892d 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -152,16 +152,11 @@ struct rte_sched_grinder {
 struct rte_sched_subport {
 	/* Token bucket (TB) */
 	uint64_t tb_time; /* time of last update */
-	uint64_t tb_period;
-	uint64_t tb_credits_per_period;
-	uint64_t tb_size;
 	uint64_t tb_credits;
 
 	/* Traffic classes (TCs) */
 	uint64_t tc_time; /* time of next update */
-	uint64_t tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
 	uint64_t tc_credits[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
-	uint64_t tc_period;
 
 	/* TC oversubscription */
 	uint64_t tc_ov_wm;
@@ -837,18 +832,6 @@ rte_sched_subport_check_params(struct rte_sched_subport_params *params,
 		return -EINVAL;
 	}
 
-	if (params->tb_rate == 0 || params->tb_rate > rate) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect value for tb rate\n", __func__);
-		return -EINVAL;
-	}
-
-	if (params->tb_size == 0) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect value for tb size\n", __func__);
-		return -EINVAL;
-	}
-
 	/* qsize: if non-zero, power of 2,
 	 * no bigger than 32K (due to 16-bit read/write pointers)
 	 */
@@ -862,29 +845,8 @@ rte_sched_subport_check_params(struct rte_sched_subport_params *params,
 		}
 	}
 
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
-		uint64_t tc_rate = params->tc_rate[i];
-		uint16_t qsize = params->qsize[i];
-
-		if ((qsize == 0 && tc_rate != 0) ||
-			(qsize != 0 && tc_rate == 0) ||
-			(tc_rate > params->tb_rate)) {
-			RTE_LOG(ERR, SCHED,
-				"%s: Incorrect value for tc rate\n", __func__);
-			return -EINVAL;
-		}
-	}
-
-	if (params->qsize[RTE_SCHED_TRAFFIC_CLASS_BE] == 0 ||
-		params->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect qsize or tc rate(best effort)\n", __func__);
-		return -EINVAL;
-	}
-
-	if (params->tc_period == 0) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect value for tc period\n", __func__);
+	if (params->qsize[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
+		RTE_LOG(ERR, SCHED, "%s: Incorrect qsize\n", __func__);
 		return -EINVAL;
 	}
 
@@ -1101,48 +1063,6 @@ rte_sched_port_free(struct rte_sched_port *port)
 }
 
 static void
-rte_sched_port_log_subport_config(struct rte_sched_port *port, uint32_t i)
-{
-	struct rte_sched_subport *s = port->subports[i];
-
-	RTE_LOG(DEBUG, SCHED, "Low level config for subport %u:\n"
-		"	Token bucket: period = %"PRIu64", credits per period = %"PRIu64
-		", size = %"PRIu64"\n"
-		"	Traffic classes: period = %"PRIu64"\n"
-		"	credits per period = [%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
-		", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
-		", %"PRIu64", %"PRIu64", %"PRIu64"]\n"
-		"	Best effort traffic class oversubscription: wm min = %"PRIu64
-		", wm max = %"PRIu64"\n",
-		i,
-
-		/* Token bucket */
-		s->tb_period,
-		s->tb_credits_per_period,
-		s->tb_size,
-
-		/* Traffic classes */
-		s->tc_period,
-		s->tc_credits_per_period[0],
-		s->tc_credits_per_period[1],
-		s->tc_credits_per_period[2],
-		s->tc_credits_per_period[3],
-		s->tc_credits_per_period[4],
-		s->tc_credits_per_period[5],
-		s->tc_credits_per_period[6],
-		s->tc_credits_per_period[7],
-		s->tc_credits_per_period[8],
-		s->tc_credits_per_period[9],
-		s->tc_credits_per_period[10],
-		s->tc_credits_per_period[11],
-		s->tc_credits_per_period[12],
-
-		/* Best effort traffic class oversubscription */
-		s->tc_ov_wm_min,
-		s->tc_ov_wm_max);
-}
-
-static void
 rte_sched_free_memory(struct rte_sched_port *port, uint32_t n_subports)
 {
 	uint32_t i;
@@ -1215,33 +1135,7 @@ rte_sched_subport_config(struct rte_sched_port *port,
 	/* Port */
 	port->subports[subport_id] = s;
 
-	/* Token Bucket (TB) */
-	if (params->tb_rate == port->rate) {
-		s->tb_credits_per_period = 1;
-		s->tb_period = 1;
-	} else {
-		double tb_rate = ((double) params->tb_rate) / ((double) port->rate);
-		double d = RTE_SCHED_TB_RATE_CONFIG_ERR;
-
-		rte_approx_64(tb_rate, d, &s->tb_credits_per_period, &s->tb_period);
-	}
-
-	s->tb_size = params->tb_size;
 	s->tb_time = port->time;
-	s->tb_credits = s->tb_size / 2;
-
-	/* Traffic Classes (TCs) */
-	s->tc_period = rte_sched_time_ms_to_bytes(params->tc_period, port->rate);
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
-		if (params->qsize[i])
-			s->tc_credits_per_period[i]
-				= rte_sched_time_ms_to_bytes(params->tc_period,
-					params->tc_rate[i]);
-	}
-	s->tc_time = port->time + s->tc_period;
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-		if (params->qsize[i])
-			s->tc_credits[i] = s->tc_credits_per_period[i];
 
 	/* compile time checks */
 	RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS == 0);
@@ -1331,17 +1225,12 @@ rte_sched_subport_config(struct rte_sched_port *port,
 #ifdef RTE_SCHED_SUBPORT_TC_OV
 	/* TC oversubscription */
 	s->tc_ov_wm_min = port->mtu;
-	s->tc_ov_wm_max = rte_sched_time_ms_to_bytes(params->tc_period,
-						     s->pipe_tc_be_rate_max);
 	s->tc_ov_wm = s->tc_ov_wm_max;
 	s->tc_ov_period_id = 0;
 	s->tc_ov = 0;
 	s->tc_ov_n = 0;
 	s->tc_ov_rate = 0;
 #endif
-
-	rte_sched_port_log_subport_config(port, subport_id);
-
 	return 0;
 }
 
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index a7c2638..7623919 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -149,18 +149,6 @@ struct rte_sched_pipe_params {
  * byte.
  */
 struct rte_sched_subport_params {
-	/** Token bucket rate (measured in bytes per second) */
-	uint64_t tb_rate;
-
-	/** Token bucket size (measured in credits) */
-	uint64_t tb_size;
-
-	/** Traffic class rates (measured in bytes per second) */
-	uint64_t tc_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
-
-	/** Enforcement period for rates (measured in milliseconds) */
-	uint64_t tc_period;
-
 	/** Number of subport pipes.
 	 * The subport can enable/allocate fewer pipes than the maximum
 	 * number set through struct port_params::n_max_pipes_per_subport,
-- 
2.7.4


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

* Re: [dpdk-dev] [PATCH v4 3/9] sched: add subport profile add and config api
  2020-09-17  8:42           ` [dpdk-dev] [PATCH v4 3/9] sched: add subport profile add and config api Savinay Dharmappa
@ 2020-09-29 21:19             ` Dumitrescu, Cristian
  0 siblings, 0 replies; 107+ messages in thread
From: Dumitrescu, Cristian @ 2020-09-29 21:19 UTC (permalink / raw)
  To: Dharmappa, Savinay, Singh, Jasvinder, dev

Hi Savinay,

Trying  to summarize the main points of what we discussed and agreed last week for the benefit of all ...

> -----Original Message-----
> From: Dharmappa, Savinay <savinay.dharmappa@intel.com>
> Sent: Thursday, September 17, 2020 9:43 AM
> To: Singh, Jasvinder <jasvinder.singh@intel.com>; Dumitrescu, Cristian
> <cristian.dumitrescu@intel.com>; dev@dpdk.org
> Cc: Dharmappa, Savinay <savinay.dharmappa@intel.com>
> Subject: [PATCH v4 3/9] sched: add subport profile add and config api
> 
> Add apis to add new subport profile and configure it.
> 
> Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
> Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
> ---
>  lib/librte_sched/rte_sched.c           | 118
> +++++++++++++++++++++++++++++++++
>  lib/librte_sched/rte_sched.h           |  45 +++++++++++++
>  lib/librte_sched/rte_sched_version.map |   2 +
>  3 files changed, 165 insertions(+)
> 
> diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
> index 5fa7865..23aaec4 100644
> --- a/lib/librte_sched/rte_sched.c
> +++ b/lib/librte_sched/rte_sched.c
> @@ -174,6 +174,8 @@ struct rte_sched_subport {
>  	/* Statistics */
>  	struct rte_sched_subport_stats stats __rte_cache_aligned;
> 
> +	/* subport profile */
> +	uint32_t profile;
>  	/* Subport pipes */
>  	uint32_t n_pipes_per_subport_enabled;
>  	uint32_t n_pipe_profiles;
> @@ -1343,6 +1345,56 @@ rte_sched_subport_config(struct rte_sched_port
> *port,
>  }
> 
>  int
> +rte_sched_subport_profile_config(struct rte_sched_port *port,
> +	uint32_t subport_id,
> +	uint32_t profile_id)
> +{
> +	int i;
> +	struct rte_sched_subport_profile *params;
> +	uint32_t n_subports = subport_id + 1;
> +	struct rte_sched_subport *s;
> +
> +	if (port == NULL) {
> +		RTE_LOG(ERR, SCHED,
> +			"%s: Incorrect value for parameter port\n",
> __func__);
> +		return -EINVAL;
> +	}
> +
> +	if (subport_id >= port->n_subports_per_port) {
> +		RTE_LOG(ERR, SCHED, "%s: "
> +		"Incorrect value for parameter subport id\n", __func__);
> +
> +		rte_sched_free_memory(port, n_subports);
> +		return -EINVAL;
> +	}
> +
> +	params =  port->subport_profiles + profile_id;
> +
> +	s = port->subports[subport_id];
> +
> +	s->tb_credits = params->tb_size / 2;
> +
> +	s->tc_time = port->time + params->tc_period;
> +
> +	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
> +		if (s->qsize[i])
> +			s->tc_credits[i] =
> +				params->tc_credits_per_period[i];
> +		else
> +			params->tc_credits_per_period[i] = 0;
> +
> +#ifdef RTE_SCHED_SUBPORT_TC_OV
> +	s->tc_ov_wm_max = rte_sched_time_ms_to_bytes(params-
> >tc_period,
> +						     s->pipe_tc_be_rate_max);
> +#endif
> +	s->profile = profile_id;
> +
> +	rte_sched_port_log_subport_profile(port, profile_id);
> +
> +	return 0;
> +}
> +
> +int
>  rte_sched_pipe_config(struct rte_sched_port *port,
>  	uint32_t subport_id,
>  	uint32_t pipe_id,
> @@ -1526,6 +1578,72 @@ rte_sched_subport_pipe_profile_add(struct
> rte_sched_port *port,
>  	return 0;
>  }
> 
> +int
> +rte_sched_port_subport_profile_add(struct rte_sched_port *port,
> +	struct rte_sched_subport_profile_params *params,
> +	uint32_t *subport_profile_id)
> +{
> +	int status;
> +	uint32_t i;
> +	struct rte_sched_subport_profile *dst;
> +
> +	/* Port */
> +	if (port == NULL) {
> +		RTE_LOG(ERR, SCHED, "%s: "
> +		"Incorrect value for parameter port\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	if (params == NULL) {
> +		RTE_LOG(ERR, SCHED, "%s: "
> +		"Incorrect value for parameter profile\n", __func__);
> +		return -EINVAL;
> +	}
> +
> +	if (subport_profile_id == NULL) {
> +		RTE_LOG(ERR, SCHED, "%s: "
> +		"Incorrect value for parameter subport_profile_id\n",
> +		__func__);
> +		return -EINVAL;
> +	}
> +
> +	dst = port->subport_profiles + port->n_subport_profiles;
> +
> +	/* Subport profiles exceeds the max limit */
> +	if (port->n_subport_profiles >= port->n_max_subport_profiles) {
> +		RTE_LOG(ERR, SCHED, "%s: "
> +		"Number of subport profiles exceeds the max limit\n",
> +		 __func__);
> +		return -EINVAL;
> +	}
> +
> +	status = subport_profile_check(params, port->rate);
> +	if (status != 0) {
> +		RTE_LOG(ERR, SCHED,
> +		"%s: subport profile check failed(%d)\n", __func__, status);
> +		return -EINVAL;
> +	}
> +
> +	rte_sched_subport_profile_convert(params, dst, port->rate);
> +
> +	/* Subport profile should not exists */
> +	for (i = 0; i < port->n_subport_profiles; i++)
> +		if (memcmp(port->subport_profiles + i,
> +		    dst, sizeof(*dst)) == 0) {
> +			RTE_LOG(ERR, SCHED,
> +			"%s: subport profile exists\n", __func__);
> +			return -EINVAL;
> +		}
> +
> +	/* Subport profile commit */
> +	*subport_profile_id = port->n_subport_profiles;
> +	port->n_subport_profiles++;
> +
> +	rte_sched_port_log_subport_profile(port, *subport_profile_id);
> +
> +	return 0;
> +}
> +
>  static inline uint32_t
>  rte_sched_port_qindex(struct rte_sched_port *port,
>  	uint32_t subport,
> diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
> index 39339b7..a7c2638 100644
> --- a/lib/librte_sched/rte_sched.h
> +++ b/lib/librte_sched/rte_sched.h
> @@ -337,6 +337,29 @@ rte_sched_subport_pipe_profile_add(struct
> rte_sched_port *port,
>  	uint32_t *pipe_profile_id);
> 
>  /**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice.
> + *
> + * Hierarchical scheduler subport bandwidth profile add
> + * Note that this function is safe to use in runtime for adding new
> + * subport bandwidth profile as it doesn't have any impact on hiearchical
> + * structure of the scheduler.
> + * @param port
> + *   Handle to port scheduler instance
> + * @param struct rte_sched_subport_profile
> + *   Subport bandwidth profile
> + * @param subport_profile_d
> + *   Subport profile id
> + * @return
> + *   0 upon success, error code otherwise
> + */
> +__rte_experimental
> +int
> +rte_sched_port_subport_profile_add(struct rte_sched_port *port,
> +	struct rte_sched_subport_profile_params *profile,
> +	uint32_t *subport_profile_id);
> +

Please make sure the internal subport profile table is freed correctly, which is not the case currently.

> +/**
>   * Hierarchical scheduler subport configuration
>   *
>   * @param port
> @@ -354,6 +377,28 @@ rte_sched_subport_config(struct rte_sched_port
> *port,
>  	struct rte_sched_subport_params *params);
> 
>  /**
> + * @warning
> + * @b EXPERIMENTAL: this API may change without prior notice.
> + *
> + * Hierarchical scheduler subport profile configuration
> + * Note that this function is safe to use in runtime for applying any specific
> + * subport bandwidth profile as it doesn't have any impact on hiearchical
> + * structure of the scheduler.
> + * @param port
> + *   Handle to port scheduler instance
> + * @param subport_id
> + *   Subport ID
> + * @param profile_d
> + *   Subport profile id
> + * @return
> + *   0 upon success, error code otherwise
> + */
> +__rte_experimental
> +int
> +rte_sched_subport_profile_config(struct rte_sched_port *port,
> +	uint32_t subport_id,
> +	uint32_t profile_id);

This function should be melted into rte_sched_subport_config(), which should get an extra profile_id argument.

This preserves the symmetry with rte_sched_pipe_config(), which is both an init time and a run-time config update function, and also avoid user confusion and error prone situation when only rte_sched_subport_config() is called while rte_sched_subport_profile_config() is not.

First time rte_sched_subport_config() is called (init time), its params argument should be non-NULL; this argument should be ignored (with NULL as the recommended value) for any subsequent calls. A subport-internal init_done flag could be maintained to distinguish between first and any subsequent calls. This should also be documented in the argument description.

> +/**
>   * Hierarchical scheduler pipe configuration
>   *
>   * @param port
> diff --git a/lib/librte_sched/rte_sched_version.map
> b/lib/librte_sched/rte_sched_version.map
> index 3faef6f..e64335f 100644
> --- a/lib/librte_sched/rte_sched_version.map
> +++ b/lib/librte_sched/rte_sched_version.map
> @@ -28,4 +28,6 @@ EXPERIMENTAL {
>  	global:
> 
>  	rte_sched_subport_pipe_profile_add;
> +	rte_sched_port_subport_profile_add;
> +	rte_sched_subport_profile_config;
>  };
> --

Need to increment the ABI version here, as new data structures and API function changes took place, inline with the deprecation note.

> 2.7.4


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

* Re: [dpdk-dev] [PATCH v4 6/9] example/ip_pipeline: add dynamic config of subport
  2020-09-17  8:42           ` [dpdk-dev] [PATCH v4 6/9] example/ip_pipeline: " Savinay Dharmappa
@ 2020-09-29 21:23             ` Dumitrescu, Cristian
  0 siblings, 0 replies; 107+ messages in thread
From: Dumitrescu, Cristian @ 2020-09-29 21:23 UTC (permalink / raw)
  To: Dharmappa, Savinay, Singh, Jasvinder, dev



> -----Original Message-----
> From: Dharmappa, Savinay <savinay.dharmappa@intel.com>
> Sent: Thursday, September 17, 2020 9:43 AM
> To: Singh, Jasvinder <jasvinder.singh@intel.com>; Dumitrescu, Cristian
> <cristian.dumitrescu@intel.com>; dev@dpdk.org
> Cc: Dharmappa, Savinay <savinay.dharmappa@intel.com>
> Subject: [PATCH v4 6/9] example/ip_pipeline: add dynamic config of subport
> 
> Modify the ip_pipeline application to build the hierarchical scheduler
> with default subport bandwidth profile. It also allows to configure
> a subport with different subport bandwidth profile dynamically
> 
> Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
> ---
>  examples/ip_pipeline/cli.c  | 14 ++++++++------
>  examples/ip_pipeline/tmgr.c | 26 ++++++++++++++++++++++++--
>  examples/ip_pipeline/tmgr.h |  3 ++-
>  3 files changed, 34 insertions(+), 9 deletions(-)
> 
> diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
> index d79699e..7eccde3 100644
> --- a/examples/ip_pipeline/cli.c
> +++ b/examples/ip_pipeline/cli.c
> @@ -407,6 +407,7 @@ cmd_tmgr_subport_profile(char **tokens,
>  	size_t out_size)
>  {
>  	struct rte_sched_subport_params p;
> +	struct rte_sched_subport_profile_params pp;
>  	int status, i;
> 
>  	if (n_tokens != 35) {
> @@ -414,23 +415,23 @@ cmd_tmgr_subport_profile(char **tokens,
>  		return;
>  	}
> 
> -	if (parser_read_uint64(&p.tb_rate, tokens[3]) != 0) {
> +	if (parser_read_uint64(&pp.tb_rate, tokens[3]) != 0) {
>  		snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
>  		return;
>  	}
> 
> -	if (parser_read_uint64(&p.tb_size, tokens[4]) != 0) {
> +	if (parser_read_uint64(&pp.tb_size, tokens[4]) != 0) {
>  		snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
>  		return;
>  	}
> 
>  	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
> -		if (parser_read_uint64(&p.tc_rate[i], tokens[5 + i]) != 0) {
> +		if (parser_read_uint64(&pp.tc_rate[i], tokens[5 + i]) != 0) {
>  			snprintf(out, out_size, MSG_ARG_INVALID,
> "tc_rate");
>  			return;
>  		}
> 
> -	if (parser_read_uint64(&p.tc_period, tokens[18]) != 0) {
> +	if (parser_read_uint64(&pp.tc_period, tokens[18]) != 0) {
>  		snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
>  		return;
>  	}
> @@ -440,7 +441,8 @@ cmd_tmgr_subport_profile(char **tokens,
>  		return;
>  	}
> 
> -	if (parser_read_uint32(&p.n_pipes_per_subport_enabled,
> tokens[20]) != 0) {
> +	if (parser_read_uint32(&p.n_pipes_per_subport_enabled,
> +		tokens[20]) != 0) {
>  		snprintf(out, out_size, MSG_ARG_INVALID,
> "n_pipes_per_subport");
>  		return;
>  	}
> @@ -456,7 +458,7 @@ cmd_tmgr_subport_profile(char **tokens,
>  			return;
>  		}
> 
> -	status = tmgr_subport_profile_add(&p);
> +	status = tmgr_subport_profile_add(&p, &pp);
>  	if (status != 0) {
>  		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
>  		return;
> diff --git a/examples/ip_pipeline/tmgr.c b/examples/ip_pipeline/tmgr.c
> index 91ccbf6..5c3df92 100644
> --- a/examples/ip_pipeline/tmgr.c
> +++ b/examples/ip_pipeline/tmgr.c
> @@ -11,6 +11,9 @@
>  static struct rte_sched_subport_params
>  	subport_profile[TMGR_SUBPORT_PROFILE_MAX];
> 
> +static struct rte_sched_subport_profile_params
> +		profile_params[TMGR_SUBPORT_PROFILE_MAX];
> +

As discussed, it is probably better to merge these two tables into one.

struct subport_profile_params {
	struct rte_sched_subport_params params;
	rte_sched_subport_profile_params profile;
};

struct subport_profile_params subport_profile[TMGR_SUBPORT_PROFILE_MAX];

It avoids confusion and also minimizes the app changes.

The same should be done for the SoftNIC code.

>  static uint32_t n_subport_profiles;
> 
>  static struct rte_sched_pipe_params
> @@ -44,10 +47,11 @@ tmgr_port_find(const char *name)
>  }
> 
>  int
> -tmgr_subport_profile_add(struct rte_sched_subport_params *p)
> +tmgr_subport_profile_add(struct rte_sched_subport_params *p,
> +			 struct rte_sched_subport_profile_params *pp)
>  {
>  	/* Check input params */
> -	if (p == NULL ||
> +	if (p == NULL || pp == NULL ||
>  		p->n_pipes_per_subport_enabled == 0)
>  		return -1;
> 
> @@ -56,6 +60,10 @@ tmgr_subport_profile_add(struct
> rte_sched_subport_params *p)
>  		p,
>  		sizeof(*p));
> 
> +	memcpy(&profile_params[n_subport_profiles],
> +		pp,
> +		sizeof(*pp));
> +
>  	n_subport_profiles++;
> 
>  	return 0;
> @@ -103,6 +111,9 @@ tmgr_port_create(const char *name, struct
> tmgr_port_params *params)
>  	p.mtu = params->mtu;
>  	p.frame_overhead = params->frame_overhead;
>  	p.n_subports_per_port = params->n_subports_per_port;
> +	p.n_subport_profiles = n_subport_profiles;
> +	p.subport_profiles = profile_params;
> +	p.n_max_subport_profiles = TMGR_SUBPORT_PROFILE_MAX;
>  	p.n_pipes_per_subport = TMGR_PIPE_SUBPORT_MAX;
> 
>  	s = rte_sched_port_config(&p);
> @@ -126,6 +137,13 @@ tmgr_port_create(const char *name, struct
> tmgr_port_params *params)
>  			return NULL;
>  		}
> 
> +		status = rte_sched_subport_profile_config(s, i, 0);
> +
> +		if (status) {
> +			rte_sched_port_free(s);
> +			return NULL;
> +		}
> +
>  		for (j = 0; j <
> subport_profile[0].n_pipes_per_subport_enabled; j++) {
>  			status = rte_sched_pipe_config(
>  				s,
> @@ -182,6 +200,10 @@ tmgr_subport_config(const char *port_name,
>  		subport_id,
>  		&subport_profile[subport_profile_id]);
> 
> +	if (!status)
> +		status = rte_sched_subport_profile_config(port->s,
> subport_id,
> +							subport_profile_id);
> +
>  	return status;
>  }
> 
> diff --git a/examples/ip_pipeline/tmgr.h b/examples/ip_pipeline/tmgr.h
> index ee50cf7..8c14523 100644
> --- a/examples/ip_pipeline/tmgr.h
> +++ b/examples/ip_pipeline/tmgr.h
> @@ -48,7 +48,8 @@ struct tmgr_port_params {
>  };
> 
>  int
> -tmgr_subport_profile_add(struct rte_sched_subport_params *p);
> +tmgr_subport_profile_add(struct rte_sched_subport_params *p,
> +			 struct rte_sched_subport_profile_params *pp);
> 
>  int
>  tmgr_pipe_profile_add(struct rte_sched_pipe_params *p);
> --
> 2.7.4


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

* [dpdk-dev] [PATCH v5 0/9] Enable dynamic config of subport bandwidth
  2020-09-17  8:42         ` [dpdk-dev] [PATCH v4 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
                             ` (8 preceding siblings ...)
  2020-09-17  8:42           ` [dpdk-dev] [PATCH v4 9/9] sched: remove the redundant code Savinay Dharmappa
@ 2020-09-30 19:24           ` Savinay Dharmappa
  2020-09-30 19:24             ` [dpdk-dev] [PATCH v5 1/9] sched: add support profile table Savinay Dharmappa
                               ` (9 more replies)
  9 siblings, 10 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-30 19:24 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

DPDK sched library allows runtime configuration of the pipe profiles to the
pipes of the subport once scheduler hierarchy is constructed. However, to
change the subport level bandwidth, existing hierarchy needs to be
dismantled and whole process of building hierarchy under subport nodes
needs to be repeated which might result in router downtime. Furthermore,
due to lack of dynamic configuration of the subport bandwidth profile
configuration (shaper and Traffic class rates), the user application
is unable to dynamically re-distribute the excess-bandwidth of one subport
among other subports in the scheduler hierarchy. Therefore, it is also not
possible to adjust the subport bandwidth profile in sync with dynamic
changes in pipe profiles of subscribers who want to consume higher
bandwidth opportunistically.

This patch series implements dynamic configuration of the subport bandwidth
profile to overcome the runtime situation when group of subscribers are not
using the allotted bandwidth and dynamic bandwidth re-distribution is
needed the without making any structural changes in the hierarchy.

The implementation work includes refactoring the existing api and
data structures defined for port and subport level, new APIs for
adding subport level bandwidth profiles that can be used in runtime

Savinay Dharmappa (9):
  sched: add support profile table
  sched: add subport profile add api
  sched : add dynamic config of subport bandwidth
  sched: update grinder credit and pipe config function
  example/qos_sched: add dynamic config of subport
  example/ip_pipeline: add dynamic config of subport
  drivers/softnic: add dynamic config of subport
  app/test_sched: add dynamic config of subport
  sched : remove redundant code

 app/test/test_sched.c                         |  17 +-
 doc/guides/rel_notes/deprecation.rst          |   6 -
 doc/guides/rel_notes/release_20_11.rst        |   4 +
 .../net/softnic/rte_eth_softnic_internals.h   |  18 +-
 drivers/net/softnic/rte_eth_softnic_tm.c      | 224 ++++--
 examples/ip_pipeline/cli.c                    |  17 +-
 examples/ip_pipeline/tmgr.c                   |  53 +-
 examples/ip_pipeline/tmgr.h                   |   7 +-
 examples/qos_sched/cfg_file.c                 | 151 ++--
 examples/qos_sched/cfg_file.h                 |   4 +
 examples/qos_sched/init.c                     |  21 +-
 examples/qos_sched/main.h                     |   1 +
 examples/qos_sched/profile.cfg                |   3 +
 lib/librte_sched/rte_sched.c                  | 701 ++++++++++++------
 lib/librte_sched/rte_sched.h                  |  74 +-
 lib/librte_sched/rte_sched_version.map        |   2 +
 16 files changed, 891 insertions(+), 412 deletions(-)

-- 
2.17.1


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

* [dpdk-dev] [PATCH v5 1/9] sched: add support profile table
  2020-09-30 19:24           ` [dpdk-dev] [PATCH v5 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
@ 2020-09-30 19:24             ` Savinay Dharmappa
  2020-09-30 19:24             ` [dpdk-dev] [PATCH v5 2/9] sched: add subport profile add api Savinay Dharmappa
                               ` (8 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-30 19:24 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

Add subport profile data structure, subport profile table to
internal port data structure and update the port config function.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c | 197 ++++++++++++++++++++++++++++++++++-
 lib/librte_sched/rte_sched.h |  25 +++++
 2 files changed, 219 insertions(+), 3 deletions(-)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index 75be8b6bd..a44638f31 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -101,6 +101,16 @@ enum grinder_state {
 	e_GRINDER_READ_MBUF
 };
 
+struct rte_sched_subport_profile {
+	/* Token bucket (TB) */
+	uint64_t tb_period;
+	uint64_t tb_credits_per_period;
+	uint64_t tb_size;
+
+	uint64_t tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+	uint64_t tc_period;
+};
+
 struct rte_sched_grinder {
 	/* Pipe cache */
 	uint16_t pcache_qmask[RTE_SCHED_GRINDER_PCACHE_SIZE];
@@ -212,6 +222,8 @@ struct rte_sched_port {
 	uint16_t pipe_queue[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
 	uint8_t pipe_tc[RTE_SCHED_QUEUES_PER_PIPE];
 	uint8_t tc_queue[RTE_SCHED_QUEUES_PER_PIPE];
+	uint32_t n_subport_profiles;
+	uint32_t n_max_subport_profiles;
 	uint64_t rate;
 	uint32_t mtu;
 	uint32_t frame_overhead;
@@ -230,6 +242,7 @@ struct rte_sched_port {
 	uint32_t subport_id;
 
 	/* Large data structures */
+	struct rte_sched_subport_profile *subport_profiles;
 	struct rte_sched_subport *subports[0] __rte_cache_aligned;
 } __rte_cache_aligned;
 
@@ -375,9 +388,61 @@ pipe_profile_check(struct rte_sched_pipe_params *params,
 	return 0;
 }
 
+static int
+subport_profile_check(struct rte_sched_subport_profile_params *params,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	/* Check user parameters */
+	if (params == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter params\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tb_rate == 0 || params->tb_rate > rate) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for tb rate\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tb_size == 0) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for tb size\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
+		uint64_t tc_rate = params->tc_rate[i];
+
+		if (tc_rate == 0 || (tc_rate > params->tb_rate)) {
+			RTE_LOG(ERR, SCHED, "%s: "
+			"Incorrect value for tc rate\n", __func__);
+			return -EINVAL;
+		}
+	}
+
+	if (params->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect tc rate(best effort)\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tc_period == 0) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for tc period\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int
 rte_sched_port_check_params(struct rte_sched_port_params *params)
 {
+	uint32_t i;
+
 	if (params == NULL) {
 		RTE_LOG(ERR, SCHED,
 			"%s: Incorrect value for parameter params\n", __func__);
@@ -414,6 +479,29 @@ rte_sched_port_check_params(struct rte_sched_port_params *params)
 		return -EINVAL;
 	}
 
+	if (params->subport_profiles == NULL ||
+		params->n_subport_profiles == 0 ||
+		params->n_max_subport_profiles == 0 ||
+		params->n_subport_profiles > params->n_max_subport_profiles) {
+		RTE_LOG(ERR, SCHED,
+		"%s: Incorrect value for subport profiles\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < params->n_subport_profiles; i++) {
+		struct rte_sched_subport_profile_params *p =
+						params->subport_profiles + i;
+		int status;
+
+		status = subport_profile_check(p, params->rate);
+		if (status != 0) {
+			RTE_LOG(ERR, SCHED,
+			"%s: subport profile check failed(%d)\n",
+			__func__, status);
+			return -EINVAL;
+		}
+	}
+
 	/* n_pipes_per_subport: non-zero, power of 2 */
 	if (params->n_pipes_per_subport == 0 ||
 	    !rte_is_power_of_2(params->n_pipes_per_subport)) {
@@ -555,6 +643,42 @@ rte_sched_port_log_pipe_profile(struct rte_sched_subport *subport, uint32_t i)
 		p->wrr_cost[0], p->wrr_cost[1], p->wrr_cost[2], p->wrr_cost[3]);
 }
 
+static void
+rte_sched_port_log_subport_profile(struct rte_sched_port *port, uint32_t i)
+{
+	struct rte_sched_subport_profile *p = port->subport_profiles + i;
+
+	RTE_LOG(DEBUG, SCHED, "Low level config for subport profile %u:\n"
+	"Token bucket: period = %"PRIu64", credits per period = %"PRIu64","
+	"size = %"PRIu64"\n"
+	"Traffic classes: period = %"PRIu64",\n"
+	"credits per period = [%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
+	" %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
+	" %"PRIu64", %"PRIu64", %"PRIu64"]\n",
+	i,
+
+	/* Token bucket */
+	p->tb_period,
+	p->tb_credits_per_period,
+	p->tb_size,
+
+	/* Traffic classes */
+	p->tc_period,
+	p->tc_credits_per_period[0],
+	p->tc_credits_per_period[1],
+	p->tc_credits_per_period[2],
+	p->tc_credits_per_period[3],
+	p->tc_credits_per_period[4],
+	p->tc_credits_per_period[5],
+	p->tc_credits_per_period[6],
+	p->tc_credits_per_period[7],
+	p->tc_credits_per_period[8],
+	p->tc_credits_per_period[9],
+	p->tc_credits_per_period[10],
+	p->tc_credits_per_period[11],
+	p->tc_credits_per_period[12]);
+}
+
 static inline uint64_t
 rte_sched_time_ms_to_bytes(uint64_t time_ms, uint64_t rate)
 {
@@ -623,6 +747,37 @@ rte_sched_pipe_profile_convert(struct rte_sched_subport *subport,
 	dst->wrr_cost[3] = (uint8_t) wrr_cost[3];
 }
 
+static void
+rte_sched_subport_profile_convert(struct rte_sched_subport_profile_params *src,
+	struct rte_sched_subport_profile *dst,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	/* Token Bucket */
+	if (src->tb_rate == rate) {
+		dst->tb_credits_per_period = 1;
+		dst->tb_period = 1;
+	} else {
+		double tb_rate = (double) src->tb_rate
+				/ (double) rate;
+		double d = RTE_SCHED_TB_RATE_CONFIG_ERR;
+
+		rte_approx_64(tb_rate, d, &dst->tb_credits_per_period,
+			&dst->tb_period);
+	}
+
+	dst->tb_size = src->tb_size;
+
+	/* Traffic Classes */
+	dst->tc_period = rte_sched_time_ms_to_bytes(src->tc_period, rate);
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		dst->tc_credits_per_period[i]
+			= rte_sched_time_ms_to_bytes(src->tc_period,
+				src->tc_rate[i]);
+}
+
 static void
 rte_sched_subport_config_pipe_profile_table(struct rte_sched_subport *subport,
 	struct rte_sched_subport_params *params, uint64_t rate)
@@ -647,6 +802,24 @@ rte_sched_subport_config_pipe_profile_table(struct rte_sched_subport *subport,
 	}
 }
 
+static void
+rte_sched_port_config_subport_profile_table(struct rte_sched_port *port,
+	struct rte_sched_port_params *params,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	for (i = 0; i < port->n_subport_profiles; i++) {
+		struct rte_sched_subport_profile_params *src
+				= params->subport_profiles + i;
+		struct rte_sched_subport_profile *dst
+				= port->subport_profiles + i;
+
+		rte_sched_subport_profile_convert(src, dst, rate);
+		rte_sched_port_log_subport_profile(port, i);
+	}
+}
+
 static int
 rte_sched_subport_check_params(struct rte_sched_subport_params *params,
 	uint32_t n_max_pipes_per_subport,
@@ -793,7 +966,7 @@ struct rte_sched_port *
 rte_sched_port_config(struct rte_sched_port_params *params)
 {
 	struct rte_sched_port *port = NULL;
-	uint32_t size0, size1;
+	uint32_t size0, size1, size2;
 	uint32_t cycles_per_byte;
 	uint32_t i, j;
 	int status;
@@ -808,10 +981,21 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 
 	size0 = sizeof(struct rte_sched_port);
 	size1 = params->n_subports_per_port * sizeof(struct rte_sched_subport *);
+	size2 = params->n_max_subport_profiles *
+		sizeof(struct rte_sched_subport_profile);
 
 	/* Allocate memory to store the data structures */
-	port = rte_zmalloc_socket("qos_params", size0 + size1, RTE_CACHE_LINE_SIZE,
-		params->socket);
+	port = rte_zmalloc_socket("qos_params", size0 + size1,
+				 RTE_CACHE_LINE_SIZE, params->socket);
+	if (port == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: Memory allocation fails\n", __func__);
+
+		return NULL;
+	}
+
+	/* Allocate memory to store the subport profile */
+	port->subport_profiles  = rte_zmalloc_socket("subport_profile", size2,
+					RTE_CACHE_LINE_SIZE, params->socket);
 	if (port == NULL) {
 		RTE_LOG(ERR, SCHED, "%s: Memory allocation fails\n", __func__);
 
@@ -820,6 +1004,8 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 
 	/* User parameters */
 	port->n_subports_per_port = params->n_subports_per_port;
+	port->n_subport_profiles = params->n_subport_profiles;
+	port->n_max_subport_profiles = params->n_max_subport_profiles;
 	port->n_pipes_per_subport = params->n_pipes_per_subport;
 	port->n_pipes_per_subport_log2 =
 			__builtin_ctz(params->n_pipes_per_subport);
@@ -850,6 +1036,9 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 	port->time_cpu_bytes = 0;
 	port->time = 0;
 
+	/* Subport profile table */
+	rte_sched_port_config_subport_profile_table(port, params, port->rate);
+
 	cycles_per_byte = (rte_get_tsc_hz() << RTE_SCHED_TIME_SHIFT)
 		/ params->rate;
 	port->inv_cycles_per_byte = rte_reciprocal_value(cycles_per_byte);
@@ -905,6 +1094,7 @@ rte_sched_port_free(struct rte_sched_port *port)
 	for (i = 0; i < port->n_subports_per_port; i++)
 		rte_sched_subport_free(port, port->subports[i]);
 
+	rte_free(port->subport_profiles);
 	rte_free(port);
 }
 
@@ -961,6 +1151,7 @@ rte_sched_free_memory(struct rte_sched_port *port, uint32_t n_subports)
 		rte_sched_subport_free(port, subport);
 	}
 
+	rte_free(port->subport_profiles);
 	rte_free(port);
 }
 
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index 8a5a93c98..39339b7f1 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -192,6 +192,20 @@ struct rte_sched_subport_params {
 #endif
 };
 
+struct rte_sched_subport_profile_params {
+	/** Token bucket rate (measured in bytes per second) */
+	uint64_t tb_rate;
+
+	/** Token bucket size (measured in credits) */
+	uint64_t tb_size;
+
+	/** Traffic class rates (measured in bytes per second) */
+	uint64_t tc_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+
+	/** Enforcement period for rates (measured in milliseconds) */
+	uint64_t tc_period;
+};
+
 /** Subport statistics */
 struct rte_sched_subport_stats {
 	/** Number of packets successfully written */
@@ -254,6 +268,17 @@ struct rte_sched_port_params {
 	/** Number of subports */
 	uint32_t n_subports_per_port;
 
+	/** subport profile table.
+	 * Every pipe is configured using one of the profiles from this table.
+	 */
+	struct rte_sched_subport_profile_params *subport_profiles;
+
+	/** Profiles in the pipe profile table */
+	uint32_t n_subport_profiles;
+
+	/** Max allowed profiles in the pipe profile table */
+	uint32_t n_max_subport_profiles;
+
 	/** Maximum number of subport pipes.
 	 * This parameter is used to reserve a fixed number of bits
 	 * in struct rte_mbuf::sched.queue_id for the pipe_id for all
-- 
2.17.1


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

* [dpdk-dev] [PATCH v5 2/9] sched: add subport profile add api
  2020-09-30 19:24           ` [dpdk-dev] [PATCH v5 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
  2020-09-30 19:24             ` [dpdk-dev] [PATCH v5 1/9] sched: add support profile table Savinay Dharmappa
@ 2020-09-30 19:24             ` Savinay Dharmappa
  2020-09-30 19:24             ` [dpdk-dev] [PATCH v5 3/9] sched : add dynamic config of subport bandwidth Savinay Dharmappa
                               ` (7 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-30 19:24 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

Add api to add new subport profile.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c           | 66 ++++++++++++++++++++++++++
 lib/librte_sched/rte_sched.h           | 23 +++++++++
 lib/librte_sched/rte_sched_version.map |  2 +
 3 files changed, 91 insertions(+)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index a44638f31..895b40d72 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -1528,6 +1528,72 @@ rte_sched_subport_pipe_profile_add(struct rte_sched_port *port,
 	return 0;
 }
 
+int
+rte_sched_port_subport_profile_add(struct rte_sched_port *port,
+	struct rte_sched_subport_profile_params *params,
+	uint32_t *subport_profile_id)
+{
+	int status;
+	uint32_t i;
+	struct rte_sched_subport_profile *dst;
+
+	/* Port */
+	if (port == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter port\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter profile\n", __func__);
+		return -EINVAL;
+	}
+
+	if (subport_profile_id == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter subport_profile_id\n",
+		__func__);
+		return -EINVAL;
+	}
+
+	dst = port->subport_profiles + port->n_subport_profiles;
+
+	/* Subport profiles exceeds the max limit */
+	if (port->n_subport_profiles >= port->n_max_subport_profiles) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Number of subport profiles exceeds the max limit\n",
+		 __func__);
+		return -EINVAL;
+	}
+
+	status = subport_profile_check(params, port->rate);
+	if (status != 0) {
+		RTE_LOG(ERR, SCHED,
+		"%s: subport profile check failed(%d)\n", __func__, status);
+		return -EINVAL;
+	}
+
+	rte_sched_subport_profile_convert(params, dst, port->rate);
+
+	/* Subport profile should not exists */
+	for (i = 0; i < port->n_subport_profiles; i++)
+		if (memcmp(port->subport_profiles + i,
+		    dst, sizeof(*dst)) == 0) {
+			RTE_LOG(ERR, SCHED,
+			"%s: subport profile exists\n", __func__);
+			return -EINVAL;
+		}
+
+	/* Subport profile commit */
+	*subport_profile_id = port->n_subport_profiles;
+	port->n_subport_profiles++;
+
+	rte_sched_port_log_subport_profile(port, *subport_profile_id);
+
+	return 0;
+}
+
 static inline uint32_t
 rte_sched_port_qindex(struct rte_sched_port *port,
 	uint32_t subport,
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index 39339b7f1..3d823692c 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -336,6 +336,29 @@ rte_sched_subport_pipe_profile_add(struct rte_sched_port *port,
 	struct rte_sched_pipe_params *params,
 	uint32_t *pipe_profile_id);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Hierarchical scheduler subport bandwidth profile add
+ * Note that this function is safe to use in runtime for adding new
+ * subport bandwidth profile as it doesn't have any impact on hiearchical
+ * structure of the scheduler.
+ * @param port
+ *   Handle to port scheduler instance
+ * @param struct rte_sched_subport_profile
+ *   Subport bandwidth profile
+ * @param subport_profile_d
+ *   Subport profile id
+ * @return
+ *   0 upon success, error code otherwise
+ */
+__rte_experimental
+int
+rte_sched_port_subport_profile_add(struct rte_sched_port *port,
+	struct rte_sched_subport_profile_params *profile,
+	uint32_t *subport_profile_id);
+
 /**
  * Hierarchical scheduler subport configuration
  *
diff --git a/lib/librte_sched/rte_sched_version.map b/lib/librte_sched/rte_sched_version.map
index 3faef6f0a..ace284b7d 100644
--- a/lib/librte_sched/rte_sched_version.map
+++ b/lib/librte_sched/rte_sched_version.map
@@ -28,4 +28,6 @@ EXPERIMENTAL {
 	global:
 
 	rte_sched_subport_pipe_profile_add;
+	# added in 20.11
+	rte_sched_port_subport_profile_add;
 };
-- 
2.17.1


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

* [dpdk-dev] [PATCH v5 3/9] sched : add dynamic config of subport bandwidth
  2020-09-30 19:24           ` [dpdk-dev] [PATCH v5 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
  2020-09-30 19:24             ` [dpdk-dev] [PATCH v5 1/9] sched: add support profile table Savinay Dharmappa
  2020-09-30 19:24             ` [dpdk-dev] [PATCH v5 2/9] sched: add subport profile add api Savinay Dharmappa
@ 2020-09-30 19:24             ` Savinay Dharmappa
  2020-09-30 19:24             ` [dpdk-dev] [PATCH v5 4/9] sched: update grinder credit and pipe config function Savinay Dharmappa
                               ` (6 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-30 19:24 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

This patch adds support for dynamic config of subport bandwidth.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c | 219 +++++++++++++++++++++++++++++++++++
 lib/librte_sched/rte_sched.h |  23 ++++
 2 files changed, 242 insertions(+)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index 895b40d72..54940c451 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -174,6 +174,8 @@ struct rte_sched_subport {
 	/* Statistics */
 	struct rte_sched_subport_stats stats __rte_cache_aligned;
 
+	/* subport profile */
+	uint32_t profile;
 	/* Subport pipes */
 	uint32_t n_pipes_per_subport_enabled;
 	uint32_t n_pipe_profiles;
@@ -1155,6 +1157,49 @@ rte_sched_free_memory(struct rte_sched_port *port, uint32_t n_subports)
 	rte_free(port);
 }
 
+static int
+rte_sched_subport_profile_config(struct rte_sched_port *port,
+	uint32_t subport_id,
+	uint32_t subport_profile_id)
+{
+	int i;
+	struct rte_sched_subport_profile *params;
+	struct rte_sched_subport *s;
+
+	/* Subport profile exceeds the max limit */
+	if (subport_profile_id >= port->n_max_subport_profiles) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Number of subport profile exceeds the max limit\n",
+		 __func__);
+		return -EINVAL;
+	}
+
+	params =  port->subport_profiles + subport_profile_id;
+
+	s = port->subports[subport_id];
+
+	s->tb_credits = params->tb_size / 2;
+
+	s->tc_time = port->time + params->tc_period;
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		if (s->qsize[i])
+			s->tc_credits[i] =
+				params->tc_credits_per_period[i];
+		else
+			params->tc_credits_per_period[i] = 0;
+
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+	s->tc_ov_wm_max = rte_sched_time_ms_to_bytes(params->tc_period,
+						     s->pipe_tc_be_rate_max);
+#endif
+	s->profile = subport_profile_id;
+
+	rte_sched_port_log_subport_profile(port, subport_profile_id);
+
+	return 0;
+}
+
 int
 rte_sched_subport_config(struct rte_sched_port *port,
 	uint32_t subport_id,
@@ -1344,6 +1389,180 @@ rte_sched_subport_config(struct rte_sched_port *port,
 	return 0;
 }
 
+int
+rte_dynamic_sched_subport_config(struct rte_sched_port *port,
+	uint32_t subport_id,
+	struct rte_sched_subport_params *params,
+	uint32_t subport_profile_id)
+{
+	struct rte_sched_subport *s = NULL;
+	uint32_t n_subports = subport_id;
+	uint32_t n_subport_pipe_queues, i;
+	uint32_t size0, size1, bmp_mem_size;
+	int status;
+
+	/* Check user parameters */
+	if (port == NULL) {
+		RTE_LOG(ERR, SCHED,
+			"%s: Incorrect value for parameter port\n", __func__);
+		return 0;
+	}
+
+	if (subport_id >= port->n_subports_per_port) {
+		RTE_LOG(ERR, SCHED,
+			"%s: Incorrect value for subport id\n", __func__);
+
+		rte_sched_free_memory(port, n_subports);
+		return -EINVAL;
+	}
+
+
+	if (port->subports[subport_id] == NULL) {
+
+		status = rte_sched_subport_check_params(params,
+			port->n_pipes_per_subport,
+			port->rate);
+
+		if (status != 0) {
+			RTE_LOG(NOTICE, SCHED,
+				"%s: Port scheduler params check failed (%d)\n",
+				__func__, status);
+
+			rte_sched_free_memory(port, n_subports);
+			return -EINVAL;
+		}
+
+		/* Determine the amount of memory to allocate */
+		size0 = sizeof(struct rte_sched_subport);
+		size1 = rte_sched_subport_get_array_base(params,
+					e_RTE_SCHED_SUBPORT_ARRAY_TOTAL);
+
+		/* Allocate memory to store the data structures */
+		s = rte_zmalloc_socket("subport_params", size0 + size1,
+			RTE_CACHE_LINE_SIZE, port->socket);
+		if (s == NULL) {
+			RTE_LOG(ERR, SCHED,
+				"%s: Memory allocation fails\n", __func__);
+
+			rte_sched_free_memory(port, n_subports);
+			return -ENOMEM;
+		}
+
+		n_subports++;
+
+		/* Port */
+		port->subports[subport_id] = s;
+
+		s->tb_time = port->time;
+
+		subport_profile_id = 0;
+
+		/* compile time checks */
+		RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS == 0);
+		RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS &
+			(RTE_SCHED_PORT_N_GRINDERS - 1));
+
+		/* User parameters */
+		s->n_pipes_per_subport_enabled =
+			params->n_pipes_per_subport_enabled;
+		memcpy(s->qsize, params->qsize, sizeof(params->qsize));
+		s->n_pipe_profiles = params->n_pipe_profiles;
+		s->n_max_pipe_profiles = params->n_max_pipe_profiles;
+
+#ifdef RTE_SCHED_RED
+		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
+			uint32_t j;
+
+			for (j = 0; j < RTE_COLORS; j++) {
+			/* if min/max are both zero, then RED is disabled */
+				if ((params->red_params[i][j].min_th |
+				     params->red_params[i][j].max_th) == 0) {
+					continue;
+				}
+
+				if (rte_red_config_init(&s->red_config[i][j],
+				    params->red_params[i][j].wq_log2,
+				    params->red_params[i][j].min_th,
+				    params->red_params[i][j].max_th,
+				    params->red_params[i][j].maxp_inv) != 0) {
+					rte_sched_free_memory(port, n_subports);
+
+					RTE_LOG(NOTICE, SCHED,
+					"%s: RED configuration init fails\n",
+					__func__);
+					return -EINVAL;
+				}
+			}
+		}
+#endif
+
+		/* Scheduling loop detection */
+		s->pipe_loop = RTE_SCHED_PIPE_INVALID;
+		s->pipe_exhaustion = 0;
+
+		/* Grinders */
+		s->busy_grinders = 0;
+
+		/* Queue base calculation */
+		rte_sched_subport_config_qsize(s);
+
+		/* Large data structures */
+		s->pipe = (struct rte_sched_pipe *)
+			(s->memory + rte_sched_subport_get_array_base(params,
+			e_RTE_SCHED_SUBPORT_ARRAY_PIPE));
+		s->queue = (struct rte_sched_queue *)
+			(s->memory + rte_sched_subport_get_array_base(params,
+			e_RTE_SCHED_SUBPORT_ARRAY_QUEUE));
+		s->queue_extra = (struct rte_sched_queue_extra *)
+			(s->memory + rte_sched_subport_get_array_base(params,
+			e_RTE_SCHED_SUBPORT_ARRAY_QUEUE_EXTRA));
+		s->pipe_profiles = (struct rte_sched_pipe_profile *)
+			(s->memory + rte_sched_subport_get_array_base(params,
+			e_RTE_SCHED_SUBPORT_ARRAY_PIPE_PROFILES));
+		s->bmp_array =  s->memory +
+			rte_sched_subport_get_array_base(params,
+			e_RTE_SCHED_SUBPORT_ARRAY_BMP_ARRAY);
+		s->queue_array = (struct rte_mbuf **)
+			(s->memory + rte_sched_subport_get_array_base(params,
+			e_RTE_SCHED_SUBPORT_ARRAY_QUEUE_ARRAY));
+
+		/* Pipe profile table */
+		rte_sched_subport_config_pipe_profile_table(s, params,
+							port->rate);
+
+		/* Bitmap */
+		n_subport_pipe_queues = rte_sched_subport_pipe_queues(s);
+		bmp_mem_size = rte_bitmap_get_memory_footprint(
+							n_subport_pipe_queues);
+		s->bmp = rte_bitmap_init(n_subport_pipe_queues, s->bmp_array,
+					bmp_mem_size);
+		if (s->bmp == NULL) {
+			RTE_LOG(ERR, SCHED,
+				"%s: Subport bitmap init error\n", __func__);
+
+			rte_sched_free_memory(port, n_subports);
+			return -EINVAL;
+		}
+
+		for (i = 0; i < RTE_SCHED_PORT_N_GRINDERS; i++)
+			s->grinder_base_bmp_pos[i] = RTE_SCHED_PIPE_INVALID;
+
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+		/* TC oversubscription */
+		s->tc_ov_wm_min = port->mtu;
+		s->tc_ov_wm = s->tc_ov_wm_max;
+		s->tc_ov_period_id = 0;
+		s->tc_ov = 0;
+		s->tc_ov_n = 0;
+		s->tc_ov_rate = 0;
+#endif
+	}
+
+	rte_sched_subport_profile_config(port, subport_id, subport_profile_id);
+
+	return 0;
+}
+
 int
 rte_sched_pipe_config(struct rte_sched_port *port,
 	uint32_t subport_id,
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index 3d823692c..3ecb0e9c3 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -376,6 +376,29 @@ rte_sched_subport_config(struct rte_sched_port *port,
 	uint32_t subport_id,
 	struct rte_sched_subport_params *params);
 
+/**
+ * Hierarchical scheduler subport configuration.
+ * Note that this function is also used at runtime
+ * to configure subport bandwidth profile.
+ * @param port
+ *   Handle to port scheduler instance
+ * @param subport_id
+ *   Subport ID
+ * @param params
+ *   Subport configuration parameters.
+ *   This parameter should be set to NULL, to
+ *   configure the subport bandwidth profile
+ *   at runtime.
+ * @param subport_profile_id
+ *   ID of profile configured for subport
+ * @return
+ *   0 upon success, error code otherwise
+ */
+int
+rte_dynamic_sched_subport_config(struct rte_sched_port *port,
+	uint32_t subport_id,
+	struct rte_sched_subport_params *params,
+	uint32_t subport_profile_id);
 /**
  * Hierarchical scheduler pipe configuration
  *
-- 
2.17.1


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

* [dpdk-dev] [PATCH v5 4/9] sched: update grinder credit and pipe config function
  2020-09-30 19:24           ` [dpdk-dev] [PATCH v5 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
                               ` (2 preceding siblings ...)
  2020-09-30 19:24             ` [dpdk-dev] [PATCH v5 3/9] sched : add dynamic config of subport bandwidth Savinay Dharmappa
@ 2020-09-30 19:24             ` Savinay Dharmappa
  2020-09-30 19:24             ` [dpdk-dev] [PATCH v5 5/9] example/qos_sched: add dynamic config of subport Savinay Dharmappa
                               ` (5 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-30 19:24 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

Credits are updated by fetching subport profile parameters from
subport profile table. Similarly subport best effort tc is
calculated in pipe config.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c | 55 +++++++++++++++++++++---------------
 1 file changed, 33 insertions(+), 22 deletions(-)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index 54940c451..2bf4a8c3c 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -123,6 +123,7 @@ struct rte_sched_grinder {
 	uint32_t productive;
 	uint32_t pindex;
 	struct rte_sched_subport *subport;
+	struct rte_sched_subport_profile *subport_params;
 	struct rte_sched_pipe *pipe;
 	struct rte_sched_pipe_profile *pipe_params;
 
@@ -1570,6 +1571,7 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 	int32_t pipe_profile)
 {
 	struct rte_sched_subport *s;
+	struct rte_sched_subport_profile *sp;
 	struct rte_sched_pipe *p;
 	struct rte_sched_pipe_profile *params;
 	uint32_t n_subports = subport_id + 1;
@@ -1610,14 +1612,15 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 		return -EINVAL;
 	}
 
+	sp = port->subport_profiles + s->profile;
 	/* Handle the case when pipe already has a valid configuration */
 	p = s->pipe + pipe_id;
 	if (p->tb_time) {
 		params = s->pipe_profiles + p->profile;
 
 		double subport_tc_be_rate =
-			(double) s->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
-			/ (double) s->tc_period;
+		(double)sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
+			/ (double) sp->tc_period;
 		double pipe_tc_be_rate =
 			(double) params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
 			/ (double) params->tc_period;
@@ -1659,8 +1662,8 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 	{
 		/* Subport best effort tc oversubscription */
 		double subport_tc_be_rate =
-			(double) s->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
-			/ (double) s->tc_period;
+		(double)sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
+			/ (double) sp->tc_period;
 		double pipe_tc_be_rate =
 			(double) params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
 			/ (double) params->tc_period;
@@ -2448,14 +2451,15 @@ grinder_credits_update(struct rte_sched_port *port,
 	struct rte_sched_grinder *grinder = subport->grinder + pos;
 	struct rte_sched_pipe *pipe = grinder->pipe;
 	struct rte_sched_pipe_profile *params = grinder->pipe_params;
+	struct rte_sched_subport_profile *sp = grinder->subport_params;
 	uint64_t n_periods;
 	uint32_t i;
 
 	/* Subport TB */
-	n_periods = (port->time - subport->tb_time) / subport->tb_period;
-	subport->tb_credits += n_periods * subport->tb_credits_per_period;
-	subport->tb_credits = RTE_MIN(subport->tb_credits, subport->tb_size);
-	subport->tb_time += n_periods * subport->tb_period;
+	n_periods = (port->time - subport->tb_time) / sp->tb_period;
+	subport->tb_credits += n_periods * sp->tb_credits_per_period;
+	subport->tb_credits = RTE_MIN(subport->tb_credits, sp->tb_size);
+	subport->tb_time += n_periods * sp->tb_period;
 
 	/* Pipe TB */
 	n_periods = (port->time - pipe->tb_time) / params->tb_period;
@@ -2466,9 +2470,9 @@ grinder_credits_update(struct rte_sched_port *port,
 	/* Subport TCs */
 	if (unlikely(port->time >= subport->tc_time)) {
 		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-			subport->tc_credits[i] = subport->tc_credits_per_period[i];
+			subport->tc_credits[i] = sp->tc_credits_per_period[i];
 
-		subport->tc_time = port->time + subport->tc_period;
+		subport->tc_time = port->time + sp->tc_period;
 	}
 
 	/* Pipe TCs */
@@ -2484,8 +2488,10 @@ grinder_credits_update(struct rte_sched_port *port,
 
 static inline uint64_t
 grinder_tc_ov_credits_update(struct rte_sched_port *port,
-	struct rte_sched_subport *subport)
+	struct rte_sched_subport *subport, uint32_t pos)
 {
+	struct rte_sched_grinder *grinder = subport->grinder + pos;
+	struct rte_sched_subport_profile *sp = grinder->subport_params;
 	uint64_t tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
 	uint64_t tc_consumption = 0, tc_ov_consumption_max;
 	uint64_t tc_ov_wm = subport->tc_ov_wm;
@@ -2495,17 +2501,17 @@ grinder_tc_ov_credits_update(struct rte_sched_port *port,
 		return subport->tc_ov_wm_max;
 
 	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASS_BE; i++) {
-		tc_ov_consumption[i] =
-			subport->tc_credits_per_period[i] - subport->tc_credits[i];
+		tc_ov_consumption[i] = sp->tc_credits_per_period[i]
+					-  subport->tc_credits[i];
 		tc_consumption += tc_ov_consumption[i];
 	}
 
 	tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] =
-		subport->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
+	sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
 		subport->tc_credits[RTE_SCHED_TRAFFIC_CLASS_BE];
 
 	tc_ov_consumption_max =
-		subport->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
+	sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
 			tc_consumption;
 
 	if (tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] >
@@ -2531,14 +2537,15 @@ grinder_credits_update(struct rte_sched_port *port,
 	struct rte_sched_grinder *grinder = subport->grinder + pos;
 	struct rte_sched_pipe *pipe = grinder->pipe;
 	struct rte_sched_pipe_profile *params = grinder->pipe_params;
+	struct rte_sched_subport_profile *sp = grinder->subport_params;
 	uint64_t n_periods;
 	uint32_t i;
 
 	/* Subport TB */
-	n_periods = (port->time - subport->tb_time) / subport->tb_period;
-	subport->tb_credits += n_periods * subport->tb_credits_per_period;
-	subport->tb_credits = RTE_MIN(subport->tb_credits, subport->tb_size);
-	subport->tb_time += n_periods * subport->tb_period;
+	n_periods = (port->time - subport->tb_time) / sp->tb_period;
+	subport->tb_credits += n_periods * sp->tb_credits_per_period;
+	subport->tb_credits = RTE_MIN(subport->tb_credits, sp->tb_size);
+	subport->tb_time += n_periods * sp->tb_period;
 
 	/* Pipe TB */
 	n_periods = (port->time - pipe->tb_time) / params->tb_period;
@@ -2548,12 +2555,13 @@ grinder_credits_update(struct rte_sched_port *port,
 
 	/* Subport TCs */
 	if (unlikely(port->time >= subport->tc_time)) {
-		subport->tc_ov_wm = grinder_tc_ov_credits_update(port, subport);
+		subport->tc_ov_wm =
+			grinder_tc_ov_credits_update(port, subport, pos);
 
 		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-			subport->tc_credits[i] = subport->tc_credits_per_period[i];
+			subport->tc_credits[i] = sp->tc_credits_per_period[i];
 
-		subport->tc_time = port->time + subport->tc_period;
+		subport->tc_time = port->time + sp->tc_period;
 		subport->tc_ov_period_id++;
 	}
 
@@ -3076,6 +3084,9 @@ grinder_handle(struct rte_sched_port *port,
 		struct rte_sched_pipe *pipe = grinder->pipe;
 
 		grinder->pipe_params = subport->pipe_profiles + pipe->profile;
+		grinder->subport_params = port->subport_profiles +
+						subport->profile;
+
 		grinder_prefetch_tc_queue_arrays(subport, pos);
 		grinder_credits_update(port, subport, pos);
 
-- 
2.17.1


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

* [dpdk-dev] [PATCH v5 5/9] example/qos_sched: add dynamic config of subport
  2020-09-30 19:24           ` [dpdk-dev] [PATCH v5 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
                               ` (3 preceding siblings ...)
  2020-09-30 19:24             ` [dpdk-dev] [PATCH v5 4/9] sched: update grinder credit and pipe config function Savinay Dharmappa
@ 2020-09-30 19:24             ` Savinay Dharmappa
  2020-09-30 19:24             ` [dpdk-dev] [PATCH v5 6/9] example/ip_pipeline: " Savinay Dharmappa
                               ` (4 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-30 19:24 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

Modify the qos_sched application to build the hierarchical scheduler
with default subport bandwidth profile. It also allows to configure
a subport with different subport bandwidth profile dynamically.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 examples/qos_sched/cfg_file.c  | 151 +++++++++++++++++++--------------
 examples/qos_sched/cfg_file.h  |   4 +
 examples/qos_sched/init.c      |  21 +++--
 examples/qos_sched/main.h      |   1 +
 examples/qos_sched/profile.cfg |   3 +
 5 files changed, 111 insertions(+), 69 deletions(-)

diff --git a/examples/qos_sched/cfg_file.c b/examples/qos_sched/cfg_file.c
index f078e4f7d..cd167bd8e 100644
--- a/examples/qos_sched/cfg_file.c
+++ b/examples/qos_sched/cfg_file.c
@@ -142,6 +142,93 @@ cfg_load_pipe(struct rte_cfgfile *cfg, struct rte_sched_pipe_params *pipe_params
 	return 0;
 }
 
+int
+cfg_load_subport_profile(struct rte_cfgfile *cfg,
+	struct rte_sched_subport_profile_params *subport_profile)
+{
+	int i;
+	const char *entry;
+	int profiles;
+
+	if (!cfg || !subport_profile)
+		return -1;
+
+	profiles = rte_cfgfile_num_sections(cfg, "subport profile",
+					   sizeof("subport profile") - 1);
+	subport_params[0].n_pipe_profiles = profiles;
+
+	for (i = 0; i < profiles; i++) {
+		char sec_name[32];
+		snprintf(sec_name, sizeof(sec_name), "subport profile %d", i);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tb rate");
+		if (entry)
+			subport_profile[i].tb_rate = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tb size");
+		if (entry)
+			subport_profile[i].tb_size = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc period");
+		if (entry)
+			subport_profile[i].tc_period = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 0 rate");
+		if (entry)
+			subport_profile[i].tc_rate[0] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 1 rate");
+		if (entry)
+			subport_profile[i].tc_rate[1] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 2 rate");
+		if (entry)
+			subport_profile[i].tc_rate[2] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 3 rate");
+		if (entry)
+			subport_profile[i].tc_rate[3] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 4 rate");
+		if (entry)
+			subport_profile[i].tc_rate[4] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 5 rate");
+		if (entry)
+			subport_profile[i].tc_rate[5] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 6 rate");
+		if (entry)
+			subport_profile[i].tc_rate[6] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 7 rate");
+		if (entry)
+			subport_profile[i].tc_rate[7] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 8 rate");
+		if (entry)
+			subport_profile[i].tc_rate[8] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 9 rate");
+		if (entry)
+			subport_profile[i].tc_rate[9] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 10 rate");
+		if (entry)
+			subport_profile[i].tc_rate[10] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 11 rate");
+		if (entry)
+			subport_profile[i].tc_rate[11] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 12 rate");
+		if (entry)
+			subport_profile[i].tc_rate[12] = (uint64_t)atoi(entry);
+	}
+
+	return 0;
+}
+
 int
 cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subport_params)
 {
@@ -267,70 +354,6 @@ cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subpo
 				}
 			}
 
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tb rate");
-			if (entry)
-				subport_params[i].tb_rate = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tb size");
-			if (entry)
-				subport_params[i].tb_size = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc period");
-			if (entry)
-				subport_params[i].tc_period = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 0 rate");
-			if (entry)
-				subport_params[i].tc_rate[0] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 1 rate");
-			if (entry)
-				subport_params[i].tc_rate[1] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 2 rate");
-			if (entry)
-				subport_params[i].tc_rate[2] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 3 rate");
-			if (entry)
-				subport_params[i].tc_rate[3] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 4 rate");
-			if (entry)
-				subport_params[i].tc_rate[4] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 5 rate");
-			if (entry)
-				subport_params[i].tc_rate[5] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 6 rate");
-			if (entry)
-				subport_params[i].tc_rate[6] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 7 rate");
-			if (entry)
-				subport_params[i].tc_rate[7] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 8 rate");
-			if (entry)
-				subport_params[i].tc_rate[8] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 9 rate");
-			if (entry)
-				subport_params[i].tc_rate[9] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 10 rate");
-			if (entry)
-				subport_params[i].tc_rate[10] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 11 rate");
-			if (entry)
-				subport_params[i].tc_rate[11] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 12 rate");
-			if (entry)
-				subport_params[i].tc_rate[12] = (uint64_t)atoi(entry);
-
 			int n_entries = rte_cfgfile_section_num_entries(cfg, sec_name);
 			struct rte_cfgfile_entry entries[n_entries];
 
diff --git a/examples/qos_sched/cfg_file.h b/examples/qos_sched/cfg_file.h
index 2eccf1ca0..0dc458aa7 100644
--- a/examples/qos_sched/cfg_file.h
+++ b/examples/qos_sched/cfg_file.h
@@ -14,4 +14,8 @@ int cfg_load_pipe(struct rte_cfgfile *cfg, struct rte_sched_pipe_params *pipe);
 
 int cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subport);
 
+int cfg_load_subport_profile(struct rte_cfgfile *cfg,
+			     struct rte_sched_subport_profile_params
+			     *subport_profile);
+
 #endif
diff --git a/examples/qos_sched/init.c b/examples/qos_sched/init.c
index 06328ddb2..9e7e21832 100644
--- a/examples/qos_sched/init.c
+++ b/examples/qos_sched/init.c
@@ -192,15 +192,20 @@ static struct rte_sched_pipe_params pipe_profiles[MAX_SCHED_PIPE_PROFILES] = {
 	},
 };
 
-struct rte_sched_subport_params subport_params[MAX_SCHED_SUBPORTS] = {
+static struct rte_sched_subport_profile_params
+		subport_profile[MAX_SCHED_SUBPORT_PROFILES] = {
 	{
 		.tb_rate = 1250000000,
 		.tb_size = 1000000,
-
 		.tc_rate = {1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000},
 		.tc_period = 10,
+	},
+};
+
+struct rte_sched_subport_params subport_params[MAX_SCHED_SUBPORTS] = {
+	{
 		.n_pipes_per_subport_enabled = 4096,
 		.qsize = {64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64},
 		.pipe_profiles = pipe_profiles,
@@ -285,6 +290,9 @@ struct rte_sched_port_params port_params = {
 	.mtu = 6 + 6 + 4 + 4 + 2 + 1500,
 	.frame_overhead = RTE_SCHED_FRAME_OVERHEAD_DEFAULT,
 	.n_subports_per_port = 1,
+	.n_subport_profiles = 1,
+	.subport_profiles = subport_profile,
+	.n_max_subport_profiles = MAX_SCHED_SUBPORT_PROFILES,
 	.n_pipes_per_subport = MAX_SCHED_PIPES,
 };
 
@@ -314,10 +322,12 @@ app_init_sched_port(uint32_t portid, uint32_t socketid)
 	}
 
 	for (subport = 0; subport < port_params.n_subports_per_port; subport ++) {
-		err = rte_sched_subport_config(port, subport, &subport_params[subport]);
+		err = rte_dynamic_sched_subport_config(port, subport,
+						&subport_params[subport],
+						0);
 		if (err) {
-			rte_exit(EXIT_FAILURE, "Unable to config sched subport %u, err=%d\n",
-					subport, err);
+			rte_exit(EXIT_FAILURE, "Unable to config schedi "
+				"subport %u, err=%d\n", subport, err);
 		}
 
 		uint32_t n_pipes_per_subport =
@@ -350,6 +360,7 @@ app_load_cfg_profile(const char *profile)
 
 	cfg_load_port(file, &port_params);
 	cfg_load_subport(file, subport_params);
+	cfg_load_subport_profile(file, subport_profile);
 	cfg_load_pipe(file, pipe_profiles);
 
 	rte_cfgfile_close(file);
diff --git a/examples/qos_sched/main.h b/examples/qos_sched/main.h
index 23bc418d9..0d6815ae6 100644
--- a/examples/qos_sched/main.h
+++ b/examples/qos_sched/main.h
@@ -51,6 +51,7 @@ extern "C" {
 #define MAX_SCHED_SUBPORTS		8
 #define MAX_SCHED_PIPES		4096
 #define MAX_SCHED_PIPE_PROFILES		256
+#define MAX_SCHED_SUBPORT_PROFILES	8
 
 #ifndef APP_COLLECT_STAT
 #define APP_COLLECT_STAT		1
diff --git a/examples/qos_sched/profile.cfg b/examples/qos_sched/profile.cfg
index 61b8b7071..4486d2799 100644
--- a/examples/qos_sched/profile.cfg
+++ b/examples/qos_sched/profile.cfg
@@ -26,6 +26,9 @@ number of subports per port = 1
 number of pipes per subport = 4096
 queue sizes = 64 64 64 64 64 64 64 64 64 64 64 64 64
 
+subport 0-8 = 0                ; These subports are configured with subport profile 0
+
+[subport profile 0]
 tb rate = 1250000000           ; Bytes per second
 tb size = 1000000              ; Bytes
 
-- 
2.17.1


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

* [dpdk-dev] [PATCH v5 6/9] example/ip_pipeline: add dynamic config of subport
  2020-09-30 19:24           ` [dpdk-dev] [PATCH v5 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
                               ` (4 preceding siblings ...)
  2020-09-30 19:24             ` [dpdk-dev] [PATCH v5 5/9] example/qos_sched: add dynamic config of subport Savinay Dharmappa
@ 2020-09-30 19:24             ` Savinay Dharmappa
  2020-09-30 19:24             ` [dpdk-dev] [PATCH v5 7/9] drivers/softnic: " Savinay Dharmappa
                               ` (3 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-30 19:24 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

Modify the ip_pipeline application to build the hierarchical scheduler
with default subport bandwidth profile. It also allows to configure
a subport with different subport bandwidth profile dynamically

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 examples/ip_pipeline/cli.c  | 17 +++++------
 examples/ip_pipeline/tmgr.c | 57 ++++++++++++++++++++++++-------------
 examples/ip_pipeline/tmgr.h |  7 ++++-
 3 files changed, 52 insertions(+), 29 deletions(-)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index dafc95ae9..b4d95bb1d 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -406,7 +406,7 @@ cmd_tmgr_subport_profile(char **tokens,
 	char *out,
 	size_t out_size)
 {
-	struct rte_sched_subport_params p;
+	struct tmgr_subport sp;
 	int status, i;
 
 	if (n_tokens != 35) {
@@ -414,23 +414,23 @@ cmd_tmgr_subport_profile(char **tokens,
 		return;
 	}
 
-	if (parser_read_uint64(&p.tb_rate, tokens[3]) != 0) {
+	if (parser_read_uint64(&sp.pp.tb_rate, tokens[3]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
 		return;
 	}
 
-	if (parser_read_uint64(&p.tb_size, tokens[4]) != 0) {
+	if (parser_read_uint64(&sp.pp.tb_size, tokens[4]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
 		return;
 	}
 
 	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-		if (parser_read_uint64(&p.tc_rate[i], tokens[5 + i]) != 0) {
+		if (parser_read_uint64(&sp.pp.tc_rate[i], tokens[5 + i]) != 0) {
 			snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
 			return;
 		}
 
-	if (parser_read_uint64(&p.tc_period, tokens[18]) != 0) {
+	if (parser_read_uint64(&sp.pp.tc_period, tokens[18]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
 		return;
 	}
@@ -440,7 +440,8 @@ cmd_tmgr_subport_profile(char **tokens,
 		return;
 	}
 
-	if (parser_read_uint32(&p.n_pipes_per_subport_enabled, tokens[20]) != 0) {
+	if (parser_read_uint32(&sp.p.n_pipes_per_subport_enabled,
+		tokens[20]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport");
 		return;
 	}
@@ -451,12 +452,12 @@ cmd_tmgr_subport_profile(char **tokens,
 	}
 
 	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-		if (parser_read_uint16(&p.qsize[i], tokens[22 + i]) != 0) {
+		if (parser_read_uint16(&sp.p.qsize[i], tokens[22 + i]) != 0) {
 			snprintf(out, out_size, MSG_ARG_INVALID, "qsize");
 			return;
 		}
 
-	status = tmgr_subport_profile_add(&p);
+	status = tmgr_subport_profile_add(&sp);
 	if (status != 0) {
 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
 		return;
diff --git a/examples/ip_pipeline/tmgr.c b/examples/ip_pipeline/tmgr.c
index 91ccbf60f..446df8fe2 100644
--- a/examples/ip_pipeline/tmgr.c
+++ b/examples/ip_pipeline/tmgr.c
@@ -8,8 +8,15 @@
 
 #include "tmgr.h"
 
-static struct rte_sched_subport_params
-	subport_profile[TMGR_SUBPORT_PROFILE_MAX];
+struct subport_profile_params {
+	struct rte_sched_subport_params
+		params[TMGR_SUBPORT_PROFILE_MAX];
+
+	struct rte_sched_subport_profile_params
+		profile[TMGR_SUBPORT_PROFILE_MAX];
+};
+
+static struct subport_profile_params subport_profile;
 
 static uint32_t n_subport_profiles;
 
@@ -44,17 +51,21 @@ tmgr_port_find(const char *name)
 }
 
 int
-tmgr_subport_profile_add(struct rte_sched_subport_params *p)
+tmgr_subport_profile_add(struct tmgr_subport *params)
 {
 	/* Check input params */
-	if (p == NULL ||
-		p->n_pipes_per_subport_enabled == 0)
+	if (params == NULL ||
+		params->p.n_pipes_per_subport_enabled == 0)
 		return -1;
 
 	/* Save profile */
-	memcpy(&subport_profile[n_subport_profiles],
-		p,
-		sizeof(*p));
+	memcpy(&subport_profile.params[n_subport_profiles],
+		&params->p,
+		sizeof(params->p));
+
+	memcpy(&subport_profile.profile[n_subport_profiles],
+		&params->pp,
+		sizeof(params->pp));
 
 	n_subport_profiles++;
 
@@ -103,30 +114,35 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 	p.mtu = params->mtu;
 	p.frame_overhead = params->frame_overhead;
 	p.n_subports_per_port = params->n_subports_per_port;
+	p.n_subport_profiles = n_subport_profiles;
+	p.subport_profiles = subport_profile.profile;
+	p.n_max_subport_profiles = TMGR_SUBPORT_PROFILE_MAX;
 	p.n_pipes_per_subport = TMGR_PIPE_SUBPORT_MAX;
 
 	s = rte_sched_port_config(&p);
 	if (s == NULL)
 		return NULL;
 
-	subport_profile[0].pipe_profiles = pipe_profile;
-	subport_profile[0].n_pipe_profiles = n_pipe_profiles;
-	subport_profile[0].n_max_pipe_profiles = TMGR_PIPE_PROFILE_MAX;
+	subport_profile.params[0].pipe_profiles = pipe_profile;
+	subport_profile.params[0].n_pipe_profiles = n_pipe_profiles;
+	subport_profile.params[0].n_max_pipe_profiles = TMGR_PIPE_PROFILE_MAX;
 
 	for (i = 0; i < params->n_subports_per_port; i++) {
 		int status;
 
-		status = rte_sched_subport_config(
+		status = rte_dynamic_sched_subport_config(
 			s,
 			i,
-			&subport_profile[0]);
+			&subport_profile.params[0], 0);
 
 		if (status) {
 			rte_sched_port_free(s);
 			return NULL;
 		}
 
-		for (j = 0; j < subport_profile[0].n_pipes_per_subport_enabled; j++) {
+		for (j = 0; j <
+		subport_profile.params[0].n_pipes_per_subport_enabled; j++) {
+
 			status = rte_sched_pipe_config(
 				s,
 				i,
@@ -177,10 +193,11 @@ tmgr_subport_config(const char *port_name,
 		return -1;
 
 	/* Resource config */
-	status = rte_sched_subport_config(
+	status = rte_dynamic_sched_subport_config(
 		port->s,
 		subport_id,
-		&subport_profile[subport_profile_id]);
+		NULL,
+		subport_profile_id);
 
 	return status;
 }
@@ -203,10 +220,10 @@ tmgr_pipe_config(const char *port_name,
 	if ((port == NULL) ||
 		(subport_id >= port->n_subports_per_port) ||
 		(pipe_id_first >=
-			subport_profile[subport_id].n_pipes_per_subport_enabled) ||
-		(pipe_id_last >=
-			subport_profile[subport_id].n_pipes_per_subport_enabled) ||
-		(pipe_id_first > pipe_id_last) ||
+		subport_profile.params[subport_id].n_pipes_per_subport_enabled)
+		|| (pipe_id_last >=
+		subport_profile.params[subport_id].n_pipes_per_subport_enabled)
+		|| (pipe_id_first > pipe_id_last) ||
 		(pipe_profile_id >= n_pipe_profiles))
 		return -1;
 
diff --git a/examples/ip_pipeline/tmgr.h b/examples/ip_pipeline/tmgr.h
index ee50cf7cc..b651ede4a 100644
--- a/examples/ip_pipeline/tmgr.h
+++ b/examples/ip_pipeline/tmgr.h
@@ -31,6 +31,11 @@ struct tmgr_port {
 	uint32_t n_subports_per_port;
 };
 
+struct tmgr_subport {
+	struct rte_sched_subport_params  p;
+	struct rte_sched_subport_profile_params pp;
+};
+
 TAILQ_HEAD(tmgr_port_list, tmgr_port);
 
 int
@@ -48,7 +53,7 @@ struct tmgr_port_params {
 };
 
 int
-tmgr_subport_profile_add(struct rte_sched_subport_params *p);
+tmgr_subport_profile_add(struct tmgr_subport *sp);
 
 int
 tmgr_pipe_profile_add(struct rte_sched_pipe_params *p);
-- 
2.17.1


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

* [dpdk-dev] [PATCH v5 7/9] drivers/softnic: add dynamic config of subport
  2020-09-30 19:24           ` [dpdk-dev] [PATCH v5 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
                               ` (5 preceding siblings ...)
  2020-09-30 19:24             ` [dpdk-dev] [PATCH v5 6/9] example/ip_pipeline: " Savinay Dharmappa
@ 2020-09-30 19:24             ` Savinay Dharmappa
  2020-09-30 19:24             ` [dpdk-dev] [PATCH v5 8/9] app/test_sched: " Savinay Dharmappa
                               ` (2 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-30 19:24 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

Modify the softnic drivers to build the hierarchical scheduler
with default subport bandwidth profile. It also allows to configure
a subport with different subport bandwidth profile dynamically.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 .../net/softnic/rte_eth_softnic_internals.h   |  18 +-
 drivers/net/softnic/rte_eth_softnic_tm.c      | 228 ++++++++++++++----
 2 files changed, 194 insertions(+), 52 deletions(-)

diff --git a/drivers/net/softnic/rte_eth_softnic_internals.h b/drivers/net/softnic/rte_eth_softnic_internals.h
index 6eec43b22..7c25e8cea 100644
--- a/drivers/net/softnic/rte_eth_softnic_internals.h
+++ b/drivers/net/softnic/rte_eth_softnic_internals.h
@@ -164,11 +164,23 @@ TAILQ_HEAD(softnic_link_list, softnic_link);
 #ifndef TM_MAX_PIPE_PROFILE
 #define TM_MAX_PIPE_PROFILE				256
 #endif
-struct tm_params {
-	struct rte_sched_port_params port_params;
 
-	struct rte_sched_subport_params subport_params[TM_MAX_SUBPORTS];
+#ifndef TM_MAX_SUBPORT_PROFILE
+#define TM_MAX_SUBPORT_PROFILE				256
+#endif
+
+struct subport_profile_params {
 
+	struct rte_sched_subport_params params[TM_MAX_SUBPORTS];
+	struct rte_sched_subport_profile_params
+					profile[TM_MAX_SUBPORT_PROFILE];
+};
+
+struct tm_params {
+	struct rte_sched_port_params port_params;
+	struct subport_profile_params subport_profile;
+	uint32_t n_subport_profiles;
+	uint32_t subport_to_profile[TM_MAX_SUBPORT_PROFILE];
 	struct rte_sched_pipe_params pipe_profiles[TM_MAX_PIPE_PROFILE];
 	uint32_t n_pipe_profiles;
 	uint32_t pipe_to_profile[TM_MAX_SUBPORTS * TM_MAX_PIPES_PER_SUBPORT];
diff --git a/drivers/net/softnic/rte_eth_softnic_tm.c b/drivers/net/softnic/rte_eth_softnic_tm.c
index d30976378..92eb921ba 100644
--- a/drivers/net/softnic/rte_eth_softnic_tm.c
+++ b/drivers/net/softnic/rte_eth_softnic_tm.c
@@ -86,13 +86,14 @@ softnic_tmgr_port_create(struct pmd_internals *p,
 	n_subports = t->port_params.n_subports_per_port;
 	for (subport_id = 0; subport_id < n_subports; subport_id++) {
 		uint32_t n_pipes_per_subport =
-			t->subport_params[subport_id].n_pipes_per_subport_enabled;
+	     t->subport_profile.params[subport_id].n_pipes_per_subport_enabled;
 		uint32_t pipe_id;
 		int status;
 
-		status = rte_sched_subport_config(sched,
+		status = rte_dynamic_sched_subport_config(sched,
 			subport_id,
-			&t->subport_params[subport_id]);
+			&t->subport_profile.params[subport_id],
+			t->subport_to_profile[subport_id]);
 		if (status) {
 			rte_sched_port_free(sched);
 			return NULL;
@@ -1114,6 +1115,26 @@ tm_shared_shaper_get_tc(struct rte_eth_dev *dev,
 	return NULL;
 }
 
+static int
+subport_profile_exists(struct rte_eth_dev *dev,
+	struct rte_sched_subport_profile_params *sp,
+	uint32_t *subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+	uint32_t i;
+
+	for (i = 0; i < t->n_subport_profiles; i++)
+		if (memcmp(&t->subport_profile.profile[i], sp,
+				sizeof(*sp)) == 0) {
+			if (subport_profile_id)
+				*subport_profile_id = i;
+			return 1;
+		}
+
+	return 0;
+}
+
 static int
 update_subport_tc_rate(struct rte_eth_dev *dev,
 	struct tm_node *nt,
@@ -1122,26 +1143,27 @@ update_subport_tc_rate(struct rte_eth_dev *dev,
 {
 	struct pmd_internals *p = dev->data->dev_private;
 	uint32_t tc_id = tm_node_tc_id(dev, nt);
-
 	struct tm_node *np = nt->parent_node;
-
 	struct tm_node *ns = np->parent_node;
 	uint32_t subport_id = tm_node_subport_id(dev, ns);
-
-	struct rte_sched_subport_params subport_params;
-
+	struct rte_sched_subport_profile_params subport_profile;
 	struct tm_shaper_profile *sp_old = tm_shaper_profile_search(dev,
 		ss->shaper_profile_id);
+	uint32_t subport_profile_id;
 
 	/* Derive new subport configuration. */
-	memcpy(&subport_params,
-		&p->soft.tm.params.subport_params[subport_id],
-		sizeof(subport_params));
-	subport_params.tc_rate[tc_id] = sp_new->params.peak.rate;
+	memcpy(&subport_profile,
+		&p->soft.tm.params.subport_profile.profile[subport_id],
+		sizeof(subport_profile));
+	subport_profile.tc_rate[tc_id] = sp_new->params.peak.rate;
+
+	if (subport_profile_exists(dev, &subport_profile,
+				  &subport_profile_id) == 0)
+		return -1;
 
 	/* Update the subport configuration. */
-	if (rte_sched_subport_config(SCHED(p),
-		subport_id, &subport_params))
+	if (rte_dynamic_sched_subport_config(SCHED(p),
+		subport_id, NULL, subport_profile_id))
 		return -1;
 
 	/* Commit changes. */
@@ -1150,9 +1172,9 @@ update_subport_tc_rate(struct rte_eth_dev *dev,
 	ss->shaper_profile_id = sp_new->shaper_profile_id;
 	sp_new->n_users++;
 
-	memcpy(&p->soft.tm.params.subport_params[subport_id],
-		&subport_params,
-		sizeof(subport_params));
+	memcpy(&p->soft.tm.params.subport_profile.profile[subport_id],
+		&subport_profile,
+		sizeof(subport_profile));
 
 	return 0;
 }
@@ -2262,6 +2284,109 @@ pipe_profiles_generate(struct rte_eth_dev *dev)
 	return 0;
 }
 
+static struct rte_sched_subport_profile_params *
+subport_profile_get(struct rte_eth_dev *dev, struct tm_node *np)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+	uint32_t subport_id = tm_node_subport_id(dev, np->parent_node);
+
+	return &t->subport_profile.profile[subport_id];
+}
+
+static void
+subport_profile_mark(struct rte_eth_dev *dev,
+	uint32_t subport_id,
+	uint32_t subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+
+	t->subport_to_profile[subport_id] = subport_profile_id;
+}
+
+static void
+subport_profile_install(struct rte_eth_dev *dev,
+	struct rte_sched_subport_profile_params *sp,
+	uint32_t subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+
+	memcpy(&t->subport_profile.profile[subport_profile_id],
+		sp, sizeof(*sp));
+	t->n_subport_profiles++;
+}
+
+static int
+subport_profile_free_exists(struct rte_eth_dev *dev,
+	uint32_t *subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+
+	if (t->n_subport_profiles < TM_MAX_SUBPORT_PROFILE) {
+		*subport_profile_id = t->n_subport_profiles;
+		return 1;
+	}
+
+	return 0;
+}
+
+static void
+subport_profile_build(struct tm_node *np,
+	struct rte_sched_subport_profile_params *sp)
+{
+	memset(sp, 0, sizeof(*sp));
+
+	/* Pipe */
+	sp->tb_rate = np->shaper_profile->params.peak.rate;
+	sp->tb_size = np->shaper_profile->params.peak.size;
+
+	/* Traffic Class (TC) */
+	sp->tc_period = SUBPORT_TC_PERIOD;
+}
+
+static int
+subport_profiles_generate(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_hierarchy *h = &p->soft.tm.h;
+	struct tm_node_list *nl = &h->nodes;
+	struct tm_node *ns;
+	uint32_t subport_id;
+
+	/* Objective: Fill in the following fields in struct tm_params:
+	 *    - subport_profiles
+	 *    - n_subport_profiles
+	 *    - subport_to_profile
+	 */
+
+	subport_id = 0;
+	TAILQ_FOREACH(ns, nl, node) {
+		if (ns->level != TM_NODE_LEVEL_SUBPORT)
+			continue;
+
+		struct rte_sched_subport_profile_params sp;
+		uint32_t pos;
+
+		subport_profile_build(ns, &sp);
+
+		if (!subport_profile_exists(dev, &sp, &pos)) {
+			if (!subport_profile_free_exists(dev, &pos))
+				return -1;
+
+			subport_profile_install(dev, &sp, pos);
+		}
+
+		subport_profile_mark(dev, subport_id, pos);
+
+		subport_id++;
+	}
+
+	return 0;
+}
+
 static struct tm_wred_profile *
 tm_tc_wred_profile_get(struct rte_eth_dev *dev, uint32_t tc_id)
 {
@@ -2288,7 +2413,7 @@ wred_profiles_set(struct rte_eth_dev *dev, uint32_t subport_id)
 {
 	struct pmd_internals *p = dev->data->dev_private;
 	struct rte_sched_subport_params *pp =
-		&p->soft.tm.params.subport_params[subport_id];
+		&p->soft.tm.params.subport_profile.params[subport_id];
 
 	uint32_t tc_id;
 	enum rte_color color;
@@ -2519,6 +2644,15 @@ hierarchy_commit_check(struct rte_eth_dev *dev, struct rte_tm_error *error)
 				rte_strerror(EINVAL));
 	}
 
+	/* Not too many subport profiles. */
+	if (subport_profiles_generate(dev))
+		return -rte_tm_error_set(error,
+			EINVAL,
+			RTE_TM_ERROR_TYPE_UNSPECIFIED,
+			NULL,
+			rte_strerror(EINVAL));
+
+
 	/* Not too many pipe profiles. */
 	if (pipe_profiles_generate(dev))
 		return -rte_tm_error_set(error,
@@ -2600,6 +2734,9 @@ hierarchy_blueprints_create(struct rte_eth_dev *dev)
 		.frame_overhead =
 			root->shaper_profile->params.pkt_length_adjust,
 		.n_subports_per_port = root->n_children,
+		.n_subport_profiles = t->n_subport_profiles,
+		.subport_profiles = t->subport_profile.profile,
+		.n_max_subport_profiles = TM_MAX_SUBPORT_PROFILE,
 		.n_pipes_per_subport = TM_MAX_PIPES_PER_SUBPORT,
 	};
 
@@ -2620,28 +2757,12 @@ hierarchy_blueprints_create(struct rte_eth_dev *dev)
 				ss->shaper_profile_id) :
 				n->shaper_profile;
 			tc_rate[i] = sp->params.peak.rate;
+			t->subport_profile.profile[subport_id].tc_rate[i] =
+								tc_rate[i];
 		}
 
-		t->subport_params[subport_id] =
+		t->subport_profile.params[subport_id] =
 			(struct rte_sched_subport_params) {
-				.tb_rate = n->shaper_profile->params.peak.rate,
-				.tb_size = n->shaper_profile->params.peak.size,
-
-				.tc_rate = {tc_rate[0],
-					tc_rate[1],
-					tc_rate[2],
-					tc_rate[3],
-					tc_rate[4],
-					tc_rate[5],
-					tc_rate[6],
-					tc_rate[7],
-					tc_rate[8],
-					tc_rate[9],
-					tc_rate[10],
-					tc_rate[11],
-					tc_rate[12],
-				},
-				.tc_period = SUBPORT_TC_PERIOD,
 				.n_pipes_per_subport_enabled =
 					h->n_tm_nodes[TM_NODE_LEVEL_PIPE] /
 					h->n_tm_nodes[TM_NODE_LEVEL_SUBPORT],
@@ -2901,30 +3022,39 @@ update_subport_rate(struct rte_eth_dev *dev,
 	struct pmd_internals *p = dev->data->dev_private;
 	uint32_t subport_id = tm_node_subport_id(dev, ns);
 
-	struct rte_sched_subport_params subport_params;
+	struct rte_sched_subport_profile_params *profile0 =
+					subport_profile_get(dev, ns);
+	struct rte_sched_subport_profile_params profile1;
+	uint32_t subport_profile_id;
 
-	/* Derive new subport configuration. */
-	memcpy(&subport_params,
-		&p->soft.tm.params.subport_params[subport_id],
-		sizeof(subport_params));
-	subport_params.tb_rate = sp->params.peak.rate;
-	subport_params.tb_size = sp->params.peak.size;
+	/* Derive new pipe profile. */
+	memcpy(&profile1, profile0, sizeof(profile1));
+	profile1.tb_rate = sp->params.peak.rate;
+	profile1.tb_size = sp->params.peak.size;
+
+	/* Since implementation does not allow adding more subport profiles
+	 * after port configuration, the pipe configuration can be successfully
+	 * updated only if the new profile is also part of the existing set of
+	 * pipe profiles.
+	 */
+	if (subport_profile_exists(dev, &profile1, &subport_profile_id) == 0)
+		return -1;
 
 	/* Update the subport configuration. */
 	if (rte_sched_subport_config(SCHED(p), subport_id,
-		&subport_params))
+			NULL, subport_profile_id))
 		return -1;
 
+	subport_profile_mark(dev, subport_id, subport_profile_id);
 	/* Commit changes. */
 	ns->shaper_profile->n_users--;
-
 	ns->shaper_profile = sp;
 	ns->params.shaper_profile_id = sp->shaper_profile_id;
 	sp->n_users++;
 
-	memcpy(&p->soft.tm.params.subport_params[subport_id],
-		&subport_params,
-		sizeof(subport_params));
+	memcpy(&p->soft.tm.params.subport_profile.profile[subport_id],
+		&profile1,
+		sizeof(profile1));
 
 	return 0;
 }
-- 
2.17.1


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

* [dpdk-dev] [PATCH v5 8/9] app/test_sched: add dynamic config of subport
  2020-09-30 19:24           ` [dpdk-dev] [PATCH v5 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
                               ` (6 preceding siblings ...)
  2020-09-30 19:24             ` [dpdk-dev] [PATCH v5 7/9] drivers/softnic: " Savinay Dharmappa
@ 2020-09-30 19:24             ` Savinay Dharmappa
  2020-09-30 19:24             ` [dpdk-dev] [PATCH v5 9/9] sched : remove redundant code Savinay Dharmappa
  2020-10-06 15:27             ` [dpdk-dev] [PATCH v6 0/8] Enable dynamic config of subport bandwidth Savinay Dharmappa
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-30 19:24 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

Modify the test_sched application to build the hierarchical scheduler
with default subport bandwidth profile. It also allows to configure
a subport with different subport bandwidth profile dynamically

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 app/test/test_sched.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/app/test/test_sched.c b/app/test/test_sched.c
index fc31080ef..92d2b12fc 100644
--- a/app/test/test_sched.c
+++ b/app/test/test_sched.c
@@ -21,6 +21,7 @@
 #define PIPE            1
 #define TC              2
 #define QUEUE           0
+#define MAX_SCHED_SUBPORT_PROFILES  8
 
 static struct rte_sched_pipe_params pipe_profile[] = {
 	{ /* Profile #0 */
@@ -36,15 +37,20 @@ static struct rte_sched_pipe_params pipe_profile[] = {
 	},
 };
 
-static struct rte_sched_subport_params subport_param[] = {
+static struct rte_sched_subport_profile_params
+		subport_profile[] = {
 	{
 		.tb_rate = 1250000000,
 		.tb_size = 1000000,
-
 		.tc_rate = {1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000},
 		.tc_period = 10,
+	},
+};
+
+static struct rte_sched_subport_params subport_param[] = {
+	{
 		.n_pipes_per_subport_enabled = 1024,
 		.qsize = {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32},
 		.pipe_profiles = pipe_profile,
@@ -59,6 +65,9 @@ static struct rte_sched_port_params port_param = {
 	.mtu = 1522,
 	.frame_overhead = RTE_SCHED_FRAME_OVERHEAD_DEFAULT,
 	.n_subports_per_port = 1,
+	.n_subport_profiles = 1,
+	.subport_profiles = subport_profile,
+	.n_max_subport_profiles = MAX_SCHED_SUBPORT_PROFILES,
 	.n_pipes_per_subport = 1024,
 };
 
@@ -66,6 +75,7 @@ static struct rte_sched_port_params port_param = {
 #define MBUF_DATA_SZ     (2048 + RTE_PKTMBUF_HEADROOM)
 #define MEMPOOL_CACHE_SZ 0
 #define SOCKET           0
+#define DEFAULT_PROFILE  0
 
 
 static struct rte_mempool *
@@ -138,7 +148,8 @@ test_sched(void)
 	port = rte_sched_port_config(&port_param);
 	TEST_ASSERT_NOT_NULL(port, "Error config sched port\n");
 
-	err = rte_sched_subport_config(port, SUBPORT, subport_param);
+	err = rte_dynamic_sched_subport_config(port, SUBPORT, subport_param,
+						DEFAULT_PROFILE);
 	TEST_ASSERT_SUCCESS(err, "Error config sched, err=%d\n", err);
 
 	for (pipe = 0; pipe < subport_param[0].n_pipes_per_subport_enabled; pipe++) {
-- 
2.17.1


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

* [dpdk-dev] [PATCH v5 9/9] sched : remove redundant code
  2020-09-30 19:24           ` [dpdk-dev] [PATCH v5 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
                               ` (7 preceding siblings ...)
  2020-09-30 19:24             ` [dpdk-dev] [PATCH v5 8/9] app/test_sched: " Savinay Dharmappa
@ 2020-09-30 19:24             ` Savinay Dharmappa
  2020-10-06 15:27             ` [dpdk-dev] [PATCH v6 0/8] Enable dynamic config of subport bandwidth Savinay Dharmappa
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-09-30 19:24 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

Remove redundant data structure fields references from
functions and subport level data structures. It also
update the release and deprecation note

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 app/test/test_sched.c                    |   2 +-
 doc/guides/rel_notes/deprecation.rst     |   6 -
 doc/guides/rel_notes/release_20_11.rst   |   4 +
 drivers/net/softnic/rte_eth_softnic_tm.c |   4 +-
 examples/ip_pipeline/tmgr.c              |   4 +-
 examples/qos_sched/init.c                |   2 +-
 lib/librte_sched/rte_sched.c             | 273 +----------------------
 lib/librte_sched/rte_sched.h             |  31 +--
 8 files changed, 13 insertions(+), 313 deletions(-)

diff --git a/app/test/test_sched.c b/app/test/test_sched.c
index 92d2b12fc..2a649e320 100644
--- a/app/test/test_sched.c
+++ b/app/test/test_sched.c
@@ -148,7 +148,7 @@ test_sched(void)
 	port = rte_sched_port_config(&port_param);
 	TEST_ASSERT_NOT_NULL(port, "Error config sched port\n");
 
-	err = rte_dynamic_sched_subport_config(port, SUBPORT, subport_param,
+	err = rte_sched_subport_config(port, SUBPORT, subport_param,
 						DEFAULT_PROFILE);
 	TEST_ASSERT_SUCCESS(err, "Error config sched, err=%d\n", err);
 
diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 9691f2c57..0589edff2 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -231,12 +231,6 @@ Deprecation Notices
   in "rte_sched.h". These changes are aligned to improvements suggested in the
   RFC https://mails.dpdk.org/archives/dev/2018-November/120035.html.
 
-* sched: To allow dynamic configuration of the subport bandwidth profile,
-  changes will be made to data structures ``rte_sched_subport_params``,
-  ``rte_sched_port_params`` and new data structure, API functions will be
-  defined in ``rte_sched.h``. These changes are aligned as suggested in the
-  RFC https://mails.dpdk.org/archives/dev/2020-July/175161.html
-
 * metrics: The function ``rte_metrics_init`` will have a non-void return
   in order to notify errors instead of calling ``rte_exit``.
 
diff --git a/doc/guides/rel_notes/release_20_11.rst b/doc/guides/rel_notes/release_20_11.rst
index 4eb3224a7..6ec2bfb53 100644
--- a/doc/guides/rel_notes/release_20_11.rst
+++ b/doc/guides/rel_notes/release_20_11.rst
@@ -91,6 +91,10 @@ Removed Items
    Also, make sure to start the actual text at the margin.
    =======================================================
 
+* sched: The subport bandwidth configuration parameters such as tb_rate,
+  tc_rate, tc_period etc., are moved from subport level data structure to
+  new a data structure. This allows to configure a subport with different
+  subport bandwidth configuration dynamically.
 
 API Changes
 -----------
diff --git a/drivers/net/softnic/rte_eth_softnic_tm.c b/drivers/net/softnic/rte_eth_softnic_tm.c
index 92eb921ba..a19b0dd44 100644
--- a/drivers/net/softnic/rte_eth_softnic_tm.c
+++ b/drivers/net/softnic/rte_eth_softnic_tm.c
@@ -90,7 +90,7 @@ softnic_tmgr_port_create(struct pmd_internals *p,
 		uint32_t pipe_id;
 		int status;
 
-		status = rte_dynamic_sched_subport_config(sched,
+		status = rte_sched_subport_config(sched,
 			subport_id,
 			&t->subport_profile.params[subport_id],
 			t->subport_to_profile[subport_id]);
@@ -1162,7 +1162,7 @@ update_subport_tc_rate(struct rte_eth_dev *dev,
 		return -1;
 
 	/* Update the subport configuration. */
-	if (rte_dynamic_sched_subport_config(SCHED(p),
+	if (rte_sched_subport_config(SCHED(p),
 		subport_id, NULL, subport_profile_id))
 		return -1;
 
diff --git a/examples/ip_pipeline/tmgr.c b/examples/ip_pipeline/tmgr.c
index 446df8fe2..0f1b34461 100644
--- a/examples/ip_pipeline/tmgr.c
+++ b/examples/ip_pipeline/tmgr.c
@@ -130,7 +130,7 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 	for (i = 0; i < params->n_subports_per_port; i++) {
 		int status;
 
-		status = rte_dynamic_sched_subport_config(
+		status = rte_sched_subport_config(
 			s,
 			i,
 			&subport_profile.params[0], 0);
@@ -193,7 +193,7 @@ tmgr_subport_config(const char *port_name,
 		return -1;
 
 	/* Resource config */
-	status = rte_dynamic_sched_subport_config(
+	status = rte_sched_subport_config(
 		port->s,
 		subport_id,
 		NULL,
diff --git a/examples/qos_sched/init.c b/examples/qos_sched/init.c
index 9e7e21832..aee7172a2 100644
--- a/examples/qos_sched/init.c
+++ b/examples/qos_sched/init.c
@@ -322,7 +322,7 @@ app_init_sched_port(uint32_t portid, uint32_t socketid)
 	}
 
 	for (subport = 0; subport < port_params.n_subports_per_port; subport ++) {
-		err = rte_dynamic_sched_subport_config(port, subport,
+		err = rte_sched_subport_config(port, subport,
 						&subport_params[subport],
 						0);
 		if (err) {
diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index 2bf4a8c3c..7dbb3aeb1 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -152,16 +152,11 @@ struct rte_sched_grinder {
 struct rte_sched_subport {
 	/* Token bucket (TB) */
 	uint64_t tb_time; /* time of last update */
-	uint64_t tb_period;
-	uint64_t tb_credits_per_period;
-	uint64_t tb_size;
 	uint64_t tb_credits;
 
 	/* Traffic classes (TCs) */
 	uint64_t tc_time; /* time of next update */
-	uint64_t tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
 	uint64_t tc_credits[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
-	uint64_t tc_period;
 
 	/* TC oversubscription */
 	uint64_t tc_ov_wm;
@@ -837,18 +832,6 @@ rte_sched_subport_check_params(struct rte_sched_subport_params *params,
 		return -EINVAL;
 	}
 
-	if (params->tb_rate == 0 || params->tb_rate > rate) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect value for tb rate\n", __func__);
-		return -EINVAL;
-	}
-
-	if (params->tb_size == 0) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect value for tb size\n", __func__);
-		return -EINVAL;
-	}
-
 	/* qsize: if non-zero, power of 2,
 	 * no bigger than 32K (due to 16-bit read/write pointers)
 	 */
@@ -862,29 +845,8 @@ rte_sched_subport_check_params(struct rte_sched_subport_params *params,
 		}
 	}
 
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
-		uint64_t tc_rate = params->tc_rate[i];
-		uint16_t qsize = params->qsize[i];
-
-		if ((qsize == 0 && tc_rate != 0) ||
-			(qsize != 0 && tc_rate == 0) ||
-			(tc_rate > params->tb_rate)) {
-			RTE_LOG(ERR, SCHED,
-				"%s: Incorrect value for tc rate\n", __func__);
-			return -EINVAL;
-		}
-	}
-
-	if (params->qsize[RTE_SCHED_TRAFFIC_CLASS_BE] == 0 ||
-		params->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect qsize or tc rate(best effort)\n", __func__);
-		return -EINVAL;
-	}
-
-	if (params->tc_period == 0) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect value for tc period\n", __func__);
+	if (params->qsize[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
+		RTE_LOG(ERR, SCHED, "%s: Incorrect qsize\n", __func__);
 		return -EINVAL;
 	}
 
@@ -1101,48 +1063,6 @@ rte_sched_port_free(struct rte_sched_port *port)
 	rte_free(port);
 }
 
-static void
-rte_sched_port_log_subport_config(struct rte_sched_port *port, uint32_t i)
-{
-	struct rte_sched_subport *s = port->subports[i];
-
-	RTE_LOG(DEBUG, SCHED, "Low level config for subport %u:\n"
-		"	Token bucket: period = %"PRIu64", credits per period = %"PRIu64
-		", size = %"PRIu64"\n"
-		"	Traffic classes: period = %"PRIu64"\n"
-		"	credits per period = [%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
-		", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
-		", %"PRIu64", %"PRIu64", %"PRIu64"]\n"
-		"	Best effort traffic class oversubscription: wm min = %"PRIu64
-		", wm max = %"PRIu64"\n",
-		i,
-
-		/* Token bucket */
-		s->tb_period,
-		s->tb_credits_per_period,
-		s->tb_size,
-
-		/* Traffic classes */
-		s->tc_period,
-		s->tc_credits_per_period[0],
-		s->tc_credits_per_period[1],
-		s->tc_credits_per_period[2],
-		s->tc_credits_per_period[3],
-		s->tc_credits_per_period[4],
-		s->tc_credits_per_period[5],
-		s->tc_credits_per_period[6],
-		s->tc_credits_per_period[7],
-		s->tc_credits_per_period[8],
-		s->tc_credits_per_period[9],
-		s->tc_credits_per_period[10],
-		s->tc_credits_per_period[11],
-		s->tc_credits_per_period[12],
-
-		/* Best effort traffic class oversubscription */
-		s->tc_ov_wm_min,
-		s->tc_ov_wm_max);
-}
-
 static void
 rte_sched_free_memory(struct rte_sched_port *port, uint32_t n_subports)
 {
@@ -1203,195 +1123,6 @@ rte_sched_subport_profile_config(struct rte_sched_port *port,
 
 int
 rte_sched_subport_config(struct rte_sched_port *port,
-	uint32_t subport_id,
-	struct rte_sched_subport_params *params)
-{
-	struct rte_sched_subport *s = NULL;
-	uint32_t n_subports = subport_id;
-	uint32_t n_subport_pipe_queues, i;
-	uint32_t size0, size1, bmp_mem_size;
-	int status;
-
-	/* Check user parameters */
-	if (port == NULL) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect value for parameter port\n", __func__);
-		return 0;
-	}
-
-	if (subport_id >= port->n_subports_per_port) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect value for subport id\n", __func__);
-
-		rte_sched_free_memory(port, n_subports);
-		return -EINVAL;
-	}
-
-	status = rte_sched_subport_check_params(params,
-		port->n_pipes_per_subport,
-		port->rate);
-	if (status != 0) {
-		RTE_LOG(NOTICE, SCHED,
-			"%s: Port scheduler params check failed (%d)\n",
-			__func__, status);
-
-		rte_sched_free_memory(port, n_subports);
-		return -EINVAL;
-	}
-
-	/* Determine the amount of memory to allocate */
-	size0 = sizeof(struct rte_sched_subport);
-	size1 = rte_sched_subport_get_array_base(params,
-				e_RTE_SCHED_SUBPORT_ARRAY_TOTAL);
-
-	/* Allocate memory to store the data structures */
-	s = rte_zmalloc_socket("subport_params", size0 + size1,
-		RTE_CACHE_LINE_SIZE, port->socket);
-	if (s == NULL) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Memory allocation fails\n", __func__);
-
-		rte_sched_free_memory(port, n_subports);
-		return -ENOMEM;
-	}
-
-	n_subports++;
-
-	/* Port */
-	port->subports[subport_id] = s;
-
-	/* Token Bucket (TB) */
-	if (params->tb_rate == port->rate) {
-		s->tb_credits_per_period = 1;
-		s->tb_period = 1;
-	} else {
-		double tb_rate = ((double) params->tb_rate) / ((double) port->rate);
-		double d = RTE_SCHED_TB_RATE_CONFIG_ERR;
-
-		rte_approx_64(tb_rate, d, &s->tb_credits_per_period, &s->tb_period);
-	}
-
-	s->tb_size = params->tb_size;
-	s->tb_time = port->time;
-	s->tb_credits = s->tb_size / 2;
-
-	/* Traffic Classes (TCs) */
-	s->tc_period = rte_sched_time_ms_to_bytes(params->tc_period, port->rate);
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
-		if (params->qsize[i])
-			s->tc_credits_per_period[i]
-				= rte_sched_time_ms_to_bytes(params->tc_period,
-					params->tc_rate[i]);
-	}
-	s->tc_time = port->time + s->tc_period;
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-		if (params->qsize[i])
-			s->tc_credits[i] = s->tc_credits_per_period[i];
-
-	/* compile time checks */
-	RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS == 0);
-	RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS &
-		(RTE_SCHED_PORT_N_GRINDERS - 1));
-
-	/* User parameters */
-	s->n_pipes_per_subport_enabled = params->n_pipes_per_subport_enabled;
-	memcpy(s->qsize, params->qsize, sizeof(params->qsize));
-	s->n_pipe_profiles = params->n_pipe_profiles;
-	s->n_max_pipe_profiles = params->n_max_pipe_profiles;
-
-#ifdef RTE_SCHED_RED
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
-		uint32_t j;
-
-		for (j = 0; j < RTE_COLORS; j++) {
-			/* if min/max are both zero, then RED is disabled */
-			if ((params->red_params[i][j].min_th |
-			     params->red_params[i][j].max_th) == 0) {
-				continue;
-			}
-
-			if (rte_red_config_init(&s->red_config[i][j],
-				params->red_params[i][j].wq_log2,
-				params->red_params[i][j].min_th,
-				params->red_params[i][j].max_th,
-				params->red_params[i][j].maxp_inv) != 0) {
-				rte_sched_free_memory(port, n_subports);
-
-				RTE_LOG(NOTICE, SCHED,
-				"%s: RED configuration init fails\n", __func__);
-				return -EINVAL;
-			}
-		}
-	}
-#endif
-
-	/* Scheduling loop detection */
-	s->pipe_loop = RTE_SCHED_PIPE_INVALID;
-	s->pipe_exhaustion = 0;
-
-	/* Grinders */
-	s->busy_grinders = 0;
-
-	/* Queue base calculation */
-	rte_sched_subport_config_qsize(s);
-
-	/* Large data structures */
-	s->pipe = (struct rte_sched_pipe *)
-		(s->memory + rte_sched_subport_get_array_base(params,
-		e_RTE_SCHED_SUBPORT_ARRAY_PIPE));
-	s->queue = (struct rte_sched_queue *)
-		(s->memory + rte_sched_subport_get_array_base(params,
-		e_RTE_SCHED_SUBPORT_ARRAY_QUEUE));
-	s->queue_extra = (struct rte_sched_queue_extra *)
-		(s->memory + rte_sched_subport_get_array_base(params,
-		e_RTE_SCHED_SUBPORT_ARRAY_QUEUE_EXTRA));
-	s->pipe_profiles = (struct rte_sched_pipe_profile *)
-		(s->memory + rte_sched_subport_get_array_base(params,
-		e_RTE_SCHED_SUBPORT_ARRAY_PIPE_PROFILES));
-	s->bmp_array =  s->memory + rte_sched_subport_get_array_base(params,
-		e_RTE_SCHED_SUBPORT_ARRAY_BMP_ARRAY);
-	s->queue_array = (struct rte_mbuf **)
-		(s->memory + rte_sched_subport_get_array_base(params,
-		e_RTE_SCHED_SUBPORT_ARRAY_QUEUE_ARRAY));
-
-	/* Pipe profile table */
-	rte_sched_subport_config_pipe_profile_table(s, params, port->rate);
-
-	/* Bitmap */
-	n_subport_pipe_queues = rte_sched_subport_pipe_queues(s);
-	bmp_mem_size = rte_bitmap_get_memory_footprint(n_subport_pipe_queues);
-	s->bmp = rte_bitmap_init(n_subport_pipe_queues, s->bmp_array,
-				bmp_mem_size);
-	if (s->bmp == NULL) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Subport bitmap init error\n", __func__);
-
-		rte_sched_free_memory(port, n_subports);
-		return -EINVAL;
-	}
-
-	for (i = 0; i < RTE_SCHED_PORT_N_GRINDERS; i++)
-		s->grinder_base_bmp_pos[i] = RTE_SCHED_PIPE_INVALID;
-
-#ifdef RTE_SCHED_SUBPORT_TC_OV
-	/* TC oversubscription */
-	s->tc_ov_wm_min = port->mtu;
-	s->tc_ov_wm_max = rte_sched_time_ms_to_bytes(params->tc_period,
-						     s->pipe_tc_be_rate_max);
-	s->tc_ov_wm = s->tc_ov_wm_max;
-	s->tc_ov_period_id = 0;
-	s->tc_ov = 0;
-	s->tc_ov_n = 0;
-	s->tc_ov_rate = 0;
-#endif
-
-	rte_sched_port_log_subport_config(port, subport_id);
-
-	return 0;
-}
-
-int
-rte_dynamic_sched_subport_config(struct rte_sched_port *port,
 	uint32_t subport_id,
 	struct rte_sched_subport_params *params,
 	uint32_t subport_profile_id)
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index 3ecb0e9c3..78aebcd9e 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -149,18 +149,6 @@ struct rte_sched_pipe_params {
  * byte.
  */
 struct rte_sched_subport_params {
-	/** Token bucket rate (measured in bytes per second) */
-	uint64_t tb_rate;
-
-	/** Token bucket size (measured in credits) */
-	uint64_t tb_size;
-
-	/** Traffic class rates (measured in bytes per second) */
-	uint64_t tc_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
-
-	/** Enforcement period for rates (measured in milliseconds) */
-	uint64_t tc_period;
-
 	/** Number of subport pipes.
 	 * The subport can enable/allocate fewer pipes than the maximum
 	 * number set through struct port_params::n_max_pipes_per_subport,
@@ -359,23 +347,6 @@ rte_sched_port_subport_profile_add(struct rte_sched_port *port,
 	struct rte_sched_subport_profile_params *profile,
 	uint32_t *subport_profile_id);
 
-/**
- * Hierarchical scheduler subport configuration
- *
- * @param port
- *   Handle to port scheduler instance
- * @param subport_id
- *   Subport ID
- * @param params
- *   Subport configuration parameters
- * @return
- *   0 upon success, error code otherwise
- */
-int
-rte_sched_subport_config(struct rte_sched_port *port,
-	uint32_t subport_id,
-	struct rte_sched_subport_params *params);
-
 /**
  * Hierarchical scheduler subport configuration.
  * Note that this function is also used at runtime
@@ -395,7 +366,7 @@ rte_sched_subport_config(struct rte_sched_port *port,
  *   0 upon success, error code otherwise
  */
 int
-rte_dynamic_sched_subport_config(struct rte_sched_port *port,
+rte_sched_subport_config(struct rte_sched_port *port,
 	uint32_t subport_id,
 	struct rte_sched_subport_params *params,
 	uint32_t subport_profile_id);
-- 
2.17.1


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

* [dpdk-dev] [PATCH v6 0/8] Enable dynamic config of subport bandwidth
  2020-09-30 19:24           ` [dpdk-dev] [PATCH v5 0/9] Enable dynamic config of subport bandwidth Savinay Dharmappa
                               ` (8 preceding siblings ...)
  2020-09-30 19:24             ` [dpdk-dev] [PATCH v5 9/9] sched : remove redundant code Savinay Dharmappa
@ 2020-10-06 15:27             ` Savinay Dharmappa
  2020-10-06 15:27               ` [dpdk-dev] [PATCH v6 1/8] sched: add support profile table Savinay Dharmappa
                                 ` (9 more replies)
  9 siblings, 10 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-10-06 15:27 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

DPDK sched library allows runtime configuration of the pipe profiles to the
pipes of the subport once scheduler hierarchy is constructed. However, to
change the subport level bandwidth, existing hierarchy needs to be
dismantled and whole process of building hierarchy under subport nodes
needs to be repeated which might result in router downtime. Furthermore,
due to lack of dynamic configuration of the subport bandwidth profile
configuration (shaper and Traffic class rates), the user application
is unable to dynamically re-distribute the excess-bandwidth of one subport
among other subports in the scheduler hierarchy. Therefore, it is also not
possible to adjust the subport bandwidth profile in sync with dynamic
changes in pipe profiles of subscribers who want to consume higher
bandwidth opportunistically.

This patch series implements dynamic configuration of the subport bandwidth
profile to overcome the runtime situation when group of subscribers are not
using the allotted bandwidth and dynamic bandwidth re-distribution is
needed the without making any structural changes in the hierarchy.

The implementation work includes refactoring the existing api and
data structures defined for port and subport level, new APIs for
adding subport level bandwidth profiles that can be used in runtime

Savinay Dharmappa (8):
  sched: add support profile table
  sched: introduce subport profile add function
  sched: update subport rate dynamically
  example/qos_sched: update subport rate dynamically
  example/ip_pipeline: update subport rate dynamically
  drivers/softnic: update subport rate dynamically
  app/test_sched: update subport rate dynamically
  sched: remove redundant code

 app/test/test_sched.c                         |  15 +-
 doc/guides/rel_notes/deprecation.rst          |   6 -
 doc/guides/rel_notes/release_20_11.rst        |   2 +
 .../net/softnic/rte_eth_softnic_internals.h   |  11 +-
 drivers/net/softnic/rte_eth_softnic_tm.c      | 243 +++++--
 examples/ip_pipeline/cli.c                    |  68 +-
 examples/ip_pipeline/tmgr.c                   | 121 +++-
 examples/ip_pipeline/tmgr.h                   |   5 +-
 examples/qos_sched/cfg_file.c                 | 151 ++--
 examples/qos_sched/cfg_file.h                 |   4 +
 examples/qos_sched/init.c                     |  21 +-
 examples/qos_sched/main.h                     |   1 +
 examples/qos_sched/profile.cfg                |   3 +
 lib/librte_sched/rte_sched.c                  | 678 ++++++++++++------
 lib/librte_sched/rte_sched.h                  |  73 +-
 lib/librte_sched/rte_sched_version.map        |   2 +
 16 files changed, 959 insertions(+), 445 deletions(-)

-- 
2.17.1


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

* [dpdk-dev] [PATCH v6 1/8] sched: add support profile table
  2020-10-06 15:27             ` [dpdk-dev] [PATCH v6 0/8] Enable dynamic config of subport bandwidth Savinay Dharmappa
@ 2020-10-06 15:27               ` Savinay Dharmappa
  2020-10-06 15:27               ` [dpdk-dev] [PATCH v6 2/8] sched: introduce subport profile add function Savinay Dharmappa
                                 ` (8 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-10-06 15:27 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

Add subport profile table to internal port data structure
and update the port config function.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c | 197 ++++++++++++++++++++++++++++++++++-
 lib/librte_sched/rte_sched.h |  25 +++++
 2 files changed, 219 insertions(+), 3 deletions(-)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index 75be8b6bd..a44638f31 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -101,6 +101,16 @@ enum grinder_state {
 	e_GRINDER_READ_MBUF
 };
 
+struct rte_sched_subport_profile {
+	/* Token bucket (TB) */
+	uint64_t tb_period;
+	uint64_t tb_credits_per_period;
+	uint64_t tb_size;
+
+	uint64_t tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+	uint64_t tc_period;
+};
+
 struct rte_sched_grinder {
 	/* Pipe cache */
 	uint16_t pcache_qmask[RTE_SCHED_GRINDER_PCACHE_SIZE];
@@ -212,6 +222,8 @@ struct rte_sched_port {
 	uint16_t pipe_queue[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
 	uint8_t pipe_tc[RTE_SCHED_QUEUES_PER_PIPE];
 	uint8_t tc_queue[RTE_SCHED_QUEUES_PER_PIPE];
+	uint32_t n_subport_profiles;
+	uint32_t n_max_subport_profiles;
 	uint64_t rate;
 	uint32_t mtu;
 	uint32_t frame_overhead;
@@ -230,6 +242,7 @@ struct rte_sched_port {
 	uint32_t subport_id;
 
 	/* Large data structures */
+	struct rte_sched_subport_profile *subport_profiles;
 	struct rte_sched_subport *subports[0] __rte_cache_aligned;
 } __rte_cache_aligned;
 
@@ -375,9 +388,61 @@ pipe_profile_check(struct rte_sched_pipe_params *params,
 	return 0;
 }
 
+static int
+subport_profile_check(struct rte_sched_subport_profile_params *params,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	/* Check user parameters */
+	if (params == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter params\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tb_rate == 0 || params->tb_rate > rate) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for tb rate\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tb_size == 0) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for tb size\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
+		uint64_t tc_rate = params->tc_rate[i];
+
+		if (tc_rate == 0 || (tc_rate > params->tb_rate)) {
+			RTE_LOG(ERR, SCHED, "%s: "
+			"Incorrect value for tc rate\n", __func__);
+			return -EINVAL;
+		}
+	}
+
+	if (params->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect tc rate(best effort)\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tc_period == 0) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for tc period\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int
 rte_sched_port_check_params(struct rte_sched_port_params *params)
 {
+	uint32_t i;
+
 	if (params == NULL) {
 		RTE_LOG(ERR, SCHED,
 			"%s: Incorrect value for parameter params\n", __func__);
@@ -414,6 +479,29 @@ rte_sched_port_check_params(struct rte_sched_port_params *params)
 		return -EINVAL;
 	}
 
+	if (params->subport_profiles == NULL ||
+		params->n_subport_profiles == 0 ||
+		params->n_max_subport_profiles == 0 ||
+		params->n_subport_profiles > params->n_max_subport_profiles) {
+		RTE_LOG(ERR, SCHED,
+		"%s: Incorrect value for subport profiles\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < params->n_subport_profiles; i++) {
+		struct rte_sched_subport_profile_params *p =
+						params->subport_profiles + i;
+		int status;
+
+		status = subport_profile_check(p, params->rate);
+		if (status != 0) {
+			RTE_LOG(ERR, SCHED,
+			"%s: subport profile check failed(%d)\n",
+			__func__, status);
+			return -EINVAL;
+		}
+	}
+
 	/* n_pipes_per_subport: non-zero, power of 2 */
 	if (params->n_pipes_per_subport == 0 ||
 	    !rte_is_power_of_2(params->n_pipes_per_subport)) {
@@ -555,6 +643,42 @@ rte_sched_port_log_pipe_profile(struct rte_sched_subport *subport, uint32_t i)
 		p->wrr_cost[0], p->wrr_cost[1], p->wrr_cost[2], p->wrr_cost[3]);
 }
 
+static void
+rte_sched_port_log_subport_profile(struct rte_sched_port *port, uint32_t i)
+{
+	struct rte_sched_subport_profile *p = port->subport_profiles + i;
+
+	RTE_LOG(DEBUG, SCHED, "Low level config for subport profile %u:\n"
+	"Token bucket: period = %"PRIu64", credits per period = %"PRIu64","
+	"size = %"PRIu64"\n"
+	"Traffic classes: period = %"PRIu64",\n"
+	"credits per period = [%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
+	" %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
+	" %"PRIu64", %"PRIu64", %"PRIu64"]\n",
+	i,
+
+	/* Token bucket */
+	p->tb_period,
+	p->tb_credits_per_period,
+	p->tb_size,
+
+	/* Traffic classes */
+	p->tc_period,
+	p->tc_credits_per_period[0],
+	p->tc_credits_per_period[1],
+	p->tc_credits_per_period[2],
+	p->tc_credits_per_period[3],
+	p->tc_credits_per_period[4],
+	p->tc_credits_per_period[5],
+	p->tc_credits_per_period[6],
+	p->tc_credits_per_period[7],
+	p->tc_credits_per_period[8],
+	p->tc_credits_per_period[9],
+	p->tc_credits_per_period[10],
+	p->tc_credits_per_period[11],
+	p->tc_credits_per_period[12]);
+}
+
 static inline uint64_t
 rte_sched_time_ms_to_bytes(uint64_t time_ms, uint64_t rate)
 {
@@ -623,6 +747,37 @@ rte_sched_pipe_profile_convert(struct rte_sched_subport *subport,
 	dst->wrr_cost[3] = (uint8_t) wrr_cost[3];
 }
 
+static void
+rte_sched_subport_profile_convert(struct rte_sched_subport_profile_params *src,
+	struct rte_sched_subport_profile *dst,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	/* Token Bucket */
+	if (src->tb_rate == rate) {
+		dst->tb_credits_per_period = 1;
+		dst->tb_period = 1;
+	} else {
+		double tb_rate = (double) src->tb_rate
+				/ (double) rate;
+		double d = RTE_SCHED_TB_RATE_CONFIG_ERR;
+
+		rte_approx_64(tb_rate, d, &dst->tb_credits_per_period,
+			&dst->tb_period);
+	}
+
+	dst->tb_size = src->tb_size;
+
+	/* Traffic Classes */
+	dst->tc_period = rte_sched_time_ms_to_bytes(src->tc_period, rate);
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		dst->tc_credits_per_period[i]
+			= rte_sched_time_ms_to_bytes(src->tc_period,
+				src->tc_rate[i]);
+}
+
 static void
 rte_sched_subport_config_pipe_profile_table(struct rte_sched_subport *subport,
 	struct rte_sched_subport_params *params, uint64_t rate)
@@ -647,6 +802,24 @@ rte_sched_subport_config_pipe_profile_table(struct rte_sched_subport *subport,
 	}
 }
 
+static void
+rte_sched_port_config_subport_profile_table(struct rte_sched_port *port,
+	struct rte_sched_port_params *params,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	for (i = 0; i < port->n_subport_profiles; i++) {
+		struct rte_sched_subport_profile_params *src
+				= params->subport_profiles + i;
+		struct rte_sched_subport_profile *dst
+				= port->subport_profiles + i;
+
+		rte_sched_subport_profile_convert(src, dst, rate);
+		rte_sched_port_log_subport_profile(port, i);
+	}
+}
+
 static int
 rte_sched_subport_check_params(struct rte_sched_subport_params *params,
 	uint32_t n_max_pipes_per_subport,
@@ -793,7 +966,7 @@ struct rte_sched_port *
 rte_sched_port_config(struct rte_sched_port_params *params)
 {
 	struct rte_sched_port *port = NULL;
-	uint32_t size0, size1;
+	uint32_t size0, size1, size2;
 	uint32_t cycles_per_byte;
 	uint32_t i, j;
 	int status;
@@ -808,10 +981,21 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 
 	size0 = sizeof(struct rte_sched_port);
 	size1 = params->n_subports_per_port * sizeof(struct rte_sched_subport *);
+	size2 = params->n_max_subport_profiles *
+		sizeof(struct rte_sched_subport_profile);
 
 	/* Allocate memory to store the data structures */
-	port = rte_zmalloc_socket("qos_params", size0 + size1, RTE_CACHE_LINE_SIZE,
-		params->socket);
+	port = rte_zmalloc_socket("qos_params", size0 + size1,
+				 RTE_CACHE_LINE_SIZE, params->socket);
+	if (port == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: Memory allocation fails\n", __func__);
+
+		return NULL;
+	}
+
+	/* Allocate memory to store the subport profile */
+	port->subport_profiles  = rte_zmalloc_socket("subport_profile", size2,
+					RTE_CACHE_LINE_SIZE, params->socket);
 	if (port == NULL) {
 		RTE_LOG(ERR, SCHED, "%s: Memory allocation fails\n", __func__);
 
@@ -820,6 +1004,8 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 
 	/* User parameters */
 	port->n_subports_per_port = params->n_subports_per_port;
+	port->n_subport_profiles = params->n_subport_profiles;
+	port->n_max_subport_profiles = params->n_max_subport_profiles;
 	port->n_pipes_per_subport = params->n_pipes_per_subport;
 	port->n_pipes_per_subport_log2 =
 			__builtin_ctz(params->n_pipes_per_subport);
@@ -850,6 +1036,9 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 	port->time_cpu_bytes = 0;
 	port->time = 0;
 
+	/* Subport profile table */
+	rte_sched_port_config_subport_profile_table(port, params, port->rate);
+
 	cycles_per_byte = (rte_get_tsc_hz() << RTE_SCHED_TIME_SHIFT)
 		/ params->rate;
 	port->inv_cycles_per_byte = rte_reciprocal_value(cycles_per_byte);
@@ -905,6 +1094,7 @@ rte_sched_port_free(struct rte_sched_port *port)
 	for (i = 0; i < port->n_subports_per_port; i++)
 		rte_sched_subport_free(port, port->subports[i]);
 
+	rte_free(port->subport_profiles);
 	rte_free(port);
 }
 
@@ -961,6 +1151,7 @@ rte_sched_free_memory(struct rte_sched_port *port, uint32_t n_subports)
 		rte_sched_subport_free(port, subport);
 	}
 
+	rte_free(port->subport_profiles);
 	rte_free(port);
 }
 
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index 8a5a93c98..39339b7f1 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -192,6 +192,20 @@ struct rte_sched_subport_params {
 #endif
 };
 
+struct rte_sched_subport_profile_params {
+	/** Token bucket rate (measured in bytes per second) */
+	uint64_t tb_rate;
+
+	/** Token bucket size (measured in credits) */
+	uint64_t tb_size;
+
+	/** Traffic class rates (measured in bytes per second) */
+	uint64_t tc_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+
+	/** Enforcement period for rates (measured in milliseconds) */
+	uint64_t tc_period;
+};
+
 /** Subport statistics */
 struct rte_sched_subport_stats {
 	/** Number of packets successfully written */
@@ -254,6 +268,17 @@ struct rte_sched_port_params {
 	/** Number of subports */
 	uint32_t n_subports_per_port;
 
+	/** subport profile table.
+	 * Every pipe is configured using one of the profiles from this table.
+	 */
+	struct rte_sched_subport_profile_params *subport_profiles;
+
+	/** Profiles in the pipe profile table */
+	uint32_t n_subport_profiles;
+
+	/** Max allowed profiles in the pipe profile table */
+	uint32_t n_max_subport_profiles;
+
 	/** Maximum number of subport pipes.
 	 * This parameter is used to reserve a fixed number of bits
 	 * in struct rte_mbuf::sched.queue_id for the pipe_id for all
-- 
2.17.1


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

* [dpdk-dev] [PATCH v6 2/8] sched: introduce subport profile add function
  2020-10-06 15:27             ` [dpdk-dev] [PATCH v6 0/8] Enable dynamic config of subport bandwidth Savinay Dharmappa
  2020-10-06 15:27               ` [dpdk-dev] [PATCH v6 1/8] sched: add support profile table Savinay Dharmappa
@ 2020-10-06 15:27               ` Savinay Dharmappa
  2020-10-06 15:27               ` [dpdk-dev] [PATCH v6 3/8] sched: update subport rate dynamically Savinay Dharmappa
                                 ` (7 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-10-06 15:27 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

API to add new subport bandwidth profile.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c           | 66 ++++++++++++++++++++++++++
 lib/librte_sched/rte_sched.h           | 23 +++++++++
 lib/librte_sched/rte_sched_version.map |  2 +
 3 files changed, 91 insertions(+)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index a44638f31..895b40d72 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -1528,6 +1528,72 @@ rte_sched_subport_pipe_profile_add(struct rte_sched_port *port,
 	return 0;
 }
 
+int
+rte_sched_port_subport_profile_add(struct rte_sched_port *port,
+	struct rte_sched_subport_profile_params *params,
+	uint32_t *subport_profile_id)
+{
+	int status;
+	uint32_t i;
+	struct rte_sched_subport_profile *dst;
+
+	/* Port */
+	if (port == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter port\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter profile\n", __func__);
+		return -EINVAL;
+	}
+
+	if (subport_profile_id == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter subport_profile_id\n",
+		__func__);
+		return -EINVAL;
+	}
+
+	dst = port->subport_profiles + port->n_subport_profiles;
+
+	/* Subport profiles exceeds the max limit */
+	if (port->n_subport_profiles >= port->n_max_subport_profiles) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Number of subport profiles exceeds the max limit\n",
+		 __func__);
+		return -EINVAL;
+	}
+
+	status = subport_profile_check(params, port->rate);
+	if (status != 0) {
+		RTE_LOG(ERR, SCHED,
+		"%s: subport profile check failed(%d)\n", __func__, status);
+		return -EINVAL;
+	}
+
+	rte_sched_subport_profile_convert(params, dst, port->rate);
+
+	/* Subport profile should not exists */
+	for (i = 0; i < port->n_subport_profiles; i++)
+		if (memcmp(port->subport_profiles + i,
+		    dst, sizeof(*dst)) == 0) {
+			RTE_LOG(ERR, SCHED,
+			"%s: subport profile exists\n", __func__);
+			return -EINVAL;
+		}
+
+	/* Subport profile commit */
+	*subport_profile_id = port->n_subport_profiles;
+	port->n_subport_profiles++;
+
+	rte_sched_port_log_subport_profile(port, *subport_profile_id);
+
+	return 0;
+}
+
 static inline uint32_t
 rte_sched_port_qindex(struct rte_sched_port *port,
 	uint32_t subport,
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index 39339b7f1..4b0abaac3 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -336,6 +336,29 @@ rte_sched_subport_pipe_profile_add(struct rte_sched_port *port,
 	struct rte_sched_pipe_params *params,
 	uint32_t *pipe_profile_id);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Hierarchical scheduler subport bandwidth profile add
+ * Note that this function is safe to use in runtime for adding new
+ * subport bandwidth profile as it doesn't have any impact on hiearchical
+ * structure of the scheduler.
+ * @param port
+ *   Handle to port scheduler instance
+ * @param profile
+ *   Subport bandwidth profile
+ * @param subport_profile_d
+ *   Subport profile id
+ * @return
+ *   0 upon success, error code otherwise
+ */
+__rte_experimental
+int
+rte_sched_port_subport_profile_add(struct rte_sched_port *port,
+	struct rte_sched_subport_profile_params *profile,
+	uint32_t *subport_profile_id);
+
 /**
  * Hierarchical scheduler subport configuration
  *
diff --git a/lib/librte_sched/rte_sched_version.map b/lib/librte_sched/rte_sched_version.map
index 3faef6f0a..ace284b7d 100644
--- a/lib/librte_sched/rte_sched_version.map
+++ b/lib/librte_sched/rte_sched_version.map
@@ -28,4 +28,6 @@ EXPERIMENTAL {
 	global:
 
 	rte_sched_subport_pipe_profile_add;
+	# added in 20.11
+	rte_sched_port_subport_profile_add;
 };
-- 
2.17.1


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

* [dpdk-dev] [PATCH v6 3/8] sched: update subport rate dynamically
  2020-10-06 15:27             ` [dpdk-dev] [PATCH v6 0/8] Enable dynamic config of subport bandwidth Savinay Dharmappa
  2020-10-06 15:27               ` [dpdk-dev] [PATCH v6 1/8] sched: add support profile table Savinay Dharmappa
  2020-10-06 15:27               ` [dpdk-dev] [PATCH v6 2/8] sched: introduce subport profile add function Savinay Dharmappa
@ 2020-10-06 15:27               ` Savinay Dharmappa
  2020-10-06 15:27               ` [dpdk-dev] [PATCH v6 4/8] example/qos_sched: " Savinay Dharmappa
                                 ` (6 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-10-06 15:27 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

Add support to update subport rate dynamically.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 app/test/test_sched.c                    |   2 +-
 drivers/net/softnic/rte_eth_softnic_tm.c |   6 +-
 examples/ip_pipeline/tmgr.c              |   6 +-
 examples/qos_sched/init.c                |   3 +-
 lib/librte_sched/rte_sched.c             | 373 +++++++++++------------
 lib/librte_sched/rte_sched.h             |  13 +-
 6 files changed, 202 insertions(+), 201 deletions(-)

diff --git a/app/test/test_sched.c b/app/test/test_sched.c
index fc31080ef..5e5c2a59b 100644
--- a/app/test/test_sched.c
+++ b/app/test/test_sched.c
@@ -138,7 +138,7 @@ test_sched(void)
 	port = rte_sched_port_config(&port_param);
 	TEST_ASSERT_NOT_NULL(port, "Error config sched port\n");
 
-	err = rte_sched_subport_config(port, SUBPORT, subport_param);
+	err = rte_sched_subport_config(port, SUBPORT, subport_param, 0);
 	TEST_ASSERT_SUCCESS(err, "Error config sched, err=%d\n", err);
 
 	for (pipe = 0; pipe < subport_param[0].n_pipes_per_subport_enabled; pipe++) {
diff --git a/drivers/net/softnic/rte_eth_softnic_tm.c b/drivers/net/softnic/rte_eth_softnic_tm.c
index d30976378..5199dd2cd 100644
--- a/drivers/net/softnic/rte_eth_softnic_tm.c
+++ b/drivers/net/softnic/rte_eth_softnic_tm.c
@@ -92,7 +92,7 @@ softnic_tmgr_port_create(struct pmd_internals *p,
 
 		status = rte_sched_subport_config(sched,
 			subport_id,
-			&t->subport_params[subport_id]);
+			&t->subport_params[subport_id], 0);
 		if (status) {
 			rte_sched_port_free(sched);
 			return NULL;
@@ -1141,7 +1141,7 @@ update_subport_tc_rate(struct rte_eth_dev *dev,
 
 	/* Update the subport configuration. */
 	if (rte_sched_subport_config(SCHED(p),
-		subport_id, &subport_params))
+		subport_id, &subport_params, 0))
 		return -1;
 
 	/* Commit changes. */
@@ -2912,7 +2912,7 @@ update_subport_rate(struct rte_eth_dev *dev,
 
 	/* Update the subport configuration. */
 	if (rte_sched_subport_config(SCHED(p), subport_id,
-		&subport_params))
+		&subport_params, 0))
 		return -1;
 
 	/* Commit changes. */
diff --git a/examples/ip_pipeline/tmgr.c b/examples/ip_pipeline/tmgr.c
index 91ccbf60f..46c6a83a4 100644
--- a/examples/ip_pipeline/tmgr.c
+++ b/examples/ip_pipeline/tmgr.c
@@ -119,7 +119,8 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 		status = rte_sched_subport_config(
 			s,
 			i,
-			&subport_profile[0]);
+			&subport_profile[0],
+			0);
 
 		if (status) {
 			rte_sched_port_free(s);
@@ -180,7 +181,8 @@ tmgr_subport_config(const char *port_name,
 	status = rte_sched_subport_config(
 		port->s,
 		subport_id,
-		&subport_profile[subport_profile_id]);
+		&subport_profile[subport_profile_id],
+		0);
 
 	return status;
 }
diff --git a/examples/qos_sched/init.c b/examples/qos_sched/init.c
index 06328ddb2..b188c624b 100644
--- a/examples/qos_sched/init.c
+++ b/examples/qos_sched/init.c
@@ -314,7 +314,8 @@ app_init_sched_port(uint32_t portid, uint32_t socketid)
 	}
 
 	for (subport = 0; subport < port_params.n_subports_per_port; subport ++) {
-		err = rte_sched_subport_config(port, subport, &subport_params[subport]);
+		err = rte_sched_subport_config(port, subport,
+				&subport_params[subport], 0);
 		if (err) {
 			rte_exit(EXIT_FAILURE, "Unable to config sched subport %u, err=%d\n",
 					subport, err);
diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index 895b40d72..c5482d6e0 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -123,6 +123,7 @@ struct rte_sched_grinder {
 	uint32_t productive;
 	uint32_t pindex;
 	struct rte_sched_subport *subport;
+	struct rte_sched_subport_profile *subport_params;
 	struct rte_sched_pipe *pipe;
 	struct rte_sched_pipe_profile *pipe_params;
 
@@ -174,6 +175,8 @@ struct rte_sched_subport {
 	/* Statistics */
 	struct rte_sched_subport_stats stats __rte_cache_aligned;
 
+	/* subport profile */
+	uint32_t profile;
 	/* Subport pipes */
 	uint32_t n_pipes_per_subport_enabled;
 	uint32_t n_pipe_profiles;
@@ -1098,48 +1101,6 @@ rte_sched_port_free(struct rte_sched_port *port)
 	rte_free(port);
 }
 
-static void
-rte_sched_port_log_subport_config(struct rte_sched_port *port, uint32_t i)
-{
-	struct rte_sched_subport *s = port->subports[i];
-
-	RTE_LOG(DEBUG, SCHED, "Low level config for subport %u:\n"
-		"	Token bucket: period = %"PRIu64", credits per period = %"PRIu64
-		", size = %"PRIu64"\n"
-		"	Traffic classes: period = %"PRIu64"\n"
-		"	credits per period = [%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
-		", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
-		", %"PRIu64", %"PRIu64", %"PRIu64"]\n"
-		"	Best effort traffic class oversubscription: wm min = %"PRIu64
-		", wm max = %"PRIu64"\n",
-		i,
-
-		/* Token bucket */
-		s->tb_period,
-		s->tb_credits_per_period,
-		s->tb_size,
-
-		/* Traffic classes */
-		s->tc_period,
-		s->tc_credits_per_period[0],
-		s->tc_credits_per_period[1],
-		s->tc_credits_per_period[2],
-		s->tc_credits_per_period[3],
-		s->tc_credits_per_period[4],
-		s->tc_credits_per_period[5],
-		s->tc_credits_per_period[6],
-		s->tc_credits_per_period[7],
-		s->tc_credits_per_period[8],
-		s->tc_credits_per_period[9],
-		s->tc_credits_per_period[10],
-		s->tc_credits_per_period[11],
-		s->tc_credits_per_period[12],
-
-		/* Best effort traffic class oversubscription */
-		s->tc_ov_wm_min,
-		s->tc_ov_wm_max);
-}
-
 static void
 rte_sched_free_memory(struct rte_sched_port *port, uint32_t n_subports)
 {
@@ -1158,10 +1119,12 @@ rte_sched_free_memory(struct rte_sched_port *port, uint32_t n_subports)
 int
 rte_sched_subport_config(struct rte_sched_port *port,
 	uint32_t subport_id,
-	struct rte_sched_subport_params *params)
+	struct rte_sched_subport_params *params,
+	uint32_t subport_profile_id)
 {
 	struct rte_sched_subport *s = NULL;
 	uint32_t n_subports = subport_id;
+	struct rte_sched_subport_profile *profile;
 	uint32_t n_subport_pipe_queues, i;
 	uint32_t size0, size1, bmp_mem_size;
 	int status;
@@ -1181,165 +1144,183 @@ rte_sched_subport_config(struct rte_sched_port *port,
 		return -EINVAL;
 	}
 
-	status = rte_sched_subport_check_params(params,
-		port->n_pipes_per_subport,
-		port->rate);
-	if (status != 0) {
-		RTE_LOG(NOTICE, SCHED,
-			"%s: Port scheduler params check failed (%d)\n",
-			__func__, status);
-
+	if (subport_profile_id >= port->n_max_subport_profiles) {
+		RTE_LOG(ERR, SCHED, "%s: "
+			"Number of subport profile exceeds the max limit\n",
+			__func__);
 		rte_sched_free_memory(port, n_subports);
 		return -EINVAL;
 	}
 
-	/* Determine the amount of memory to allocate */
-	size0 = sizeof(struct rte_sched_subport);
-	size1 = rte_sched_subport_get_array_base(params,
-				e_RTE_SCHED_SUBPORT_ARRAY_TOTAL);
+	/** Memory is allocated only on first invocation of the api for a
+	 * given subport. Subsequent invocation on same subport will just
+	 * update subport bandwidth parameter.
+	 **/
+	if (port->subports[subport_id] == NULL) {
 
-	/* Allocate memory to store the data structures */
-	s = rte_zmalloc_socket("subport_params", size0 + size1,
-		RTE_CACHE_LINE_SIZE, port->socket);
-	if (s == NULL) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Memory allocation fails\n", __func__);
+		status = rte_sched_subport_check_params(params,
+			port->n_pipes_per_subport,
+			port->rate);
+		if (status != 0) {
+			RTE_LOG(NOTICE, SCHED,
+				"%s: Port scheduler params check failed (%d)\n",
+				__func__, status);
 
-		rte_sched_free_memory(port, n_subports);
-		return -ENOMEM;
-	}
+			rte_sched_free_memory(port, n_subports);
+			return -EINVAL;
+		}
 
-	n_subports++;
+		/* Determine the amount of memory to allocate */
+		size0 = sizeof(struct rte_sched_subport);
+		size1 = rte_sched_subport_get_array_base(params,
+					e_RTE_SCHED_SUBPORT_ARRAY_TOTAL);
 
-	/* Port */
-	port->subports[subport_id] = s;
+		/* Allocate memory to store the data structures */
+		s = rte_zmalloc_socket("subport_params", size0 + size1,
+			RTE_CACHE_LINE_SIZE, port->socket);
+		if (s == NULL) {
+			RTE_LOG(ERR, SCHED,
+				"%s: Memory allocation fails\n", __func__);
 
-	/* Token Bucket (TB) */
-	if (params->tb_rate == port->rate) {
-		s->tb_credits_per_period = 1;
-		s->tb_period = 1;
-	} else {
-		double tb_rate = ((double) params->tb_rate) / ((double) port->rate);
-		double d = RTE_SCHED_TB_RATE_CONFIG_ERR;
+			rte_sched_free_memory(port, n_subports);
+			return -ENOMEM;
+		}
 
-		rte_approx_64(tb_rate, d, &s->tb_credits_per_period, &s->tb_period);
-	}
+		n_subports++;
 
-	s->tb_size = params->tb_size;
-	s->tb_time = port->time;
-	s->tb_credits = s->tb_size / 2;
+		subport_profile_id = 0;
 
-	/* Traffic Classes (TCs) */
-	s->tc_period = rte_sched_time_ms_to_bytes(params->tc_period, port->rate);
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
-		if (params->qsize[i])
-			s->tc_credits_per_period[i]
-				= rte_sched_time_ms_to_bytes(params->tc_period,
-					params->tc_rate[i]);
-	}
-	s->tc_time = port->time + s->tc_period;
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-		if (params->qsize[i])
-			s->tc_credits[i] = s->tc_credits_per_period[i];
+		/* Port */
+		port->subports[subport_id] = s;
 
-	/* compile time checks */
-	RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS == 0);
-	RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS &
-		(RTE_SCHED_PORT_N_GRINDERS - 1));
+		s->tb_time = port->time;
 
-	/* User parameters */
-	s->n_pipes_per_subport_enabled = params->n_pipes_per_subport_enabled;
-	memcpy(s->qsize, params->qsize, sizeof(params->qsize));
-	s->n_pipe_profiles = params->n_pipe_profiles;
-	s->n_max_pipe_profiles = params->n_max_pipe_profiles;
+		/* compile time checks */
+		RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS == 0);
+		RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS &
+			(RTE_SCHED_PORT_N_GRINDERS - 1));
+
+		/* User parameters */
+		s->n_pipes_per_subport_enabled =
+				params->n_pipes_per_subport_enabled;
+		memcpy(s->qsize, params->qsize, sizeof(params->qsize));
+		s->n_pipe_profiles = params->n_pipe_profiles;
+		s->n_max_pipe_profiles = params->n_max_pipe_profiles;
 
 #ifdef RTE_SCHED_RED
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
-		uint32_t j;
+		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
+			uint32_t j;
 
-		for (j = 0; j < RTE_COLORS; j++) {
+			for (j = 0; j < RTE_COLORS; j++) {
 			/* if min/max are both zero, then RED is disabled */
-			if ((params->red_params[i][j].min_th |
-			     params->red_params[i][j].max_th) == 0) {
-				continue;
+				if ((params->red_params[i][j].min_th |
+				     params->red_params[i][j].max_th) == 0) {
+					continue;
+				}
+
+				if (rte_red_config_init(&s->red_config[i][j],
+				    params->red_params[i][j].wq_log2,
+				    params->red_params[i][j].min_th,
+				    params->red_params[i][j].max_th,
+				    params->red_params[i][j].maxp_inv) != 0) {
+					rte_sched_free_memory(port, n_subports);
+
+					RTE_LOG(NOTICE, SCHED,
+					"%s: RED configuration init fails\n",
+					__func__);
+					return -EINVAL;
+				}
 			}
+		}
+#endif
 
-			if (rte_red_config_init(&s->red_config[i][j],
-				params->red_params[i][j].wq_log2,
-				params->red_params[i][j].min_th,
-				params->red_params[i][j].max_th,
-				params->red_params[i][j].maxp_inv) != 0) {
-				rte_sched_free_memory(port, n_subports);
+		/* Scheduling loop detection */
+		s->pipe_loop = RTE_SCHED_PIPE_INVALID;
+		s->pipe_exhaustion = 0;
+
+		/* Grinders */
+		s->busy_grinders = 0;
+
+		/* Queue base calculation */
+		rte_sched_subport_config_qsize(s);
+
+		/* Large data structures */
+		s->pipe = (struct rte_sched_pipe *)
+			(s->memory + rte_sched_subport_get_array_base(params,
+			e_RTE_SCHED_SUBPORT_ARRAY_PIPE));
+		s->queue = (struct rte_sched_queue *)
+			(s->memory + rte_sched_subport_get_array_base(params,
+			e_RTE_SCHED_SUBPORT_ARRAY_QUEUE));
+		s->queue_extra = (struct rte_sched_queue_extra *)
+			(s->memory + rte_sched_subport_get_array_base(params,
+			e_RTE_SCHED_SUBPORT_ARRAY_QUEUE_EXTRA));
+		s->pipe_profiles = (struct rte_sched_pipe_profile *)
+			(s->memory + rte_sched_subport_get_array_base(params,
+			e_RTE_SCHED_SUBPORT_ARRAY_PIPE_PROFILES));
+		s->bmp_array =  s->memory + rte_sched_subport_get_array_base(
+				params, e_RTE_SCHED_SUBPORT_ARRAY_BMP_ARRAY);
+		s->queue_array = (struct rte_mbuf **)
+			(s->memory + rte_sched_subport_get_array_base(params,
+			e_RTE_SCHED_SUBPORT_ARRAY_QUEUE_ARRAY));
+
+		/* Pipe profile table */
+		rte_sched_subport_config_pipe_profile_table(s, params,
+							    port->rate);
+
+		/* Bitmap */
+		n_subport_pipe_queues = rte_sched_subport_pipe_queues(s);
+		bmp_mem_size = rte_bitmap_get_memory_footprint(
+						n_subport_pipe_queues);
+		s->bmp = rte_bitmap_init(n_subport_pipe_queues, s->bmp_array,
+					bmp_mem_size);
+		if (s->bmp == NULL) {
+			RTE_LOG(ERR, SCHED,
+				"%s: Subport bitmap init error\n", __func__);
 
-				RTE_LOG(NOTICE, SCHED,
-				"%s: RED configuration init fails\n", __func__);
-				return -EINVAL;
-			}
+			rte_sched_free_memory(port, n_subports);
+			return -EINVAL;
 		}
-	}
-#endif
 
-	/* Scheduling loop detection */
-	s->pipe_loop = RTE_SCHED_PIPE_INVALID;
-	s->pipe_exhaustion = 0;
+		for (i = 0; i < RTE_SCHED_PORT_N_GRINDERS; i++)
+			s->grinder_base_bmp_pos[i] = RTE_SCHED_PIPE_INVALID;
 
-	/* Grinders */
-	s->busy_grinders = 0;
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+		/* TC oversubscription */
+		s->tc_ov_wm_min = port->mtu;
+		s->tc_ov_wm = s->tc_ov_wm_max;
+		s->tc_ov_period_id = 0;
+		s->tc_ov = 0;
+		s->tc_ov_n = 0;
+		s->tc_ov_rate = 0;
+#endif
+	}
 
-	/* Queue base calculation */
-	rte_sched_subport_config_qsize(s);
+	{
+	/* update subport parameters from subport profile table*/
+		profile = port->subport_profiles + subport_profile_id;
 
-	/* Large data structures */
-	s->pipe = (struct rte_sched_pipe *)
-		(s->memory + rte_sched_subport_get_array_base(params,
-		e_RTE_SCHED_SUBPORT_ARRAY_PIPE));
-	s->queue = (struct rte_sched_queue *)
-		(s->memory + rte_sched_subport_get_array_base(params,
-		e_RTE_SCHED_SUBPORT_ARRAY_QUEUE));
-	s->queue_extra = (struct rte_sched_queue_extra *)
-		(s->memory + rte_sched_subport_get_array_base(params,
-		e_RTE_SCHED_SUBPORT_ARRAY_QUEUE_EXTRA));
-	s->pipe_profiles = (struct rte_sched_pipe_profile *)
-		(s->memory + rte_sched_subport_get_array_base(params,
-		e_RTE_SCHED_SUBPORT_ARRAY_PIPE_PROFILES));
-	s->bmp_array =  s->memory + rte_sched_subport_get_array_base(params,
-		e_RTE_SCHED_SUBPORT_ARRAY_BMP_ARRAY);
-	s->queue_array = (struct rte_mbuf **)
-		(s->memory + rte_sched_subport_get_array_base(params,
-		e_RTE_SCHED_SUBPORT_ARRAY_QUEUE_ARRAY));
-
-	/* Pipe profile table */
-	rte_sched_subport_config_pipe_profile_table(s, params, port->rate);
+		s = port->subports[subport_id];
 
-	/* Bitmap */
-	n_subport_pipe_queues = rte_sched_subport_pipe_queues(s);
-	bmp_mem_size = rte_bitmap_get_memory_footprint(n_subport_pipe_queues);
-	s->bmp = rte_bitmap_init(n_subport_pipe_queues, s->bmp_array,
-				bmp_mem_size);
-	if (s->bmp == NULL) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Subport bitmap init error\n", __func__);
+		s->tb_credits = profile->tb_size / 2;
 
-		rte_sched_free_memory(port, n_subports);
-		return -EINVAL;
-	}
+		s->tc_time = port->time + profile->tc_period;
 
-	for (i = 0; i < RTE_SCHED_PORT_N_GRINDERS; i++)
-		s->grinder_base_bmp_pos[i] = RTE_SCHED_PIPE_INVALID;
+		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+			if (s->qsize[i])
+				s->tc_credits[i] =
+					profile->tc_credits_per_period[i];
+			else
+				profile->tc_credits_per_period[i] = 0;
 
 #ifdef RTE_SCHED_SUBPORT_TC_OV
-	/* TC oversubscription */
-	s->tc_ov_wm_min = port->mtu;
-	s->tc_ov_wm_max = rte_sched_time_ms_to_bytes(params->tc_period,
-						     s->pipe_tc_be_rate_max);
-	s->tc_ov_wm = s->tc_ov_wm_max;
-	s->tc_ov_period_id = 0;
-	s->tc_ov = 0;
-	s->tc_ov_n = 0;
-	s->tc_ov_rate = 0;
+		s->tc_ov_wm_max = rte_sched_time_ms_to_bytes(profile->tc_period,
+							s->pipe_tc_be_rate_max);
 #endif
+		s->profile = subport_profile_id;
+
+	}
 
-	rte_sched_port_log_subport_config(port, subport_id);
+	rte_sched_port_log_subport_profile(port, subport_profile_id);
 
 	return 0;
 }
@@ -1351,6 +1332,7 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 	int32_t pipe_profile)
 {
 	struct rte_sched_subport *s;
+	struct rte_sched_subport_profile *sp;
 	struct rte_sched_pipe *p;
 	struct rte_sched_pipe_profile *params;
 	uint32_t n_subports = subport_id + 1;
@@ -1391,14 +1373,15 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 		return -EINVAL;
 	}
 
+	sp = port->subport_profiles + s->profile;
 	/* Handle the case when pipe already has a valid configuration */
 	p = s->pipe + pipe_id;
 	if (p->tb_time) {
 		params = s->pipe_profiles + p->profile;
 
 		double subport_tc_be_rate =
-			(double) s->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
-			/ (double) s->tc_period;
+		(double)sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
+			/ (double) sp->tc_period;
 		double pipe_tc_be_rate =
 			(double) params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
 			/ (double) params->tc_period;
@@ -1440,8 +1423,8 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 	{
 		/* Subport best effort tc oversubscription */
 		double subport_tc_be_rate =
-			(double) s->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
-			/ (double) s->tc_period;
+		(double)sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
+			/ (double) sp->tc_period;
 		double pipe_tc_be_rate =
 			(double) params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
 			/ (double) params->tc_period;
@@ -2229,14 +2212,15 @@ grinder_credits_update(struct rte_sched_port *port,
 	struct rte_sched_grinder *grinder = subport->grinder + pos;
 	struct rte_sched_pipe *pipe = grinder->pipe;
 	struct rte_sched_pipe_profile *params = grinder->pipe_params;
+	struct rte_sched_subport_profile *sp = grinder->subport_params;
 	uint64_t n_periods;
 	uint32_t i;
 
 	/* Subport TB */
-	n_periods = (port->time - subport->tb_time) / subport->tb_period;
-	subport->tb_credits += n_periods * subport->tb_credits_per_period;
-	subport->tb_credits = RTE_MIN(subport->tb_credits, subport->tb_size);
-	subport->tb_time += n_periods * subport->tb_period;
+	n_periods = (port->time - subport->tb_time) / sp->tb_period;
+	subport->tb_credits += n_periods * sp->tb_credits_per_period;
+	subport->tb_credits = RTE_MIN(subport->tb_credits, sp->tb_size);
+	subport->tb_time += n_periods * sp->tb_period;
 
 	/* Pipe TB */
 	n_periods = (port->time - pipe->tb_time) / params->tb_period;
@@ -2247,9 +2231,9 @@ grinder_credits_update(struct rte_sched_port *port,
 	/* Subport TCs */
 	if (unlikely(port->time >= subport->tc_time)) {
 		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-			subport->tc_credits[i] = subport->tc_credits_per_period[i];
+			subport->tc_credits[i] = sp->tc_credits_per_period[i];
 
-		subport->tc_time = port->time + subport->tc_period;
+		subport->tc_time = port->time + sp->tc_period;
 	}
 
 	/* Pipe TCs */
@@ -2265,8 +2249,10 @@ grinder_credits_update(struct rte_sched_port *port,
 
 static inline uint64_t
 grinder_tc_ov_credits_update(struct rte_sched_port *port,
-	struct rte_sched_subport *subport)
+	struct rte_sched_subport *subport, uint32_t pos)
 {
+	struct rte_sched_grinder *grinder = subport->grinder + pos;
+	struct rte_sched_subport_profile *sp = grinder->subport_params;
 	uint64_t tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
 	uint64_t tc_consumption = 0, tc_ov_consumption_max;
 	uint64_t tc_ov_wm = subport->tc_ov_wm;
@@ -2276,17 +2262,17 @@ grinder_tc_ov_credits_update(struct rte_sched_port *port,
 		return subport->tc_ov_wm_max;
 
 	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASS_BE; i++) {
-		tc_ov_consumption[i] =
-			subport->tc_credits_per_period[i] - subport->tc_credits[i];
+		tc_ov_consumption[i] = sp->tc_credits_per_period[i]
+					-  subport->tc_credits[i];
 		tc_consumption += tc_ov_consumption[i];
 	}
 
 	tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] =
-		subport->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
+	sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
 		subport->tc_credits[RTE_SCHED_TRAFFIC_CLASS_BE];
 
 	tc_ov_consumption_max =
-		subport->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
+	sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
 			tc_consumption;
 
 	if (tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] >
@@ -2312,14 +2298,15 @@ grinder_credits_update(struct rte_sched_port *port,
 	struct rte_sched_grinder *grinder = subport->grinder + pos;
 	struct rte_sched_pipe *pipe = grinder->pipe;
 	struct rte_sched_pipe_profile *params = grinder->pipe_params;
+	struct rte_sched_subport_profile *sp = grinder->subport_params;
 	uint64_t n_periods;
 	uint32_t i;
 
 	/* Subport TB */
-	n_periods = (port->time - subport->tb_time) / subport->tb_period;
-	subport->tb_credits += n_periods * subport->tb_credits_per_period;
-	subport->tb_credits = RTE_MIN(subport->tb_credits, subport->tb_size);
-	subport->tb_time += n_periods * subport->tb_period;
+	n_periods = (port->time - subport->tb_time) / sp->tb_period;
+	subport->tb_credits += n_periods * sp->tb_credits_per_period;
+	subport->tb_credits = RTE_MIN(subport->tb_credits, sp->tb_size);
+	subport->tb_time += n_periods * sp->tb_period;
 
 	/* Pipe TB */
 	n_periods = (port->time - pipe->tb_time) / params->tb_period;
@@ -2329,12 +2316,13 @@ grinder_credits_update(struct rte_sched_port *port,
 
 	/* Subport TCs */
 	if (unlikely(port->time >= subport->tc_time)) {
-		subport->tc_ov_wm = grinder_tc_ov_credits_update(port, subport);
+		subport->tc_ov_wm =
+			grinder_tc_ov_credits_update(port, subport, pos);
 
 		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-			subport->tc_credits[i] = subport->tc_credits_per_period[i];
+			subport->tc_credits[i] = sp->tc_credits_per_period[i];
 
-		subport->tc_time = port->time + subport->tc_period;
+		subport->tc_time = port->time + sp->tc_period;
 		subport->tc_ov_period_id++;
 	}
 
@@ -2857,6 +2845,9 @@ grinder_handle(struct rte_sched_port *port,
 		struct rte_sched_pipe *pipe = grinder->pipe;
 
 		grinder->pipe_params = subport->pipe_profiles + pipe->profile;
+		grinder->subport_params = port->subport_profiles +
+						subport->profile;
+
 		grinder_prefetch_tc_queue_arrays(subport, pos);
 		grinder_credits_update(port, subport, pos);
 
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index 4b0abaac3..697f66460 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -361,20 +361,27 @@ rte_sched_port_subport_profile_add(struct rte_sched_port *port,
 
 /**
  * Hierarchical scheduler subport configuration
- *
+ * Note that this function is safe to use at runtime
+ * to configure subport bandwidth profile.
  * @param port
  *   Handle to port scheduler instance
  * @param subport_id
  *   Subport ID
  * @param params
- *   Subport configuration parameters
+ *   Subport configuration parameters. Must be non-NULL
+ *   for first invocation (i.e intialization) for a given
+ *   subport. Ignored (recommended value is NULL) for all
+ *   subsequent invocation on the same subport.
+ * @param subport_profile_id
+ *   ID of subport bandwidth profile
  * @return
  *   0 upon success, error code otherwise
  */
 int
 rte_sched_subport_config(struct rte_sched_port *port,
 	uint32_t subport_id,
-	struct rte_sched_subport_params *params);
+	struct rte_sched_subport_params *params,
+	uint32_t subport_profile_id);
 
 /**
  * Hierarchical scheduler pipe configuration
-- 
2.17.1


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

* [dpdk-dev] [PATCH v6 4/8] example/qos_sched: update subport rate dynamically
  2020-10-06 15:27             ` [dpdk-dev] [PATCH v6 0/8] Enable dynamic config of subport bandwidth Savinay Dharmappa
                                 ` (2 preceding siblings ...)
  2020-10-06 15:27               ` [dpdk-dev] [PATCH v6 3/8] sched: update subport rate dynamically Savinay Dharmappa
@ 2020-10-06 15:27               ` Savinay Dharmappa
  2020-10-06 15:27               ` [dpdk-dev] [PATCH v6 5/8] example/ip_pipeline: " Savinay Dharmappa
                                 ` (5 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-10-06 15:27 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

Modify the qos_sched application to build the hierarchical scheduler
with default subport bandwidth profile. It also allows to update
a subport with different subport rates dynamically.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 examples/qos_sched/cfg_file.c  | 151 +++++++++++++++++++--------------
 examples/qos_sched/cfg_file.h  |   4 +
 examples/qos_sched/init.c      |  20 +++--
 examples/qos_sched/main.h      |   1 +
 examples/qos_sched/profile.cfg |   3 +
 5 files changed, 110 insertions(+), 69 deletions(-)

diff --git a/examples/qos_sched/cfg_file.c b/examples/qos_sched/cfg_file.c
index f078e4f7d..cd167bd8e 100644
--- a/examples/qos_sched/cfg_file.c
+++ b/examples/qos_sched/cfg_file.c
@@ -142,6 +142,93 @@ cfg_load_pipe(struct rte_cfgfile *cfg, struct rte_sched_pipe_params *pipe_params
 	return 0;
 }
 
+int
+cfg_load_subport_profile(struct rte_cfgfile *cfg,
+	struct rte_sched_subport_profile_params *subport_profile)
+{
+	int i;
+	const char *entry;
+	int profiles;
+
+	if (!cfg || !subport_profile)
+		return -1;
+
+	profiles = rte_cfgfile_num_sections(cfg, "subport profile",
+					   sizeof("subport profile") - 1);
+	subport_params[0].n_pipe_profiles = profiles;
+
+	for (i = 0; i < profiles; i++) {
+		char sec_name[32];
+		snprintf(sec_name, sizeof(sec_name), "subport profile %d", i);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tb rate");
+		if (entry)
+			subport_profile[i].tb_rate = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tb size");
+		if (entry)
+			subport_profile[i].tb_size = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc period");
+		if (entry)
+			subport_profile[i].tc_period = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 0 rate");
+		if (entry)
+			subport_profile[i].tc_rate[0] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 1 rate");
+		if (entry)
+			subport_profile[i].tc_rate[1] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 2 rate");
+		if (entry)
+			subport_profile[i].tc_rate[2] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 3 rate");
+		if (entry)
+			subport_profile[i].tc_rate[3] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 4 rate");
+		if (entry)
+			subport_profile[i].tc_rate[4] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 5 rate");
+		if (entry)
+			subport_profile[i].tc_rate[5] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 6 rate");
+		if (entry)
+			subport_profile[i].tc_rate[6] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 7 rate");
+		if (entry)
+			subport_profile[i].tc_rate[7] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 8 rate");
+		if (entry)
+			subport_profile[i].tc_rate[8] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 9 rate");
+		if (entry)
+			subport_profile[i].tc_rate[9] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 10 rate");
+		if (entry)
+			subport_profile[i].tc_rate[10] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 11 rate");
+		if (entry)
+			subport_profile[i].tc_rate[11] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 12 rate");
+		if (entry)
+			subport_profile[i].tc_rate[12] = (uint64_t)atoi(entry);
+	}
+
+	return 0;
+}
+
 int
 cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subport_params)
 {
@@ -267,70 +354,6 @@ cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subpo
 				}
 			}
 
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tb rate");
-			if (entry)
-				subport_params[i].tb_rate = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tb size");
-			if (entry)
-				subport_params[i].tb_size = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc period");
-			if (entry)
-				subport_params[i].tc_period = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 0 rate");
-			if (entry)
-				subport_params[i].tc_rate[0] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 1 rate");
-			if (entry)
-				subport_params[i].tc_rate[1] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 2 rate");
-			if (entry)
-				subport_params[i].tc_rate[2] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 3 rate");
-			if (entry)
-				subport_params[i].tc_rate[3] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 4 rate");
-			if (entry)
-				subport_params[i].tc_rate[4] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 5 rate");
-			if (entry)
-				subport_params[i].tc_rate[5] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 6 rate");
-			if (entry)
-				subport_params[i].tc_rate[6] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 7 rate");
-			if (entry)
-				subport_params[i].tc_rate[7] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 8 rate");
-			if (entry)
-				subport_params[i].tc_rate[8] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 9 rate");
-			if (entry)
-				subport_params[i].tc_rate[9] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 10 rate");
-			if (entry)
-				subport_params[i].tc_rate[10] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 11 rate");
-			if (entry)
-				subport_params[i].tc_rate[11] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 12 rate");
-			if (entry)
-				subport_params[i].tc_rate[12] = (uint64_t)atoi(entry);
-
 			int n_entries = rte_cfgfile_section_num_entries(cfg, sec_name);
 			struct rte_cfgfile_entry entries[n_entries];
 
diff --git a/examples/qos_sched/cfg_file.h b/examples/qos_sched/cfg_file.h
index 2eccf1ca0..0dc458aa7 100644
--- a/examples/qos_sched/cfg_file.h
+++ b/examples/qos_sched/cfg_file.h
@@ -14,4 +14,8 @@ int cfg_load_pipe(struct rte_cfgfile *cfg, struct rte_sched_pipe_params *pipe);
 
 int cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subport);
 
+int cfg_load_subport_profile(struct rte_cfgfile *cfg,
+			     struct rte_sched_subport_profile_params
+			     *subport_profile);
+
 #endif
diff --git a/examples/qos_sched/init.c b/examples/qos_sched/init.c
index b188c624b..1abe003fc 100644
--- a/examples/qos_sched/init.c
+++ b/examples/qos_sched/init.c
@@ -192,15 +192,20 @@ static struct rte_sched_pipe_params pipe_profiles[MAX_SCHED_PIPE_PROFILES] = {
 	},
 };
 
-struct rte_sched_subport_params subport_params[MAX_SCHED_SUBPORTS] = {
+static struct rte_sched_subport_profile_params
+		subport_profile[MAX_SCHED_SUBPORT_PROFILES] = {
 	{
 		.tb_rate = 1250000000,
 		.tb_size = 1000000,
-
 		.tc_rate = {1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000},
 		.tc_period = 10,
+	},
+};
+
+struct rte_sched_subport_params subport_params[MAX_SCHED_SUBPORTS] = {
+	{
 		.n_pipes_per_subport_enabled = 4096,
 		.qsize = {64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64},
 		.pipe_profiles = pipe_profiles,
@@ -285,6 +290,9 @@ struct rte_sched_port_params port_params = {
 	.mtu = 6 + 6 + 4 + 4 + 2 + 1500,
 	.frame_overhead = RTE_SCHED_FRAME_OVERHEAD_DEFAULT,
 	.n_subports_per_port = 1,
+	.n_subport_profiles = 1,
+	.subport_profiles = subport_profile,
+	.n_max_subport_profiles = MAX_SCHED_SUBPORT_PROFILES,
 	.n_pipes_per_subport = MAX_SCHED_PIPES,
 };
 
@@ -315,10 +323,11 @@ app_init_sched_port(uint32_t portid, uint32_t socketid)
 
 	for (subport = 0; subport < port_params.n_subports_per_port; subport ++) {
 		err = rte_sched_subport_config(port, subport,
-				&subport_params[subport], 0);
+				&subport_params[subport],
+				0);
 		if (err) {
-			rte_exit(EXIT_FAILURE, "Unable to config sched subport %u, err=%d\n",
-					subport, err);
+			rte_exit(EXIT_FAILURE, "Unable to config sched "
+				 "subport %u, err=%d\n", subport, err);
 		}
 
 		uint32_t n_pipes_per_subport =
@@ -351,6 +360,7 @@ app_load_cfg_profile(const char *profile)
 
 	cfg_load_port(file, &port_params);
 	cfg_load_subport(file, subport_params);
+	cfg_load_subport_profile(file, subport_profile);
 	cfg_load_pipe(file, pipe_profiles);
 
 	rte_cfgfile_close(file);
diff --git a/examples/qos_sched/main.h b/examples/qos_sched/main.h
index 23bc418d9..0d6815ae6 100644
--- a/examples/qos_sched/main.h
+++ b/examples/qos_sched/main.h
@@ -51,6 +51,7 @@ extern "C" {
 #define MAX_SCHED_SUBPORTS		8
 #define MAX_SCHED_PIPES		4096
 #define MAX_SCHED_PIPE_PROFILES		256
+#define MAX_SCHED_SUBPORT_PROFILES	8
 
 #ifndef APP_COLLECT_STAT
 #define APP_COLLECT_STAT		1
diff --git a/examples/qos_sched/profile.cfg b/examples/qos_sched/profile.cfg
index 61b8b7071..4486d2799 100644
--- a/examples/qos_sched/profile.cfg
+++ b/examples/qos_sched/profile.cfg
@@ -26,6 +26,9 @@ number of subports per port = 1
 number of pipes per subport = 4096
 queue sizes = 64 64 64 64 64 64 64 64 64 64 64 64 64
 
+subport 0-8 = 0                ; These subports are configured with subport profile 0
+
+[subport profile 0]
 tb rate = 1250000000           ; Bytes per second
 tb size = 1000000              ; Bytes
 
-- 
2.17.1


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

* [dpdk-dev] [PATCH v6 5/8] example/ip_pipeline: update subport rate dynamically
  2020-10-06 15:27             ` [dpdk-dev] [PATCH v6 0/8] Enable dynamic config of subport bandwidth Savinay Dharmappa
                                 ` (3 preceding siblings ...)
  2020-10-06 15:27               ` [dpdk-dev] [PATCH v6 4/8] example/qos_sched: " Savinay Dharmappa
@ 2020-10-06 15:27               ` Savinay Dharmappa
  2020-10-06 15:27               ` [dpdk-dev] [PATCH v6 6/8] drivers/softnic: " Savinay Dharmappa
                                 ` (4 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-10-06 15:27 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

Modify the ip_pipeline application to build the hierarchical scheduler
with default subport bandwidth profile. It also allows to update
a subport with different subport rates dynamically

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 examples/ip_pipeline/cli.c  |  68 ++++++++------------
 examples/ip_pipeline/tmgr.c | 121 ++++++++++++++++++++++++++++++------
 examples/ip_pipeline/tmgr.h |   5 +-
 3 files changed, 134 insertions(+), 60 deletions(-)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index dafc95ae9..6b62a3271 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -393,12 +393,7 @@ static const char cmd_tmgr_subport_profile_help[] =
 "   <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate> <tc4_rate>"
 "        <tc5_rate> <tc6_rate> <tc7_rate> <tc8_rate>"
 "        <tc9_rate> <tc10_rate> <tc11_rate> <tc12_rate>\n"
-"   <tc_period>\n"
-"   pps <n_pipes_per_subport>\n"
-"   qsize <qsize_tc0> <qsize_tc1> <qsize_tc2>"
-"       <qsize_tc3> <qsize_tc4> <qsize_tc5> <qsize_tc6>"
-"       <qsize_tc7> <qsize_tc8> <qsize_tc9> <qsize_tc10>"
-"       <qsize_tc11> <qsize_tc12>";
+"   <tc_period>\n";
 
 static void
 cmd_tmgr_subport_profile(char **tokens,
@@ -406,57 +401,37 @@ cmd_tmgr_subport_profile(char **tokens,
 	char *out,
 	size_t out_size)
 {
-	struct rte_sched_subport_params p;
+	struct rte_sched_subport_profile_params subport_profile;
 	int status, i;
 
-	if (n_tokens != 35) {
+	if (n_tokens != 21) {
 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
 		return;
 	}
 
-	if (parser_read_uint64(&p.tb_rate, tokens[3]) != 0) {
+	if (parser_read_uint64(&subport_profile.tb_rate, tokens[3]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
 		return;
 	}
 
-	if (parser_read_uint64(&p.tb_size, tokens[4]) != 0) {
+	if (parser_read_uint64(&subport_profile.tb_size, tokens[4]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
 		return;
 	}
 
 	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-		if (parser_read_uint64(&p.tc_rate[i], tokens[5 + i]) != 0) {
+		if (parser_read_uint64(&subport_profile.tc_rate[i],
+				tokens[5 + i]) != 0) {
 			snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
 			return;
 		}
 
-	if (parser_read_uint64(&p.tc_period, tokens[18]) != 0) {
+	if (parser_read_uint64(&subport_profile.tc_period, tokens[18]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
 		return;
 	}
 
-	if (strcmp(tokens[19], "pps") != 0) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
-		return;
-	}
-
-	if (parser_read_uint32(&p.n_pipes_per_subport_enabled, tokens[20]) != 0) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport");
-		return;
-	}
-
-	if (strcmp(tokens[21], "qsize") != 0) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "qsize");
-		return;
-	}
-
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-		if (parser_read_uint16(&p.qsize[i], tokens[22 + i]) != 0) {
-			snprintf(out, out_size, MSG_ARG_INVALID, "qsize");
-			return;
-		}
-
-	status = tmgr_subport_profile_add(&p);
+	status = tmgr_subport_profile_add(&subport_profile);
 	if (status != 0) {
 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
 		return;
@@ -530,6 +505,7 @@ static const char cmd_tmgr_help[] =
 "tmgr <tmgr_name>\n"
 "   rate <rate>\n"
 "   spp <n_subports_per_port>\n"
+"   pps <n_pipes_per_subport>\n"
 "   fo <frame_overhead>\n"
 "   mtu <mtu>\n"
 "   cpu <cpu_id>\n";
@@ -544,7 +520,7 @@ cmd_tmgr(char **tokens,
 	char *name;
 	struct tmgr_port *tmgr_port;
 
-	if (n_tokens != 12) {
+	if (n_tokens != 14) {
 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
 		return;
 	}
@@ -571,32 +547,42 @@ cmd_tmgr(char **tokens,
 		return;
 	}
 
-	if (strcmp(tokens[6], "fo") != 0) {
+	if (strcmp(tokens[6], "pps") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
+		return;
+	}
+
+	if (parser_read_uint32(&p.n_pipes_per_subport, tokens[7]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport");
+		return;
+	}
+
+	if (strcmp(tokens[8], "fo") != 0) {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fo");
 		return;
 	}
 
-	if (parser_read_uint32(&p.frame_overhead, tokens[7]) != 0) {
+	if (parser_read_uint32(&p.frame_overhead, tokens[9]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "frame_overhead");
 		return;
 	}
 
-	if (strcmp(tokens[8], "mtu") != 0) {
+	if (strcmp(tokens[10], "mtu") != 0) {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mtu");
 		return;
 	}
 
-	if (parser_read_uint32(&p.mtu, tokens[9]) != 0) {
+	if (parser_read_uint32(&p.mtu, tokens[11]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
 		return;
 	}
 
-	if (strcmp(tokens[10], "cpu") != 0) {
+	if (strcmp(tokens[12], "cpu") != 0) {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
 		return;
 	}
 
-	if (parser_read_uint32(&p.cpu_id, tokens[11]) != 0) {
+	if (parser_read_uint32(&p.cpu_id, tokens[13]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
 		return;
 	}
diff --git a/examples/ip_pipeline/tmgr.c b/examples/ip_pipeline/tmgr.c
index 46c6a83a4..7848a18ab 100644
--- a/examples/ip_pipeline/tmgr.c
+++ b/examples/ip_pipeline/tmgr.c
@@ -4,11 +4,12 @@
 
 #include <stdlib.h>
 
+#include <rte_common.h>
 #include <rte_string_fns.h>
 
 #include "tmgr.h"
 
-static struct rte_sched_subport_params
+static struct rte_sched_subport_profile_params
 	subport_profile[TMGR_SUBPORT_PROFILE_MAX];
 
 static uint32_t n_subport_profiles;
@@ -18,6 +19,82 @@ static struct rte_sched_pipe_params
 
 static uint32_t n_pipe_profiles;
 
+const static struct rte_sched_subport_params subport_params_default = {
+	.n_pipes_per_subport_enabled = 0, /* filled at runtime */
+	.qsize = {64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64},
+	.pipe_profiles = pipe_profile,
+	.n_pipe_profiles = 0, /* filled at run time */
+	.n_max_pipe_profiles = RTE_DIM(pipe_profile),
+#ifdef RTE_SCHED_RED
+.red_params = {
+	/* Traffic Class 0 Colors Green / Yellow / Red */
+	[0][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[0][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[0][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 1 - Colors Green / Yellow / Red */
+	[1][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[1][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[1][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 2 - Colors Green / Yellow / Red */
+	[2][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[2][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[2][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 3 - Colors Green / Yellow / Red */
+	[3][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[3][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[3][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 4 - Colors Green / Yellow / Red */
+	[4][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[4][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[4][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 5 - Colors Green / Yellow / Red */
+	[5][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[5][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[5][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 6 - Colors Green / Yellow / Red */
+	[6][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[6][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[6][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 7 - Colors Green / Yellow / Red */
+	[7][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[7][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[7][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 8 - Colors Green / Yellow / Red */
+	[8][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[8][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[8][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 9 - Colors Green / Yellow / Red */
+	[9][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[9][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[9][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 10 - Colors Green / Yellow / Red */
+	[10][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[10][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[10][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 11 - Colors Green / Yellow / Red */
+	[11][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[11][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[11][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 12 - Colors Green / Yellow / Red */
+	[12][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[12][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[12][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	},
+#endif /* RTE_SCHED_RED */
+};
+
 static struct tmgr_port_list tmgr_port_list;
 
 int
@@ -44,17 +121,16 @@ tmgr_port_find(const char *name)
 }
 
 int
-tmgr_subport_profile_add(struct rte_sched_subport_params *p)
+tmgr_subport_profile_add(struct rte_sched_subport_profile_params *params)
 {
 	/* Check input params */
-	if (p == NULL ||
-		p->n_pipes_per_subport_enabled == 0)
+	if (params == NULL)
 		return -1;
 
 	/* Save profile */
 	memcpy(&subport_profile[n_subport_profiles],
-		p,
-		sizeof(*p));
+		&params,
+		sizeof(params));
 
 	n_subport_profiles++;
 
@@ -81,6 +157,7 @@ tmgr_pipe_profile_add(struct rte_sched_pipe_params *p)
 struct tmgr_port *
 tmgr_port_create(const char *name, struct tmgr_port_params *params)
 {
+	struct rte_sched_subport_params subport_params;
 	struct rte_sched_port_params p;
 	struct tmgr_port *tmgr_port;
 	struct rte_sched_port *s;
@@ -91,6 +168,7 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 		tmgr_port_find(name) ||
 		(params == NULL) ||
 		(params->n_subports_per_port == 0) ||
+		(params->n_pipes_per_subport == 0) ||
 		(params->cpu_id >= RTE_MAX_NUMA_NODES) ||
 		(n_subport_profiles == 0) ||
 		(n_pipe_profiles == 0))
@@ -103,15 +181,22 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 	p.mtu = params->mtu;
 	p.frame_overhead = params->frame_overhead;
 	p.n_subports_per_port = params->n_subports_per_port;
-	p.n_pipes_per_subport = TMGR_PIPE_SUBPORT_MAX;
+	p.n_subport_profiles = n_subport_profiles;
+	p.subport_profiles = subport_profile;
+	p.n_max_subport_profiles = TMGR_SUBPORT_PROFILE_MAX;
+	p.n_pipes_per_subport = params->n_pipes_per_subport;
+
 
 	s = rte_sched_port_config(&p);
 	if (s == NULL)
 		return NULL;
 
-	subport_profile[0].pipe_profiles = pipe_profile;
-	subport_profile[0].n_pipe_profiles = n_pipe_profiles;
-	subport_profile[0].n_max_pipe_profiles = TMGR_PIPE_PROFILE_MAX;
+	memcpy(&subport_params, &subport_params_default,
+		sizeof(subport_params_default));
+
+	subport_params.n_pipe_profiles = n_pipe_profiles;
+	subport_params.n_pipes_per_subport_enabled =
+						params->n_pipes_per_subport;
 
 	for (i = 0; i < params->n_subports_per_port; i++) {
 		int status;
@@ -119,7 +204,7 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 		status = rte_sched_subport_config(
 			s,
 			i,
-			&subport_profile[0],
+			&subport_params,
 			0);
 
 		if (status) {
@@ -127,7 +212,8 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 			return NULL;
 		}
 
-		for (j = 0; j < subport_profile[0].n_pipes_per_subport_enabled; j++) {
+		for (j = 0; j < params->n_pipes_per_subport; j++) {
+
 			status = rte_sched_pipe_config(
 				s,
 				i,
@@ -152,6 +238,7 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 	strlcpy(tmgr_port->name, name, sizeof(tmgr_port->name));
 	tmgr_port->s = s;
 	tmgr_port->n_subports_per_port = params->n_subports_per_port;
+	tmgr_port->n_pipes_per_subport = params->n_pipes_per_subport;
 
 	/* Node add to list */
 	TAILQ_INSERT_TAIL(&tmgr_port_list, tmgr_port, node);
@@ -181,8 +268,8 @@ tmgr_subport_config(const char *port_name,
 	status = rte_sched_subport_config(
 		port->s,
 		subport_id,
-		&subport_profile[subport_profile_id],
-		0);
+		NULL,
+		subport_profile_id);
 
 	return status;
 }
@@ -204,10 +291,8 @@ tmgr_pipe_config(const char *port_name,
 	port = tmgr_port_find(port_name);
 	if ((port == NULL) ||
 		(subport_id >= port->n_subports_per_port) ||
-		(pipe_id_first >=
-			subport_profile[subport_id].n_pipes_per_subport_enabled) ||
-		(pipe_id_last >=
-			subport_profile[subport_id].n_pipes_per_subport_enabled) ||
+		(pipe_id_first >= port->n_pipes_per_subport) ||
+		(pipe_id_last >= port->n_pipes_per_subport) ||
 		(pipe_id_first > pipe_id_last) ||
 		(pipe_profile_id >= n_pipe_profiles))
 		return -1;
diff --git a/examples/ip_pipeline/tmgr.h b/examples/ip_pipeline/tmgr.h
index ee50cf7cc..1994c55bc 100644
--- a/examples/ip_pipeline/tmgr.h
+++ b/examples/ip_pipeline/tmgr.h
@@ -9,6 +9,7 @@
 #include <sys/queue.h>
 
 #include <rte_sched.h>
+#include <rte_red.h>
 
 #include "common.h"
 
@@ -29,6 +30,7 @@ struct tmgr_port {
 	char name[NAME_SIZE];
 	struct rte_sched_port *s;
 	uint32_t n_subports_per_port;
+	uint32_t n_pipes_per_subport;
 };
 
 TAILQ_HEAD(tmgr_port_list, tmgr_port);
@@ -42,13 +44,14 @@ tmgr_port_find(const char *name);
 struct tmgr_port_params {
 	uint64_t rate;
 	uint32_t n_subports_per_port;
+	uint32_t n_pipes_per_subport;
 	uint32_t frame_overhead;
 	uint32_t mtu;
 	uint32_t cpu_id;
 };
 
 int
-tmgr_subport_profile_add(struct rte_sched_subport_params *p);
+tmgr_subport_profile_add(struct rte_sched_subport_profile_params *sp);
 
 int
 tmgr_pipe_profile_add(struct rte_sched_pipe_params *p);
-- 
2.17.1


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

* [dpdk-dev] [PATCH v6 6/8] drivers/softnic: update subport rate dynamically
  2020-10-06 15:27             ` [dpdk-dev] [PATCH v6 0/8] Enable dynamic config of subport bandwidth Savinay Dharmappa
                                 ` (4 preceding siblings ...)
  2020-10-06 15:27               ` [dpdk-dev] [PATCH v6 5/8] example/ip_pipeline: " Savinay Dharmappa
@ 2020-10-06 15:27               ` Savinay Dharmappa
  2020-10-06 15:27               ` [dpdk-dev] [PATCH v6 7/8] app/test_sched: " Savinay Dharmappa
                                 ` (3 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-10-06 15:27 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

Modify the softnic drivers to build the hierarchical scheduler
with default subport bandwidth profile. It also allows to update
a subport with different subport rates dynamically.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 .../net/softnic/rte_eth_softnic_internals.h   |  11 +-
 drivers/net/softnic/rte_eth_softnic_tm.c      | 243 ++++++++++++++----
 2 files changed, 195 insertions(+), 59 deletions(-)

diff --git a/drivers/net/softnic/rte_eth_softnic_internals.h b/drivers/net/softnic/rte_eth_softnic_internals.h
index 6eec43b22..77e0139a6 100644
--- a/drivers/net/softnic/rte_eth_softnic_internals.h
+++ b/drivers/net/softnic/rte_eth_softnic_internals.h
@@ -164,11 +164,18 @@ TAILQ_HEAD(softnic_link_list, softnic_link);
 #ifndef TM_MAX_PIPE_PROFILE
 #define TM_MAX_PIPE_PROFILE				256
 #endif
+
+#ifndef TM_MAX_SUBPORT_PROFILE
+#define TM_MAX_SUBPORT_PROFILE				256
+#endif
+
 struct tm_params {
 	struct rte_sched_port_params port_params;
-
 	struct rte_sched_subport_params subport_params[TM_MAX_SUBPORTS];
-
+	struct rte_sched_subport_profile_params
+		subport_profile[TM_MAX_SUBPORT_PROFILE];
+	uint32_t n_subport_profiles;
+	uint32_t subport_to_profile[TM_MAX_SUBPORT_PROFILE];
 	struct rte_sched_pipe_params pipe_profiles[TM_MAX_PIPE_PROFILE];
 	uint32_t n_pipe_profiles;
 	uint32_t pipe_to_profile[TM_MAX_SUBPORTS * TM_MAX_PIPES_PER_SUBPORT];
diff --git a/drivers/net/softnic/rte_eth_softnic_tm.c b/drivers/net/softnic/rte_eth_softnic_tm.c
index 5199dd2cd..725b0231a 100644
--- a/drivers/net/softnic/rte_eth_softnic_tm.c
+++ b/drivers/net/softnic/rte_eth_softnic_tm.c
@@ -86,13 +86,14 @@ softnic_tmgr_port_create(struct pmd_internals *p,
 	n_subports = t->port_params.n_subports_per_port;
 	for (subport_id = 0; subport_id < n_subports; subport_id++) {
 		uint32_t n_pipes_per_subport =
-			t->subport_params[subport_id].n_pipes_per_subport_enabled;
+		t->subport_params[subport_id].n_pipes_per_subport_enabled;
 		uint32_t pipe_id;
 		int status;
 
 		status = rte_sched_subport_config(sched,
 			subport_id,
-			&t->subport_params[subport_id], 0);
+			&t->subport_params[subport_id],
+			t->subport_to_profile[subport_id]);
 		if (status) {
 			rte_sched_port_free(sched);
 			return NULL;
@@ -1114,34 +1115,51 @@ tm_shared_shaper_get_tc(struct rte_eth_dev *dev,
 	return NULL;
 }
 
+static int
+subport_profile_exists(struct rte_eth_dev *dev,
+	struct rte_sched_subport_profile_params *sp,
+	uint32_t *subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+	uint32_t i;
+
+	for (i = 0; i < t->n_subport_profiles; i++)
+		if (memcmp(&t->subport_profile[i], sp, sizeof(*sp)) == 0) {
+			if (subport_profile_id)
+				*subport_profile_id = i;
+			return 1;
+		}
+
+	return 0;
+}
+
 static int
 update_subport_tc_rate(struct rte_eth_dev *dev,
 	struct tm_node *nt,
 	struct tm_shared_shaper *ss,
 	struct tm_shaper_profile *sp_new)
 {
+	struct rte_sched_subport_profile_params subport_profile;
 	struct pmd_internals *p = dev->data->dev_private;
 	uint32_t tc_id = tm_node_tc_id(dev, nt);
-
 	struct tm_node *np = nt->parent_node;
-
 	struct tm_node *ns = np->parent_node;
 	uint32_t subport_id = tm_node_subport_id(dev, ns);
-
-	struct rte_sched_subport_params subport_params;
-
+	struct tm_params *t = &p->soft.tm.params;
+	uint32_t subport_profile_id = t->subport_to_profile[subport_id];
 	struct tm_shaper_profile *sp_old = tm_shaper_profile_search(dev,
 		ss->shaper_profile_id);
 
 	/* Derive new subport configuration. */
-	memcpy(&subport_params,
-		&p->soft.tm.params.subport_params[subport_id],
-		sizeof(subport_params));
-	subport_params.tc_rate[tc_id] = sp_new->params.peak.rate;
+	memcpy(&subport_profile,
+		&p->soft.tm.params.subport_profile[subport_profile_id],
+		sizeof(subport_profile));
+	subport_profile.tc_rate[tc_id] = sp_new->params.peak.rate;
 
 	/* Update the subport configuration. */
 	if (rte_sched_subport_config(SCHED(p),
-		subport_id, &subport_params, 0))
+		subport_id, NULL, subport_profile_id))
 		return -1;
 
 	/* Commit changes. */
@@ -1150,9 +1168,9 @@ update_subport_tc_rate(struct rte_eth_dev *dev,
 	ss->shaper_profile_id = sp_new->shaper_profile_id;
 	sp_new->n_users++;
 
-	memcpy(&p->soft.tm.params.subport_params[subport_id],
-		&subport_params,
-		sizeof(subport_params));
+	memcpy(&p->soft.tm.params.subport_profile[subport_profile_id],
+		&subport_profile,
+		sizeof(subport_profile));
 
 	return 0;
 }
@@ -2238,6 +2256,8 @@ pipe_profiles_generate(struct rte_eth_dev *dev)
 			struct rte_sched_pipe_params pp;
 			uint32_t pos;
 
+			memset(&pp, 0, sizeof(pp));
+
 			if (np->level != TM_NODE_LEVEL_PIPE ||
 				np->parent_node_id != ns->node_id)
 				continue;
@@ -2343,6 +2363,123 @@ tm_subport_tc_shared_shaper_get(struct rte_eth_dev *dev,
 	return NULL;
 }
 
+static struct rte_sched_subport_profile_params *
+subport_profile_get(struct rte_eth_dev *dev, struct tm_node *np)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+	uint32_t subport_id = tm_node_subport_id(dev, np->parent_node);
+
+	return &t->subport_profile[subport_id];
+}
+
+static void
+subport_profile_mark(struct rte_eth_dev *dev,
+	uint32_t subport_id,
+	uint32_t subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+
+	t->subport_to_profile[subport_id] = subport_profile_id;
+}
+
+static void
+subport_profile_install(struct rte_eth_dev *dev,
+	struct rte_sched_subport_profile_params *sp,
+	uint32_t subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+
+	memcpy(&t->subport_profile[subport_profile_id],
+		sp, sizeof(*sp));
+	t->n_subport_profiles++;
+}
+
+static int
+subport_profile_free_exists(struct rte_eth_dev *dev,
+	uint32_t *subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+
+	if (t->n_subport_profiles < TM_MAX_SUBPORT_PROFILE) {
+		*subport_profile_id = t->n_subport_profiles;
+		return 1;
+	}
+
+	return 0;
+}
+
+static void
+subport_profile_build(struct rte_eth_dev *dev, struct tm_node *np,
+	struct rte_sched_subport_profile_params *sp)
+{
+	uint32_t i;
+	memset(sp, 0, sizeof(*sp));
+
+	sp->tb_rate = np->shaper_profile->params.peak.rate;
+	sp->tb_size = np->shaper_profile->params.peak.size;
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
+		struct tm_shared_shaper *ss;
+		struct tm_shaper_profile *ssp;
+
+		ss = tm_subport_tc_shared_shaper_get(dev, np, i);
+		ssp = (ss) ? tm_shaper_profile_search(dev,
+			ss->shaper_profile_id) :
+			np->shaper_profile;
+		sp->tc_rate[i] = ssp->params.peak.rate;
+	}
+
+	/* Traffic Class (TC) */
+	sp->tc_period = SUBPORT_TC_PERIOD;
+}
+
+static int
+subport_profiles_generate(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_hierarchy *h = &p->soft.tm.h;
+	struct tm_node_list *nl = &h->nodes;
+	struct tm_node *ns;
+	uint32_t subport_id;
+
+	/* Objective: Fill in the following fields in struct tm_params:
+	 *    - subport_profiles
+	 *    - n_subport_profiles
+	 *    - subport_to_profile
+	 */
+
+	subport_id = 0;
+	TAILQ_FOREACH(ns, nl, node) {
+		if (ns->level != TM_NODE_LEVEL_SUBPORT)
+			continue;
+
+		struct rte_sched_subport_profile_params sp;
+		uint32_t pos;
+
+		memset(&sp, 0, sizeof(sp));
+
+		subport_profile_build(dev, ns, &sp);
+
+		if (!subport_profile_exists(dev, &sp, &pos)) {
+			if (!subport_profile_free_exists(dev, &pos))
+				return -1;
+
+			subport_profile_install(dev, &sp, pos);
+		}
+
+		subport_profile_mark(dev, subport_id, pos);
+
+		subport_id++;
+	}
+
+	return 0;
+}
+
+
 static int
 hierarchy_commit_check(struct rte_eth_dev *dev, struct rte_tm_error *error)
 {
@@ -2519,6 +2656,15 @@ hierarchy_commit_check(struct rte_eth_dev *dev, struct rte_tm_error *error)
 				rte_strerror(EINVAL));
 	}
 
+	/* Not too many subport profiles. */
+	if (subport_profiles_generate(dev))
+		return -rte_tm_error_set(error,
+			EINVAL,
+			RTE_TM_ERROR_TYPE_UNSPECIFIED,
+			NULL,
+			rte_strerror(EINVAL));
+
+
 	/* Not too many pipe profiles. */
 	if (pipe_profiles_generate(dev))
 		return -rte_tm_error_set(error,
@@ -2600,48 +2746,20 @@ hierarchy_blueprints_create(struct rte_eth_dev *dev)
 		.frame_overhead =
 			root->shaper_profile->params.pkt_length_adjust,
 		.n_subports_per_port = root->n_children,
+		.n_subport_profiles = t->n_subport_profiles,
+		.subport_profiles = t->subport_profile,
+		.n_max_subport_profiles = TM_MAX_SUBPORT_PROFILE,
 		.n_pipes_per_subport = TM_MAX_PIPES_PER_SUBPORT,
 	};
 
 	subport_id = 0;
 	TAILQ_FOREACH(n, nl, node) {
-		uint64_t tc_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
-		uint32_t i;
 
 		if (n->level != TM_NODE_LEVEL_SUBPORT)
 			continue;
 
-		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
-			struct tm_shared_shaper *ss;
-			struct tm_shaper_profile *sp;
-
-			ss = tm_subport_tc_shared_shaper_get(dev, n, i);
-			sp = (ss) ? tm_shaper_profile_search(dev,
-				ss->shaper_profile_id) :
-				n->shaper_profile;
-			tc_rate[i] = sp->params.peak.rate;
-		}
-
 		t->subport_params[subport_id] =
 			(struct rte_sched_subport_params) {
-				.tb_rate = n->shaper_profile->params.peak.rate,
-				.tb_size = n->shaper_profile->params.peak.size,
-
-				.tc_rate = {tc_rate[0],
-					tc_rate[1],
-					tc_rate[2],
-					tc_rate[3],
-					tc_rate[4],
-					tc_rate[5],
-					tc_rate[6],
-					tc_rate[7],
-					tc_rate[8],
-					tc_rate[9],
-					tc_rate[10],
-					tc_rate[11],
-					tc_rate[12],
-				},
-				.tc_period = SUBPORT_TC_PERIOD,
 				.n_pipes_per_subport_enabled =
 					h->n_tm_nodes[TM_NODE_LEVEL_PIPE] /
 					h->n_tm_nodes[TM_NODE_LEVEL_SUBPORT],
@@ -2901,18 +3019,27 @@ update_subport_rate(struct rte_eth_dev *dev,
 	struct pmd_internals *p = dev->data->dev_private;
 	uint32_t subport_id = tm_node_subport_id(dev, ns);
 
-	struct rte_sched_subport_params subport_params;
+	struct rte_sched_subport_profile_params *profile0 =
+					subport_profile_get(dev, ns);
+	struct rte_sched_subport_profile_params profile1;
+	uint32_t subport_profile_id;
 
-	/* Derive new subport configuration. */
-	memcpy(&subport_params,
-		&p->soft.tm.params.subport_params[subport_id],
-		sizeof(subport_params));
-	subport_params.tb_rate = sp->params.peak.rate;
-	subport_params.tb_size = sp->params.peak.size;
+	/* Derive new pipe profile. */
+	memcpy(&profile1, profile0, sizeof(profile1));
+	profile1.tb_rate = sp->params.peak.rate;
+	profile1.tb_size = sp->params.peak.size;
+
+	/* Since implementation does not allow adding more subport profiles
+	 * after port configuration, the pipe configuration can be successfully
+	 * updated only if the new profile is also part of the existing set of
+	 * pipe profiles.
+	 */
+	if (subport_profile_exists(dev, &profile1, &subport_profile_id) == 0)
+		return -1;
 
 	/* Update the subport configuration. */
 	if (rte_sched_subport_config(SCHED(p), subport_id,
-		&subport_params, 0))
+		NULL, subport_profile_id))
 		return -1;
 
 	/* Commit changes. */
@@ -2922,9 +3049,11 @@ update_subport_rate(struct rte_eth_dev *dev,
 	ns->params.shaper_profile_id = sp->shaper_profile_id;
 	sp->n_users++;
 
-	memcpy(&p->soft.tm.params.subport_params[subport_id],
-		&subport_params,
-		sizeof(subport_params));
+	subport_profile_mark(dev, subport_id, subport_profile_id);
+
+	memcpy(&p->soft.tm.params.subport_profile[subport_profile_id],
+		&profile1,
+		sizeof(profile1));
 
 	return 0;
 }
-- 
2.17.1


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

* [dpdk-dev] [PATCH v6 7/8] app/test_sched: update subport rate dynamically
  2020-10-06 15:27             ` [dpdk-dev] [PATCH v6 0/8] Enable dynamic config of subport bandwidth Savinay Dharmappa
                                 ` (5 preceding siblings ...)
  2020-10-06 15:27               ` [dpdk-dev] [PATCH v6 6/8] drivers/softnic: " Savinay Dharmappa
@ 2020-10-06 15:27               ` Savinay Dharmappa
  2020-10-06 15:27               ` [dpdk-dev] [PATCH v6 8/8] sched: remove redundant code Savinay Dharmappa
                                 ` (2 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-10-06 15:27 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

Modify the test_sched application to build the hierarchical scheduler
with default subport bandwidth profile. It also allows to update
a subport with different subport rates dynamically

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 app/test/test_sched.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/app/test/test_sched.c b/app/test/test_sched.c
index 5e5c2a59b..958b63114 100644
--- a/app/test/test_sched.c
+++ b/app/test/test_sched.c
@@ -21,6 +21,7 @@
 #define PIPE            1
 #define TC              2
 #define QUEUE           0
+#define MAX_SCHED_SUBPORT_PROFILES  8
 
 static struct rte_sched_pipe_params pipe_profile[] = {
 	{ /* Profile #0 */
@@ -36,15 +37,20 @@ static struct rte_sched_pipe_params pipe_profile[] = {
 	},
 };
 
-static struct rte_sched_subport_params subport_param[] = {
+static struct rte_sched_subport_profile_params
+		subport_profile[] = {
 	{
 		.tb_rate = 1250000000,
 		.tb_size = 1000000,
-
 		.tc_rate = {1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000},
 		.tc_period = 10,
+	},
+};
+
+static struct rte_sched_subport_params subport_param[] = {
+	{
 		.n_pipes_per_subport_enabled = 1024,
 		.qsize = {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32},
 		.pipe_profiles = pipe_profile,
@@ -59,6 +65,9 @@ static struct rte_sched_port_params port_param = {
 	.mtu = 1522,
 	.frame_overhead = RTE_SCHED_FRAME_OVERHEAD_DEFAULT,
 	.n_subports_per_port = 1,
+	.n_subport_profiles = 1,
+	.subport_profiles = subport_profile,
+	.n_max_subport_profiles = MAX_SCHED_SUBPORT_PROFILES,
 	.n_pipes_per_subport = 1024,
 };
 
-- 
2.17.1


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

* [dpdk-dev] [PATCH v6 8/8] sched: remove redundant code
  2020-10-06 15:27             ` [dpdk-dev] [PATCH v6 0/8] Enable dynamic config of subport bandwidth Savinay Dharmappa
                                 ` (6 preceding siblings ...)
  2020-10-06 15:27               ` [dpdk-dev] [PATCH v6 7/8] app/test_sched: " Savinay Dharmappa
@ 2020-10-06 15:27               ` Savinay Dharmappa
  2020-10-06 15:52               ` [dpdk-dev] [PATCH v6 0/8] Enable dynamic config of subport bandwidth Dumitrescu, Cristian
  2020-10-06 18:02               ` [dpdk-dev] [PATCH v7 " Savinay Dharmappa
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-10-06 15:27 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

Remove redundant data structure fields references from
functions and subport level data structures. It also
update the release and deprecation note

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 doc/guides/rel_notes/deprecation.rst   |  6 ----
 doc/guides/rel_notes/release_20_11.rst |  2 ++
 lib/librte_sched/rte_sched.c           | 42 ++------------------------
 lib/librte_sched/rte_sched.h           | 12 --------
 4 files changed, 4 insertions(+), 58 deletions(-)

diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 584e72087..f7363a585 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -212,12 +212,6 @@ Deprecation Notices
   in "rte_sched.h". These changes are aligned to improvements suggested in the
   RFC https://mails.dpdk.org/archives/dev/2018-November/120035.html.
 
-* sched: To allow dynamic configuration of the subport bandwidth profile,
-  changes will be made to data structures ``rte_sched_subport_params``,
-  ``rte_sched_port_params`` and new data structure, API functions will be
-  defined in ``rte_sched.h``. These changes are aligned as suggested in the
-  RFC https://mails.dpdk.org/archives/dev/2020-July/175161.html
-
 * metrics: The function ``rte_metrics_init`` will have a non-void return
   in order to notify errors instead of calling ``rte_exit``.
 
diff --git a/doc/guides/rel_notes/release_20_11.rst b/doc/guides/rel_notes/release_20_11.rst
index ca5ec7391..886a3c122 100644
--- a/doc/guides/rel_notes/release_20_11.rst
+++ b/doc/guides/rel_notes/release_20_11.rst
@@ -131,6 +131,8 @@ Removed Items
 
 * Removed Python 2 support since it was EOL'd in January 2020.
 
+* sched: Add support to update subport bandwidth dynamically.
+
 API Changes
 -----------
 
diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index c5482d6e0..7c5688068 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -152,16 +152,11 @@ struct rte_sched_grinder {
 struct rte_sched_subport {
 	/* Token bucket (TB) */
 	uint64_t tb_time; /* time of last update */
-	uint64_t tb_period;
-	uint64_t tb_credits_per_period;
-	uint64_t tb_size;
 	uint64_t tb_credits;
 
 	/* Traffic classes (TCs) */
 	uint64_t tc_time; /* time of next update */
-	uint64_t tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
 	uint64_t tc_credits[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
-	uint64_t tc_period;
 
 	/* TC oversubscription */
 	uint64_t tc_ov_wm;
@@ -837,18 +832,6 @@ rte_sched_subport_check_params(struct rte_sched_subport_params *params,
 		return -EINVAL;
 	}
 
-	if (params->tb_rate == 0 || params->tb_rate > rate) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect value for tb rate\n", __func__);
-		return -EINVAL;
-	}
-
-	if (params->tb_size == 0) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect value for tb size\n", __func__);
-		return -EINVAL;
-	}
-
 	/* qsize: if non-zero, power of 2,
 	 * no bigger than 32K (due to 16-bit read/write pointers)
 	 */
@@ -862,29 +845,8 @@ rte_sched_subport_check_params(struct rte_sched_subport_params *params,
 		}
 	}
 
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
-		uint64_t tc_rate = params->tc_rate[i];
-		uint16_t qsize = params->qsize[i];
-
-		if ((qsize == 0 && tc_rate != 0) ||
-			(qsize != 0 && tc_rate == 0) ||
-			(tc_rate > params->tb_rate)) {
-			RTE_LOG(ERR, SCHED,
-				"%s: Incorrect value for tc rate\n", __func__);
-			return -EINVAL;
-		}
-	}
-
-	if (params->qsize[RTE_SCHED_TRAFFIC_CLASS_BE] == 0 ||
-		params->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect qsize or tc rate(best effort)\n", __func__);
-		return -EINVAL;
-	}
-
-	if (params->tc_period == 0) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect value for tc period\n", __func__);
+	if (params->qsize[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
+		RTE_LOG(ERR, SCHED, "%s: Incorrect qsize\n", __func__);
 		return -EINVAL;
 	}
 
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index 697f66460..aee847471 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -149,18 +149,6 @@ struct rte_sched_pipe_params {
  * byte.
  */
 struct rte_sched_subport_params {
-	/** Token bucket rate (measured in bytes per second) */
-	uint64_t tb_rate;
-
-	/** Token bucket size (measured in credits) */
-	uint64_t tb_size;
-
-	/** Traffic class rates (measured in bytes per second) */
-	uint64_t tc_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
-
-	/** Enforcement period for rates (measured in milliseconds) */
-	uint64_t tc_period;
-
 	/** Number of subport pipes.
 	 * The subport can enable/allocate fewer pipes than the maximum
 	 * number set through struct port_params::n_max_pipes_per_subport,
-- 
2.17.1


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

* Re: [dpdk-dev] [PATCH v6 0/8] Enable dynamic config of subport bandwidth
  2020-10-06 15:27             ` [dpdk-dev] [PATCH v6 0/8] Enable dynamic config of subport bandwidth Savinay Dharmappa
                                 ` (7 preceding siblings ...)
  2020-10-06 15:27               ` [dpdk-dev] [PATCH v6 8/8] sched: remove redundant code Savinay Dharmappa
@ 2020-10-06 15:52               ` Dumitrescu, Cristian
  2020-10-06 18:02               ` [dpdk-dev] [PATCH v7 " Savinay Dharmappa
  9 siblings, 0 replies; 107+ messages in thread
From: Dumitrescu, Cristian @ 2020-10-06 15:52 UTC (permalink / raw)
  To: Dharmappa, Savinay, Singh, Jasvinder, dev



> -----Original Message-----
> From: Dharmappa, Savinay <savinay.dharmappa@intel.com>
> Sent: Tuesday, October 6, 2020 4:27 PM
> To: Dumitrescu, Cristian <cristian.dumitrescu@intel.com>; Singh, Jasvinder
> <jasvinder.singh@intel.com>; dev@dpdk.org
> Cc: Dharmappa, Savinay <savinay.dharmappa@intel.com>
> Subject: [PATCH v6 0/8] Enable dynamic config of subport bandwidth
> 
> DPDK sched library allows runtime configuration of the pipe profiles to the
> pipes of the subport once scheduler hierarchy is constructed. However, to
> change the subport level bandwidth, existing hierarchy needs to be
> dismantled and whole process of building hierarchy under subport nodes
> needs to be repeated which might result in router downtime. Furthermore,
> due to lack of dynamic configuration of the subport bandwidth profile
> configuration (shaper and Traffic class rates), the user application
> is unable to dynamically re-distribute the excess-bandwidth of one subport
> among other subports in the scheduler hierarchy. Therefore, it is also not
> possible to adjust the subport bandwidth profile in sync with dynamic
> changes in pipe profiles of subscribers who want to consume higher
> bandwidth opportunistically.
> 
> This patch series implements dynamic configuration of the subport
> bandwidth
> profile to overcome the runtime situation when group of subscribers are not
> using the allotted bandwidth and dynamic bandwidth re-distribution is
> needed the without making any structural changes in the hierarchy.
> 
> The implementation work includes refactoring the existing api and
> data structures defined for port and subport level, new APIs for
> adding subport level bandwidth profiles that can be used in runtime
> 

Acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>


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

* [dpdk-dev] [PATCH v7 0/8] Enable dynamic config of subport bandwidth
  2020-10-06 15:27             ` [dpdk-dev] [PATCH v6 0/8] Enable dynamic config of subport bandwidth Savinay Dharmappa
                                 ` (8 preceding siblings ...)
  2020-10-06 15:52               ` [dpdk-dev] [PATCH v6 0/8] Enable dynamic config of subport bandwidth Dumitrescu, Cristian
@ 2020-10-06 18:02               ` Savinay Dharmappa
  2020-10-06 18:02                 ` [dpdk-dev] [PATCH v7 1/8] sched: add support profile table Savinay Dharmappa
                                   ` (9 more replies)
  9 siblings, 10 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-10-06 18:02 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

DPDK sched library allows runtime configuration of the pipe profiles to the
pipes of the subport once scheduler hierarchy is constructed. However, to
change the subport level bandwidth, existing hierarchy needs to be
dismantled and whole process of building hierarchy under subport nodes
needs to be repeated which might result in router downtime. Furthermore,
due to lack of dynamic configuration of the subport bandwidth profile
configuration (shaper and Traffic class rates), the user application
is unable to dynamically re-distribute the excess-bandwidth of one subport
among other subports in the scheduler hierarchy. Therefore, it is also not
possible to adjust the subport bandwidth profile in sync with dynamic
changes in pipe profiles of subscribers who want to consume higher
bandwidth opportunistically.

This patch series implements dynamic configuration of the subport bandwidth
profile to overcome the runtime situation when group of subscribers are not
using the allotted bandwidth and dynamic bandwidth re-distribution is
needed the without making any structural changes in the hierarchy.

The implementation work includes refactoring the existing api and
data structures defined for port and subport level, new APIs for
adding subport level bandwidth profiles that can be used in runtime

Savinay Dharmappa (8):
  sched: add support profile table
  sched: introduce subport profile add function
  sched: update subport rate dynamically
  example/qos_sched: update subport rate dynamically
  example/ip_pipeline: update subport rate dynamically
  drivers/softnic: update subport rate dynamically
  app/test_sched: update subport rate dynamically
  sched: remove redundant code

 app/test/test_sched.c                         |  15 +-
 doc/guides/rel_notes/deprecation.rst          |   6 -
 doc/guides/rel_notes/release_20_11.rst        |   1 +
 .../net/softnic/rte_eth_softnic_internals.h   |  11 +-
 drivers/net/softnic/rte_eth_softnic_tm.c      | 243 +++++--
 examples/ip_pipeline/cli.c                    |  68 +-
 examples/ip_pipeline/tmgr.c                   | 121 +++-
 examples/ip_pipeline/tmgr.h                   |   5 +-
 examples/qos_sched/cfg_file.c                 | 151 ++--
 examples/qos_sched/cfg_file.h                 |   4 +
 examples/qos_sched/init.c                     |  21 +-
 examples/qos_sched/main.h                     |   1 +
 examples/qos_sched/profile.cfg                |   3 +
 lib/librte_sched/rte_sched.c                  | 678 ++++++++++++------
 lib/librte_sched/rte_sched.h                  |  73 +-
 lib/librte_sched/rte_sched_version.map        |   2 +
 16 files changed, 958 insertions(+), 445 deletions(-)

-- 
2.17.1


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

* [dpdk-dev] [PATCH v7 1/8] sched: add support profile table
  2020-10-06 18:02               ` [dpdk-dev] [PATCH v7 " Savinay Dharmappa
@ 2020-10-06 18:02                 ` Savinay Dharmappa
  2020-10-06 18:02                 ` [dpdk-dev] [PATCH v7 2/8] sched: introduce subport profile add function Savinay Dharmappa
                                   ` (8 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-10-06 18:02 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

Add subport profile table to internal port data structure
and update the port config function.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c | 197 ++++++++++++++++++++++++++++++++++-
 lib/librte_sched/rte_sched.h |  25 +++++
 2 files changed, 219 insertions(+), 3 deletions(-)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index 75be8b6bd..a44638f31 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -101,6 +101,16 @@ enum grinder_state {
 	e_GRINDER_READ_MBUF
 };
 
+struct rte_sched_subport_profile {
+	/* Token bucket (TB) */
+	uint64_t tb_period;
+	uint64_t tb_credits_per_period;
+	uint64_t tb_size;
+
+	uint64_t tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+	uint64_t tc_period;
+};
+
 struct rte_sched_grinder {
 	/* Pipe cache */
 	uint16_t pcache_qmask[RTE_SCHED_GRINDER_PCACHE_SIZE];
@@ -212,6 +222,8 @@ struct rte_sched_port {
 	uint16_t pipe_queue[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
 	uint8_t pipe_tc[RTE_SCHED_QUEUES_PER_PIPE];
 	uint8_t tc_queue[RTE_SCHED_QUEUES_PER_PIPE];
+	uint32_t n_subport_profiles;
+	uint32_t n_max_subport_profiles;
 	uint64_t rate;
 	uint32_t mtu;
 	uint32_t frame_overhead;
@@ -230,6 +242,7 @@ struct rte_sched_port {
 	uint32_t subport_id;
 
 	/* Large data structures */
+	struct rte_sched_subport_profile *subport_profiles;
 	struct rte_sched_subport *subports[0] __rte_cache_aligned;
 } __rte_cache_aligned;
 
@@ -375,9 +388,61 @@ pipe_profile_check(struct rte_sched_pipe_params *params,
 	return 0;
 }
 
+static int
+subport_profile_check(struct rte_sched_subport_profile_params *params,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	/* Check user parameters */
+	if (params == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter params\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tb_rate == 0 || params->tb_rate > rate) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for tb rate\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tb_size == 0) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for tb size\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
+		uint64_t tc_rate = params->tc_rate[i];
+
+		if (tc_rate == 0 || (tc_rate > params->tb_rate)) {
+			RTE_LOG(ERR, SCHED, "%s: "
+			"Incorrect value for tc rate\n", __func__);
+			return -EINVAL;
+		}
+	}
+
+	if (params->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect tc rate(best effort)\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tc_period == 0) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for tc period\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int
 rte_sched_port_check_params(struct rte_sched_port_params *params)
 {
+	uint32_t i;
+
 	if (params == NULL) {
 		RTE_LOG(ERR, SCHED,
 			"%s: Incorrect value for parameter params\n", __func__);
@@ -414,6 +479,29 @@ rte_sched_port_check_params(struct rte_sched_port_params *params)
 		return -EINVAL;
 	}
 
+	if (params->subport_profiles == NULL ||
+		params->n_subport_profiles == 0 ||
+		params->n_max_subport_profiles == 0 ||
+		params->n_subport_profiles > params->n_max_subport_profiles) {
+		RTE_LOG(ERR, SCHED,
+		"%s: Incorrect value for subport profiles\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < params->n_subport_profiles; i++) {
+		struct rte_sched_subport_profile_params *p =
+						params->subport_profiles + i;
+		int status;
+
+		status = subport_profile_check(p, params->rate);
+		if (status != 0) {
+			RTE_LOG(ERR, SCHED,
+			"%s: subport profile check failed(%d)\n",
+			__func__, status);
+			return -EINVAL;
+		}
+	}
+
 	/* n_pipes_per_subport: non-zero, power of 2 */
 	if (params->n_pipes_per_subport == 0 ||
 	    !rte_is_power_of_2(params->n_pipes_per_subport)) {
@@ -555,6 +643,42 @@ rte_sched_port_log_pipe_profile(struct rte_sched_subport *subport, uint32_t i)
 		p->wrr_cost[0], p->wrr_cost[1], p->wrr_cost[2], p->wrr_cost[3]);
 }
 
+static void
+rte_sched_port_log_subport_profile(struct rte_sched_port *port, uint32_t i)
+{
+	struct rte_sched_subport_profile *p = port->subport_profiles + i;
+
+	RTE_LOG(DEBUG, SCHED, "Low level config for subport profile %u:\n"
+	"Token bucket: period = %"PRIu64", credits per period = %"PRIu64","
+	"size = %"PRIu64"\n"
+	"Traffic classes: period = %"PRIu64",\n"
+	"credits per period = [%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
+	" %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
+	" %"PRIu64", %"PRIu64", %"PRIu64"]\n",
+	i,
+
+	/* Token bucket */
+	p->tb_period,
+	p->tb_credits_per_period,
+	p->tb_size,
+
+	/* Traffic classes */
+	p->tc_period,
+	p->tc_credits_per_period[0],
+	p->tc_credits_per_period[1],
+	p->tc_credits_per_period[2],
+	p->tc_credits_per_period[3],
+	p->tc_credits_per_period[4],
+	p->tc_credits_per_period[5],
+	p->tc_credits_per_period[6],
+	p->tc_credits_per_period[7],
+	p->tc_credits_per_period[8],
+	p->tc_credits_per_period[9],
+	p->tc_credits_per_period[10],
+	p->tc_credits_per_period[11],
+	p->tc_credits_per_period[12]);
+}
+
 static inline uint64_t
 rte_sched_time_ms_to_bytes(uint64_t time_ms, uint64_t rate)
 {
@@ -623,6 +747,37 @@ rte_sched_pipe_profile_convert(struct rte_sched_subport *subport,
 	dst->wrr_cost[3] = (uint8_t) wrr_cost[3];
 }
 
+static void
+rte_sched_subport_profile_convert(struct rte_sched_subport_profile_params *src,
+	struct rte_sched_subport_profile *dst,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	/* Token Bucket */
+	if (src->tb_rate == rate) {
+		dst->tb_credits_per_period = 1;
+		dst->tb_period = 1;
+	} else {
+		double tb_rate = (double) src->tb_rate
+				/ (double) rate;
+		double d = RTE_SCHED_TB_RATE_CONFIG_ERR;
+
+		rte_approx_64(tb_rate, d, &dst->tb_credits_per_period,
+			&dst->tb_period);
+	}
+
+	dst->tb_size = src->tb_size;
+
+	/* Traffic Classes */
+	dst->tc_period = rte_sched_time_ms_to_bytes(src->tc_period, rate);
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		dst->tc_credits_per_period[i]
+			= rte_sched_time_ms_to_bytes(src->tc_period,
+				src->tc_rate[i]);
+}
+
 static void
 rte_sched_subport_config_pipe_profile_table(struct rte_sched_subport *subport,
 	struct rte_sched_subport_params *params, uint64_t rate)
@@ -647,6 +802,24 @@ rte_sched_subport_config_pipe_profile_table(struct rte_sched_subport *subport,
 	}
 }
 
+static void
+rte_sched_port_config_subport_profile_table(struct rte_sched_port *port,
+	struct rte_sched_port_params *params,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	for (i = 0; i < port->n_subport_profiles; i++) {
+		struct rte_sched_subport_profile_params *src
+				= params->subport_profiles + i;
+		struct rte_sched_subport_profile *dst
+				= port->subport_profiles + i;
+
+		rte_sched_subport_profile_convert(src, dst, rate);
+		rte_sched_port_log_subport_profile(port, i);
+	}
+}
+
 static int
 rte_sched_subport_check_params(struct rte_sched_subport_params *params,
 	uint32_t n_max_pipes_per_subport,
@@ -793,7 +966,7 @@ struct rte_sched_port *
 rte_sched_port_config(struct rte_sched_port_params *params)
 {
 	struct rte_sched_port *port = NULL;
-	uint32_t size0, size1;
+	uint32_t size0, size1, size2;
 	uint32_t cycles_per_byte;
 	uint32_t i, j;
 	int status;
@@ -808,10 +981,21 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 
 	size0 = sizeof(struct rte_sched_port);
 	size1 = params->n_subports_per_port * sizeof(struct rte_sched_subport *);
+	size2 = params->n_max_subport_profiles *
+		sizeof(struct rte_sched_subport_profile);
 
 	/* Allocate memory to store the data structures */
-	port = rte_zmalloc_socket("qos_params", size0 + size1, RTE_CACHE_LINE_SIZE,
-		params->socket);
+	port = rte_zmalloc_socket("qos_params", size0 + size1,
+				 RTE_CACHE_LINE_SIZE, params->socket);
+	if (port == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: Memory allocation fails\n", __func__);
+
+		return NULL;
+	}
+
+	/* Allocate memory to store the subport profile */
+	port->subport_profiles  = rte_zmalloc_socket("subport_profile", size2,
+					RTE_CACHE_LINE_SIZE, params->socket);
 	if (port == NULL) {
 		RTE_LOG(ERR, SCHED, "%s: Memory allocation fails\n", __func__);
 
@@ -820,6 +1004,8 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 
 	/* User parameters */
 	port->n_subports_per_port = params->n_subports_per_port;
+	port->n_subport_profiles = params->n_subport_profiles;
+	port->n_max_subport_profiles = params->n_max_subport_profiles;
 	port->n_pipes_per_subport = params->n_pipes_per_subport;
 	port->n_pipes_per_subport_log2 =
 			__builtin_ctz(params->n_pipes_per_subport);
@@ -850,6 +1036,9 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 	port->time_cpu_bytes = 0;
 	port->time = 0;
 
+	/* Subport profile table */
+	rte_sched_port_config_subport_profile_table(port, params, port->rate);
+
 	cycles_per_byte = (rte_get_tsc_hz() << RTE_SCHED_TIME_SHIFT)
 		/ params->rate;
 	port->inv_cycles_per_byte = rte_reciprocal_value(cycles_per_byte);
@@ -905,6 +1094,7 @@ rte_sched_port_free(struct rte_sched_port *port)
 	for (i = 0; i < port->n_subports_per_port; i++)
 		rte_sched_subport_free(port, port->subports[i]);
 
+	rte_free(port->subport_profiles);
 	rte_free(port);
 }
 
@@ -961,6 +1151,7 @@ rte_sched_free_memory(struct rte_sched_port *port, uint32_t n_subports)
 		rte_sched_subport_free(port, subport);
 	}
 
+	rte_free(port->subport_profiles);
 	rte_free(port);
 }
 
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index 8a5a93c98..39339b7f1 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -192,6 +192,20 @@ struct rte_sched_subport_params {
 #endif
 };
 
+struct rte_sched_subport_profile_params {
+	/** Token bucket rate (measured in bytes per second) */
+	uint64_t tb_rate;
+
+	/** Token bucket size (measured in credits) */
+	uint64_t tb_size;
+
+	/** Traffic class rates (measured in bytes per second) */
+	uint64_t tc_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+
+	/** Enforcement period for rates (measured in milliseconds) */
+	uint64_t tc_period;
+};
+
 /** Subport statistics */
 struct rte_sched_subport_stats {
 	/** Number of packets successfully written */
@@ -254,6 +268,17 @@ struct rte_sched_port_params {
 	/** Number of subports */
 	uint32_t n_subports_per_port;
 
+	/** subport profile table.
+	 * Every pipe is configured using one of the profiles from this table.
+	 */
+	struct rte_sched_subport_profile_params *subport_profiles;
+
+	/** Profiles in the pipe profile table */
+	uint32_t n_subport_profiles;
+
+	/** Max allowed profiles in the pipe profile table */
+	uint32_t n_max_subport_profiles;
+
 	/** Maximum number of subport pipes.
 	 * This parameter is used to reserve a fixed number of bits
 	 * in struct rte_mbuf::sched.queue_id for the pipe_id for all
-- 
2.17.1


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

* [dpdk-dev] [PATCH v7 2/8] sched: introduce subport profile add function
  2020-10-06 18:02               ` [dpdk-dev] [PATCH v7 " Savinay Dharmappa
  2020-10-06 18:02                 ` [dpdk-dev] [PATCH v7 1/8] sched: add support profile table Savinay Dharmappa
@ 2020-10-06 18:02                 ` Savinay Dharmappa
  2020-10-06 18:02                 ` [dpdk-dev] [PATCH v7 3/8] sched: update subport rate dynamically Savinay Dharmappa
                                   ` (7 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-10-06 18:02 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

API to add new subport bandwidth profile.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c           | 66 ++++++++++++++++++++++++++
 lib/librte_sched/rte_sched.h           | 23 +++++++++
 lib/librte_sched/rte_sched_version.map |  2 +
 3 files changed, 91 insertions(+)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index a44638f31..895b40d72 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -1528,6 +1528,72 @@ rte_sched_subport_pipe_profile_add(struct rte_sched_port *port,
 	return 0;
 }
 
+int
+rte_sched_port_subport_profile_add(struct rte_sched_port *port,
+	struct rte_sched_subport_profile_params *params,
+	uint32_t *subport_profile_id)
+{
+	int status;
+	uint32_t i;
+	struct rte_sched_subport_profile *dst;
+
+	/* Port */
+	if (port == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter port\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter profile\n", __func__);
+		return -EINVAL;
+	}
+
+	if (subport_profile_id == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter subport_profile_id\n",
+		__func__);
+		return -EINVAL;
+	}
+
+	dst = port->subport_profiles + port->n_subport_profiles;
+
+	/* Subport profiles exceeds the max limit */
+	if (port->n_subport_profiles >= port->n_max_subport_profiles) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Number of subport profiles exceeds the max limit\n",
+		 __func__);
+		return -EINVAL;
+	}
+
+	status = subport_profile_check(params, port->rate);
+	if (status != 0) {
+		RTE_LOG(ERR, SCHED,
+		"%s: subport profile check failed(%d)\n", __func__, status);
+		return -EINVAL;
+	}
+
+	rte_sched_subport_profile_convert(params, dst, port->rate);
+
+	/* Subport profile should not exists */
+	for (i = 0; i < port->n_subport_profiles; i++)
+		if (memcmp(port->subport_profiles + i,
+		    dst, sizeof(*dst)) == 0) {
+			RTE_LOG(ERR, SCHED,
+			"%s: subport profile exists\n", __func__);
+			return -EINVAL;
+		}
+
+	/* Subport profile commit */
+	*subport_profile_id = port->n_subport_profiles;
+	port->n_subport_profiles++;
+
+	rte_sched_port_log_subport_profile(port, *subport_profile_id);
+
+	return 0;
+}
+
 static inline uint32_t
 rte_sched_port_qindex(struct rte_sched_port *port,
 	uint32_t subport,
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index 39339b7f1..4b0abaac3 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -336,6 +336,29 @@ rte_sched_subport_pipe_profile_add(struct rte_sched_port *port,
 	struct rte_sched_pipe_params *params,
 	uint32_t *pipe_profile_id);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Hierarchical scheduler subport bandwidth profile add
+ * Note that this function is safe to use in runtime for adding new
+ * subport bandwidth profile as it doesn't have any impact on hiearchical
+ * structure of the scheduler.
+ * @param port
+ *   Handle to port scheduler instance
+ * @param profile
+ *   Subport bandwidth profile
+ * @param subport_profile_d
+ *   Subport profile id
+ * @return
+ *   0 upon success, error code otherwise
+ */
+__rte_experimental
+int
+rte_sched_port_subport_profile_add(struct rte_sched_port *port,
+	struct rte_sched_subport_profile_params *profile,
+	uint32_t *subport_profile_id);
+
 /**
  * Hierarchical scheduler subport configuration
  *
diff --git a/lib/librte_sched/rte_sched_version.map b/lib/librte_sched/rte_sched_version.map
index 3faef6f0a..ace284b7d 100644
--- a/lib/librte_sched/rte_sched_version.map
+++ b/lib/librte_sched/rte_sched_version.map
@@ -28,4 +28,6 @@ EXPERIMENTAL {
 	global:
 
 	rte_sched_subport_pipe_profile_add;
+	# added in 20.11
+	rte_sched_port_subport_profile_add;
 };
-- 
2.17.1


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

* [dpdk-dev] [PATCH v7 3/8] sched: update subport rate dynamically
  2020-10-06 18:02               ` [dpdk-dev] [PATCH v7 " Savinay Dharmappa
  2020-10-06 18:02                 ` [dpdk-dev] [PATCH v7 1/8] sched: add support profile table Savinay Dharmappa
  2020-10-06 18:02                 ` [dpdk-dev] [PATCH v7 2/8] sched: introduce subport profile add function Savinay Dharmappa
@ 2020-10-06 18:02                 ` Savinay Dharmappa
  2020-10-06 18:02                 ` [dpdk-dev] [PATCH v7 4/8] example/qos_sched: " Savinay Dharmappa
                                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-10-06 18:02 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

Add support to update subport rate dynamically.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 app/test/test_sched.c                    |   2 +-
 drivers/net/softnic/rte_eth_softnic_tm.c |   6 +-
 examples/ip_pipeline/tmgr.c              |   6 +-
 examples/qos_sched/init.c                |   3 +-
 lib/librte_sched/rte_sched.c             | 373 +++++++++++------------
 lib/librte_sched/rte_sched.h             |  13 +-
 6 files changed, 202 insertions(+), 201 deletions(-)

diff --git a/app/test/test_sched.c b/app/test/test_sched.c
index fc31080ef..5e5c2a59b 100644
--- a/app/test/test_sched.c
+++ b/app/test/test_sched.c
@@ -138,7 +138,7 @@ test_sched(void)
 	port = rte_sched_port_config(&port_param);
 	TEST_ASSERT_NOT_NULL(port, "Error config sched port\n");
 
-	err = rte_sched_subport_config(port, SUBPORT, subport_param);
+	err = rte_sched_subport_config(port, SUBPORT, subport_param, 0);
 	TEST_ASSERT_SUCCESS(err, "Error config sched, err=%d\n", err);
 
 	for (pipe = 0; pipe < subport_param[0].n_pipes_per_subport_enabled; pipe++) {
diff --git a/drivers/net/softnic/rte_eth_softnic_tm.c b/drivers/net/softnic/rte_eth_softnic_tm.c
index d30976378..5199dd2cd 100644
--- a/drivers/net/softnic/rte_eth_softnic_tm.c
+++ b/drivers/net/softnic/rte_eth_softnic_tm.c
@@ -92,7 +92,7 @@ softnic_tmgr_port_create(struct pmd_internals *p,
 
 		status = rte_sched_subport_config(sched,
 			subport_id,
-			&t->subport_params[subport_id]);
+			&t->subport_params[subport_id], 0);
 		if (status) {
 			rte_sched_port_free(sched);
 			return NULL;
@@ -1141,7 +1141,7 @@ update_subport_tc_rate(struct rte_eth_dev *dev,
 
 	/* Update the subport configuration. */
 	if (rte_sched_subport_config(SCHED(p),
-		subport_id, &subport_params))
+		subport_id, &subport_params, 0))
 		return -1;
 
 	/* Commit changes. */
@@ -2912,7 +2912,7 @@ update_subport_rate(struct rte_eth_dev *dev,
 
 	/* Update the subport configuration. */
 	if (rte_sched_subport_config(SCHED(p), subport_id,
-		&subport_params))
+		&subport_params, 0))
 		return -1;
 
 	/* Commit changes. */
diff --git a/examples/ip_pipeline/tmgr.c b/examples/ip_pipeline/tmgr.c
index 91ccbf60f..46c6a83a4 100644
--- a/examples/ip_pipeline/tmgr.c
+++ b/examples/ip_pipeline/tmgr.c
@@ -119,7 +119,8 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 		status = rte_sched_subport_config(
 			s,
 			i,
-			&subport_profile[0]);
+			&subport_profile[0],
+			0);
 
 		if (status) {
 			rte_sched_port_free(s);
@@ -180,7 +181,8 @@ tmgr_subport_config(const char *port_name,
 	status = rte_sched_subport_config(
 		port->s,
 		subport_id,
-		&subport_profile[subport_profile_id]);
+		&subport_profile[subport_profile_id],
+		0);
 
 	return status;
 }
diff --git a/examples/qos_sched/init.c b/examples/qos_sched/init.c
index 06328ddb2..b188c624b 100644
--- a/examples/qos_sched/init.c
+++ b/examples/qos_sched/init.c
@@ -314,7 +314,8 @@ app_init_sched_port(uint32_t portid, uint32_t socketid)
 	}
 
 	for (subport = 0; subport < port_params.n_subports_per_port; subport ++) {
-		err = rte_sched_subport_config(port, subport, &subport_params[subport]);
+		err = rte_sched_subport_config(port, subport,
+				&subport_params[subport], 0);
 		if (err) {
 			rte_exit(EXIT_FAILURE, "Unable to config sched subport %u, err=%d\n",
 					subport, err);
diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index 895b40d72..c5482d6e0 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -123,6 +123,7 @@ struct rte_sched_grinder {
 	uint32_t productive;
 	uint32_t pindex;
 	struct rte_sched_subport *subport;
+	struct rte_sched_subport_profile *subport_params;
 	struct rte_sched_pipe *pipe;
 	struct rte_sched_pipe_profile *pipe_params;
 
@@ -174,6 +175,8 @@ struct rte_sched_subport {
 	/* Statistics */
 	struct rte_sched_subport_stats stats __rte_cache_aligned;
 
+	/* subport profile */
+	uint32_t profile;
 	/* Subport pipes */
 	uint32_t n_pipes_per_subport_enabled;
 	uint32_t n_pipe_profiles;
@@ -1098,48 +1101,6 @@ rte_sched_port_free(struct rte_sched_port *port)
 	rte_free(port);
 }
 
-static void
-rte_sched_port_log_subport_config(struct rte_sched_port *port, uint32_t i)
-{
-	struct rte_sched_subport *s = port->subports[i];
-
-	RTE_LOG(DEBUG, SCHED, "Low level config for subport %u:\n"
-		"	Token bucket: period = %"PRIu64", credits per period = %"PRIu64
-		", size = %"PRIu64"\n"
-		"	Traffic classes: period = %"PRIu64"\n"
-		"	credits per period = [%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
-		", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
-		", %"PRIu64", %"PRIu64", %"PRIu64"]\n"
-		"	Best effort traffic class oversubscription: wm min = %"PRIu64
-		", wm max = %"PRIu64"\n",
-		i,
-
-		/* Token bucket */
-		s->tb_period,
-		s->tb_credits_per_period,
-		s->tb_size,
-
-		/* Traffic classes */
-		s->tc_period,
-		s->tc_credits_per_period[0],
-		s->tc_credits_per_period[1],
-		s->tc_credits_per_period[2],
-		s->tc_credits_per_period[3],
-		s->tc_credits_per_period[4],
-		s->tc_credits_per_period[5],
-		s->tc_credits_per_period[6],
-		s->tc_credits_per_period[7],
-		s->tc_credits_per_period[8],
-		s->tc_credits_per_period[9],
-		s->tc_credits_per_period[10],
-		s->tc_credits_per_period[11],
-		s->tc_credits_per_period[12],
-
-		/* Best effort traffic class oversubscription */
-		s->tc_ov_wm_min,
-		s->tc_ov_wm_max);
-}
-
 static void
 rte_sched_free_memory(struct rte_sched_port *port, uint32_t n_subports)
 {
@@ -1158,10 +1119,12 @@ rte_sched_free_memory(struct rte_sched_port *port, uint32_t n_subports)
 int
 rte_sched_subport_config(struct rte_sched_port *port,
 	uint32_t subport_id,
-	struct rte_sched_subport_params *params)
+	struct rte_sched_subport_params *params,
+	uint32_t subport_profile_id)
 {
 	struct rte_sched_subport *s = NULL;
 	uint32_t n_subports = subport_id;
+	struct rte_sched_subport_profile *profile;
 	uint32_t n_subport_pipe_queues, i;
 	uint32_t size0, size1, bmp_mem_size;
 	int status;
@@ -1181,165 +1144,183 @@ rte_sched_subport_config(struct rte_sched_port *port,
 		return -EINVAL;
 	}
 
-	status = rte_sched_subport_check_params(params,
-		port->n_pipes_per_subport,
-		port->rate);
-	if (status != 0) {
-		RTE_LOG(NOTICE, SCHED,
-			"%s: Port scheduler params check failed (%d)\n",
-			__func__, status);
-
+	if (subport_profile_id >= port->n_max_subport_profiles) {
+		RTE_LOG(ERR, SCHED, "%s: "
+			"Number of subport profile exceeds the max limit\n",
+			__func__);
 		rte_sched_free_memory(port, n_subports);
 		return -EINVAL;
 	}
 
-	/* Determine the amount of memory to allocate */
-	size0 = sizeof(struct rte_sched_subport);
-	size1 = rte_sched_subport_get_array_base(params,
-				e_RTE_SCHED_SUBPORT_ARRAY_TOTAL);
+	/** Memory is allocated only on first invocation of the api for a
+	 * given subport. Subsequent invocation on same subport will just
+	 * update subport bandwidth parameter.
+	 **/
+	if (port->subports[subport_id] == NULL) {
 
-	/* Allocate memory to store the data structures */
-	s = rte_zmalloc_socket("subport_params", size0 + size1,
-		RTE_CACHE_LINE_SIZE, port->socket);
-	if (s == NULL) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Memory allocation fails\n", __func__);
+		status = rte_sched_subport_check_params(params,
+			port->n_pipes_per_subport,
+			port->rate);
+		if (status != 0) {
+			RTE_LOG(NOTICE, SCHED,
+				"%s: Port scheduler params check failed (%d)\n",
+				__func__, status);
 
-		rte_sched_free_memory(port, n_subports);
-		return -ENOMEM;
-	}
+			rte_sched_free_memory(port, n_subports);
+			return -EINVAL;
+		}
 
-	n_subports++;
+		/* Determine the amount of memory to allocate */
+		size0 = sizeof(struct rte_sched_subport);
+		size1 = rte_sched_subport_get_array_base(params,
+					e_RTE_SCHED_SUBPORT_ARRAY_TOTAL);
 
-	/* Port */
-	port->subports[subport_id] = s;
+		/* Allocate memory to store the data structures */
+		s = rte_zmalloc_socket("subport_params", size0 + size1,
+			RTE_CACHE_LINE_SIZE, port->socket);
+		if (s == NULL) {
+			RTE_LOG(ERR, SCHED,
+				"%s: Memory allocation fails\n", __func__);
 
-	/* Token Bucket (TB) */
-	if (params->tb_rate == port->rate) {
-		s->tb_credits_per_period = 1;
-		s->tb_period = 1;
-	} else {
-		double tb_rate = ((double) params->tb_rate) / ((double) port->rate);
-		double d = RTE_SCHED_TB_RATE_CONFIG_ERR;
+			rte_sched_free_memory(port, n_subports);
+			return -ENOMEM;
+		}
 
-		rte_approx_64(tb_rate, d, &s->tb_credits_per_period, &s->tb_period);
-	}
+		n_subports++;
 
-	s->tb_size = params->tb_size;
-	s->tb_time = port->time;
-	s->tb_credits = s->tb_size / 2;
+		subport_profile_id = 0;
 
-	/* Traffic Classes (TCs) */
-	s->tc_period = rte_sched_time_ms_to_bytes(params->tc_period, port->rate);
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
-		if (params->qsize[i])
-			s->tc_credits_per_period[i]
-				= rte_sched_time_ms_to_bytes(params->tc_period,
-					params->tc_rate[i]);
-	}
-	s->tc_time = port->time + s->tc_period;
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-		if (params->qsize[i])
-			s->tc_credits[i] = s->tc_credits_per_period[i];
+		/* Port */
+		port->subports[subport_id] = s;
 
-	/* compile time checks */
-	RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS == 0);
-	RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS &
-		(RTE_SCHED_PORT_N_GRINDERS - 1));
+		s->tb_time = port->time;
 
-	/* User parameters */
-	s->n_pipes_per_subport_enabled = params->n_pipes_per_subport_enabled;
-	memcpy(s->qsize, params->qsize, sizeof(params->qsize));
-	s->n_pipe_profiles = params->n_pipe_profiles;
-	s->n_max_pipe_profiles = params->n_max_pipe_profiles;
+		/* compile time checks */
+		RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS == 0);
+		RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS &
+			(RTE_SCHED_PORT_N_GRINDERS - 1));
+
+		/* User parameters */
+		s->n_pipes_per_subport_enabled =
+				params->n_pipes_per_subport_enabled;
+		memcpy(s->qsize, params->qsize, sizeof(params->qsize));
+		s->n_pipe_profiles = params->n_pipe_profiles;
+		s->n_max_pipe_profiles = params->n_max_pipe_profiles;
 
 #ifdef RTE_SCHED_RED
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
-		uint32_t j;
+		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
+			uint32_t j;
 
-		for (j = 0; j < RTE_COLORS; j++) {
+			for (j = 0; j < RTE_COLORS; j++) {
 			/* if min/max are both zero, then RED is disabled */
-			if ((params->red_params[i][j].min_th |
-			     params->red_params[i][j].max_th) == 0) {
-				continue;
+				if ((params->red_params[i][j].min_th |
+				     params->red_params[i][j].max_th) == 0) {
+					continue;
+				}
+
+				if (rte_red_config_init(&s->red_config[i][j],
+				    params->red_params[i][j].wq_log2,
+				    params->red_params[i][j].min_th,
+				    params->red_params[i][j].max_th,
+				    params->red_params[i][j].maxp_inv) != 0) {
+					rte_sched_free_memory(port, n_subports);
+
+					RTE_LOG(NOTICE, SCHED,
+					"%s: RED configuration init fails\n",
+					__func__);
+					return -EINVAL;
+				}
 			}
+		}
+#endif
 
-			if (rte_red_config_init(&s->red_config[i][j],
-				params->red_params[i][j].wq_log2,
-				params->red_params[i][j].min_th,
-				params->red_params[i][j].max_th,
-				params->red_params[i][j].maxp_inv) != 0) {
-				rte_sched_free_memory(port, n_subports);
+		/* Scheduling loop detection */
+		s->pipe_loop = RTE_SCHED_PIPE_INVALID;
+		s->pipe_exhaustion = 0;
+
+		/* Grinders */
+		s->busy_grinders = 0;
+
+		/* Queue base calculation */
+		rte_sched_subport_config_qsize(s);
+
+		/* Large data structures */
+		s->pipe = (struct rte_sched_pipe *)
+			(s->memory + rte_sched_subport_get_array_base(params,
+			e_RTE_SCHED_SUBPORT_ARRAY_PIPE));
+		s->queue = (struct rte_sched_queue *)
+			(s->memory + rte_sched_subport_get_array_base(params,
+			e_RTE_SCHED_SUBPORT_ARRAY_QUEUE));
+		s->queue_extra = (struct rte_sched_queue_extra *)
+			(s->memory + rte_sched_subport_get_array_base(params,
+			e_RTE_SCHED_SUBPORT_ARRAY_QUEUE_EXTRA));
+		s->pipe_profiles = (struct rte_sched_pipe_profile *)
+			(s->memory + rte_sched_subport_get_array_base(params,
+			e_RTE_SCHED_SUBPORT_ARRAY_PIPE_PROFILES));
+		s->bmp_array =  s->memory + rte_sched_subport_get_array_base(
+				params, e_RTE_SCHED_SUBPORT_ARRAY_BMP_ARRAY);
+		s->queue_array = (struct rte_mbuf **)
+			(s->memory + rte_sched_subport_get_array_base(params,
+			e_RTE_SCHED_SUBPORT_ARRAY_QUEUE_ARRAY));
+
+		/* Pipe profile table */
+		rte_sched_subport_config_pipe_profile_table(s, params,
+							    port->rate);
+
+		/* Bitmap */
+		n_subport_pipe_queues = rte_sched_subport_pipe_queues(s);
+		bmp_mem_size = rte_bitmap_get_memory_footprint(
+						n_subport_pipe_queues);
+		s->bmp = rte_bitmap_init(n_subport_pipe_queues, s->bmp_array,
+					bmp_mem_size);
+		if (s->bmp == NULL) {
+			RTE_LOG(ERR, SCHED,
+				"%s: Subport bitmap init error\n", __func__);
 
-				RTE_LOG(NOTICE, SCHED,
-				"%s: RED configuration init fails\n", __func__);
-				return -EINVAL;
-			}
+			rte_sched_free_memory(port, n_subports);
+			return -EINVAL;
 		}
-	}
-#endif
 
-	/* Scheduling loop detection */
-	s->pipe_loop = RTE_SCHED_PIPE_INVALID;
-	s->pipe_exhaustion = 0;
+		for (i = 0; i < RTE_SCHED_PORT_N_GRINDERS; i++)
+			s->grinder_base_bmp_pos[i] = RTE_SCHED_PIPE_INVALID;
 
-	/* Grinders */
-	s->busy_grinders = 0;
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+		/* TC oversubscription */
+		s->tc_ov_wm_min = port->mtu;
+		s->tc_ov_wm = s->tc_ov_wm_max;
+		s->tc_ov_period_id = 0;
+		s->tc_ov = 0;
+		s->tc_ov_n = 0;
+		s->tc_ov_rate = 0;
+#endif
+	}
 
-	/* Queue base calculation */
-	rte_sched_subport_config_qsize(s);
+	{
+	/* update subport parameters from subport profile table*/
+		profile = port->subport_profiles + subport_profile_id;
 
-	/* Large data structures */
-	s->pipe = (struct rte_sched_pipe *)
-		(s->memory + rte_sched_subport_get_array_base(params,
-		e_RTE_SCHED_SUBPORT_ARRAY_PIPE));
-	s->queue = (struct rte_sched_queue *)
-		(s->memory + rte_sched_subport_get_array_base(params,
-		e_RTE_SCHED_SUBPORT_ARRAY_QUEUE));
-	s->queue_extra = (struct rte_sched_queue_extra *)
-		(s->memory + rte_sched_subport_get_array_base(params,
-		e_RTE_SCHED_SUBPORT_ARRAY_QUEUE_EXTRA));
-	s->pipe_profiles = (struct rte_sched_pipe_profile *)
-		(s->memory + rte_sched_subport_get_array_base(params,
-		e_RTE_SCHED_SUBPORT_ARRAY_PIPE_PROFILES));
-	s->bmp_array =  s->memory + rte_sched_subport_get_array_base(params,
-		e_RTE_SCHED_SUBPORT_ARRAY_BMP_ARRAY);
-	s->queue_array = (struct rte_mbuf **)
-		(s->memory + rte_sched_subport_get_array_base(params,
-		e_RTE_SCHED_SUBPORT_ARRAY_QUEUE_ARRAY));
-
-	/* Pipe profile table */
-	rte_sched_subport_config_pipe_profile_table(s, params, port->rate);
+		s = port->subports[subport_id];
 
-	/* Bitmap */
-	n_subport_pipe_queues = rte_sched_subport_pipe_queues(s);
-	bmp_mem_size = rte_bitmap_get_memory_footprint(n_subport_pipe_queues);
-	s->bmp = rte_bitmap_init(n_subport_pipe_queues, s->bmp_array,
-				bmp_mem_size);
-	if (s->bmp == NULL) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Subport bitmap init error\n", __func__);
+		s->tb_credits = profile->tb_size / 2;
 
-		rte_sched_free_memory(port, n_subports);
-		return -EINVAL;
-	}
+		s->tc_time = port->time + profile->tc_period;
 
-	for (i = 0; i < RTE_SCHED_PORT_N_GRINDERS; i++)
-		s->grinder_base_bmp_pos[i] = RTE_SCHED_PIPE_INVALID;
+		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+			if (s->qsize[i])
+				s->tc_credits[i] =
+					profile->tc_credits_per_period[i];
+			else
+				profile->tc_credits_per_period[i] = 0;
 
 #ifdef RTE_SCHED_SUBPORT_TC_OV
-	/* TC oversubscription */
-	s->tc_ov_wm_min = port->mtu;
-	s->tc_ov_wm_max = rte_sched_time_ms_to_bytes(params->tc_period,
-						     s->pipe_tc_be_rate_max);
-	s->tc_ov_wm = s->tc_ov_wm_max;
-	s->tc_ov_period_id = 0;
-	s->tc_ov = 0;
-	s->tc_ov_n = 0;
-	s->tc_ov_rate = 0;
+		s->tc_ov_wm_max = rte_sched_time_ms_to_bytes(profile->tc_period,
+							s->pipe_tc_be_rate_max);
 #endif
+		s->profile = subport_profile_id;
+
+	}
 
-	rte_sched_port_log_subport_config(port, subport_id);
+	rte_sched_port_log_subport_profile(port, subport_profile_id);
 
 	return 0;
 }
@@ -1351,6 +1332,7 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 	int32_t pipe_profile)
 {
 	struct rte_sched_subport *s;
+	struct rte_sched_subport_profile *sp;
 	struct rte_sched_pipe *p;
 	struct rte_sched_pipe_profile *params;
 	uint32_t n_subports = subport_id + 1;
@@ -1391,14 +1373,15 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 		return -EINVAL;
 	}
 
+	sp = port->subport_profiles + s->profile;
 	/* Handle the case when pipe already has a valid configuration */
 	p = s->pipe + pipe_id;
 	if (p->tb_time) {
 		params = s->pipe_profiles + p->profile;
 
 		double subport_tc_be_rate =
-			(double) s->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
-			/ (double) s->tc_period;
+		(double)sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
+			/ (double) sp->tc_period;
 		double pipe_tc_be_rate =
 			(double) params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
 			/ (double) params->tc_period;
@@ -1440,8 +1423,8 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 	{
 		/* Subport best effort tc oversubscription */
 		double subport_tc_be_rate =
-			(double) s->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
-			/ (double) s->tc_period;
+		(double)sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
+			/ (double) sp->tc_period;
 		double pipe_tc_be_rate =
 			(double) params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
 			/ (double) params->tc_period;
@@ -2229,14 +2212,15 @@ grinder_credits_update(struct rte_sched_port *port,
 	struct rte_sched_grinder *grinder = subport->grinder + pos;
 	struct rte_sched_pipe *pipe = grinder->pipe;
 	struct rte_sched_pipe_profile *params = grinder->pipe_params;
+	struct rte_sched_subport_profile *sp = grinder->subport_params;
 	uint64_t n_periods;
 	uint32_t i;
 
 	/* Subport TB */
-	n_periods = (port->time - subport->tb_time) / subport->tb_period;
-	subport->tb_credits += n_periods * subport->tb_credits_per_period;
-	subport->tb_credits = RTE_MIN(subport->tb_credits, subport->tb_size);
-	subport->tb_time += n_periods * subport->tb_period;
+	n_periods = (port->time - subport->tb_time) / sp->tb_period;
+	subport->tb_credits += n_periods * sp->tb_credits_per_period;
+	subport->tb_credits = RTE_MIN(subport->tb_credits, sp->tb_size);
+	subport->tb_time += n_periods * sp->tb_period;
 
 	/* Pipe TB */
 	n_periods = (port->time - pipe->tb_time) / params->tb_period;
@@ -2247,9 +2231,9 @@ grinder_credits_update(struct rte_sched_port *port,
 	/* Subport TCs */
 	if (unlikely(port->time >= subport->tc_time)) {
 		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-			subport->tc_credits[i] = subport->tc_credits_per_period[i];
+			subport->tc_credits[i] = sp->tc_credits_per_period[i];
 
-		subport->tc_time = port->time + subport->tc_period;
+		subport->tc_time = port->time + sp->tc_period;
 	}
 
 	/* Pipe TCs */
@@ -2265,8 +2249,10 @@ grinder_credits_update(struct rte_sched_port *port,
 
 static inline uint64_t
 grinder_tc_ov_credits_update(struct rte_sched_port *port,
-	struct rte_sched_subport *subport)
+	struct rte_sched_subport *subport, uint32_t pos)
 {
+	struct rte_sched_grinder *grinder = subport->grinder + pos;
+	struct rte_sched_subport_profile *sp = grinder->subport_params;
 	uint64_t tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
 	uint64_t tc_consumption = 0, tc_ov_consumption_max;
 	uint64_t tc_ov_wm = subport->tc_ov_wm;
@@ -2276,17 +2262,17 @@ grinder_tc_ov_credits_update(struct rte_sched_port *port,
 		return subport->tc_ov_wm_max;
 
 	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASS_BE; i++) {
-		tc_ov_consumption[i] =
-			subport->tc_credits_per_period[i] - subport->tc_credits[i];
+		tc_ov_consumption[i] = sp->tc_credits_per_period[i]
+					-  subport->tc_credits[i];
 		tc_consumption += tc_ov_consumption[i];
 	}
 
 	tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] =
-		subport->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
+	sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
 		subport->tc_credits[RTE_SCHED_TRAFFIC_CLASS_BE];
 
 	tc_ov_consumption_max =
-		subport->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
+	sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
 			tc_consumption;
 
 	if (tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] >
@@ -2312,14 +2298,15 @@ grinder_credits_update(struct rte_sched_port *port,
 	struct rte_sched_grinder *grinder = subport->grinder + pos;
 	struct rte_sched_pipe *pipe = grinder->pipe;
 	struct rte_sched_pipe_profile *params = grinder->pipe_params;
+	struct rte_sched_subport_profile *sp = grinder->subport_params;
 	uint64_t n_periods;
 	uint32_t i;
 
 	/* Subport TB */
-	n_periods = (port->time - subport->tb_time) / subport->tb_period;
-	subport->tb_credits += n_periods * subport->tb_credits_per_period;
-	subport->tb_credits = RTE_MIN(subport->tb_credits, subport->tb_size);
-	subport->tb_time += n_periods * subport->tb_period;
+	n_periods = (port->time - subport->tb_time) / sp->tb_period;
+	subport->tb_credits += n_periods * sp->tb_credits_per_period;
+	subport->tb_credits = RTE_MIN(subport->tb_credits, sp->tb_size);
+	subport->tb_time += n_periods * sp->tb_period;
 
 	/* Pipe TB */
 	n_periods = (port->time - pipe->tb_time) / params->tb_period;
@@ -2329,12 +2316,13 @@ grinder_credits_update(struct rte_sched_port *port,
 
 	/* Subport TCs */
 	if (unlikely(port->time >= subport->tc_time)) {
-		subport->tc_ov_wm = grinder_tc_ov_credits_update(port, subport);
+		subport->tc_ov_wm =
+			grinder_tc_ov_credits_update(port, subport, pos);
 
 		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-			subport->tc_credits[i] = subport->tc_credits_per_period[i];
+			subport->tc_credits[i] = sp->tc_credits_per_period[i];
 
-		subport->tc_time = port->time + subport->tc_period;
+		subport->tc_time = port->time + sp->tc_period;
 		subport->tc_ov_period_id++;
 	}
 
@@ -2857,6 +2845,9 @@ grinder_handle(struct rte_sched_port *port,
 		struct rte_sched_pipe *pipe = grinder->pipe;
 
 		grinder->pipe_params = subport->pipe_profiles + pipe->profile;
+		grinder->subport_params = port->subport_profiles +
+						subport->profile;
+
 		grinder_prefetch_tc_queue_arrays(subport, pos);
 		grinder_credits_update(port, subport, pos);
 
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index 4b0abaac3..fbcd9c954 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -361,20 +361,27 @@ rte_sched_port_subport_profile_add(struct rte_sched_port *port,
 
 /**
  * Hierarchical scheduler subport configuration
- *
+ * Note that this function is safe to use at runtime
+ * to configure subport bandwidth profile.
  * @param port
  *   Handle to port scheduler instance
  * @param subport_id
  *   Subport ID
  * @param params
- *   Subport configuration parameters
+ *   Subport configuration parameters. Must be non-NULL
+ *   for first invocation (i.e initialization) for a given
+ *   subport. Ignored (recommended value is NULL) for all
+ *   subsequent invocation on the same subport.
+ * @param subport_profile_id
+ *   ID of subport bandwidth profile
  * @return
  *   0 upon success, error code otherwise
  */
 int
 rte_sched_subport_config(struct rte_sched_port *port,
 	uint32_t subport_id,
-	struct rte_sched_subport_params *params);
+	struct rte_sched_subport_params *params,
+	uint32_t subport_profile_id);
 
 /**
  * Hierarchical scheduler pipe configuration
-- 
2.17.1


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

* [dpdk-dev] [PATCH v7 4/8] example/qos_sched: update subport rate dynamically
  2020-10-06 18:02               ` [dpdk-dev] [PATCH v7 " Savinay Dharmappa
                                   ` (2 preceding siblings ...)
  2020-10-06 18:02                 ` [dpdk-dev] [PATCH v7 3/8] sched: update subport rate dynamically Savinay Dharmappa
@ 2020-10-06 18:02                 ` Savinay Dharmappa
  2020-10-06 18:02                 ` [dpdk-dev] [PATCH v7 5/8] example/ip_pipeline: " Savinay Dharmappa
                                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-10-06 18:02 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

Modify the qos_sched application to build the hierarchical scheduler
with default subport bandwidth profile. It also allows to update
a subport with different subport rates dynamically.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 examples/qos_sched/cfg_file.c  | 151 +++++++++++++++++++--------------
 examples/qos_sched/cfg_file.h  |   4 +
 examples/qos_sched/init.c      |  20 +++--
 examples/qos_sched/main.h      |   1 +
 examples/qos_sched/profile.cfg |   3 +
 5 files changed, 110 insertions(+), 69 deletions(-)

diff --git a/examples/qos_sched/cfg_file.c b/examples/qos_sched/cfg_file.c
index f078e4f7d..cd167bd8e 100644
--- a/examples/qos_sched/cfg_file.c
+++ b/examples/qos_sched/cfg_file.c
@@ -142,6 +142,93 @@ cfg_load_pipe(struct rte_cfgfile *cfg, struct rte_sched_pipe_params *pipe_params
 	return 0;
 }
 
+int
+cfg_load_subport_profile(struct rte_cfgfile *cfg,
+	struct rte_sched_subport_profile_params *subport_profile)
+{
+	int i;
+	const char *entry;
+	int profiles;
+
+	if (!cfg || !subport_profile)
+		return -1;
+
+	profiles = rte_cfgfile_num_sections(cfg, "subport profile",
+					   sizeof("subport profile") - 1);
+	subport_params[0].n_pipe_profiles = profiles;
+
+	for (i = 0; i < profiles; i++) {
+		char sec_name[32];
+		snprintf(sec_name, sizeof(sec_name), "subport profile %d", i);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tb rate");
+		if (entry)
+			subport_profile[i].tb_rate = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tb size");
+		if (entry)
+			subport_profile[i].tb_size = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc period");
+		if (entry)
+			subport_profile[i].tc_period = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 0 rate");
+		if (entry)
+			subport_profile[i].tc_rate[0] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 1 rate");
+		if (entry)
+			subport_profile[i].tc_rate[1] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 2 rate");
+		if (entry)
+			subport_profile[i].tc_rate[2] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 3 rate");
+		if (entry)
+			subport_profile[i].tc_rate[3] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 4 rate");
+		if (entry)
+			subport_profile[i].tc_rate[4] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 5 rate");
+		if (entry)
+			subport_profile[i].tc_rate[5] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 6 rate");
+		if (entry)
+			subport_profile[i].tc_rate[6] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 7 rate");
+		if (entry)
+			subport_profile[i].tc_rate[7] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 8 rate");
+		if (entry)
+			subport_profile[i].tc_rate[8] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 9 rate");
+		if (entry)
+			subport_profile[i].tc_rate[9] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 10 rate");
+		if (entry)
+			subport_profile[i].tc_rate[10] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 11 rate");
+		if (entry)
+			subport_profile[i].tc_rate[11] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 12 rate");
+		if (entry)
+			subport_profile[i].tc_rate[12] = (uint64_t)atoi(entry);
+	}
+
+	return 0;
+}
+
 int
 cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subport_params)
 {
@@ -267,70 +354,6 @@ cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subpo
 				}
 			}
 
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tb rate");
-			if (entry)
-				subport_params[i].tb_rate = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tb size");
-			if (entry)
-				subport_params[i].tb_size = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc period");
-			if (entry)
-				subport_params[i].tc_period = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 0 rate");
-			if (entry)
-				subport_params[i].tc_rate[0] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 1 rate");
-			if (entry)
-				subport_params[i].tc_rate[1] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 2 rate");
-			if (entry)
-				subport_params[i].tc_rate[2] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 3 rate");
-			if (entry)
-				subport_params[i].tc_rate[3] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 4 rate");
-			if (entry)
-				subport_params[i].tc_rate[4] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 5 rate");
-			if (entry)
-				subport_params[i].tc_rate[5] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 6 rate");
-			if (entry)
-				subport_params[i].tc_rate[6] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 7 rate");
-			if (entry)
-				subport_params[i].tc_rate[7] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 8 rate");
-			if (entry)
-				subport_params[i].tc_rate[8] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 9 rate");
-			if (entry)
-				subport_params[i].tc_rate[9] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 10 rate");
-			if (entry)
-				subport_params[i].tc_rate[10] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 11 rate");
-			if (entry)
-				subport_params[i].tc_rate[11] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 12 rate");
-			if (entry)
-				subport_params[i].tc_rate[12] = (uint64_t)atoi(entry);
-
 			int n_entries = rte_cfgfile_section_num_entries(cfg, sec_name);
 			struct rte_cfgfile_entry entries[n_entries];
 
diff --git a/examples/qos_sched/cfg_file.h b/examples/qos_sched/cfg_file.h
index 2eccf1ca0..0dc458aa7 100644
--- a/examples/qos_sched/cfg_file.h
+++ b/examples/qos_sched/cfg_file.h
@@ -14,4 +14,8 @@ int cfg_load_pipe(struct rte_cfgfile *cfg, struct rte_sched_pipe_params *pipe);
 
 int cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subport);
 
+int cfg_load_subport_profile(struct rte_cfgfile *cfg,
+			     struct rte_sched_subport_profile_params
+			     *subport_profile);
+
 #endif
diff --git a/examples/qos_sched/init.c b/examples/qos_sched/init.c
index b188c624b..1abe003fc 100644
--- a/examples/qos_sched/init.c
+++ b/examples/qos_sched/init.c
@@ -192,15 +192,20 @@ static struct rte_sched_pipe_params pipe_profiles[MAX_SCHED_PIPE_PROFILES] = {
 	},
 };
 
-struct rte_sched_subport_params subport_params[MAX_SCHED_SUBPORTS] = {
+static struct rte_sched_subport_profile_params
+		subport_profile[MAX_SCHED_SUBPORT_PROFILES] = {
 	{
 		.tb_rate = 1250000000,
 		.tb_size = 1000000,
-
 		.tc_rate = {1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000},
 		.tc_period = 10,
+	},
+};
+
+struct rte_sched_subport_params subport_params[MAX_SCHED_SUBPORTS] = {
+	{
 		.n_pipes_per_subport_enabled = 4096,
 		.qsize = {64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64},
 		.pipe_profiles = pipe_profiles,
@@ -285,6 +290,9 @@ struct rte_sched_port_params port_params = {
 	.mtu = 6 + 6 + 4 + 4 + 2 + 1500,
 	.frame_overhead = RTE_SCHED_FRAME_OVERHEAD_DEFAULT,
 	.n_subports_per_port = 1,
+	.n_subport_profiles = 1,
+	.subport_profiles = subport_profile,
+	.n_max_subport_profiles = MAX_SCHED_SUBPORT_PROFILES,
 	.n_pipes_per_subport = MAX_SCHED_PIPES,
 };
 
@@ -315,10 +323,11 @@ app_init_sched_port(uint32_t portid, uint32_t socketid)
 
 	for (subport = 0; subport < port_params.n_subports_per_port; subport ++) {
 		err = rte_sched_subport_config(port, subport,
-				&subport_params[subport], 0);
+				&subport_params[subport],
+				0);
 		if (err) {
-			rte_exit(EXIT_FAILURE, "Unable to config sched subport %u, err=%d\n",
-					subport, err);
+			rte_exit(EXIT_FAILURE, "Unable to config sched "
+				 "subport %u, err=%d\n", subport, err);
 		}
 
 		uint32_t n_pipes_per_subport =
@@ -351,6 +360,7 @@ app_load_cfg_profile(const char *profile)
 
 	cfg_load_port(file, &port_params);
 	cfg_load_subport(file, subport_params);
+	cfg_load_subport_profile(file, subport_profile);
 	cfg_load_pipe(file, pipe_profiles);
 
 	rte_cfgfile_close(file);
diff --git a/examples/qos_sched/main.h b/examples/qos_sched/main.h
index 23bc418d9..0d6815ae6 100644
--- a/examples/qos_sched/main.h
+++ b/examples/qos_sched/main.h
@@ -51,6 +51,7 @@ extern "C" {
 #define MAX_SCHED_SUBPORTS		8
 #define MAX_SCHED_PIPES		4096
 #define MAX_SCHED_PIPE_PROFILES		256
+#define MAX_SCHED_SUBPORT_PROFILES	8
 
 #ifndef APP_COLLECT_STAT
 #define APP_COLLECT_STAT		1
diff --git a/examples/qos_sched/profile.cfg b/examples/qos_sched/profile.cfg
index 61b8b7071..4486d2799 100644
--- a/examples/qos_sched/profile.cfg
+++ b/examples/qos_sched/profile.cfg
@@ -26,6 +26,9 @@ number of subports per port = 1
 number of pipes per subport = 4096
 queue sizes = 64 64 64 64 64 64 64 64 64 64 64 64 64
 
+subport 0-8 = 0                ; These subports are configured with subport profile 0
+
+[subport profile 0]
 tb rate = 1250000000           ; Bytes per second
 tb size = 1000000              ; Bytes
 
-- 
2.17.1


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

* [dpdk-dev] [PATCH v7 5/8] example/ip_pipeline: update subport rate dynamically
  2020-10-06 18:02               ` [dpdk-dev] [PATCH v7 " Savinay Dharmappa
                                   ` (3 preceding siblings ...)
  2020-10-06 18:02                 ` [dpdk-dev] [PATCH v7 4/8] example/qos_sched: " Savinay Dharmappa
@ 2020-10-06 18:02                 ` Savinay Dharmappa
  2020-10-06 18:02                 ` [dpdk-dev] [PATCH v7 6/8] drivers/softnic: " Savinay Dharmappa
                                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-10-06 18:02 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

Modify the ip_pipeline application to build the hierarchical scheduler
with default subport bandwidth profile. It also allows to update
a subport with different subport rates dynamically

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 examples/ip_pipeline/cli.c  |  68 ++++++++------------
 examples/ip_pipeline/tmgr.c | 121 ++++++++++++++++++++++++++++++------
 examples/ip_pipeline/tmgr.h |   5 +-
 3 files changed, 134 insertions(+), 60 deletions(-)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index dafc95ae9..6b62a3271 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -393,12 +393,7 @@ static const char cmd_tmgr_subport_profile_help[] =
 "   <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate> <tc4_rate>"
 "        <tc5_rate> <tc6_rate> <tc7_rate> <tc8_rate>"
 "        <tc9_rate> <tc10_rate> <tc11_rate> <tc12_rate>\n"
-"   <tc_period>\n"
-"   pps <n_pipes_per_subport>\n"
-"   qsize <qsize_tc0> <qsize_tc1> <qsize_tc2>"
-"       <qsize_tc3> <qsize_tc4> <qsize_tc5> <qsize_tc6>"
-"       <qsize_tc7> <qsize_tc8> <qsize_tc9> <qsize_tc10>"
-"       <qsize_tc11> <qsize_tc12>";
+"   <tc_period>\n";
 
 static void
 cmd_tmgr_subport_profile(char **tokens,
@@ -406,57 +401,37 @@ cmd_tmgr_subport_profile(char **tokens,
 	char *out,
 	size_t out_size)
 {
-	struct rte_sched_subport_params p;
+	struct rte_sched_subport_profile_params subport_profile;
 	int status, i;
 
-	if (n_tokens != 35) {
+	if (n_tokens != 21) {
 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
 		return;
 	}
 
-	if (parser_read_uint64(&p.tb_rate, tokens[3]) != 0) {
+	if (parser_read_uint64(&subport_profile.tb_rate, tokens[3]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
 		return;
 	}
 
-	if (parser_read_uint64(&p.tb_size, tokens[4]) != 0) {
+	if (parser_read_uint64(&subport_profile.tb_size, tokens[4]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
 		return;
 	}
 
 	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-		if (parser_read_uint64(&p.tc_rate[i], tokens[5 + i]) != 0) {
+		if (parser_read_uint64(&subport_profile.tc_rate[i],
+				tokens[5 + i]) != 0) {
 			snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
 			return;
 		}
 
-	if (parser_read_uint64(&p.tc_period, tokens[18]) != 0) {
+	if (parser_read_uint64(&subport_profile.tc_period, tokens[18]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
 		return;
 	}
 
-	if (strcmp(tokens[19], "pps") != 0) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
-		return;
-	}
-
-	if (parser_read_uint32(&p.n_pipes_per_subport_enabled, tokens[20]) != 0) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport");
-		return;
-	}
-
-	if (strcmp(tokens[21], "qsize") != 0) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "qsize");
-		return;
-	}
-
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-		if (parser_read_uint16(&p.qsize[i], tokens[22 + i]) != 0) {
-			snprintf(out, out_size, MSG_ARG_INVALID, "qsize");
-			return;
-		}
-
-	status = tmgr_subport_profile_add(&p);
+	status = tmgr_subport_profile_add(&subport_profile);
 	if (status != 0) {
 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
 		return;
@@ -530,6 +505,7 @@ static const char cmd_tmgr_help[] =
 "tmgr <tmgr_name>\n"
 "   rate <rate>\n"
 "   spp <n_subports_per_port>\n"
+"   pps <n_pipes_per_subport>\n"
 "   fo <frame_overhead>\n"
 "   mtu <mtu>\n"
 "   cpu <cpu_id>\n";
@@ -544,7 +520,7 @@ cmd_tmgr(char **tokens,
 	char *name;
 	struct tmgr_port *tmgr_port;
 
-	if (n_tokens != 12) {
+	if (n_tokens != 14) {
 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
 		return;
 	}
@@ -571,32 +547,42 @@ cmd_tmgr(char **tokens,
 		return;
 	}
 
-	if (strcmp(tokens[6], "fo") != 0) {
+	if (strcmp(tokens[6], "pps") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
+		return;
+	}
+
+	if (parser_read_uint32(&p.n_pipes_per_subport, tokens[7]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport");
+		return;
+	}
+
+	if (strcmp(tokens[8], "fo") != 0) {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fo");
 		return;
 	}
 
-	if (parser_read_uint32(&p.frame_overhead, tokens[7]) != 0) {
+	if (parser_read_uint32(&p.frame_overhead, tokens[9]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "frame_overhead");
 		return;
 	}
 
-	if (strcmp(tokens[8], "mtu") != 0) {
+	if (strcmp(tokens[10], "mtu") != 0) {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mtu");
 		return;
 	}
 
-	if (parser_read_uint32(&p.mtu, tokens[9]) != 0) {
+	if (parser_read_uint32(&p.mtu, tokens[11]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
 		return;
 	}
 
-	if (strcmp(tokens[10], "cpu") != 0) {
+	if (strcmp(tokens[12], "cpu") != 0) {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
 		return;
 	}
 
-	if (parser_read_uint32(&p.cpu_id, tokens[11]) != 0) {
+	if (parser_read_uint32(&p.cpu_id, tokens[13]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
 		return;
 	}
diff --git a/examples/ip_pipeline/tmgr.c b/examples/ip_pipeline/tmgr.c
index 46c6a83a4..ef8c30bdf 100644
--- a/examples/ip_pipeline/tmgr.c
+++ b/examples/ip_pipeline/tmgr.c
@@ -4,11 +4,12 @@
 
 #include <stdlib.h>
 
+#include <rte_common.h>
 #include <rte_string_fns.h>
 
 #include "tmgr.h"
 
-static struct rte_sched_subport_params
+static struct rte_sched_subport_profile_params
 	subport_profile[TMGR_SUBPORT_PROFILE_MAX];
 
 static uint32_t n_subport_profiles;
@@ -18,6 +19,82 @@ static struct rte_sched_pipe_params
 
 static uint32_t n_pipe_profiles;
 
+static const struct rte_sched_subport_params subport_params_default = {
+	.n_pipes_per_subport_enabled = 0, /* filled at runtime */
+	.qsize = {64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64},
+	.pipe_profiles = pipe_profile,
+	.n_pipe_profiles = 0, /* filled at run time */
+	.n_max_pipe_profiles = RTE_DIM(pipe_profile),
+#ifdef RTE_SCHED_RED
+.red_params = {
+	/* Traffic Class 0 Colors Green / Yellow / Red */
+	[0][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[0][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[0][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 1 - Colors Green / Yellow / Red */
+	[1][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[1][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[1][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 2 - Colors Green / Yellow / Red */
+	[2][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[2][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[2][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 3 - Colors Green / Yellow / Red */
+	[3][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[3][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[3][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 4 - Colors Green / Yellow / Red */
+	[4][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[4][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[4][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 5 - Colors Green / Yellow / Red */
+	[5][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[5][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[5][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 6 - Colors Green / Yellow / Red */
+	[6][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[6][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[6][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 7 - Colors Green / Yellow / Red */
+	[7][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[7][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[7][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 8 - Colors Green / Yellow / Red */
+	[8][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[8][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[8][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 9 - Colors Green / Yellow / Red */
+	[9][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[9][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[9][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 10 - Colors Green / Yellow / Red */
+	[10][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[10][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[10][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 11 - Colors Green / Yellow / Red */
+	[11][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[11][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[11][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 12 - Colors Green / Yellow / Red */
+	[12][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[12][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[12][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	},
+#endif /* RTE_SCHED_RED */
+};
+
 static struct tmgr_port_list tmgr_port_list;
 
 int
@@ -44,17 +121,16 @@ tmgr_port_find(const char *name)
 }
 
 int
-tmgr_subport_profile_add(struct rte_sched_subport_params *p)
+tmgr_subport_profile_add(struct rte_sched_subport_profile_params *params)
 {
 	/* Check input params */
-	if (p == NULL ||
-		p->n_pipes_per_subport_enabled == 0)
+	if (params == NULL)
 		return -1;
 
 	/* Save profile */
 	memcpy(&subport_profile[n_subport_profiles],
-		p,
-		sizeof(*p));
+		&params,
+		sizeof(params));
 
 	n_subport_profiles++;
 
@@ -81,6 +157,7 @@ tmgr_pipe_profile_add(struct rte_sched_pipe_params *p)
 struct tmgr_port *
 tmgr_port_create(const char *name, struct tmgr_port_params *params)
 {
+	struct rte_sched_subport_params subport_params;
 	struct rte_sched_port_params p;
 	struct tmgr_port *tmgr_port;
 	struct rte_sched_port *s;
@@ -91,6 +168,7 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 		tmgr_port_find(name) ||
 		(params == NULL) ||
 		(params->n_subports_per_port == 0) ||
+		(params->n_pipes_per_subport == 0) ||
 		(params->cpu_id >= RTE_MAX_NUMA_NODES) ||
 		(n_subport_profiles == 0) ||
 		(n_pipe_profiles == 0))
@@ -103,15 +181,22 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 	p.mtu = params->mtu;
 	p.frame_overhead = params->frame_overhead;
 	p.n_subports_per_port = params->n_subports_per_port;
-	p.n_pipes_per_subport = TMGR_PIPE_SUBPORT_MAX;
+	p.n_subport_profiles = n_subport_profiles;
+	p.subport_profiles = subport_profile;
+	p.n_max_subport_profiles = TMGR_SUBPORT_PROFILE_MAX;
+	p.n_pipes_per_subport = params->n_pipes_per_subport;
+
 
 	s = rte_sched_port_config(&p);
 	if (s == NULL)
 		return NULL;
 
-	subport_profile[0].pipe_profiles = pipe_profile;
-	subport_profile[0].n_pipe_profiles = n_pipe_profiles;
-	subport_profile[0].n_max_pipe_profiles = TMGR_PIPE_PROFILE_MAX;
+	memcpy(&subport_params, &subport_params_default,
+		sizeof(subport_params_default));
+
+	subport_params.n_pipe_profiles = n_pipe_profiles;
+	subport_params.n_pipes_per_subport_enabled =
+						params->n_pipes_per_subport;
 
 	for (i = 0; i < params->n_subports_per_port; i++) {
 		int status;
@@ -119,7 +204,7 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 		status = rte_sched_subport_config(
 			s,
 			i,
-			&subport_profile[0],
+			&subport_params,
 			0);
 
 		if (status) {
@@ -127,7 +212,8 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 			return NULL;
 		}
 
-		for (j = 0; j < subport_profile[0].n_pipes_per_subport_enabled; j++) {
+		for (j = 0; j < params->n_pipes_per_subport; j++) {
+
 			status = rte_sched_pipe_config(
 				s,
 				i,
@@ -152,6 +238,7 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 	strlcpy(tmgr_port->name, name, sizeof(tmgr_port->name));
 	tmgr_port->s = s;
 	tmgr_port->n_subports_per_port = params->n_subports_per_port;
+	tmgr_port->n_pipes_per_subport = params->n_pipes_per_subport;
 
 	/* Node add to list */
 	TAILQ_INSERT_TAIL(&tmgr_port_list, tmgr_port, node);
@@ -181,8 +268,8 @@ tmgr_subport_config(const char *port_name,
 	status = rte_sched_subport_config(
 		port->s,
 		subport_id,
-		&subport_profile[subport_profile_id],
-		0);
+		NULL,
+		subport_profile_id);
 
 	return status;
 }
@@ -204,10 +291,8 @@ tmgr_pipe_config(const char *port_name,
 	port = tmgr_port_find(port_name);
 	if ((port == NULL) ||
 		(subport_id >= port->n_subports_per_port) ||
-		(pipe_id_first >=
-			subport_profile[subport_id].n_pipes_per_subport_enabled) ||
-		(pipe_id_last >=
-			subport_profile[subport_id].n_pipes_per_subport_enabled) ||
+		(pipe_id_first >= port->n_pipes_per_subport) ||
+		(pipe_id_last >= port->n_pipes_per_subport) ||
 		(pipe_id_first > pipe_id_last) ||
 		(pipe_profile_id >= n_pipe_profiles))
 		return -1;
diff --git a/examples/ip_pipeline/tmgr.h b/examples/ip_pipeline/tmgr.h
index ee50cf7cc..1994c55bc 100644
--- a/examples/ip_pipeline/tmgr.h
+++ b/examples/ip_pipeline/tmgr.h
@@ -9,6 +9,7 @@
 #include <sys/queue.h>
 
 #include <rte_sched.h>
+#include <rte_red.h>
 
 #include "common.h"
 
@@ -29,6 +30,7 @@ struct tmgr_port {
 	char name[NAME_SIZE];
 	struct rte_sched_port *s;
 	uint32_t n_subports_per_port;
+	uint32_t n_pipes_per_subport;
 };
 
 TAILQ_HEAD(tmgr_port_list, tmgr_port);
@@ -42,13 +44,14 @@ tmgr_port_find(const char *name);
 struct tmgr_port_params {
 	uint64_t rate;
 	uint32_t n_subports_per_port;
+	uint32_t n_pipes_per_subport;
 	uint32_t frame_overhead;
 	uint32_t mtu;
 	uint32_t cpu_id;
 };
 
 int
-tmgr_subport_profile_add(struct rte_sched_subport_params *p);
+tmgr_subport_profile_add(struct rte_sched_subport_profile_params *sp);
 
 int
 tmgr_pipe_profile_add(struct rte_sched_pipe_params *p);
-- 
2.17.1


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

* [dpdk-dev] [PATCH v7 6/8] drivers/softnic: update subport rate dynamically
  2020-10-06 18:02               ` [dpdk-dev] [PATCH v7 " Savinay Dharmappa
                                   ` (4 preceding siblings ...)
  2020-10-06 18:02                 ` [dpdk-dev] [PATCH v7 5/8] example/ip_pipeline: " Savinay Dharmappa
@ 2020-10-06 18:02                 ` Savinay Dharmappa
  2020-10-06 18:02                 ` [dpdk-dev] [PATCH v7 7/8] app/test_sched: " Savinay Dharmappa
                                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-10-06 18:02 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

Modify the softnic drivers to build the hierarchical scheduler
with default subport bandwidth profile. It also allows to update
a subport with different subport rates dynamically.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 .../net/softnic/rte_eth_softnic_internals.h   |  11 +-
 drivers/net/softnic/rte_eth_softnic_tm.c      | 243 ++++++++++++++----
 2 files changed, 195 insertions(+), 59 deletions(-)

diff --git a/drivers/net/softnic/rte_eth_softnic_internals.h b/drivers/net/softnic/rte_eth_softnic_internals.h
index 6eec43b22..77e0139a6 100644
--- a/drivers/net/softnic/rte_eth_softnic_internals.h
+++ b/drivers/net/softnic/rte_eth_softnic_internals.h
@@ -164,11 +164,18 @@ TAILQ_HEAD(softnic_link_list, softnic_link);
 #ifndef TM_MAX_PIPE_PROFILE
 #define TM_MAX_PIPE_PROFILE				256
 #endif
+
+#ifndef TM_MAX_SUBPORT_PROFILE
+#define TM_MAX_SUBPORT_PROFILE				256
+#endif
+
 struct tm_params {
 	struct rte_sched_port_params port_params;
-
 	struct rte_sched_subport_params subport_params[TM_MAX_SUBPORTS];
-
+	struct rte_sched_subport_profile_params
+		subport_profile[TM_MAX_SUBPORT_PROFILE];
+	uint32_t n_subport_profiles;
+	uint32_t subport_to_profile[TM_MAX_SUBPORT_PROFILE];
 	struct rte_sched_pipe_params pipe_profiles[TM_MAX_PIPE_PROFILE];
 	uint32_t n_pipe_profiles;
 	uint32_t pipe_to_profile[TM_MAX_SUBPORTS * TM_MAX_PIPES_PER_SUBPORT];
diff --git a/drivers/net/softnic/rte_eth_softnic_tm.c b/drivers/net/softnic/rte_eth_softnic_tm.c
index 5199dd2cd..725b0231a 100644
--- a/drivers/net/softnic/rte_eth_softnic_tm.c
+++ b/drivers/net/softnic/rte_eth_softnic_tm.c
@@ -86,13 +86,14 @@ softnic_tmgr_port_create(struct pmd_internals *p,
 	n_subports = t->port_params.n_subports_per_port;
 	for (subport_id = 0; subport_id < n_subports; subport_id++) {
 		uint32_t n_pipes_per_subport =
-			t->subport_params[subport_id].n_pipes_per_subport_enabled;
+		t->subport_params[subport_id].n_pipes_per_subport_enabled;
 		uint32_t pipe_id;
 		int status;
 
 		status = rte_sched_subport_config(sched,
 			subport_id,
-			&t->subport_params[subport_id], 0);
+			&t->subport_params[subport_id],
+			t->subport_to_profile[subport_id]);
 		if (status) {
 			rte_sched_port_free(sched);
 			return NULL;
@@ -1114,34 +1115,51 @@ tm_shared_shaper_get_tc(struct rte_eth_dev *dev,
 	return NULL;
 }
 
+static int
+subport_profile_exists(struct rte_eth_dev *dev,
+	struct rte_sched_subport_profile_params *sp,
+	uint32_t *subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+	uint32_t i;
+
+	for (i = 0; i < t->n_subport_profiles; i++)
+		if (memcmp(&t->subport_profile[i], sp, sizeof(*sp)) == 0) {
+			if (subport_profile_id)
+				*subport_profile_id = i;
+			return 1;
+		}
+
+	return 0;
+}
+
 static int
 update_subport_tc_rate(struct rte_eth_dev *dev,
 	struct tm_node *nt,
 	struct tm_shared_shaper *ss,
 	struct tm_shaper_profile *sp_new)
 {
+	struct rte_sched_subport_profile_params subport_profile;
 	struct pmd_internals *p = dev->data->dev_private;
 	uint32_t tc_id = tm_node_tc_id(dev, nt);
-
 	struct tm_node *np = nt->parent_node;
-
 	struct tm_node *ns = np->parent_node;
 	uint32_t subport_id = tm_node_subport_id(dev, ns);
-
-	struct rte_sched_subport_params subport_params;
-
+	struct tm_params *t = &p->soft.tm.params;
+	uint32_t subport_profile_id = t->subport_to_profile[subport_id];
 	struct tm_shaper_profile *sp_old = tm_shaper_profile_search(dev,
 		ss->shaper_profile_id);
 
 	/* Derive new subport configuration. */
-	memcpy(&subport_params,
-		&p->soft.tm.params.subport_params[subport_id],
-		sizeof(subport_params));
-	subport_params.tc_rate[tc_id] = sp_new->params.peak.rate;
+	memcpy(&subport_profile,
+		&p->soft.tm.params.subport_profile[subport_profile_id],
+		sizeof(subport_profile));
+	subport_profile.tc_rate[tc_id] = sp_new->params.peak.rate;
 
 	/* Update the subport configuration. */
 	if (rte_sched_subport_config(SCHED(p),
-		subport_id, &subport_params, 0))
+		subport_id, NULL, subport_profile_id))
 		return -1;
 
 	/* Commit changes. */
@@ -1150,9 +1168,9 @@ update_subport_tc_rate(struct rte_eth_dev *dev,
 	ss->shaper_profile_id = sp_new->shaper_profile_id;
 	sp_new->n_users++;
 
-	memcpy(&p->soft.tm.params.subport_params[subport_id],
-		&subport_params,
-		sizeof(subport_params));
+	memcpy(&p->soft.tm.params.subport_profile[subport_profile_id],
+		&subport_profile,
+		sizeof(subport_profile));
 
 	return 0;
 }
@@ -2238,6 +2256,8 @@ pipe_profiles_generate(struct rte_eth_dev *dev)
 			struct rte_sched_pipe_params pp;
 			uint32_t pos;
 
+			memset(&pp, 0, sizeof(pp));
+
 			if (np->level != TM_NODE_LEVEL_PIPE ||
 				np->parent_node_id != ns->node_id)
 				continue;
@@ -2343,6 +2363,123 @@ tm_subport_tc_shared_shaper_get(struct rte_eth_dev *dev,
 	return NULL;
 }
 
+static struct rte_sched_subport_profile_params *
+subport_profile_get(struct rte_eth_dev *dev, struct tm_node *np)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+	uint32_t subport_id = tm_node_subport_id(dev, np->parent_node);
+
+	return &t->subport_profile[subport_id];
+}
+
+static void
+subport_profile_mark(struct rte_eth_dev *dev,
+	uint32_t subport_id,
+	uint32_t subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+
+	t->subport_to_profile[subport_id] = subport_profile_id;
+}
+
+static void
+subport_profile_install(struct rte_eth_dev *dev,
+	struct rte_sched_subport_profile_params *sp,
+	uint32_t subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+
+	memcpy(&t->subport_profile[subport_profile_id],
+		sp, sizeof(*sp));
+	t->n_subport_profiles++;
+}
+
+static int
+subport_profile_free_exists(struct rte_eth_dev *dev,
+	uint32_t *subport_profile_id)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_params *t = &p->soft.tm.params;
+
+	if (t->n_subport_profiles < TM_MAX_SUBPORT_PROFILE) {
+		*subport_profile_id = t->n_subport_profiles;
+		return 1;
+	}
+
+	return 0;
+}
+
+static void
+subport_profile_build(struct rte_eth_dev *dev, struct tm_node *np,
+	struct rte_sched_subport_profile_params *sp)
+{
+	uint32_t i;
+	memset(sp, 0, sizeof(*sp));
+
+	sp->tb_rate = np->shaper_profile->params.peak.rate;
+	sp->tb_size = np->shaper_profile->params.peak.size;
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
+		struct tm_shared_shaper *ss;
+		struct tm_shaper_profile *ssp;
+
+		ss = tm_subport_tc_shared_shaper_get(dev, np, i);
+		ssp = (ss) ? tm_shaper_profile_search(dev,
+			ss->shaper_profile_id) :
+			np->shaper_profile;
+		sp->tc_rate[i] = ssp->params.peak.rate;
+	}
+
+	/* Traffic Class (TC) */
+	sp->tc_period = SUBPORT_TC_PERIOD;
+}
+
+static int
+subport_profiles_generate(struct rte_eth_dev *dev)
+{
+	struct pmd_internals *p = dev->data->dev_private;
+	struct tm_hierarchy *h = &p->soft.tm.h;
+	struct tm_node_list *nl = &h->nodes;
+	struct tm_node *ns;
+	uint32_t subport_id;
+
+	/* Objective: Fill in the following fields in struct tm_params:
+	 *    - subport_profiles
+	 *    - n_subport_profiles
+	 *    - subport_to_profile
+	 */
+
+	subport_id = 0;
+	TAILQ_FOREACH(ns, nl, node) {
+		if (ns->level != TM_NODE_LEVEL_SUBPORT)
+			continue;
+
+		struct rte_sched_subport_profile_params sp;
+		uint32_t pos;
+
+		memset(&sp, 0, sizeof(sp));
+
+		subport_profile_build(dev, ns, &sp);
+
+		if (!subport_profile_exists(dev, &sp, &pos)) {
+			if (!subport_profile_free_exists(dev, &pos))
+				return -1;
+
+			subport_profile_install(dev, &sp, pos);
+		}
+
+		subport_profile_mark(dev, subport_id, pos);
+
+		subport_id++;
+	}
+
+	return 0;
+}
+
+
 static int
 hierarchy_commit_check(struct rte_eth_dev *dev, struct rte_tm_error *error)
 {
@@ -2519,6 +2656,15 @@ hierarchy_commit_check(struct rte_eth_dev *dev, struct rte_tm_error *error)
 				rte_strerror(EINVAL));
 	}
 
+	/* Not too many subport profiles. */
+	if (subport_profiles_generate(dev))
+		return -rte_tm_error_set(error,
+			EINVAL,
+			RTE_TM_ERROR_TYPE_UNSPECIFIED,
+			NULL,
+			rte_strerror(EINVAL));
+
+
 	/* Not too many pipe profiles. */
 	if (pipe_profiles_generate(dev))
 		return -rte_tm_error_set(error,
@@ -2600,48 +2746,20 @@ hierarchy_blueprints_create(struct rte_eth_dev *dev)
 		.frame_overhead =
 			root->shaper_profile->params.pkt_length_adjust,
 		.n_subports_per_port = root->n_children,
+		.n_subport_profiles = t->n_subport_profiles,
+		.subport_profiles = t->subport_profile,
+		.n_max_subport_profiles = TM_MAX_SUBPORT_PROFILE,
 		.n_pipes_per_subport = TM_MAX_PIPES_PER_SUBPORT,
 	};
 
 	subport_id = 0;
 	TAILQ_FOREACH(n, nl, node) {
-		uint64_t tc_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
-		uint32_t i;
 
 		if (n->level != TM_NODE_LEVEL_SUBPORT)
 			continue;
 
-		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
-			struct tm_shared_shaper *ss;
-			struct tm_shaper_profile *sp;
-
-			ss = tm_subport_tc_shared_shaper_get(dev, n, i);
-			sp = (ss) ? tm_shaper_profile_search(dev,
-				ss->shaper_profile_id) :
-				n->shaper_profile;
-			tc_rate[i] = sp->params.peak.rate;
-		}
-
 		t->subport_params[subport_id] =
 			(struct rte_sched_subport_params) {
-				.tb_rate = n->shaper_profile->params.peak.rate,
-				.tb_size = n->shaper_profile->params.peak.size,
-
-				.tc_rate = {tc_rate[0],
-					tc_rate[1],
-					tc_rate[2],
-					tc_rate[3],
-					tc_rate[4],
-					tc_rate[5],
-					tc_rate[6],
-					tc_rate[7],
-					tc_rate[8],
-					tc_rate[9],
-					tc_rate[10],
-					tc_rate[11],
-					tc_rate[12],
-				},
-				.tc_period = SUBPORT_TC_PERIOD,
 				.n_pipes_per_subport_enabled =
 					h->n_tm_nodes[TM_NODE_LEVEL_PIPE] /
 					h->n_tm_nodes[TM_NODE_LEVEL_SUBPORT],
@@ -2901,18 +3019,27 @@ update_subport_rate(struct rte_eth_dev *dev,
 	struct pmd_internals *p = dev->data->dev_private;
 	uint32_t subport_id = tm_node_subport_id(dev, ns);
 
-	struct rte_sched_subport_params subport_params;
+	struct rte_sched_subport_profile_params *profile0 =
+					subport_profile_get(dev, ns);
+	struct rte_sched_subport_profile_params profile1;
+	uint32_t subport_profile_id;
 
-	/* Derive new subport configuration. */
-	memcpy(&subport_params,
-		&p->soft.tm.params.subport_params[subport_id],
-		sizeof(subport_params));
-	subport_params.tb_rate = sp->params.peak.rate;
-	subport_params.tb_size = sp->params.peak.size;
+	/* Derive new pipe profile. */
+	memcpy(&profile1, profile0, sizeof(profile1));
+	profile1.tb_rate = sp->params.peak.rate;
+	profile1.tb_size = sp->params.peak.size;
+
+	/* Since implementation does not allow adding more subport profiles
+	 * after port configuration, the pipe configuration can be successfully
+	 * updated only if the new profile is also part of the existing set of
+	 * pipe profiles.
+	 */
+	if (subport_profile_exists(dev, &profile1, &subport_profile_id) == 0)
+		return -1;
 
 	/* Update the subport configuration. */
 	if (rte_sched_subport_config(SCHED(p), subport_id,
-		&subport_params, 0))
+		NULL, subport_profile_id))
 		return -1;
 
 	/* Commit changes. */
@@ -2922,9 +3049,11 @@ update_subport_rate(struct rte_eth_dev *dev,
 	ns->params.shaper_profile_id = sp->shaper_profile_id;
 	sp->n_users++;
 
-	memcpy(&p->soft.tm.params.subport_params[subport_id],
-		&subport_params,
-		sizeof(subport_params));
+	subport_profile_mark(dev, subport_id, subport_profile_id);
+
+	memcpy(&p->soft.tm.params.subport_profile[subport_profile_id],
+		&profile1,
+		sizeof(profile1));
 
 	return 0;
 }
-- 
2.17.1


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

* [dpdk-dev] [PATCH v7 7/8] app/test_sched: update subport rate dynamically
  2020-10-06 18:02               ` [dpdk-dev] [PATCH v7 " Savinay Dharmappa
                                   ` (5 preceding siblings ...)
  2020-10-06 18:02                 ` [dpdk-dev] [PATCH v7 6/8] drivers/softnic: " Savinay Dharmappa
@ 2020-10-06 18:02                 ` Savinay Dharmappa
  2020-10-06 18:02                 ` [dpdk-dev] [PATCH v7 8/8] sched: remove redundant code Savinay Dharmappa
                                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-10-06 18:02 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

Modify the test_sched application to build the hierarchical scheduler
with default subport bandwidth profile. It also allows to update
a subport with different subport rates dynamically

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 app/test/test_sched.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/app/test/test_sched.c b/app/test/test_sched.c
index 5e5c2a59b..958b63114 100644
--- a/app/test/test_sched.c
+++ b/app/test/test_sched.c
@@ -21,6 +21,7 @@
 #define PIPE            1
 #define TC              2
 #define QUEUE           0
+#define MAX_SCHED_SUBPORT_PROFILES  8
 
 static struct rte_sched_pipe_params pipe_profile[] = {
 	{ /* Profile #0 */
@@ -36,15 +37,20 @@ static struct rte_sched_pipe_params pipe_profile[] = {
 	},
 };
 
-static struct rte_sched_subport_params subport_param[] = {
+static struct rte_sched_subport_profile_params
+		subport_profile[] = {
 	{
 		.tb_rate = 1250000000,
 		.tb_size = 1000000,
-
 		.tc_rate = {1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000},
 		.tc_period = 10,
+	},
+};
+
+static struct rte_sched_subport_params subport_param[] = {
+	{
 		.n_pipes_per_subport_enabled = 1024,
 		.qsize = {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32},
 		.pipe_profiles = pipe_profile,
@@ -59,6 +65,9 @@ static struct rte_sched_port_params port_param = {
 	.mtu = 1522,
 	.frame_overhead = RTE_SCHED_FRAME_OVERHEAD_DEFAULT,
 	.n_subports_per_port = 1,
+	.n_subport_profiles = 1,
+	.subport_profiles = subport_profile,
+	.n_max_subport_profiles = MAX_SCHED_SUBPORT_PROFILES,
 	.n_pipes_per_subport = 1024,
 };
 
-- 
2.17.1


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

* [dpdk-dev] [PATCH v7 8/8] sched: remove redundant code
  2020-10-06 18:02               ` [dpdk-dev] [PATCH v7 " Savinay Dharmappa
                                   ` (6 preceding siblings ...)
  2020-10-06 18:02                 ` [dpdk-dev] [PATCH v7 7/8] app/test_sched: " Savinay Dharmappa
@ 2020-10-06 18:02                 ` Savinay Dharmappa
  2020-10-06 19:05                 ` [dpdk-dev] [PATCH v7 0/8] Enable dynamic config of subport bandwidth Dumitrescu, Cristian
  2020-10-07 14:09                 ` [dpdk-dev] [PATCH v8 " Savinay Dharmappa
  9 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-10-06 18:02 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

Remove redundant data structure fields references from
functions and subport level data structures. It also
update the release and deprecation note

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 doc/guides/rel_notes/deprecation.rst   |  6 ----
 doc/guides/rel_notes/release_20_11.rst |  1 +
 lib/librte_sched/rte_sched.c           | 42 ++------------------------
 lib/librte_sched/rte_sched.h           | 12 --------
 4 files changed, 3 insertions(+), 58 deletions(-)

diff --git a/doc/guides/rel_notes/deprecation.rst b/doc/guides/rel_notes/deprecation.rst
index 584e72087..f7363a585 100644
--- a/doc/guides/rel_notes/deprecation.rst
+++ b/doc/guides/rel_notes/deprecation.rst
@@ -212,12 +212,6 @@ Deprecation Notices
   in "rte_sched.h". These changes are aligned to improvements suggested in the
   RFC https://mails.dpdk.org/archives/dev/2018-November/120035.html.
 
-* sched: To allow dynamic configuration of the subport bandwidth profile,
-  changes will be made to data structures ``rte_sched_subport_params``,
-  ``rte_sched_port_params`` and new data structure, API functions will be
-  defined in ``rte_sched.h``. These changes are aligned as suggested in the
-  RFC https://mails.dpdk.org/archives/dev/2020-July/175161.html
-
 * metrics: The function ``rte_metrics_init`` will have a non-void return
   in order to notify errors instead of calling ``rte_exit``.
 
diff --git a/doc/guides/rel_notes/release_20_11.rst b/doc/guides/rel_notes/release_20_11.rst
index ca5ec7391..d2cfd6d52 100644
--- a/doc/guides/rel_notes/release_20_11.rst
+++ b/doc/guides/rel_notes/release_20_11.rst
@@ -111,6 +111,7 @@ New Features
   * Extern objects and functions can be plugged into the pipeline.
   * Transaction-oriented table updates.
 
+* sched: Add support to update subport bandwidth dynamically.
 
 Removed Items
 -------------
diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index c5482d6e0..7c5688068 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -152,16 +152,11 @@ struct rte_sched_grinder {
 struct rte_sched_subport {
 	/* Token bucket (TB) */
 	uint64_t tb_time; /* time of last update */
-	uint64_t tb_period;
-	uint64_t tb_credits_per_period;
-	uint64_t tb_size;
 	uint64_t tb_credits;
 
 	/* Traffic classes (TCs) */
 	uint64_t tc_time; /* time of next update */
-	uint64_t tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
 	uint64_t tc_credits[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
-	uint64_t tc_period;
 
 	/* TC oversubscription */
 	uint64_t tc_ov_wm;
@@ -837,18 +832,6 @@ rte_sched_subport_check_params(struct rte_sched_subport_params *params,
 		return -EINVAL;
 	}
 
-	if (params->tb_rate == 0 || params->tb_rate > rate) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect value for tb rate\n", __func__);
-		return -EINVAL;
-	}
-
-	if (params->tb_size == 0) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect value for tb size\n", __func__);
-		return -EINVAL;
-	}
-
 	/* qsize: if non-zero, power of 2,
 	 * no bigger than 32K (due to 16-bit read/write pointers)
 	 */
@@ -862,29 +845,8 @@ rte_sched_subport_check_params(struct rte_sched_subport_params *params,
 		}
 	}
 
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
-		uint64_t tc_rate = params->tc_rate[i];
-		uint16_t qsize = params->qsize[i];
-
-		if ((qsize == 0 && tc_rate != 0) ||
-			(qsize != 0 && tc_rate == 0) ||
-			(tc_rate > params->tb_rate)) {
-			RTE_LOG(ERR, SCHED,
-				"%s: Incorrect value for tc rate\n", __func__);
-			return -EINVAL;
-		}
-	}
-
-	if (params->qsize[RTE_SCHED_TRAFFIC_CLASS_BE] == 0 ||
-		params->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect qsize or tc rate(best effort)\n", __func__);
-		return -EINVAL;
-	}
-
-	if (params->tc_period == 0) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Incorrect value for tc period\n", __func__);
+	if (params->qsize[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
+		RTE_LOG(ERR, SCHED, "%s: Incorrect qsize\n", __func__);
 		return -EINVAL;
 	}
 
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index fbcd9c954..778c30c29 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -149,18 +149,6 @@ struct rte_sched_pipe_params {
  * byte.
  */
 struct rte_sched_subport_params {
-	/** Token bucket rate (measured in bytes per second) */
-	uint64_t tb_rate;
-
-	/** Token bucket size (measured in credits) */
-	uint64_t tb_size;
-
-	/** Traffic class rates (measured in bytes per second) */
-	uint64_t tc_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
-
-	/** Enforcement period for rates (measured in milliseconds) */
-	uint64_t tc_period;
-
 	/** Number of subport pipes.
 	 * The subport can enable/allocate fewer pipes than the maximum
 	 * number set through struct port_params::n_max_pipes_per_subport,
-- 
2.17.1


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

* Re: [dpdk-dev] [PATCH v7 0/8] Enable dynamic config of subport bandwidth
  2020-10-06 18:02               ` [dpdk-dev] [PATCH v7 " Savinay Dharmappa
                                   ` (7 preceding siblings ...)
  2020-10-06 18:02                 ` [dpdk-dev] [PATCH v7 8/8] sched: remove redundant code Savinay Dharmappa
@ 2020-10-06 19:05                 ` Dumitrescu, Cristian
  2020-10-07 14:09                 ` [dpdk-dev] [PATCH v8 " Savinay Dharmappa
  9 siblings, 0 replies; 107+ messages in thread
From: Dumitrescu, Cristian @ 2020-10-06 19:05 UTC (permalink / raw)
  To: Dharmappa, Savinay, Singh, Jasvinder, dev



> -----Original Message-----
> From: Dharmappa, Savinay <savinay.dharmappa@intel.com>
> Sent: Tuesday, October 6, 2020 7:02 PM
> To: Dumitrescu, Cristian <cristian.dumitrescu@intel.com>; Singh, Jasvinder
> <jasvinder.singh@intel.com>; dev@dpdk.org
> Cc: Dharmappa, Savinay <savinay.dharmappa@intel.com>
> Subject: [PATCH v7 0/8] Enable dynamic config of subport bandwidth
> 
> DPDK sched library allows runtime configuration of the pipe profiles to the
> pipes of the subport once scheduler hierarchy is constructed. However, to
> change the subport level bandwidth, existing hierarchy needs to be
> dismantled and whole process of building hierarchy under subport nodes
> needs to be repeated which might result in router downtime. Furthermore,
> due to lack of dynamic configuration of the subport bandwidth profile
> configuration (shaper and Traffic class rates), the user application
> is unable to dynamically re-distribute the excess-bandwidth of one subport
> among other subports in the scheduler hierarchy. Therefore, it is also not
> possible to adjust the subport bandwidth profile in sync with dynamic
> changes in pipe profiles of subscribers who want to consume higher
> bandwidth opportunistically.
> 
> This patch series implements dynamic configuration of the subport
> bandwidth
> profile to overcome the runtime situation when group of subscribers are not
> using the allotted bandwidth and dynamic bandwidth re-distribution is
> needed the without making any structural changes in the hierarchy.
> 
> The implementation work includes refactoring the existing api and
> data structures defined for port and subport level, new APIs for
> adding subport level bandwidth profiles that can be used in runtime
> 
> Savinay Dharmappa (8):
>   sched: add support profile table
>   sched: introduce subport profile add function
>   sched: update subport rate dynamically
>   example/qos_sched: update subport rate dynamically
>   example/ip_pipeline: update subport rate dynamically
>   drivers/softnic: update subport rate dynamically
>   app/test_sched: update subport rate dynamically
>   sched: remove redundant code
> 
>  app/test/test_sched.c                         |  15 +-
>  doc/guides/rel_notes/deprecation.rst          |   6 -
>  doc/guides/rel_notes/release_20_11.rst        |   1 +
>  .../net/softnic/rte_eth_softnic_internals.h   |  11 +-
>  drivers/net/softnic/rte_eth_softnic_tm.c      | 243 +++++--
>  examples/ip_pipeline/cli.c                    |  68 +-
>  examples/ip_pipeline/tmgr.c                   | 121 +++-
>  examples/ip_pipeline/tmgr.h                   |   5 +-
>  examples/qos_sched/cfg_file.c                 | 151 ++--
>  examples/qos_sched/cfg_file.h                 |   4 +
>  examples/qos_sched/init.c                     |  21 +-
>  examples/qos_sched/main.h                     |   1 +
>  examples/qos_sched/profile.cfg                |   3 +
>  lib/librte_sched/rte_sched.c                  | 678 ++++++++++++------
>  lib/librte_sched/rte_sched.h                  |  73 +-
>  lib/librte_sched/rte_sched_version.map        |   2 +
>  16 files changed, 958 insertions(+), 445 deletions(-)
> 
> --
> 2.17.1

Series-acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>


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

* [dpdk-dev] [PATCH v8 0/8] Enable dynamic config of subport bandwidth
  2020-10-06 18:02               ` [dpdk-dev] [PATCH v7 " Savinay Dharmappa
                                   ` (8 preceding siblings ...)
  2020-10-06 19:05                 ` [dpdk-dev] [PATCH v7 0/8] Enable dynamic config of subport bandwidth Dumitrescu, Cristian
@ 2020-10-07 14:09                 ` Savinay Dharmappa
  2020-10-07 14:09                   ` [dpdk-dev] [PATCH v8 1/8] sched: add support profile table Savinay Dharmappa
                                     ` (8 more replies)
  9 siblings, 9 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-10-07 14:09 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

DPDK sched library allows runtime configuration of the pipe profiles to the
pipes of the subport once scheduler hierarchy is constructed. However, to
change the subport level bandwidth, existing hierarchy needs to be
dismantled and whole process of building hierarchy under subport nodes
needs to be repeated which might result in router downtime. Furthermore,
due to lack of dynamic configuration of the subport bandwidth profile
configuration (shaper and Traffic class rates), the user application
is unable to dynamically re-distribute the excess-bandwidth of one subport
among other subports in the scheduler hierarchy. Therefore, it is also not
possible to adjust the subport bandwidth profile in sync with dynamic
changes in pipe profiles of subscribers who want to consume higher
bandwidth opportunistically.

This patch series implements dynamic configuration of the subport bandwidth
profile to overcome the runtime situation when group of subscribers are not
using the allotted bandwidth and dynamic bandwidth re-distribution is
needed the without making any structural changes in the hierarchy.

The implementation work includes refactoring the existing api and
data structures defined for port and subport level, new APIs for
adding subport level bandwidth profiles that can be used in runtime.

---
v7 -> v8
   - Fix doxygen and clang build error.

v6 -> v7
   - Fix checkpatch warning
     and patch apply issue.

v5 -> v6
   - Fix build warning.
   - change cli of tmgr :
       * remove queue size and pipes per subport 
	 from cmdline argument to add traffic 
	 manager subport profile.
      
       * add pipes per subport as cmdline argument
	 to create traffic manger port.
   
v4 -> v5
   - Review comments from patch 3 & 6
     from v4 are addressed.

v3 -> v4
   - Fix patch apply issue.

v2 -> v3
   - Review comments from patch 3 & 5
     from v2 are addressed.

v1 -> v2
   - Fix checkpatch warnings.
---

Savinay Dharmappa (8):
  sched: add support profile table
  sched: introduce subport profile add function
  sched: update subport rate dynamically
  example/qos_sched: update subport rate dynamically
  example/ip_pipeline: update subport rate dynamically
  drivers/softnic: update subport rate dynamically
  app/test_sched: update subport rate dynamically
  sched: remove redundant code

 app/test/test_sched.c                         |  15 +-
 doc/guides/rel_notes/deprecation.rst          |   6 -
 doc/guides/rel_notes/release_20_11.rst        |   1 +
 .../net/softnic/rte_eth_softnic_internals.h   |  11 +-
 drivers/net/softnic/rte_eth_softnic_tm.c      | 243 +++++--
 examples/ip_pipeline/cli.c                    |  68 +-
 examples/ip_pipeline/tmgr.c                   | 121 +++-
 examples/ip_pipeline/tmgr.h                   |   5 +-
 examples/qos_sched/cfg_file.c                 | 151 ++--
 examples/qos_sched/cfg_file.h                 |   4 +
 examples/qos_sched/init.c                     |  21 +-
 examples/qos_sched/main.h                     |   1 +
 examples/qos_sched/profile.cfg                |   3 +
 lib/librte_sched/rte_sched.c                  | 678 ++++++++++++------
 lib/librte_sched/rte_sched.h                  |  73 +-
 lib/librte_sched/rte_sched_version.map        |   2 +
 16 files changed, 958 insertions(+), 445 deletions(-)

Series-acked-by: Cristian Dumitrescu <cristian.dumitrescu@intel.com>
-- 
2.17.1


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

* [dpdk-dev] [PATCH v8 1/8] sched: add support profile table
  2020-10-07 14:09                 ` [dpdk-dev] [PATCH v8 " Savinay Dharmappa
@ 2020-10-07 14:09                   ` Savinay Dharmappa
  2020-10-07 14:09                   ` [dpdk-dev] [PATCH v8 2/8] sched: introduce subport profile add function Savinay Dharmappa
                                     ` (7 subsequent siblings)
  8 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-10-07 14:09 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

Add subport profile table to internal port data structure
and update the port config function.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c | 197 ++++++++++++++++++++++++++++++++++-
 lib/librte_sched/rte_sched.h |  25 +++++
 2 files changed, 219 insertions(+), 3 deletions(-)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index 75be8b6bd..a44638f31 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -101,6 +101,16 @@ enum grinder_state {
 	e_GRINDER_READ_MBUF
 };
 
+struct rte_sched_subport_profile {
+	/* Token bucket (TB) */
+	uint64_t tb_period;
+	uint64_t tb_credits_per_period;
+	uint64_t tb_size;
+
+	uint64_t tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+	uint64_t tc_period;
+};
+
 struct rte_sched_grinder {
 	/* Pipe cache */
 	uint16_t pcache_qmask[RTE_SCHED_GRINDER_PCACHE_SIZE];
@@ -212,6 +222,8 @@ struct rte_sched_port {
 	uint16_t pipe_queue[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
 	uint8_t pipe_tc[RTE_SCHED_QUEUES_PER_PIPE];
 	uint8_t tc_queue[RTE_SCHED_QUEUES_PER_PIPE];
+	uint32_t n_subport_profiles;
+	uint32_t n_max_subport_profiles;
 	uint64_t rate;
 	uint32_t mtu;
 	uint32_t frame_overhead;
@@ -230,6 +242,7 @@ struct rte_sched_port {
 	uint32_t subport_id;
 
 	/* Large data structures */
+	struct rte_sched_subport_profile *subport_profiles;
 	struct rte_sched_subport *subports[0] __rte_cache_aligned;
 } __rte_cache_aligned;
 
@@ -375,9 +388,61 @@ pipe_profile_check(struct rte_sched_pipe_params *params,
 	return 0;
 }
 
+static int
+subport_profile_check(struct rte_sched_subport_profile_params *params,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	/* Check user parameters */
+	if (params == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter params\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tb_rate == 0 || params->tb_rate > rate) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for tb rate\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tb_size == 0) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for tb size\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
+		uint64_t tc_rate = params->tc_rate[i];
+
+		if (tc_rate == 0 || (tc_rate > params->tb_rate)) {
+			RTE_LOG(ERR, SCHED, "%s: "
+			"Incorrect value for tc rate\n", __func__);
+			return -EINVAL;
+		}
+	}
+
+	if (params->tc_rate[RTE_SCHED_TRAFFIC_CLASS_BE] == 0) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect tc rate(best effort)\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params->tc_period == 0) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for tc period\n", __func__);
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int
 rte_sched_port_check_params(struct rte_sched_port_params *params)
 {
+	uint32_t i;
+
 	if (params == NULL) {
 		RTE_LOG(ERR, SCHED,
 			"%s: Incorrect value for parameter params\n", __func__);
@@ -414,6 +479,29 @@ rte_sched_port_check_params(struct rte_sched_port_params *params)
 		return -EINVAL;
 	}
 
+	if (params->subport_profiles == NULL ||
+		params->n_subport_profiles == 0 ||
+		params->n_max_subport_profiles == 0 ||
+		params->n_subport_profiles > params->n_max_subport_profiles) {
+		RTE_LOG(ERR, SCHED,
+		"%s: Incorrect value for subport profiles\n", __func__);
+		return -EINVAL;
+	}
+
+	for (i = 0; i < params->n_subport_profiles; i++) {
+		struct rte_sched_subport_profile_params *p =
+						params->subport_profiles + i;
+		int status;
+
+		status = subport_profile_check(p, params->rate);
+		if (status != 0) {
+			RTE_LOG(ERR, SCHED,
+			"%s: subport profile check failed(%d)\n",
+			__func__, status);
+			return -EINVAL;
+		}
+	}
+
 	/* n_pipes_per_subport: non-zero, power of 2 */
 	if (params->n_pipes_per_subport == 0 ||
 	    !rte_is_power_of_2(params->n_pipes_per_subport)) {
@@ -555,6 +643,42 @@ rte_sched_port_log_pipe_profile(struct rte_sched_subport *subport, uint32_t i)
 		p->wrr_cost[0], p->wrr_cost[1], p->wrr_cost[2], p->wrr_cost[3]);
 }
 
+static void
+rte_sched_port_log_subport_profile(struct rte_sched_port *port, uint32_t i)
+{
+	struct rte_sched_subport_profile *p = port->subport_profiles + i;
+
+	RTE_LOG(DEBUG, SCHED, "Low level config for subport profile %u:\n"
+	"Token bucket: period = %"PRIu64", credits per period = %"PRIu64","
+	"size = %"PRIu64"\n"
+	"Traffic classes: period = %"PRIu64",\n"
+	"credits per period = [%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
+	" %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
+	" %"PRIu64", %"PRIu64", %"PRIu64"]\n",
+	i,
+
+	/* Token bucket */
+	p->tb_period,
+	p->tb_credits_per_period,
+	p->tb_size,
+
+	/* Traffic classes */
+	p->tc_period,
+	p->tc_credits_per_period[0],
+	p->tc_credits_per_period[1],
+	p->tc_credits_per_period[2],
+	p->tc_credits_per_period[3],
+	p->tc_credits_per_period[4],
+	p->tc_credits_per_period[5],
+	p->tc_credits_per_period[6],
+	p->tc_credits_per_period[7],
+	p->tc_credits_per_period[8],
+	p->tc_credits_per_period[9],
+	p->tc_credits_per_period[10],
+	p->tc_credits_per_period[11],
+	p->tc_credits_per_period[12]);
+}
+
 static inline uint64_t
 rte_sched_time_ms_to_bytes(uint64_t time_ms, uint64_t rate)
 {
@@ -623,6 +747,37 @@ rte_sched_pipe_profile_convert(struct rte_sched_subport *subport,
 	dst->wrr_cost[3] = (uint8_t) wrr_cost[3];
 }
 
+static void
+rte_sched_subport_profile_convert(struct rte_sched_subport_profile_params *src,
+	struct rte_sched_subport_profile *dst,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	/* Token Bucket */
+	if (src->tb_rate == rate) {
+		dst->tb_credits_per_period = 1;
+		dst->tb_period = 1;
+	} else {
+		double tb_rate = (double) src->tb_rate
+				/ (double) rate;
+		double d = RTE_SCHED_TB_RATE_CONFIG_ERR;
+
+		rte_approx_64(tb_rate, d, &dst->tb_credits_per_period,
+			&dst->tb_period);
+	}
+
+	dst->tb_size = src->tb_size;
+
+	/* Traffic Classes */
+	dst->tc_period = rte_sched_time_ms_to_bytes(src->tc_period, rate);
+
+	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+		dst->tc_credits_per_period[i]
+			= rte_sched_time_ms_to_bytes(src->tc_period,
+				src->tc_rate[i]);
+}
+
 static void
 rte_sched_subport_config_pipe_profile_table(struct rte_sched_subport *subport,
 	struct rte_sched_subport_params *params, uint64_t rate)
@@ -647,6 +802,24 @@ rte_sched_subport_config_pipe_profile_table(struct rte_sched_subport *subport,
 	}
 }
 
+static void
+rte_sched_port_config_subport_profile_table(struct rte_sched_port *port,
+	struct rte_sched_port_params *params,
+	uint64_t rate)
+{
+	uint32_t i;
+
+	for (i = 0; i < port->n_subport_profiles; i++) {
+		struct rte_sched_subport_profile_params *src
+				= params->subport_profiles + i;
+		struct rte_sched_subport_profile *dst
+				= port->subport_profiles + i;
+
+		rte_sched_subport_profile_convert(src, dst, rate);
+		rte_sched_port_log_subport_profile(port, i);
+	}
+}
+
 static int
 rte_sched_subport_check_params(struct rte_sched_subport_params *params,
 	uint32_t n_max_pipes_per_subport,
@@ -793,7 +966,7 @@ struct rte_sched_port *
 rte_sched_port_config(struct rte_sched_port_params *params)
 {
 	struct rte_sched_port *port = NULL;
-	uint32_t size0, size1;
+	uint32_t size0, size1, size2;
 	uint32_t cycles_per_byte;
 	uint32_t i, j;
 	int status;
@@ -808,10 +981,21 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 
 	size0 = sizeof(struct rte_sched_port);
 	size1 = params->n_subports_per_port * sizeof(struct rte_sched_subport *);
+	size2 = params->n_max_subport_profiles *
+		sizeof(struct rte_sched_subport_profile);
 
 	/* Allocate memory to store the data structures */
-	port = rte_zmalloc_socket("qos_params", size0 + size1, RTE_CACHE_LINE_SIZE,
-		params->socket);
+	port = rte_zmalloc_socket("qos_params", size0 + size1,
+				 RTE_CACHE_LINE_SIZE, params->socket);
+	if (port == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: Memory allocation fails\n", __func__);
+
+		return NULL;
+	}
+
+	/* Allocate memory to store the subport profile */
+	port->subport_profiles  = rte_zmalloc_socket("subport_profile", size2,
+					RTE_CACHE_LINE_SIZE, params->socket);
 	if (port == NULL) {
 		RTE_LOG(ERR, SCHED, "%s: Memory allocation fails\n", __func__);
 
@@ -820,6 +1004,8 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 
 	/* User parameters */
 	port->n_subports_per_port = params->n_subports_per_port;
+	port->n_subport_profiles = params->n_subport_profiles;
+	port->n_max_subport_profiles = params->n_max_subport_profiles;
 	port->n_pipes_per_subport = params->n_pipes_per_subport;
 	port->n_pipes_per_subport_log2 =
 			__builtin_ctz(params->n_pipes_per_subport);
@@ -850,6 +1036,9 @@ rte_sched_port_config(struct rte_sched_port_params *params)
 	port->time_cpu_bytes = 0;
 	port->time = 0;
 
+	/* Subport profile table */
+	rte_sched_port_config_subport_profile_table(port, params, port->rate);
+
 	cycles_per_byte = (rte_get_tsc_hz() << RTE_SCHED_TIME_SHIFT)
 		/ params->rate;
 	port->inv_cycles_per_byte = rte_reciprocal_value(cycles_per_byte);
@@ -905,6 +1094,7 @@ rte_sched_port_free(struct rte_sched_port *port)
 	for (i = 0; i < port->n_subports_per_port; i++)
 		rte_sched_subport_free(port, port->subports[i]);
 
+	rte_free(port->subport_profiles);
 	rte_free(port);
 }
 
@@ -961,6 +1151,7 @@ rte_sched_free_memory(struct rte_sched_port *port, uint32_t n_subports)
 		rte_sched_subport_free(port, subport);
 	}
 
+	rte_free(port->subport_profiles);
 	rte_free(port);
 }
 
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index 8a5a93c98..39339b7f1 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -192,6 +192,20 @@ struct rte_sched_subport_params {
 #endif
 };
 
+struct rte_sched_subport_profile_params {
+	/** Token bucket rate (measured in bytes per second) */
+	uint64_t tb_rate;
+
+	/** Token bucket size (measured in credits) */
+	uint64_t tb_size;
+
+	/** Traffic class rates (measured in bytes per second) */
+	uint64_t tc_rate[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
+
+	/** Enforcement period for rates (measured in milliseconds) */
+	uint64_t tc_period;
+};
+
 /** Subport statistics */
 struct rte_sched_subport_stats {
 	/** Number of packets successfully written */
@@ -254,6 +268,17 @@ struct rte_sched_port_params {
 	/** Number of subports */
 	uint32_t n_subports_per_port;
 
+	/** subport profile table.
+	 * Every pipe is configured using one of the profiles from this table.
+	 */
+	struct rte_sched_subport_profile_params *subport_profiles;
+
+	/** Profiles in the pipe profile table */
+	uint32_t n_subport_profiles;
+
+	/** Max allowed profiles in the pipe profile table */
+	uint32_t n_max_subport_profiles;
+
 	/** Maximum number of subport pipes.
 	 * This parameter is used to reserve a fixed number of bits
 	 * in struct rte_mbuf::sched.queue_id for the pipe_id for all
-- 
2.17.1


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

* [dpdk-dev] [PATCH v8 2/8] sched: introduce subport profile add function
  2020-10-07 14:09                 ` [dpdk-dev] [PATCH v8 " Savinay Dharmappa
  2020-10-07 14:09                   ` [dpdk-dev] [PATCH v8 1/8] sched: add support profile table Savinay Dharmappa
@ 2020-10-07 14:09                   ` Savinay Dharmappa
  2020-10-07 14:09                   ` [dpdk-dev] [PATCH v8 3/8] sched: update subport rate dynamically Savinay Dharmappa
                                     ` (6 subsequent siblings)
  8 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-10-07 14:09 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

API to add new subport bandwidth profile.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
Signed-off-by: Jasvinder Singh <jasvinder.singh@intel.com>
---
 lib/librte_sched/rte_sched.c           | 66 ++++++++++++++++++++++++++
 lib/librte_sched/rte_sched.h           | 23 +++++++++
 lib/librte_sched/rte_sched_version.map |  2 +
 3 files changed, 91 insertions(+)

diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index a44638f31..895b40d72 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -1528,6 +1528,72 @@ rte_sched_subport_pipe_profile_add(struct rte_sched_port *port,
 	return 0;
 }
 
+int
+rte_sched_port_subport_profile_add(struct rte_sched_port *port,
+	struct rte_sched_subport_profile_params *params,
+	uint32_t *subport_profile_id)
+{
+	int status;
+	uint32_t i;
+	struct rte_sched_subport_profile *dst;
+
+	/* Port */
+	if (port == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter port\n", __func__);
+		return -EINVAL;
+	}
+
+	if (params == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter profile\n", __func__);
+		return -EINVAL;
+	}
+
+	if (subport_profile_id == NULL) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Incorrect value for parameter subport_profile_id\n",
+		__func__);
+		return -EINVAL;
+	}
+
+	dst = port->subport_profiles + port->n_subport_profiles;
+
+	/* Subport profiles exceeds the max limit */
+	if (port->n_subport_profiles >= port->n_max_subport_profiles) {
+		RTE_LOG(ERR, SCHED, "%s: "
+		"Number of subport profiles exceeds the max limit\n",
+		 __func__);
+		return -EINVAL;
+	}
+
+	status = subport_profile_check(params, port->rate);
+	if (status != 0) {
+		RTE_LOG(ERR, SCHED,
+		"%s: subport profile check failed(%d)\n", __func__, status);
+		return -EINVAL;
+	}
+
+	rte_sched_subport_profile_convert(params, dst, port->rate);
+
+	/* Subport profile should not exists */
+	for (i = 0; i < port->n_subport_profiles; i++)
+		if (memcmp(port->subport_profiles + i,
+		    dst, sizeof(*dst)) == 0) {
+			RTE_LOG(ERR, SCHED,
+			"%s: subport profile exists\n", __func__);
+			return -EINVAL;
+		}
+
+	/* Subport profile commit */
+	*subport_profile_id = port->n_subport_profiles;
+	port->n_subport_profiles++;
+
+	rte_sched_port_log_subport_profile(port, *subport_profile_id);
+
+	return 0;
+}
+
 static inline uint32_t
 rte_sched_port_qindex(struct rte_sched_port *port,
 	uint32_t subport,
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index 39339b7f1..aede2e986 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -336,6 +336,29 @@ rte_sched_subport_pipe_profile_add(struct rte_sched_port *port,
 	struct rte_sched_pipe_params *params,
 	uint32_t *pipe_profile_id);
 
+/**
+ * @warning
+ * @b EXPERIMENTAL: this API may change without prior notice.
+ *
+ * Hierarchical scheduler subport bandwidth profile add
+ * Note that this function is safe to use in runtime for adding new
+ * subport bandwidth profile as it doesn't have any impact on hiearchical
+ * structure of the scheduler.
+ * @param port
+ *   Handle to port scheduler instance
+ * @param profile
+ *   Subport bandwidth profile
+ * @param subport_profile_id
+ *   Subport profile id
+ * @return
+ *   0 upon success, error code otherwise
+ */
+__rte_experimental
+int
+rte_sched_port_subport_profile_add(struct rte_sched_port *port,
+	struct rte_sched_subport_profile_params *profile,
+	uint32_t *subport_profile_id);
+
 /**
  * Hierarchical scheduler subport configuration
  *
diff --git a/lib/librte_sched/rte_sched_version.map b/lib/librte_sched/rte_sched_version.map
index 3faef6f0a..ace284b7d 100644
--- a/lib/librte_sched/rte_sched_version.map
+++ b/lib/librte_sched/rte_sched_version.map
@@ -28,4 +28,6 @@ EXPERIMENTAL {
 	global:
 
 	rte_sched_subport_pipe_profile_add;
+	# added in 20.11
+	rte_sched_port_subport_profile_add;
 };
-- 
2.17.1


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

* [dpdk-dev] [PATCH v8 3/8] sched: update subport rate dynamically
  2020-10-07 14:09                 ` [dpdk-dev] [PATCH v8 " Savinay Dharmappa
  2020-10-07 14:09                   ` [dpdk-dev] [PATCH v8 1/8] sched: add support profile table Savinay Dharmappa
  2020-10-07 14:09                   ` [dpdk-dev] [PATCH v8 2/8] sched: introduce subport profile add function Savinay Dharmappa
@ 2020-10-07 14:09                   ` Savinay Dharmappa
  2020-10-07 14:09                   ` [dpdk-dev] [PATCH v8 4/8] example/qos_sched: " Savinay Dharmappa
                                     ` (5 subsequent siblings)
  8 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-10-07 14:09 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

Add support to update subport rate dynamically.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 app/test/test_sched.c                    |   2 +-
 drivers/net/softnic/rte_eth_softnic_tm.c |   6 +-
 examples/ip_pipeline/tmgr.c              |   6 +-
 examples/qos_sched/init.c                |   3 +-
 lib/librte_sched/rte_sched.c             | 373 +++++++++++------------
 lib/librte_sched/rte_sched.h             |  13 +-
 6 files changed, 202 insertions(+), 201 deletions(-)

diff --git a/app/test/test_sched.c b/app/test/test_sched.c
index fc31080ef..5e5c2a59b 100644
--- a/app/test/test_sched.c
+++ b/app/test/test_sched.c
@@ -138,7 +138,7 @@ test_sched(void)
 	port = rte_sched_port_config(&port_param);
 	TEST_ASSERT_NOT_NULL(port, "Error config sched port\n");
 
-	err = rte_sched_subport_config(port, SUBPORT, subport_param);
+	err = rte_sched_subport_config(port, SUBPORT, subport_param, 0);
 	TEST_ASSERT_SUCCESS(err, "Error config sched, err=%d\n", err);
 
 	for (pipe = 0; pipe < subport_param[0].n_pipes_per_subport_enabled; pipe++) {
diff --git a/drivers/net/softnic/rte_eth_softnic_tm.c b/drivers/net/softnic/rte_eth_softnic_tm.c
index d30976378..5199dd2cd 100644
--- a/drivers/net/softnic/rte_eth_softnic_tm.c
+++ b/drivers/net/softnic/rte_eth_softnic_tm.c
@@ -92,7 +92,7 @@ softnic_tmgr_port_create(struct pmd_internals *p,
 
 		status = rte_sched_subport_config(sched,
 			subport_id,
-			&t->subport_params[subport_id]);
+			&t->subport_params[subport_id], 0);
 		if (status) {
 			rte_sched_port_free(sched);
 			return NULL;
@@ -1141,7 +1141,7 @@ update_subport_tc_rate(struct rte_eth_dev *dev,
 
 	/* Update the subport configuration. */
 	if (rte_sched_subport_config(SCHED(p),
-		subport_id, &subport_params))
+		subport_id, &subport_params, 0))
 		return -1;
 
 	/* Commit changes. */
@@ -2912,7 +2912,7 @@ update_subport_rate(struct rte_eth_dev *dev,
 
 	/* Update the subport configuration. */
 	if (rte_sched_subport_config(SCHED(p), subport_id,
-		&subport_params))
+		&subport_params, 0))
 		return -1;
 
 	/* Commit changes. */
diff --git a/examples/ip_pipeline/tmgr.c b/examples/ip_pipeline/tmgr.c
index 91ccbf60f..46c6a83a4 100644
--- a/examples/ip_pipeline/tmgr.c
+++ b/examples/ip_pipeline/tmgr.c
@@ -119,7 +119,8 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 		status = rte_sched_subport_config(
 			s,
 			i,
-			&subport_profile[0]);
+			&subport_profile[0],
+			0);
 
 		if (status) {
 			rte_sched_port_free(s);
@@ -180,7 +181,8 @@ tmgr_subport_config(const char *port_name,
 	status = rte_sched_subport_config(
 		port->s,
 		subport_id,
-		&subport_profile[subport_profile_id]);
+		&subport_profile[subport_profile_id],
+		0);
 
 	return status;
 }
diff --git a/examples/qos_sched/init.c b/examples/qos_sched/init.c
index 06328ddb2..b188c624b 100644
--- a/examples/qos_sched/init.c
+++ b/examples/qos_sched/init.c
@@ -314,7 +314,8 @@ app_init_sched_port(uint32_t portid, uint32_t socketid)
 	}
 
 	for (subport = 0; subport < port_params.n_subports_per_port; subport ++) {
-		err = rte_sched_subport_config(port, subport, &subport_params[subport]);
+		err = rte_sched_subport_config(port, subport,
+				&subport_params[subport], 0);
 		if (err) {
 			rte_exit(EXIT_FAILURE, "Unable to config sched subport %u, err=%d\n",
 					subport, err);
diff --git a/lib/librte_sched/rte_sched.c b/lib/librte_sched/rte_sched.c
index 895b40d72..c5482d6e0 100644
--- a/lib/librte_sched/rte_sched.c
+++ b/lib/librte_sched/rte_sched.c
@@ -123,6 +123,7 @@ struct rte_sched_grinder {
 	uint32_t productive;
 	uint32_t pindex;
 	struct rte_sched_subport *subport;
+	struct rte_sched_subport_profile *subport_params;
 	struct rte_sched_pipe *pipe;
 	struct rte_sched_pipe_profile *pipe_params;
 
@@ -174,6 +175,8 @@ struct rte_sched_subport {
 	/* Statistics */
 	struct rte_sched_subport_stats stats __rte_cache_aligned;
 
+	/* subport profile */
+	uint32_t profile;
 	/* Subport pipes */
 	uint32_t n_pipes_per_subport_enabled;
 	uint32_t n_pipe_profiles;
@@ -1098,48 +1101,6 @@ rte_sched_port_free(struct rte_sched_port *port)
 	rte_free(port);
 }
 
-static void
-rte_sched_port_log_subport_config(struct rte_sched_port *port, uint32_t i)
-{
-	struct rte_sched_subport *s = port->subports[i];
-
-	RTE_LOG(DEBUG, SCHED, "Low level config for subport %u:\n"
-		"	Token bucket: period = %"PRIu64", credits per period = %"PRIu64
-		", size = %"PRIu64"\n"
-		"	Traffic classes: period = %"PRIu64"\n"
-		"	credits per period = [%"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
-		", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64", %"PRIu64
-		", %"PRIu64", %"PRIu64", %"PRIu64"]\n"
-		"	Best effort traffic class oversubscription: wm min = %"PRIu64
-		", wm max = %"PRIu64"\n",
-		i,
-
-		/* Token bucket */
-		s->tb_period,
-		s->tb_credits_per_period,
-		s->tb_size,
-
-		/* Traffic classes */
-		s->tc_period,
-		s->tc_credits_per_period[0],
-		s->tc_credits_per_period[1],
-		s->tc_credits_per_period[2],
-		s->tc_credits_per_period[3],
-		s->tc_credits_per_period[4],
-		s->tc_credits_per_period[5],
-		s->tc_credits_per_period[6],
-		s->tc_credits_per_period[7],
-		s->tc_credits_per_period[8],
-		s->tc_credits_per_period[9],
-		s->tc_credits_per_period[10],
-		s->tc_credits_per_period[11],
-		s->tc_credits_per_period[12],
-
-		/* Best effort traffic class oversubscription */
-		s->tc_ov_wm_min,
-		s->tc_ov_wm_max);
-}
-
 static void
 rte_sched_free_memory(struct rte_sched_port *port, uint32_t n_subports)
 {
@@ -1158,10 +1119,12 @@ rte_sched_free_memory(struct rte_sched_port *port, uint32_t n_subports)
 int
 rte_sched_subport_config(struct rte_sched_port *port,
 	uint32_t subport_id,
-	struct rte_sched_subport_params *params)
+	struct rte_sched_subport_params *params,
+	uint32_t subport_profile_id)
 {
 	struct rte_sched_subport *s = NULL;
 	uint32_t n_subports = subport_id;
+	struct rte_sched_subport_profile *profile;
 	uint32_t n_subport_pipe_queues, i;
 	uint32_t size0, size1, bmp_mem_size;
 	int status;
@@ -1181,165 +1144,183 @@ rte_sched_subport_config(struct rte_sched_port *port,
 		return -EINVAL;
 	}
 
-	status = rte_sched_subport_check_params(params,
-		port->n_pipes_per_subport,
-		port->rate);
-	if (status != 0) {
-		RTE_LOG(NOTICE, SCHED,
-			"%s: Port scheduler params check failed (%d)\n",
-			__func__, status);
-
+	if (subport_profile_id >= port->n_max_subport_profiles) {
+		RTE_LOG(ERR, SCHED, "%s: "
+			"Number of subport profile exceeds the max limit\n",
+			__func__);
 		rte_sched_free_memory(port, n_subports);
 		return -EINVAL;
 	}
 
-	/* Determine the amount of memory to allocate */
-	size0 = sizeof(struct rte_sched_subport);
-	size1 = rte_sched_subport_get_array_base(params,
-				e_RTE_SCHED_SUBPORT_ARRAY_TOTAL);
+	/** Memory is allocated only on first invocation of the api for a
+	 * given subport. Subsequent invocation on same subport will just
+	 * update subport bandwidth parameter.
+	 **/
+	if (port->subports[subport_id] == NULL) {
 
-	/* Allocate memory to store the data structures */
-	s = rte_zmalloc_socket("subport_params", size0 + size1,
-		RTE_CACHE_LINE_SIZE, port->socket);
-	if (s == NULL) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Memory allocation fails\n", __func__);
+		status = rte_sched_subport_check_params(params,
+			port->n_pipes_per_subport,
+			port->rate);
+		if (status != 0) {
+			RTE_LOG(NOTICE, SCHED,
+				"%s: Port scheduler params check failed (%d)\n",
+				__func__, status);
 
-		rte_sched_free_memory(port, n_subports);
-		return -ENOMEM;
-	}
+			rte_sched_free_memory(port, n_subports);
+			return -EINVAL;
+		}
 
-	n_subports++;
+		/* Determine the amount of memory to allocate */
+		size0 = sizeof(struct rte_sched_subport);
+		size1 = rte_sched_subport_get_array_base(params,
+					e_RTE_SCHED_SUBPORT_ARRAY_TOTAL);
 
-	/* Port */
-	port->subports[subport_id] = s;
+		/* Allocate memory to store the data structures */
+		s = rte_zmalloc_socket("subport_params", size0 + size1,
+			RTE_CACHE_LINE_SIZE, port->socket);
+		if (s == NULL) {
+			RTE_LOG(ERR, SCHED,
+				"%s: Memory allocation fails\n", __func__);
 
-	/* Token Bucket (TB) */
-	if (params->tb_rate == port->rate) {
-		s->tb_credits_per_period = 1;
-		s->tb_period = 1;
-	} else {
-		double tb_rate = ((double) params->tb_rate) / ((double) port->rate);
-		double d = RTE_SCHED_TB_RATE_CONFIG_ERR;
+			rte_sched_free_memory(port, n_subports);
+			return -ENOMEM;
+		}
 
-		rte_approx_64(tb_rate, d, &s->tb_credits_per_period, &s->tb_period);
-	}
+		n_subports++;
 
-	s->tb_size = params->tb_size;
-	s->tb_time = port->time;
-	s->tb_credits = s->tb_size / 2;
+		subport_profile_id = 0;
 
-	/* Traffic Classes (TCs) */
-	s->tc_period = rte_sched_time_ms_to_bytes(params->tc_period, port->rate);
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
-		if (params->qsize[i])
-			s->tc_credits_per_period[i]
-				= rte_sched_time_ms_to_bytes(params->tc_period,
-					params->tc_rate[i]);
-	}
-	s->tc_time = port->time + s->tc_period;
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-		if (params->qsize[i])
-			s->tc_credits[i] = s->tc_credits_per_period[i];
+		/* Port */
+		port->subports[subport_id] = s;
 
-	/* compile time checks */
-	RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS == 0);
-	RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS &
-		(RTE_SCHED_PORT_N_GRINDERS - 1));
+		s->tb_time = port->time;
 
-	/* User parameters */
-	s->n_pipes_per_subport_enabled = params->n_pipes_per_subport_enabled;
-	memcpy(s->qsize, params->qsize, sizeof(params->qsize));
-	s->n_pipe_profiles = params->n_pipe_profiles;
-	s->n_max_pipe_profiles = params->n_max_pipe_profiles;
+		/* compile time checks */
+		RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS == 0);
+		RTE_BUILD_BUG_ON(RTE_SCHED_PORT_N_GRINDERS &
+			(RTE_SCHED_PORT_N_GRINDERS - 1));
+
+		/* User parameters */
+		s->n_pipes_per_subport_enabled =
+				params->n_pipes_per_subport_enabled;
+		memcpy(s->qsize, params->qsize, sizeof(params->qsize));
+		s->n_pipe_profiles = params->n_pipe_profiles;
+		s->n_max_pipe_profiles = params->n_max_pipe_profiles;
 
 #ifdef RTE_SCHED_RED
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
-		uint32_t j;
+		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++) {
+			uint32_t j;
 
-		for (j = 0; j < RTE_COLORS; j++) {
+			for (j = 0; j < RTE_COLORS; j++) {
 			/* if min/max are both zero, then RED is disabled */
-			if ((params->red_params[i][j].min_th |
-			     params->red_params[i][j].max_th) == 0) {
-				continue;
+				if ((params->red_params[i][j].min_th |
+				     params->red_params[i][j].max_th) == 0) {
+					continue;
+				}
+
+				if (rte_red_config_init(&s->red_config[i][j],
+				    params->red_params[i][j].wq_log2,
+				    params->red_params[i][j].min_th,
+				    params->red_params[i][j].max_th,
+				    params->red_params[i][j].maxp_inv) != 0) {
+					rte_sched_free_memory(port, n_subports);
+
+					RTE_LOG(NOTICE, SCHED,
+					"%s: RED configuration init fails\n",
+					__func__);
+					return -EINVAL;
+				}
 			}
+		}
+#endif
 
-			if (rte_red_config_init(&s->red_config[i][j],
-				params->red_params[i][j].wq_log2,
-				params->red_params[i][j].min_th,
-				params->red_params[i][j].max_th,
-				params->red_params[i][j].maxp_inv) != 0) {
-				rte_sched_free_memory(port, n_subports);
+		/* Scheduling loop detection */
+		s->pipe_loop = RTE_SCHED_PIPE_INVALID;
+		s->pipe_exhaustion = 0;
+
+		/* Grinders */
+		s->busy_grinders = 0;
+
+		/* Queue base calculation */
+		rte_sched_subport_config_qsize(s);
+
+		/* Large data structures */
+		s->pipe = (struct rte_sched_pipe *)
+			(s->memory + rte_sched_subport_get_array_base(params,
+			e_RTE_SCHED_SUBPORT_ARRAY_PIPE));
+		s->queue = (struct rte_sched_queue *)
+			(s->memory + rte_sched_subport_get_array_base(params,
+			e_RTE_SCHED_SUBPORT_ARRAY_QUEUE));
+		s->queue_extra = (struct rte_sched_queue_extra *)
+			(s->memory + rte_sched_subport_get_array_base(params,
+			e_RTE_SCHED_SUBPORT_ARRAY_QUEUE_EXTRA));
+		s->pipe_profiles = (struct rte_sched_pipe_profile *)
+			(s->memory + rte_sched_subport_get_array_base(params,
+			e_RTE_SCHED_SUBPORT_ARRAY_PIPE_PROFILES));
+		s->bmp_array =  s->memory + rte_sched_subport_get_array_base(
+				params, e_RTE_SCHED_SUBPORT_ARRAY_BMP_ARRAY);
+		s->queue_array = (struct rte_mbuf **)
+			(s->memory + rte_sched_subport_get_array_base(params,
+			e_RTE_SCHED_SUBPORT_ARRAY_QUEUE_ARRAY));
+
+		/* Pipe profile table */
+		rte_sched_subport_config_pipe_profile_table(s, params,
+							    port->rate);
+
+		/* Bitmap */
+		n_subport_pipe_queues = rte_sched_subport_pipe_queues(s);
+		bmp_mem_size = rte_bitmap_get_memory_footprint(
+						n_subport_pipe_queues);
+		s->bmp = rte_bitmap_init(n_subport_pipe_queues, s->bmp_array,
+					bmp_mem_size);
+		if (s->bmp == NULL) {
+			RTE_LOG(ERR, SCHED,
+				"%s: Subport bitmap init error\n", __func__);
 
-				RTE_LOG(NOTICE, SCHED,
-				"%s: RED configuration init fails\n", __func__);
-				return -EINVAL;
-			}
+			rte_sched_free_memory(port, n_subports);
+			return -EINVAL;
 		}
-	}
-#endif
 
-	/* Scheduling loop detection */
-	s->pipe_loop = RTE_SCHED_PIPE_INVALID;
-	s->pipe_exhaustion = 0;
+		for (i = 0; i < RTE_SCHED_PORT_N_GRINDERS; i++)
+			s->grinder_base_bmp_pos[i] = RTE_SCHED_PIPE_INVALID;
 
-	/* Grinders */
-	s->busy_grinders = 0;
+#ifdef RTE_SCHED_SUBPORT_TC_OV
+		/* TC oversubscription */
+		s->tc_ov_wm_min = port->mtu;
+		s->tc_ov_wm = s->tc_ov_wm_max;
+		s->tc_ov_period_id = 0;
+		s->tc_ov = 0;
+		s->tc_ov_n = 0;
+		s->tc_ov_rate = 0;
+#endif
+	}
 
-	/* Queue base calculation */
-	rte_sched_subport_config_qsize(s);
+	{
+	/* update subport parameters from subport profile table*/
+		profile = port->subport_profiles + subport_profile_id;
 
-	/* Large data structures */
-	s->pipe = (struct rte_sched_pipe *)
-		(s->memory + rte_sched_subport_get_array_base(params,
-		e_RTE_SCHED_SUBPORT_ARRAY_PIPE));
-	s->queue = (struct rte_sched_queue *)
-		(s->memory + rte_sched_subport_get_array_base(params,
-		e_RTE_SCHED_SUBPORT_ARRAY_QUEUE));
-	s->queue_extra = (struct rte_sched_queue_extra *)
-		(s->memory + rte_sched_subport_get_array_base(params,
-		e_RTE_SCHED_SUBPORT_ARRAY_QUEUE_EXTRA));
-	s->pipe_profiles = (struct rte_sched_pipe_profile *)
-		(s->memory + rte_sched_subport_get_array_base(params,
-		e_RTE_SCHED_SUBPORT_ARRAY_PIPE_PROFILES));
-	s->bmp_array =  s->memory + rte_sched_subport_get_array_base(params,
-		e_RTE_SCHED_SUBPORT_ARRAY_BMP_ARRAY);
-	s->queue_array = (struct rte_mbuf **)
-		(s->memory + rte_sched_subport_get_array_base(params,
-		e_RTE_SCHED_SUBPORT_ARRAY_QUEUE_ARRAY));
-
-	/* Pipe profile table */
-	rte_sched_subport_config_pipe_profile_table(s, params, port->rate);
+		s = port->subports[subport_id];
 
-	/* Bitmap */
-	n_subport_pipe_queues = rte_sched_subport_pipe_queues(s);
-	bmp_mem_size = rte_bitmap_get_memory_footprint(n_subport_pipe_queues);
-	s->bmp = rte_bitmap_init(n_subport_pipe_queues, s->bmp_array,
-				bmp_mem_size);
-	if (s->bmp == NULL) {
-		RTE_LOG(ERR, SCHED,
-			"%s: Subport bitmap init error\n", __func__);
+		s->tb_credits = profile->tb_size / 2;
 
-		rte_sched_free_memory(port, n_subports);
-		return -EINVAL;
-	}
+		s->tc_time = port->time + profile->tc_period;
 
-	for (i = 0; i < RTE_SCHED_PORT_N_GRINDERS; i++)
-		s->grinder_base_bmp_pos[i] = RTE_SCHED_PIPE_INVALID;
+		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
+			if (s->qsize[i])
+				s->tc_credits[i] =
+					profile->tc_credits_per_period[i];
+			else
+				profile->tc_credits_per_period[i] = 0;
 
 #ifdef RTE_SCHED_SUBPORT_TC_OV
-	/* TC oversubscription */
-	s->tc_ov_wm_min = port->mtu;
-	s->tc_ov_wm_max = rte_sched_time_ms_to_bytes(params->tc_period,
-						     s->pipe_tc_be_rate_max);
-	s->tc_ov_wm = s->tc_ov_wm_max;
-	s->tc_ov_period_id = 0;
-	s->tc_ov = 0;
-	s->tc_ov_n = 0;
-	s->tc_ov_rate = 0;
+		s->tc_ov_wm_max = rte_sched_time_ms_to_bytes(profile->tc_period,
+							s->pipe_tc_be_rate_max);
 #endif
+		s->profile = subport_profile_id;
+
+	}
 
-	rte_sched_port_log_subport_config(port, subport_id);
+	rte_sched_port_log_subport_profile(port, subport_profile_id);
 
 	return 0;
 }
@@ -1351,6 +1332,7 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 	int32_t pipe_profile)
 {
 	struct rte_sched_subport *s;
+	struct rte_sched_subport_profile *sp;
 	struct rte_sched_pipe *p;
 	struct rte_sched_pipe_profile *params;
 	uint32_t n_subports = subport_id + 1;
@@ -1391,14 +1373,15 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 		return -EINVAL;
 	}
 
+	sp = port->subport_profiles + s->profile;
 	/* Handle the case when pipe already has a valid configuration */
 	p = s->pipe + pipe_id;
 	if (p->tb_time) {
 		params = s->pipe_profiles + p->profile;
 
 		double subport_tc_be_rate =
-			(double) s->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
-			/ (double) s->tc_period;
+		(double)sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
+			/ (double) sp->tc_period;
 		double pipe_tc_be_rate =
 			(double) params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
 			/ (double) params->tc_period;
@@ -1440,8 +1423,8 @@ rte_sched_pipe_config(struct rte_sched_port *port,
 	{
 		/* Subport best effort tc oversubscription */
 		double subport_tc_be_rate =
-			(double) s->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
-			/ (double) s->tc_period;
+		(double)sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
+			/ (double) sp->tc_period;
 		double pipe_tc_be_rate =
 			(double) params->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE]
 			/ (double) params->tc_period;
@@ -2229,14 +2212,15 @@ grinder_credits_update(struct rte_sched_port *port,
 	struct rte_sched_grinder *grinder = subport->grinder + pos;
 	struct rte_sched_pipe *pipe = grinder->pipe;
 	struct rte_sched_pipe_profile *params = grinder->pipe_params;
+	struct rte_sched_subport_profile *sp = grinder->subport_params;
 	uint64_t n_periods;
 	uint32_t i;
 
 	/* Subport TB */
-	n_periods = (port->time - subport->tb_time) / subport->tb_period;
-	subport->tb_credits += n_periods * subport->tb_credits_per_period;
-	subport->tb_credits = RTE_MIN(subport->tb_credits, subport->tb_size);
-	subport->tb_time += n_periods * subport->tb_period;
+	n_periods = (port->time - subport->tb_time) / sp->tb_period;
+	subport->tb_credits += n_periods * sp->tb_credits_per_period;
+	subport->tb_credits = RTE_MIN(subport->tb_credits, sp->tb_size);
+	subport->tb_time += n_periods * sp->tb_period;
 
 	/* Pipe TB */
 	n_periods = (port->time - pipe->tb_time) / params->tb_period;
@@ -2247,9 +2231,9 @@ grinder_credits_update(struct rte_sched_port *port,
 	/* Subport TCs */
 	if (unlikely(port->time >= subport->tc_time)) {
 		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-			subport->tc_credits[i] = subport->tc_credits_per_period[i];
+			subport->tc_credits[i] = sp->tc_credits_per_period[i];
 
-		subport->tc_time = port->time + subport->tc_period;
+		subport->tc_time = port->time + sp->tc_period;
 	}
 
 	/* Pipe TCs */
@@ -2265,8 +2249,10 @@ grinder_credits_update(struct rte_sched_port *port,
 
 static inline uint64_t
 grinder_tc_ov_credits_update(struct rte_sched_port *port,
-	struct rte_sched_subport *subport)
+	struct rte_sched_subport *subport, uint32_t pos)
 {
+	struct rte_sched_grinder *grinder = subport->grinder + pos;
+	struct rte_sched_subport_profile *sp = grinder->subport_params;
 	uint64_t tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE];
 	uint64_t tc_consumption = 0, tc_ov_consumption_max;
 	uint64_t tc_ov_wm = subport->tc_ov_wm;
@@ -2276,17 +2262,17 @@ grinder_tc_ov_credits_update(struct rte_sched_port *port,
 		return subport->tc_ov_wm_max;
 
 	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASS_BE; i++) {
-		tc_ov_consumption[i] =
-			subport->tc_credits_per_period[i] - subport->tc_credits[i];
+		tc_ov_consumption[i] = sp->tc_credits_per_period[i]
+					-  subport->tc_credits[i];
 		tc_consumption += tc_ov_consumption[i];
 	}
 
 	tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] =
-		subport->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
+	sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
 		subport->tc_credits[RTE_SCHED_TRAFFIC_CLASS_BE];
 
 	tc_ov_consumption_max =
-		subport->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
+	sp->tc_credits_per_period[RTE_SCHED_TRAFFIC_CLASS_BE] -
 			tc_consumption;
 
 	if (tc_ov_consumption[RTE_SCHED_TRAFFIC_CLASS_BE] >
@@ -2312,14 +2298,15 @@ grinder_credits_update(struct rte_sched_port *port,
 	struct rte_sched_grinder *grinder = subport->grinder + pos;
 	struct rte_sched_pipe *pipe = grinder->pipe;
 	struct rte_sched_pipe_profile *params = grinder->pipe_params;
+	struct rte_sched_subport_profile *sp = grinder->subport_params;
 	uint64_t n_periods;
 	uint32_t i;
 
 	/* Subport TB */
-	n_periods = (port->time - subport->tb_time) / subport->tb_period;
-	subport->tb_credits += n_periods * subport->tb_credits_per_period;
-	subport->tb_credits = RTE_MIN(subport->tb_credits, subport->tb_size);
-	subport->tb_time += n_periods * subport->tb_period;
+	n_periods = (port->time - subport->tb_time) / sp->tb_period;
+	subport->tb_credits += n_periods * sp->tb_credits_per_period;
+	subport->tb_credits = RTE_MIN(subport->tb_credits, sp->tb_size);
+	subport->tb_time += n_periods * sp->tb_period;
 
 	/* Pipe TB */
 	n_periods = (port->time - pipe->tb_time) / params->tb_period;
@@ -2329,12 +2316,13 @@ grinder_credits_update(struct rte_sched_port *port,
 
 	/* Subport TCs */
 	if (unlikely(port->time >= subport->tc_time)) {
-		subport->tc_ov_wm = grinder_tc_ov_credits_update(port, subport);
+		subport->tc_ov_wm =
+			grinder_tc_ov_credits_update(port, subport, pos);
 
 		for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-			subport->tc_credits[i] = subport->tc_credits_per_period[i];
+			subport->tc_credits[i] = sp->tc_credits_per_period[i];
 
-		subport->tc_time = port->time + subport->tc_period;
+		subport->tc_time = port->time + sp->tc_period;
 		subport->tc_ov_period_id++;
 	}
 
@@ -2857,6 +2845,9 @@ grinder_handle(struct rte_sched_port *port,
 		struct rte_sched_pipe *pipe = grinder->pipe;
 
 		grinder->pipe_params = subport->pipe_profiles + pipe->profile;
+		grinder->subport_params = port->subport_profiles +
+						subport->profile;
+
 		grinder_prefetch_tc_queue_arrays(subport, pos);
 		grinder_credits_update(port, subport, pos);
 
diff --git a/lib/librte_sched/rte_sched.h b/lib/librte_sched/rte_sched.h
index aede2e986..1506c6487 100644
--- a/lib/librte_sched/rte_sched.h
+++ b/lib/librte_sched/rte_sched.h
@@ -361,20 +361,27 @@ rte_sched_port_subport_profile_add(struct rte_sched_port *port,
 
 /**
  * Hierarchical scheduler subport configuration
- *
+ * Note that this function is safe to use at runtime
+ * to configure subport bandwidth profile.
  * @param port
  *   Handle to port scheduler instance
  * @param subport_id
  *   Subport ID
  * @param params
- *   Subport configuration parameters
+ *   Subport configuration parameters. Must be non-NULL
+ *   for first invocation (i.e initialization) for a given
+ *   subport. Ignored (recommended value is NULL) for all
+ *   subsequent invocation on the same subport.
+ * @param subport_profile_id
+ *   ID of subport bandwidth profile
  * @return
  *   0 upon success, error code otherwise
  */
 int
 rte_sched_subport_config(struct rte_sched_port *port,
 	uint32_t subport_id,
-	struct rte_sched_subport_params *params);
+	struct rte_sched_subport_params *params,
+	uint32_t subport_profile_id);
 
 /**
  * Hierarchical scheduler pipe configuration
-- 
2.17.1


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

* [dpdk-dev] [PATCH v8 4/8] example/qos_sched: update subport rate dynamically
  2020-10-07 14:09                 ` [dpdk-dev] [PATCH v8 " Savinay Dharmappa
                                     ` (2 preceding siblings ...)
  2020-10-07 14:09                   ` [dpdk-dev] [PATCH v8 3/8] sched: update subport rate dynamically Savinay Dharmappa
@ 2020-10-07 14:09                   ` Savinay Dharmappa
  2020-10-07 14:09                   ` [dpdk-dev] [PATCH v8 5/8] example/ip_pipeline: " Savinay Dharmappa
                                     ` (4 subsequent siblings)
  8 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-10-07 14:09 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

Modify the qos_sched application to build the hierarchical scheduler
with default subport bandwidth profile. It also allows to update
a subport with different subport rates dynamically.

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 examples/qos_sched/cfg_file.c  | 151 +++++++++++++++++++--------------
 examples/qos_sched/cfg_file.h  |   4 +
 examples/qos_sched/init.c      |  20 +++--
 examples/qos_sched/main.h      |   1 +
 examples/qos_sched/profile.cfg |   3 +
 5 files changed, 110 insertions(+), 69 deletions(-)

diff --git a/examples/qos_sched/cfg_file.c b/examples/qos_sched/cfg_file.c
index f078e4f7d..cd167bd8e 100644
--- a/examples/qos_sched/cfg_file.c
+++ b/examples/qos_sched/cfg_file.c
@@ -142,6 +142,93 @@ cfg_load_pipe(struct rte_cfgfile *cfg, struct rte_sched_pipe_params *pipe_params
 	return 0;
 }
 
+int
+cfg_load_subport_profile(struct rte_cfgfile *cfg,
+	struct rte_sched_subport_profile_params *subport_profile)
+{
+	int i;
+	const char *entry;
+	int profiles;
+
+	if (!cfg || !subport_profile)
+		return -1;
+
+	profiles = rte_cfgfile_num_sections(cfg, "subport profile",
+					   sizeof("subport profile") - 1);
+	subport_params[0].n_pipe_profiles = profiles;
+
+	for (i = 0; i < profiles; i++) {
+		char sec_name[32];
+		snprintf(sec_name, sizeof(sec_name), "subport profile %d", i);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tb rate");
+		if (entry)
+			subport_profile[i].tb_rate = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tb size");
+		if (entry)
+			subport_profile[i].tb_size = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc period");
+		if (entry)
+			subport_profile[i].tc_period = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 0 rate");
+		if (entry)
+			subport_profile[i].tc_rate[0] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 1 rate");
+		if (entry)
+			subport_profile[i].tc_rate[1] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 2 rate");
+		if (entry)
+			subport_profile[i].tc_rate[2] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 3 rate");
+		if (entry)
+			subport_profile[i].tc_rate[3] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 4 rate");
+		if (entry)
+			subport_profile[i].tc_rate[4] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 5 rate");
+		if (entry)
+			subport_profile[i].tc_rate[5] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 6 rate");
+		if (entry)
+			subport_profile[i].tc_rate[6] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 7 rate");
+		if (entry)
+			subport_profile[i].tc_rate[7] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 8 rate");
+		if (entry)
+			subport_profile[i].tc_rate[8] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 9 rate");
+		if (entry)
+			subport_profile[i].tc_rate[9] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 10 rate");
+		if (entry)
+			subport_profile[i].tc_rate[10] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 11 rate");
+		if (entry)
+			subport_profile[i].tc_rate[11] = (uint64_t)atoi(entry);
+
+		entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 12 rate");
+		if (entry)
+			subport_profile[i].tc_rate[12] = (uint64_t)atoi(entry);
+	}
+
+	return 0;
+}
+
 int
 cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subport_params)
 {
@@ -267,70 +354,6 @@ cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subpo
 				}
 			}
 
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tb rate");
-			if (entry)
-				subport_params[i].tb_rate = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tb size");
-			if (entry)
-				subport_params[i].tb_size = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc period");
-			if (entry)
-				subport_params[i].tc_period = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 0 rate");
-			if (entry)
-				subport_params[i].tc_rate[0] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 1 rate");
-			if (entry)
-				subport_params[i].tc_rate[1] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 2 rate");
-			if (entry)
-				subport_params[i].tc_rate[2] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 3 rate");
-			if (entry)
-				subport_params[i].tc_rate[3] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 4 rate");
-			if (entry)
-				subport_params[i].tc_rate[4] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 5 rate");
-			if (entry)
-				subport_params[i].tc_rate[5] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 6 rate");
-			if (entry)
-				subport_params[i].tc_rate[6] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 7 rate");
-			if (entry)
-				subport_params[i].tc_rate[7] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 8 rate");
-			if (entry)
-				subport_params[i].tc_rate[8] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 9 rate");
-			if (entry)
-				subport_params[i].tc_rate[9] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 10 rate");
-			if (entry)
-				subport_params[i].tc_rate[10] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 11 rate");
-			if (entry)
-				subport_params[i].tc_rate[11] = (uint64_t)atoi(entry);
-
-			entry = rte_cfgfile_get_entry(cfg, sec_name, "tc 12 rate");
-			if (entry)
-				subport_params[i].tc_rate[12] = (uint64_t)atoi(entry);
-
 			int n_entries = rte_cfgfile_section_num_entries(cfg, sec_name);
 			struct rte_cfgfile_entry entries[n_entries];
 
diff --git a/examples/qos_sched/cfg_file.h b/examples/qos_sched/cfg_file.h
index 2eccf1ca0..0dc458aa7 100644
--- a/examples/qos_sched/cfg_file.h
+++ b/examples/qos_sched/cfg_file.h
@@ -14,4 +14,8 @@ int cfg_load_pipe(struct rte_cfgfile *cfg, struct rte_sched_pipe_params *pipe);
 
 int cfg_load_subport(struct rte_cfgfile *cfg, struct rte_sched_subport_params *subport);
 
+int cfg_load_subport_profile(struct rte_cfgfile *cfg,
+			     struct rte_sched_subport_profile_params
+			     *subport_profile);
+
 #endif
diff --git a/examples/qos_sched/init.c b/examples/qos_sched/init.c
index b188c624b..1abe003fc 100644
--- a/examples/qos_sched/init.c
+++ b/examples/qos_sched/init.c
@@ -192,15 +192,20 @@ static struct rte_sched_pipe_params pipe_profiles[MAX_SCHED_PIPE_PROFILES] = {
 	},
 };
 
-struct rte_sched_subport_params subport_params[MAX_SCHED_SUBPORTS] = {
+static struct rte_sched_subport_profile_params
+		subport_profile[MAX_SCHED_SUBPORT_PROFILES] = {
 	{
 		.tb_rate = 1250000000,
 		.tb_size = 1000000,
-
 		.tc_rate = {1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000, 1250000000,
 			1250000000, 1250000000, 1250000000, 1250000000},
 		.tc_period = 10,
+	},
+};
+
+struct rte_sched_subport_params subport_params[MAX_SCHED_SUBPORTS] = {
+	{
 		.n_pipes_per_subport_enabled = 4096,
 		.qsize = {64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64},
 		.pipe_profiles = pipe_profiles,
@@ -285,6 +290,9 @@ struct rte_sched_port_params port_params = {
 	.mtu = 6 + 6 + 4 + 4 + 2 + 1500,
 	.frame_overhead = RTE_SCHED_FRAME_OVERHEAD_DEFAULT,
 	.n_subports_per_port = 1,
+	.n_subport_profiles = 1,
+	.subport_profiles = subport_profile,
+	.n_max_subport_profiles = MAX_SCHED_SUBPORT_PROFILES,
 	.n_pipes_per_subport = MAX_SCHED_PIPES,
 };
 
@@ -315,10 +323,11 @@ app_init_sched_port(uint32_t portid, uint32_t socketid)
 
 	for (subport = 0; subport < port_params.n_subports_per_port; subport ++) {
 		err = rte_sched_subport_config(port, subport,
-				&subport_params[subport], 0);
+				&subport_params[subport],
+				0);
 		if (err) {
-			rte_exit(EXIT_FAILURE, "Unable to config sched subport %u, err=%d\n",
-					subport, err);
+			rte_exit(EXIT_FAILURE, "Unable to config sched "
+				 "subport %u, err=%d\n", subport, err);
 		}
 
 		uint32_t n_pipes_per_subport =
@@ -351,6 +360,7 @@ app_load_cfg_profile(const char *profile)
 
 	cfg_load_port(file, &port_params);
 	cfg_load_subport(file, subport_params);
+	cfg_load_subport_profile(file, subport_profile);
 	cfg_load_pipe(file, pipe_profiles);
 
 	rte_cfgfile_close(file);
diff --git a/examples/qos_sched/main.h b/examples/qos_sched/main.h
index 23bc418d9..0d6815ae6 100644
--- a/examples/qos_sched/main.h
+++ b/examples/qos_sched/main.h
@@ -51,6 +51,7 @@ extern "C" {
 #define MAX_SCHED_SUBPORTS		8
 #define MAX_SCHED_PIPES		4096
 #define MAX_SCHED_PIPE_PROFILES		256
+#define MAX_SCHED_SUBPORT_PROFILES	8
 
 #ifndef APP_COLLECT_STAT
 #define APP_COLLECT_STAT		1
diff --git a/examples/qos_sched/profile.cfg b/examples/qos_sched/profile.cfg
index 61b8b7071..4486d2799 100644
--- a/examples/qos_sched/profile.cfg
+++ b/examples/qos_sched/profile.cfg
@@ -26,6 +26,9 @@ number of subports per port = 1
 number of pipes per subport = 4096
 queue sizes = 64 64 64 64 64 64 64 64 64 64 64 64 64
 
+subport 0-8 = 0                ; These subports are configured with subport profile 0
+
+[subport profile 0]
 tb rate = 1250000000           ; Bytes per second
 tb size = 1000000              ; Bytes
 
-- 
2.17.1


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

* [dpdk-dev] [PATCH v8 5/8] example/ip_pipeline: update subport rate dynamically
  2020-10-07 14:09                 ` [dpdk-dev] [PATCH v8 " Savinay Dharmappa
                                     ` (3 preceding siblings ...)
  2020-10-07 14:09                   ` [dpdk-dev] [PATCH v8 4/8] example/qos_sched: " Savinay Dharmappa
@ 2020-10-07 14:09                   ` Savinay Dharmappa
  2020-10-07 14:09                   ` [dpdk-dev] [PATCH v8 6/8] drivers/softnic: " Savinay Dharmappa
                                     ` (3 subsequent siblings)
  8 siblings, 0 replies; 107+ messages in thread
From: Savinay Dharmappa @ 2020-10-07 14:09 UTC (permalink / raw)
  To: cristian.dumitrescu, jasvinder.singh, dev; +Cc: savinay.dharmappa

Modify the ip_pipeline application to build the hierarchical scheduler
with default subport bandwidth profile. It also allows to update
a subport with different subport rates dynamically

Signed-off-by: Savinay Dharmappa <savinay.dharmappa@intel.com>
---
 examples/ip_pipeline/cli.c  |  68 ++++++++------------
 examples/ip_pipeline/tmgr.c | 121 ++++++++++++++++++++++++++++++------
 examples/ip_pipeline/tmgr.h |   5 +-
 3 files changed, 134 insertions(+), 60 deletions(-)

diff --git a/examples/ip_pipeline/cli.c b/examples/ip_pipeline/cli.c
index dafc95ae9..ec4acf0ac 100644
--- a/examples/ip_pipeline/cli.c
+++ b/examples/ip_pipeline/cli.c
@@ -393,12 +393,7 @@ static const char cmd_tmgr_subport_profile_help[] =
 "   <tc0_rate> <tc1_rate> <tc2_rate> <tc3_rate> <tc4_rate>"
 "        <tc5_rate> <tc6_rate> <tc7_rate> <tc8_rate>"
 "        <tc9_rate> <tc10_rate> <tc11_rate> <tc12_rate>\n"
-"   <tc_period>\n"
-"   pps <n_pipes_per_subport>\n"
-"   qsize <qsize_tc0> <qsize_tc1> <qsize_tc2>"
-"       <qsize_tc3> <qsize_tc4> <qsize_tc5> <qsize_tc6>"
-"       <qsize_tc7> <qsize_tc8> <qsize_tc9> <qsize_tc10>"
-"       <qsize_tc11> <qsize_tc12>";
+"   <tc_period>\n";
 
 static void
 cmd_tmgr_subport_profile(char **tokens,
@@ -406,57 +401,37 @@ cmd_tmgr_subport_profile(char **tokens,
 	char *out,
 	size_t out_size)
 {
-	struct rte_sched_subport_params p;
+	struct rte_sched_subport_profile_params subport_profile;
 	int status, i;
 
-	if (n_tokens != 35) {
+	if (n_tokens != 19) {
 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
 		return;
 	}
 
-	if (parser_read_uint64(&p.tb_rate, tokens[3]) != 0) {
+	if (parser_read_uint64(&subport_profile.tb_rate, tokens[3]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "tb_rate");
 		return;
 	}
 
-	if (parser_read_uint64(&p.tb_size, tokens[4]) != 0) {
+	if (parser_read_uint64(&subport_profile.tb_size, tokens[4]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "tb_size");
 		return;
 	}
 
 	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-		if (parser_read_uint64(&p.tc_rate[i], tokens[5 + i]) != 0) {
+		if (parser_read_uint64(&subport_profile.tc_rate[i],
+				tokens[5 + i]) != 0) {
 			snprintf(out, out_size, MSG_ARG_INVALID, "tc_rate");
 			return;
 		}
 
-	if (parser_read_uint64(&p.tc_period, tokens[18]) != 0) {
+	if (parser_read_uint64(&subport_profile.tc_period, tokens[18]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "tc_period");
 		return;
 	}
 
-	if (strcmp(tokens[19], "pps") != 0) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "pps");
-		return;
-	}
-
-	if (parser_read_uint32(&p.n_pipes_per_subport_enabled, tokens[20]) != 0) {
-		snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport");
-		return;
-	}
-
-	if (strcmp(tokens[21], "qsize") != 0) {
-		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "qsize");
-		return;
-	}
-
-	for (i = 0; i < RTE_SCHED_TRAFFIC_CLASSES_PER_PIPE; i++)
-		if (parser_read_uint16(&p.qsize[i], tokens[22 + i]) != 0) {
-			snprintf(out, out_size, MSG_ARG_INVALID, "qsize");
-			return;
-		}
-
-	status = tmgr_subport_profile_add(&p);
+	status = tmgr_subport_profile_add(&subport_profile);
 	if (status != 0) {
 		snprintf(out, out_size, MSG_CMD_FAIL, tokens[0]);
 		return;
@@ -530,6 +505,7 @@ static const char cmd_tmgr_help[] =
 "tmgr <tmgr_name>\n"
 "   rate <rate>\n"
 "   spp <n_subports_per_port>\n"
+"   pps <n_pipes_per_subport>\n"
 "   fo <frame_overhead>\n"
 "   mtu <mtu>\n"
 "   cpu <cpu_id>\n";
@@ -544,7 +520,7 @@ cmd_tmgr(char **tokens,
 	char *name;
 	struct tmgr_port *tmgr_port;
 
-	if (n_tokens != 12) {
+	if (n_tokens != 14) {
 		snprintf(out, out_size, MSG_ARG_MISMATCH, tokens[0]);
 		return;
 	}
@@ -571,32 +547,42 @@ cmd_tmgr(char **tokens,
 		return;
 	}
 
-	if (strcmp(tokens[6], "fo") != 0) {
+	if (strcmp(tokens[6], "pps") != 0) {
+		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "spp");
+		return;
+	}
+
+	if (parser_read_uint32(&p.n_pipes_per_subport, tokens[7]) != 0) {
+		snprintf(out, out_size, MSG_ARG_INVALID, "n_pipes_per_subport");
+		return;
+	}
+
+	if (strcmp(tokens[8], "fo") != 0) {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "fo");
 		return;
 	}
 
-	if (parser_read_uint32(&p.frame_overhead, tokens[7]) != 0) {
+	if (parser_read_uint32(&p.frame_overhead, tokens[9]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "frame_overhead");
 		return;
 	}
 
-	if (strcmp(tokens[8], "mtu") != 0) {
+	if (strcmp(tokens[10], "mtu") != 0) {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "mtu");
 		return;
 	}
 
-	if (parser_read_uint32(&p.mtu, tokens[9]) != 0) {
+	if (parser_read_uint32(&p.mtu, tokens[11]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "mtu");
 		return;
 	}
 
-	if (strcmp(tokens[10], "cpu") != 0) {
+	if (strcmp(tokens[12], "cpu") != 0) {
 		snprintf(out, out_size, MSG_ARG_NOT_FOUND, "cpu");
 		return;
 	}
 
-	if (parser_read_uint32(&p.cpu_id, tokens[11]) != 0) {
+	if (parser_read_uint32(&p.cpu_id, tokens[13]) != 0) {
 		snprintf(out, out_size, MSG_ARG_INVALID, "cpu_id");
 		return;
 	}
diff --git a/examples/ip_pipeline/tmgr.c b/examples/ip_pipeline/tmgr.c
index 46c6a83a4..e4e364cbc 100644
--- a/examples/ip_pipeline/tmgr.c
+++ b/examples/ip_pipeline/tmgr.c
@@ -4,11 +4,12 @@
 
 #include <stdlib.h>
 
+#include <rte_common.h>
 #include <rte_string_fns.h>
 
 #include "tmgr.h"
 
-static struct rte_sched_subport_params
+static struct rte_sched_subport_profile_params
 	subport_profile[TMGR_SUBPORT_PROFILE_MAX];
 
 static uint32_t n_subport_profiles;
@@ -18,6 +19,82 @@ static struct rte_sched_pipe_params
 
 static uint32_t n_pipe_profiles;
 
+static const struct rte_sched_subport_params subport_params_default = {
+	.n_pipes_per_subport_enabled = 0, /* filled at runtime */
+	.qsize = {64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64},
+	.pipe_profiles = pipe_profile,
+	.n_pipe_profiles = 0, /* filled at run time */
+	.n_max_pipe_profiles = RTE_DIM(pipe_profile),
+#ifdef RTE_SCHED_RED
+.red_params = {
+	/* Traffic Class 0 Colors Green / Yellow / Red */
+	[0][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[0][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[0][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 1 - Colors Green / Yellow / Red */
+	[1][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[1][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[1][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 2 - Colors Green / Yellow / Red */
+	[2][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[2][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[2][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 3 - Colors Green / Yellow / Red */
+	[3][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[3][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[3][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 4 - Colors Green / Yellow / Red */
+	[4][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[4][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[4][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 5 - Colors Green / Yellow / Red */
+	[5][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[5][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[5][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 6 - Colors Green / Yellow / Red */
+	[6][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[6][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[6][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 7 - Colors Green / Yellow / Red */
+	[7][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[7][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[7][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 8 - Colors Green / Yellow / Red */
+	[8][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[8][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[8][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 9 - Colors Green / Yellow / Red */
+	[9][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[9][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[9][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 10 - Colors Green / Yellow / Red */
+	[10][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[10][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[10][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 11 - Colors Green / Yellow / Red */
+	[11][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[11][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[11][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+
+	/* Traffic Class 12 - Colors Green / Yellow / Red */
+	[12][0] = {.min_th = 48, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[12][1] = {.min_th = 40, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	[12][2] = {.min_th = 32, .max_th = 64, .maxp_inv = 10, .wq_log2 = 9},
+	},
+#endif /* RTE_SCHED_RED */
+};
+
 static struct tmgr_port_list tmgr_port_list;
 
 int
@@ -44,17 +121,16 @@ tmgr_port_find(const char *name)
 }
 
 int
-tmgr_subport_profile_add(struct rte_sched_subport_params *p)
+tmgr_subport_profile_add(struct rte_sched_subport_profile_params *params)
 {
 	/* Check input params */
-	if (p == NULL ||
-		p->n_pipes_per_subport_enabled == 0)
+	if (params == NULL)
 		return -1;
 
 	/* Save profile */
 	memcpy(&subport_profile[n_subport_profiles],
-		p,
-		sizeof(*p));
+		params,
+		sizeof(*params));
 
 	n_subport_profiles++;
 
@@ -81,6 +157,7 @@ tmgr_pipe_profile_add(struct rte_sched_pipe_params *p)
 struct tmgr_port *
 tmgr_port_create(const char *name, struct tmgr_port_params *params)
 {
+	struct rte_sched_subport_params subport_params;
 	struct rte_sched_port_params p;
 	struct tmgr_port *tmgr_port;
 	struct rte_sched_port *s;
@@ -91,6 +168,7 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 		tmgr_port_find(name) ||
 		(params == NULL) ||
 		(params->n_subports_per_port == 0) ||
+		(params->n_pipes_per_subport == 0) ||
 		(params->cpu_id >= RTE_MAX_NUMA_NODES) ||
 		(n_subport_profiles == 0) ||
 		(n_pipe_profiles == 0))
@@ -103,15 +181,22 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 	p.mtu = params->mtu;
 	p.frame_overhead = params->frame_overhead;
 	p.n_subports_per_port = params->n_subports_per_port;
-	p.n_pipes_per_subport = TMGR_PIPE_SUBPORT_MAX;
+	p.n_subport_profiles = n_subport_profiles;
+	p.subport_profiles = subport_profile;
+	p.n_max_subport_profiles = TMGR_SUBPORT_PROFILE_MAX;
+	p.n_pipes_per_subport = params->n_pipes_per_subport;
+
 
 	s = rte_sched_port_config(&p);
 	if (s == NULL)
 		return NULL;
 
-	subport_profile[0].pipe_profiles = pipe_profile;
-	subport_profile[0].n_pipe_profiles = n_pipe_profiles;
-	subport_profile[0].n_max_pipe_profiles = TMGR_PIPE_PROFILE_MAX;
+	memcpy(&subport_params, &subport_params_default,
+		sizeof(subport_params_default));
+
+	subport_params.n_pipe_profiles = n_pipe_profiles;
+	subport_params.n_pipes_per_subport_enabled =
+						params->n_pipes_per_subport;
 
 	for (i = 0; i < params->n_subports_per_port; i++) {
 		int status;
@@ -119,7 +204,7 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 		status = rte_sched_subport_config(
 			s,
 			i,
-			&subport_profile[0],
+			&subport_params,
 			0);
 
 		if (status) {
@@ -127,7 +212,8 @@ tmgr_port_create(const char *name, struct tmgr_port_params *params)
 			return NULL;
 		}
 
-		for (j = 0; j < subport_profile[0].n_pipes_per_subport_enabled; j++) {