diff mbox series

devlink: Extend the devlink rate API to support rate management on traffic classes

Message ID 20240814085320.134075-2-cratiu@nvidia.com (mailing list archive)
State Changes Requested
Delegated to: Netdev Maintainers
Headers show
Series devlink: Extend the devlink rate API to support rate management on traffic classes | expand

Checks

Context Check Description
netdev/series_format warning Single patches do not need cover letters; Target tree name not specified in the subject
netdev/tree_selection success Guessed tree name to be net-next
netdev/ynl success Generated files up to date; no warnings/errors; GEN HAS DIFF 2 files changed, 42 insertions(+);
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit fail Errors and warnings before: 29 this patch: 32
netdev/build_tools success Errors and warnings before: 0 this patch: 0
netdev/cc_maintainers warning 7 maintainers not CCed: pabeni@redhat.com kuba@kernel.org donald.hunter@gmail.com edumazet@google.com corbet@lwn.net swarupkotikalapudi@gmail.com linux-doc@vger.kernel.org
netdev/build_clang fail Errors and warnings before: 36 this patch: 39
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn fail Errors and warnings before: 557 this patch: 560
netdev/checkpatch fail ERROR: Remove Gerrit Change-Id's before submitting upstream WARNING: line length of 103 exceeds 80 columns WARNING: line length of 107 exceeds 80 columns WARNING: line length of 109 exceeds 80 columns WARNING: line length of 81 exceeds 80 columns WARNING: line length of 84 exceeds 80 columns WARNING: line length of 86 exceeds 80 columns WARNING: line length of 88 exceeds 80 columns WARNING: line length of 89 exceeds 80 columns WARNING: line length of 90 exceeds 80 columns WARNING: line length of 91 exceeds 80 columns WARNING: line length of 92 exceeds 80 columns WARNING: line length of 93 exceeds 80 columns WARNING: line length of 94 exceeds 80 columns WARNING: line length of 95 exceeds 80 columns WARNING: line length of 96 exceeds 80 columns WARNING: line length of 97 exceeds 80 columns WARNING: line length of 98 exceeds 80 columns WARNING: line length of 99 exceeds 80 columns
netdev/build_clang_rust success No Rust files in patch. Skipping build
netdev/kdoc fail Errors and warnings before: 2 this patch: 6
netdev/source_inline fail Was 0 now: 1

Commit Message

Cosmin Ratiu Aug. 14, 2024, 8:51 a.m. UTC
From: Carolina Jubran <cjubran@nvidia.com>

Introduce support for traffic classes (TC) in the devlink-rate API,
expanding beyond the current two object types: nodes and leafs. The
support of traffic classes provides more granular control, especially
in scenarios where customers need to implement Enhanced Transmission
Selection (ETS) for specific groups of Virtual Functions (VFs).

For instance, users can now allocate specific traffic classes, such as
TC0 and TC5, to handle TCP/UDP and RoCE traffic respectively, with
defined bandwidth shares (e.g., 20% for TC0 and 80% for TC5).

Example:
DEV=pci/0000:08:00.0

devlink port function rate add $DEV/vfs_group tx_share 10Gbit tx_max 50Gbit
devlink port function rate add $DEV/group_tc0 tx_weight 20 parent vfs_group
devlink port function rate add $DEV/group_tc5 tx_weight 80 parent vfs_group
devlink port function rate set $DEV/1/tc0 parent group_tc0
devlink port function rate set $DEV/2/tc0 parent group_tc0

devlink port function rate set $DEV/1/tc5 parent group_tc5
devlink port function rate set $DEV/2/tc5 parent group_tc5

Signed-off-by: Carolina Jubran <cjubran@nvidia.com>
Change-Id: If14e37966db416e1ff715c19439d071814800efe
---
 Documentation/netlink/specs/devlink.yaml      |   8 ++
 .../networking/devlink/devlink-port.rst       |  18 ++-
 include/net/devlink.h                         |  16 +++
 include/uapi/linux/devlink.h                  |   2 +
 net/devlink/netlink_gen.c                     |   3 +
 net/devlink/rate.c                            | 128 ++++++++++++++++++
 6 files changed, 170 insertions(+), 5 deletions(-)

Comments

kernel test robot Aug. 15, 2024, 2:02 a.m. UTC | #1
Hi Cosmin,

kernel test robot noticed the following build warnings:

