diff mbox series

[net-next,1/5] devlink: Introduce limit_type attr for rate objects

Message ID 20220620152647.2498927-2-dchumak@nvidia.com (mailing list archive)
State Rejected
Delegated to: Netdev Maintainers
Headers show
Series devlink rate police limiter | expand

Checks

Context Check Description
netdev/tree_selection success Clearly marked for net-next
netdev/fixes_present success Fixes tag not required for -next series
netdev/subject_prefix success Link
netdev/cover_letter success Series has a cover letter
netdev/patch_count success Link
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 383 this patch: 383
netdev/cc_maintainers warning 16 maintainers not CCed: leon@kernel.org linux-rdma@vger.kernel.org daniel@iogearbox.net songliubraving@fb.com ast@kernel.org bpf@vger.kernel.org saeedm@nvidia.com parav@nvidia.com yhs@fb.com mbloch@nvidia.com john.fastabend@gmail.com kafai@fb.com huyn@nvidia.com dlinkin@nvidia.com andrii@kernel.org kpsingh@kernel.org
netdev/build_clang success Errors and warnings before: 35 this patch: 35
netdev/module_param success Was 0 now: 0
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 530 this patch: 530
netdev/checkpatch warning WARNING: line length of 81 exceeds 80 columns WARNING: line length of 82 exceeds 80 columns WARNING: line length of 83 exceeds 80 columns WARNING: line length of 85 exceeds 80 columns WARNING: line length of 86 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
netdev/kdoc success Errors and warnings before: 14 this patch: 14
netdev/source_inline fail Was 0 now: 2

Commit Message

Dima Chumak June 20, 2022, 3:26 p.m. UTC
Lay foundation to support different kinds of rate limiting that may be
performed by rate objects.

Existing rate limiting type is dubbed as 'shaping' and it is assumed by
default when limit_type attribute isn't set explicitly. Following patch
in the series will introduce new limit type 'police'.

Leaf rate objects inherit their limit_type from a parent node object if
it hasn't been explicitly set for the leaf object.

Signed-off-by: Dima Chumak <dchumak@nvidia.com>
---
 .../net/ethernet/mellanox/mlx5/core/esw/qos.c |  28 +++-
 include/net/devlink.h                         |  12 +-
 include/uapi/linux/devlink.h                  |   7 +
 net/core/devlink.c                            | 123 ++++++++++++++----
 4 files changed, 140 insertions(+), 30 deletions(-)
diff mbox series

Patch

