lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Mon, 20 Jun 2022 18:26:43 +0300
From:   Dima Chumak <dchumak@...dia.com>
To:     Jakub Kicinski <kuba@...nel.org>
CC:     Jiri Pirko <jiri@...dia.com>,
        "David S. Miller" <davem@...emloft.net>,
        Eric Dumazet <edumazet@...gle.com>,
        Paolo Abeni <pabeni@...hat.com>, <netdev@...r.kernel.org>,
        Dima Chumak <dchumak@...dia.com>
Subject: [PATCH net-next 1/5] devlink: Introduce limit_type attr for rate objects

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@...dia.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 --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[] = {
-- 
2.36.1

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