[auto build test WARNING on linus/master]
[also build test WARNING on v6.11-rc3 next-20240814]
[cannot apply to horms-ipvs/master]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Cosmin-Ratiu/devlink-Extend-the-devlink-rate-API-to-support-rate-management-on-traffic-classes/20240814-232253
base:   linus/master
patch link:    https://lore.kernel.org/r/20240814085320.134075-2-cratiu%40nvidia.com
patch subject: [PATCH] devlink: Extend the devlink rate API to support rate management on traffic classes
config: arc-randconfig-001-20240815 (https://download.01.org/0day-ci/archive/20240815/202408150939.GeZ6uR8S-lkp@intel.com/config)
compiler: arc-elf-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20240815/202408150939.GeZ6uR8S-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202408150939.GeZ6uR8S-lkp@intel.com/

All warnings (new ones prefixed by >>):

>> net/devlink/rate.c:755: warning: Function parameter or struct member 'devlink_port' not described in 'devl_rate_traffic_class_create'
>> net/devlink/rate.c:755: warning: Function parameter or struct member 'parent' not described in 'devl_rate_traffic_class_create'
>> net/devlink/rate.c:755: warning: Excess function parameter 'devlink' description in 'devl_rate_traffic_class_create'


vim +755 net/devlink/rate.c

   744	
   745	/**
   746	 * devl_rate_traffic_class_create - create devlink rate queue
   747	 * @devlink: devlink instance
   748	 * @priv: driver private data
   749	 * @tc_id: identifier of the new traffic class
   750	 *
   751	 * Create devlink rate object of type node
   752	 */
   753	int devl_rate_traffic_class_create(struct devlink_port *devlink_port, void *priv, u16 tc_id,
   754					   struct devlink_rate *parent)
 > 755	{
   756		struct devlink *devlink = devlink_port->devlink;
   757		struct devlink_rate *devlink_rate;
   758	
   759		devl_assert_locked(devlink);
   760	
   761		devlink_rate = devlink_rate_traffic_class_get_by_id(devlink, tc_id);
   762		if (!IS_ERR(devlink_rate))
   763			return -EEXIST;
   764	
   765		devlink_rate = kzalloc(sizeof(*devlink_rate), GFP_KERNEL);
   766		if (!devlink_rate)
   767			return -ENOMEM;
   768	
   769		if (parent) {
   770			devlink_rate->parent = parent;
   771			refcount_inc(&devlink_rate->parent->refcnt);
   772		}
   773	
   774		devlink_rate->type = DEVLINK_RATE_TYPE_TRAFFIC_CLASS;
   775		devlink_rate->devlink = devlink;
   776		devlink_rate->devlink_port = devlink_port;
   777		devlink_rate->tc_id = tc_id;
   778		devlink_rate->priv = priv;
   779		list_add_tail(&devlink_rate->list, &devlink->rate_list);
   780		devlink_port->devlink_rate = devlink_rate;
   781		devlink_rate_notify(devlink_rate, DEVLINK_CMD_RATE_NEW);
   782	
   783		return 0;
   784	}
   785	EXPORT_SYMBOL_GPL(devl_rate_traffic_class_create);
   786
diff mbox series

Patch

diff --git a/Documentation/netlink/specs/devlink.yaml b/Documentation/netlink/specs/devlink.yaml
index 09fbb4c03fc8..14e702c17387 100644
--- a/Documentation/netlink/specs/devlink.yaml
+++ b/Documentation/netlink/specs/devlink.yaml
@@ -83,6 +83,8 @@  definitions:
         name: leaf
       -
         name: node
+      -
+        name: traffic-class
   -
     type: enum
     name: sb-threshold-type
@@ -781,6 +783,9 @@  attribute-sets:
       -
         name: rate-tx-max
         type: u64
+      -
+        name: rate-traffic-class-index
+        type: u16
       -
         name: rate-node-name
         type: string
@@ -2121,6 +2126,7 @@  operations:
             - bus-name
             - dev-name
             - port-index
+            - rate-traffic-class-index
             - rate-node-name
         reply: &rate-get-reply
           value: 76
@@ -2143,6 +2149,7 @@  operations:
           attributes:
             - bus-name
             - dev-name
+            - rate-traffic-class-index
             - rate-node-name
             - rate-tx-share
             - rate-tx-max
@@ -2163,6 +2170,7 @@  operations:
           attributes:
             - bus-name
             - dev-name
+            - rate-traffic-class-index
             - rate-node-name
             - rate-tx-share
             - rate-tx-max
diff --git a/Documentation/networking/devlink/devlink-port.rst b/Documentation/networking/devlink/devlink-port.rst
index 9d22d41a7cd1..6ea50b7cf769 100644
--- a/Documentation/networking/devlink/devlink-port.rst
+++ b/Documentation/networking/devlink/devlink-port.rst
@@ -374,14 +374,21 @@  At this point a matching subfunction driver binds to the subfunction's auxiliary
 Rate object management
 ======================
 
-Devlink provides API to manage tx rates of single devlink port or a group.
-This is done through rate objects, which can be one of the two types:
+Devlink provides API to manage tx rates of single devlink port, specific traffic classes or a group.
+This is done through rate objects, which can be one of the three types:
 
 ``leaf``
   Represents a single devlink port; created/destroyed by the driver. Since leaf
   have 1to1 mapping to its devlink port, in user space it is referred as
   ``pci/<bus_addr>/<port_index>``;
 
+``traffic class (tc)``
+  Represents a traffic class on a devlink port; created/destroyed by the
+  driver. The traffic class object is referred to in userspace as
+  ``pci/<bus_addr>/<port_index>/tc<traffic_class_index>``. This object allows
+  for the management of TX rates at the traffic class level on a specific
+  devlink port.
+
 ``node``
   Represents a group of rate objects (leafs and/or nodes); created/deleted by
   request from the userspace; initially empty (no rate objects added). In
@@ -437,9 +444,10 @@  Arbitration flow from the high level:
 #. If all the nodes from the highest priority sub-group are satisfied, or
    overused their assigned BW, move to the lower priority nodes.
 
-Driver implementations are allowed to support both or either rate object types
-and setting methods of their parameters. Additionally driver implementation
-may export nodes/leafs and their child-parent relationships.
+Driver implementations are allowed to support any combination of the rate
+object types and setting methods of their parameters. Additionally driver
+implementation may export nodes, leafs, traffic classes, and their
+child-parent relationships.
 
 Terms and Definitions
 =====================
diff --git a/include/net/devlink.h b/include/net/devlink.h
index db5eff6cb60f..a485c489acd6 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -117,6 +117,7 @@  struct devlink_rate {
 
 	u32 tx_priority;
 	u32 tx_weight;
+	u16 tc_id;
 };
 
 struct devlink_port {
@@ -1477,6 +1478,14 @@  struct devlink_ops {
 					 u32 tx_priority, struct netlink_ext_ack *extack);
 	int (*rate_node_tx_weight_set)(struct devlink_rate *devlink_rate, void *priv,
 				       u32 tx_weight, struct netlink_ext_ack *extack);
+	int (*rate_traffic_class_tx_share_set)(struct devlink_rate *devlink_rate, void *priv,
+					       u64 tx_share, struct netlink_ext_ack *extack);
+	int (*rate_traffic_class_tx_max_set)(struct devlink_rate *devlink_rate, void *priv,
+					     u64 tx_max, struct netlink_ext_ack *extack);
+	int (*rate_traffic_class_tx_priority_set)(struct devlink_rate *devlink_rate, void *priv,
+						  u32 tx_priority, struct netlink_ext_ack *extack);
+	int (*rate_traffic_class_tx_weight_set)(struct devlink_rate *devlink_rate, void *priv,
+						u32 tx_weight, struct netlink_ext_ack *extack);
 	int (*rate_node_new)(struct devlink_rate *rate_node, void **priv,
 			     struct netlink_ext_ack *extack);
 	int (*rate_node_del)(struct devlink_rate *rate_node, void *priv,
@@ -1489,6 +1498,10 @@  struct devlink_ops {
 				    struct devlink_rate *parent,
 				    void *priv_child, void *priv_parent,
 				    struct netlink_ext_ack *extack);
+	int (*rate_traffic_class_parent_set)(struct devlink_rate *child,
+					     struct devlink_rate *parent,
+					     void *priv_child, void *priv_parent,
+					     struct netlink_ext_ack *extack);
 	/**
 	 * selftests_check() - queries if selftest is supported
 	 * @devlink: devlink instance
@@ -1723,6 +1736,9 @@  devl_rate_node_create(struct devlink *devlink, void *priv, char *node_name,
 int
 devl_rate_leaf_create(struct devlink_port *devlink_port, void *priv,
 		      struct devlink_rate *parent);
+int
+devl_rate_traffic_class_create(struct devlink_port *devlink_port, void *priv, u16 tc_id,
+			       struct devlink_rate *parent);
 void devl_rate_leaf_destroy(struct devlink_port *devlink_port);
 void devl_rate_nodes_destroy(struct devlink *devlink);
 void devlink_port_linecard_set(struct devlink_port *devlink_port,
diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
index 9401aa343673..94f6e3ca5f8d 100644
--- a/include/uapi/linux/devlink.h
+++ b/include/uapi/linux/devlink.h
@@ -224,6 +224,7 @@  enum devlink_port_flavour {
 enum devlink_rate_type {
 	DEVLINK_RATE_TYPE_LEAF,
 	DEVLINK_RATE_TYPE_NODE,
+	DEVLINK_RATE_TYPE_TRAFFIC_CLASS,
 };
 
 enum devlink_param_cmode {
@@ -595,6 +596,7 @@  enum devlink_attr {
 	DEVLINK_ATTR_RATE_TYPE,			/* u16 */
 	DEVLINK_ATTR_RATE_TX_SHARE,		/* u64 */
 	DEVLINK_ATTR_RATE_TX_MAX,		/* u64 */
+	DEVLINK_ATTR_RATE_TRAFFIC_CLASS_INDEX,	/* u16 */
 	DEVLINK_ATTR_RATE_NODE_NAME,		/* string */
 	DEVLINK_ATTR_RATE_PARENT_NODE_NAME,	/* string */
 
diff --git a/net/devlink/netlink_gen.c b/net/devlink/netlink_gen.c
index f9786d51f68f..d62772a02930 100644
--- a/net/devlink/netlink_gen.c
+++ b/net/devlink/netlink_gen.c
@@ -486,6 +486,7 @@  static const struct nla_policy devlink_rate_get_do_nl_policy[DEVLINK_ATTR_RATE_N
 	[DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, },
 	[DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, },
 	[DEVLINK_ATTR_PORT_INDEX] = { .type = NLA_U32, },
+	[DEVLINK_ATTR_RATE_TRAFFIC_CLASS_INDEX] = { .type = NLA_U16, },
 	[DEVLINK_ATTR_RATE_NODE_NAME] = { .type = NLA_NUL_STRING, },
 };
 
@@ -499,6 +500,7 @@  static const struct nla_policy devlink_rate_get_dump_nl_policy[DEVLINK_ATTR_DEV_
 static const struct nla_policy devlink_rate_set_nl_policy[DEVLINK_ATTR_RATE_TX_WEIGHT + 1] = {
 	[DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, },
 	[DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, },
+	[DEVLINK_ATTR_RATE_TRAFFIC_CLASS_INDEX] = { .type = NLA_U16, },
 	[DEVLINK_ATTR_RATE_NODE_NAME] = { .type = NLA_NUL_STRING, },
 	[DEVLINK_ATTR_RATE_TX_SHARE] = { .type = NLA_U64, },
 	[DEVLINK_ATTR_RATE_TX_MAX] = { .type = NLA_U64, },
@@ -511,6 +513,7 @@  static const struct nla_policy devlink_rate_set_nl_policy[DEVLINK_ATTR_RATE_TX_W
 static const struct nla_policy devlink_rate_new_nl_policy[DEVLINK_ATTR_RATE_TX_WEIGHT + 1] = {
 	[DEVLINK_ATTR_BUS_NAME] = { .type = NLA_NUL_STRING, },
 	[DEVLINK_ATTR_DEV_NAME] = { .type = NLA_NUL_STRING, },
+	[DEVLINK_ATTR_RATE_TRAFFIC_CLASS_INDEX] = { .type = NLA_U16, },
 	[DEVLINK_ATTR_RATE_NODE_NAME] = { .type = NLA_NUL_STRING, },
 	[DEVLINK_ATTR_RATE_TX_SHARE] = { .type = NLA_U64, },
 	[DEVLINK_ATTR_RATE_TX_MAX] = { .type = NLA_U64, },
diff --git a/net/devlink/rate.c b/net/devlink/rate.c
index 7139e67e93ae..6812690883df 100644
--- a/net/devlink/rate.c
+++ b/net/devlink/rate.c
@@ -18,6 +18,12 @@  devlink_rate_is_node(struct devlink_rate *devlink_rate)
 	return devlink_rate->type == DEVLINK_RATE_TYPE_NODE;
 }
 
+static inline bool
+devlink_rate_is_traffic_class(struct devlink_rate *devlink_rate)
+{
+	return devlink_rate->type == DEVLINK_RATE_TYPE_TRAFFIC_CLASS;
+}
+
 static struct devlink_rate *
 devlink_rate_leaf_get_from_info(struct devlink *devlink, struct genl_info *info)
 {
@@ -31,6 +37,43 @@  devlink_rate_leaf_get_from_info(struct devlink *devlink, struct genl_info *info)
 	return devlink_rate ?: ERR_PTR(-ENODEV);
 }
 
+static struct devlink_rate *
+devlink_rate_traffic_class_get_by_id(struct devlink *devlink, u16 tc_id)
+{
+	static struct devlink_rate *devlink_rate;
+
+	list_for_each_entry(devlink_rate, &devlink->rate_list, list) {
+		if (devlink_rate_is_traffic_class(devlink_rate) &&
+		    devlink_rate->tc_id == tc_id)
+			return devlink_rate;
+	}
+
+	return ERR_PTR(-ENODEV);
+}
+
+static struct devlink_rate *
+devlink_rate_traffic_class_get_from_attrs(struct devlink *devlink, struct nlattr **attrs)
+{
+	struct devlink_rate *devlink_rate;
+	u16 tc_id;
+
+	if (!attrs[DEVLINK_ATTR_RATE_TRAFFIC_CLASS_INDEX])
+		return ERR_PTR(-EINVAL);
+
+	tc_id = nla_get_u16(attrs[DEVLINK_ATTR_RATE_TRAFFIC_CLASS_INDEX]);
+	devlink_rate = devlink_rate_traffic_class_get_by_id(devlink, tc_id);
+	if (!devlink_rate)
+		return ERR_PTR(-ENODEV);
+
+	return devlink_rate;
+}
+
+static struct devlink_rate *
+devlink_rate_traffic_class_get_from_info(struct devlink *devlink, struct genl_info *info)
+{
+	return devlink_rate_traffic_class_get_from_attrs(devlink, info->attrs);
+}
+
 static struct devlink_rate *
 devlink_rate_node_get_by_name(struct devlink *devlink, const char *node_name)
 {
@@ -76,6 +119,8 @@  devlink_rate_get_from_info(struct devlink *devlink, struct genl_info *info)
 		return devlink_rate_leaf_get_from_info(devlink, info);
 	else if (attrs[DEVLINK_ATTR_RATE_NODE_NAME])
 		return devlink_rate_node_get_from_info(devlink, info);
+	else if (attrs[DEVLINK_ATTR_RATE_TRAFFIC_CLASS_INDEX])
+		return devlink_rate_traffic_class_get_from_info(devlink, info);
 	else
 		return ERR_PTR(-EINVAL);
 }
@@ -106,6 +151,10 @@  static int devlink_nl_rate_fill(struct sk_buff *msg,
 		if (nla_put_string(msg, DEVLINK_ATTR_RATE_NODE_NAME,
 				   devlink_rate->name))
 			goto nla_put_failure;
+	} else if (devlink_rate_is_traffic_class(devlink_rate)) {
+		if (nla_put_u16(msg, DEVLINK_ATTR_RATE_TRAFFIC_CLASS_INDEX, devlink_rate->tc_id) ||
+		    nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX, devlink_rate->devlink_port->index))
+			goto nla_put_failure;
 	}
 
 	if (nla_put_u64_64bit(msg, DEVLINK_ATTR_RATE_TX_SHARE,
@@ -273,6 +322,10 @@  devlink_nl_rate_parent_node_set(struct devlink_rate *devlink_rate,
 			err = ops->rate_node_parent_set(devlink_rate, NULL,
 							devlink_rate->priv, NULL,
 							info->extack);
+		else if (devlink_rate_is_traffic_class(devlink_rate))
+			err = ops->rate_traffic_class_parent_set(devlink_rate, NULL,
+								 devlink_rate->priv, NULL,
+								 info->extack);
 		if (err)
 			return err;
 
@@ -302,6 +355,10 @@  devlink_nl_rate_parent_node_set(struct devlink_rate *devlink_rate,
 			err = ops->rate_node_parent_set(devlink_rate, parent,
 							devlink_rate->priv, parent->priv,
 							info->extack);
+		else if (devlink_rate_is_traffic_class(devlink_rate))
+			err = ops->rate_traffic_class_parent_set(devlink_rate, parent,
+								 devlink_rate->priv, parent->priv,
+								 info->extack);
 		if (err)
 			return err;
 
@@ -449,6 +506,32 @@  static bool devlink_rate_set_ops_supported(const struct devlink_ops *ops,
 					    "TX weight set isn't supported for the nodes");
 			return false;
 		}
+	} else if (type == DEVLINK_RATE_TYPE_TRAFFIC_CLASS) {
+		if (attrs[DEVLINK_ATTR_RATE_TX_SHARE] && !ops->rate_traffic_class_tx_share_set) {
+			NL_SET_ERR_MSG(info->extack, "TX share set isn't supported for the traffic classes");
+			return false;
+		}
+		if (attrs[DEVLINK_ATTR_RATE_TX_MAX] && !ops->rate_traffic_class_tx_max_set) {
+			NL_SET_ERR_MSG(info->extack, "TX max set isn't supported for the traffic classes");
+			return false;
+		}
+		if (attrs[DEVLINK_ATTR_RATE_PARENT_NODE_NAME] &&
+		    !ops->rate_traffic_class_parent_set) {
+			NL_SET_ERR_MSG(info->extack, "Parent set isn't supported for the traffic classes");
+			return false;
+		}
+		if (attrs[DEVLINK_ATTR_RATE_TX_PRIORITY] && !ops->rate_traffic_class_tx_priority_set) {
+			NL_SET_ERR_MSG_ATTR(info->extack,
+					    attrs[DEVLINK_ATTR_RATE_TX_PRIORITY],
+					    "TX priority set isn't supported for the traffic classes");
+			return false;
+		}
+		if (attrs[DEVLINK_ATTR_RATE_TX_WEIGHT] && !ops->rate_traffic_class_tx_weight_set) {
+			NL_SET_ERR_MSG_ATTR(info->extack,
+					    attrs[DEVLINK_ATTR_RATE_TX_WEIGHT],
+					    "TX weight set isn't supported for the traffic classes");
+			return false;
+		}
 	} else {
 		WARN(1, "Unknown type of rate object");
 		return false;
@@ -659,6 +742,48 @@  int devl_rate_leaf_create(struct devlink_port *devlink_port, void *priv,
 }
 EXPORT_SYMBOL_GPL(devl_rate_leaf_create);
 
+/**
+ * devl_rate_traffic_class_create - create devlink rate queue
+ * @devlink: devlink instance
+ * @priv: driver private data
+ * @tc_id: identifier of the new traffic class
+ *
+ * Create devlink rate object of type node
+ */
+int devl_rate_traffic_class_create(struct devlink_port *devlink_port, void *priv, u16 tc_id,
+				   struct devlink_rate *parent)
+{
+	struct devlink *devlink = devlink_port->devlink;
+	struct devlink_rate *devlink_rate;
+
+	devl_assert_locked(devlink);
+
+	devlink_rate = devlink_rate_traffic_class_get_by_id(devlink, tc_id);
+	if (!IS_ERR(devlink_rate))
+		return -EEXIST;
+
+	devlink_rate = kzalloc(sizeof(*devlink_rate), GFP_KERNEL);
+	if (!devlink_rate)
+		return -ENOMEM;
+
+	if (parent) {
+		devlink_rate->parent = parent;
+		refcount_inc(&devlink_rate->parent->refcnt);
+	}
+
+	devlink_rate->type = DEVLINK_RATE_TYPE_TRAFFIC_CLASS;
+	devlink_rate->devlink = devlink;
+	devlink_rate->devlink_port = devlink_port;
+	devlink_rate->tc_id = tc_id;
+	devlink_rate->priv = priv;
+	list_add_tail(&devlink_rate->list, &devlink->rate_list);
+	devlink_port->devlink_rate = devlink_rate;
+	devlink_rate_notify(devlink_rate, DEVLINK_CMD_RATE_NEW);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(devl_rate_traffic_class_create);
+
 /**
  * devl_rate_leaf_destroy - destroy devlink rate leaf
  *
@@ -708,6 +833,9 @@  void devl_rate_nodes_destroy(struct devlink *devlink)
 		else if (devlink_rate_is_node(devlink_rate))
 			ops->rate_node_parent_set(devlink_rate, NULL, devlink_rate->priv,
 						  NULL, NULL);
+		else if (devlink_rate_is_traffic_class(devlink_rate))
+			ops->rate_traffic_class_parent_set(devlink_rate, NULL, devlink_rate->priv,
+							   NULL, NULL);
 	}
 	list_for_each_entry_safe(devlink_rate, tmp, &devlink->rate_list, list) {
 		if (devlink_rate_is_node(devlink_rate)) {