diff --git a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c
index 694c54066955..50bd4536fab1 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/esw/qos.c
@@ -874,8 +874,8 @@  int mlx5_esw_devlink_rate_node_tx_max_set(struct devlink_rate *rate_node, void *
 int mlx5_esw_devlink_rate_node_new(struct devlink_rate *rate_node, void **priv,
 				   struct netlink_ext_ack *extack)
 {
-	struct mlx5_esw_rate_group *group;
 	struct mlx5_eswitch *esw;
+	void *group;
 	int err = 0;
 
 	esw = mlx5_devlink_eswitch_get(rate_node->devlink);
@@ -890,7 +890,17 @@  int mlx5_esw_devlink_rate_node_new(struct devlink_rate *rate_node, void **priv,
 		goto unlock;
 	}
 
-	group = esw_qos_create_rate_group(esw, extack);
+	switch (rate_node->limit_type) {
+	case DEVLINK_RATE_LIMIT_TYPE_UNSET:
+		group = ERR_PTR(-EINVAL);
+		break;
+	case DEVLINK_RATE_LIMIT_TYPE_SHAPING:
+		group = esw_qos_create_rate_group(esw, extack);
+		break;
+	default:
+		group = ERR_PTR(-EOPNOTSUPP);
+	}
+
 	if (IS_ERR(group)) {
 		err = PTR_ERR(group);
 		goto unlock;
@@ -905,7 +915,6 @@  int mlx5_esw_devlink_rate_node_new(struct devlink_rate *rate_node, void **priv,
 int mlx5_esw_devlink_rate_node_del(struct devlink_rate *rate_node, void *priv,
 				   struct netlink_ext_ack *extack)
 {
-	struct mlx5_esw_rate_group *group = priv;
 	struct mlx5_eswitch *esw;
 	int err;
 
@@ -914,7 +923,18 @@  int mlx5_esw_devlink_rate_node_del(struct devlink_rate *rate_node, void *priv,
 		return PTR_ERR(esw);
 
 	mutex_lock(&esw->state_lock);
-	err = esw_qos_destroy_rate_group(esw, group, extack);
+
+	switch (rate_node->limit_type) {
+	case DEVLINK_RATE_LIMIT_TYPE_UNSET:
+		err = -EINVAL;
+		break;
+	case DEVLINK_RATE_LIMIT_TYPE_SHAPING:
+		err = esw_qos_destroy_rate_group(esw, priv, extack);
+		break;
+	default:
+		err = -EOPNOTSUPP;
+	}
+
 	mutex_unlock(&esw->state_lock);
 	return err;
 }
diff --git a/include/net/devlink.h b/include/net/devlink.h
index 2a2a2a0c93f7..4fe8e657da44 100644
--- a/include/net/devlink.h
+++ b/include/net/devlink.h
@@ -98,13 +98,21 @@  struct devlink_port_attrs {
 	};
 };
 
+struct devlink_rate_shaping_attrs {
+	u64 tx_max;
+	u64 tx_share;
+};
+
 struct devlink_rate {
 	struct list_head list;
+	enum devlink_rate_limit_type limit_type;
 	enum devlink_rate_type type;
 	struct devlink *devlink;
 	void *priv;
-	u64 tx_share;
-	u64 tx_max;
+
+	union { /* on limit_type */
+		struct devlink_rate_shaping_attrs shaping_attrs;
+	};
 
 	struct devlink_rate *parent;
 	union {
diff --git a/include/uapi/linux/devlink.h b/include/uapi/linux/devlink.h
index b3d40a5d72ff..53aad0d09231 100644
--- a/include/uapi/linux/devlink.h
+++ b/include/uapi/linux/devlink.h
@@ -221,6 +221,11 @@  enum devlink_rate_type {
 	DEVLINK_RATE_TYPE_NODE,
 };
 
+enum devlink_rate_limit_type {
+	DEVLINK_RATE_LIMIT_TYPE_UNSET,
+	DEVLINK_RATE_LIMIT_TYPE_SHAPING,
+};
+
 enum devlink_param_cmode {
 	DEVLINK_PARAM_CMODE_RUNTIME,
 	DEVLINK_PARAM_CMODE_DRIVERINIT,
@@ -576,6 +581,8 @@  enum devlink_attr {
 	DEVLINK_ATTR_LINECARD_TYPE,		/* string */
 	DEVLINK_ATTR_LINECARD_SUPPORTED_TYPES,	/* nested */
 
+	DEVLINK_ATTR_RATE_LIMIT_TYPE,		/* u16 */
+
 	/* add new attributes above here, update the policy in devlink.c */
 
 	__DEVLINK_ATTR_MAX,
diff --git a/net/core/devlink.c b/net/core/devlink.c
index db61f3a341cb..756d95c72b4d 100644
--- a/net/core/devlink.c
+++ b/net/core/devlink.c
@@ -354,6 +354,18 @@  devlink_rate_is_node(struct devlink_rate *devlink_rate)
 	return devlink_rate->type == DEVLINK_RATE_TYPE_NODE;
 }
 
+static inline bool
+devlink_rate_is_unset(struct devlink_rate *devlink_rate)
+{
+	return devlink_rate->limit_type == DEVLINK_RATE_LIMIT_TYPE_UNSET;
+}
+
+static inline bool
+devlink_rate_is_shaping(struct devlink_rate *devlink_rate)
+{
+	return devlink_rate->limit_type == DEVLINK_RATE_LIMIT_TYPE_SHAPING;
+}
+
 static struct devlink_rate *
 devlink_rate_leaf_get_from_info(struct devlink *devlink, struct genl_info *info)
 {
@@ -1093,13 +1105,27 @@  static int devlink_nl_rate_fill(struct sk_buff *msg,
 			goto nla_put_failure;
 	}
 
-	if (nla_put_u64_64bit(msg, DEVLINK_ATTR_RATE_TX_SHARE,
-			      devlink_rate->tx_share, DEVLINK_ATTR_PAD))
+	if (nla_put_u64_64bit(msg, DEVLINK_ATTR_RATE_LIMIT_TYPE,
+			      devlink_rate->limit_type, DEVLINK_ATTR_PAD))
 		goto nla_put_failure;
 
-	if (nla_put_u64_64bit(msg, DEVLINK_ATTR_RATE_TX_MAX,
-			      devlink_rate->tx_max, DEVLINK_ATTR_PAD))
-		goto nla_put_failure;
+	if (devlink_rate_is_unset(devlink_rate)) {
+		/* For backward compatibility with older user-space clients that
+		 * don't understatnd DEVLINK_ATTR_RATE_LIMIT_TYPE, report tx_max
+		 * and tx_share as being "unlimited".
+		 */
+		if (nla_put_u64_64bit(msg, DEVLINK_ATTR_RATE_TX_MAX, 0, DEVLINK_ATTR_PAD))
+			goto nla_put_failure;
+		if (nla_put_u64_64bit(msg, DEVLINK_ATTR_RATE_TX_SHARE, 0, DEVLINK_ATTR_PAD))
+			goto nla_put_failure;
+	} else if (devlink_rate_is_shaping(devlink_rate)) {
+		if (nla_put_u64_64bit(msg, DEVLINK_ATTR_RATE_TX_MAX,
+				      devlink_rate->shaping_attrs.tx_max, DEVLINK_ATTR_PAD))
+			goto nla_put_failure;
+		if (nla_put_u64_64bit(msg, DEVLINK_ATTR_RATE_TX_SHARE,
+				      devlink_rate->shaping_attrs.tx_share, DEVLINK_ATTR_PAD))
+			goto nla_put_failure;
+	}
 
 	if (devlink_rate->parent)
 		if (nla_put_string(msg, DEVLINK_ATTR_RATE_PARENT_NODE_NAME,
@@ -1850,6 +1876,12 @@  devlink_nl_rate_parent_node_set(struct devlink_rate *devlink_rate,
 			return -EEXIST;
 		}
 
+		if (parent->limit_type != devlink_rate->limit_type) {
+			NL_SET_ERR_MSG_MOD(info->extack,
+					   "Parent and object should be of the same limit_type");
+			return -EINVAL;
+		}
+
 		if (devlink_rate_is_leaf(devlink_rate))
 			err = ops->rate_leaf_parent_set(devlink_rate, parent,
 							devlink_rate->priv, parent->priv,
@@ -1873,44 +1905,82 @@  static int devlink_nl_rate_set(struct devlink_rate *devlink_rate,
 			       struct genl_info *info)
 {
 	struct nlattr *nla_parent, **attrs = info->attrs;
-	int err = -EOPNOTSUPP;
-	u64 rate;
+	struct devlink_rate *parent;
+	int err = 0;
+	u16 new_limit_type;
+	u64 new_val;
+
+	nla_parent = attrs[DEVLINK_ATTR_RATE_PARENT_NODE_NAME];
+
+	if (attrs[DEVLINK_ATTR_RATE_LIMIT_TYPE]) {
+		new_limit_type = nla_get_u16(attrs[DEVLINK_ATTR_RATE_LIMIT_TYPE]);
+		if (devlink_rate_is_unset(devlink_rate))
+			devlink_rate->limit_type = new_limit_type;
+		if (devlink_rate->limit_type != new_limit_type) {
+			if (devlink_rate_is_node(devlink_rate)) {
+				NL_SET_ERR_MSG_MOD(info->extack,
+						   "Cannot change limit_type of the rate node object, delete and add a new one instead.");
+				return -EINVAL;
+			}
+			NL_SET_ERR_MSG_MOD(info->extack,
+					   "Cannot change limit_type of the rate leaf object, reset current rate attributes first.");
+			return -EBUSY;
+		}
+	}
+
+	if (devlink_rate_is_unset(devlink_rate)) {
+		if (nla_parent) {
+			parent = devlink_rate_node_get_by_name(devlink_rate->devlink,
+							       nla_data(nla_parent));
+			if (!IS_ERR(parent))
+				devlink_rate->limit_type = parent->limit_type;
+			else
+				devlink_rate->limit_type = DEVLINK_RATE_LIMIT_TYPE_SHAPING;
+		} else {
+			devlink_rate->limit_type = DEVLINK_RATE_LIMIT_TYPE_SHAPING;
+		}
+	}
+
+	if (attrs[DEVLINK_ATTR_RATE_TX_SHARE] && devlink_rate_is_shaping(devlink_rate)) {
+		new_val = nla_get_u64(attrs[DEVLINK_ATTR_RATE_TX_SHARE]);
 
-	if (attrs[DEVLINK_ATTR_RATE_TX_SHARE]) {
-		rate = nla_get_u64(attrs[DEVLINK_ATTR_RATE_TX_SHARE]);
 		if (devlink_rate_is_leaf(devlink_rate))
 			err = ops->rate_leaf_tx_share_set(devlink_rate, devlink_rate->priv,
-							  rate, info->extack);
+							  new_val, info->extack);
 		else if (devlink_rate_is_node(devlink_rate))
 			err = ops->rate_node_tx_share_set(devlink_rate, devlink_rate->priv,
-							  rate, info->extack);
+							  new_val, info->extack);
 		if (err)
 			return err;
-		devlink_rate->tx_share = rate;
+		devlink_rate->shaping_attrs.tx_share = new_val;
 	}
 
 	if (attrs[DEVLINK_ATTR_RATE_TX_MAX]) {
-		rate = nla_get_u64(attrs[DEVLINK_ATTR_RATE_TX_MAX]);
+		new_val = nla_get_u64(attrs[DEVLINK_ATTR_RATE_TX_MAX]);
+
 		if (devlink_rate_is_leaf(devlink_rate))
 			err = ops->rate_leaf_tx_max_set(devlink_rate, devlink_rate->priv,
-							rate, info->extack);
+							new_val, info->extack);
 		else if (devlink_rate_is_node(devlink_rate))
 			err = ops->rate_node_tx_max_set(devlink_rate, devlink_rate->priv,
-							rate, info->extack);
+							new_val, info->extack);
 		if (err)
 			return err;
-		devlink_rate->tx_max = rate;
+		devlink_rate->shaping_attrs.tx_max = new_val;
 	}
 
-	nla_parent = attrs[DEVLINK_ATTR_RATE_PARENT_NODE_NAME];
-	if (nla_parent) {
-		err = devlink_nl_rate_parent_node_set(devlink_rate, info,
-						      nla_parent);
-		if (err)
-			return err;
-	}
+	if (nla_parent)
+		err = devlink_nl_rate_parent_node_set(devlink_rate, info, nla_parent);
 
-	return 0;
+	/* reset limit_type when all attrs have been cleared, relevant only for
+	 * leaf objects as node objects get deleted altogether
+	 */
+	if (devlink_rate_is_leaf(devlink_rate) && !devlink_rate->parent &&
+	    ((devlink_rate_is_shaping(devlink_rate) &&
+	      !devlink_rate->shaping_attrs.tx_max && !devlink_rate->shaping_attrs.tx_share)))
+		devlink_rate->limit_type = DEVLINK_RATE_LIMIT_TYPE_UNSET;
+
+	return err;
 }
 
 static bool devlink_rate_set_ops_supported(const struct devlink_ops *ops,
@@ -2002,6 +2072,10 @@  static int devlink_nl_cmd_rate_new_doit(struct sk_buff *skb,
 
 	rate_node->devlink = devlink;
 	rate_node->type = DEVLINK_RATE_TYPE_NODE;
+	if (info->attrs[DEVLINK_ATTR_RATE_LIMIT_TYPE])
+		rate_node->limit_type = nla_get_u16(info->attrs[DEVLINK_ATTR_RATE_LIMIT_TYPE]);
+	if (rate_node->limit_type == DEVLINK_RATE_LIMIT_TYPE_UNSET)
+		rate_node->limit_type = DEVLINK_RATE_LIMIT_TYPE_SHAPING;
 	rate_node->name = nla_strdup(info->attrs[DEVLINK_ATTR_RATE_NODE_NAME], GFP_KERNEL);
 	if (!rate_node->name) {
 		err = -ENOMEM;
@@ -9000,6 +9074,7 @@  static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
 	[DEVLINK_ATTR_RATE_PARENT_NODE_NAME] = { .type = NLA_NUL_STRING },
 	[DEVLINK_ATTR_LINECARD_INDEX] = { .type = NLA_U32 },
 	[DEVLINK_ATTR_LINECARD_TYPE] = { .type = NLA_NUL_STRING },
+	[DEVLINK_ATTR_RATE_LIMIT_TYPE] = { .type = NLA_U16 },
 };
 
 static const struct genl_small_ops devlink_nl_ops[] = {