Commit 1897db2e authored by Dmytro Linkin's avatar Dmytro Linkin Committed by David S. Miller
Browse files

devlink: Allow setting tx rate for devlink rate leaf objects



Implement support for DEVLINK_CMD_RATE_SET command with new attributes
DEVLINK_ATTR_RATE_TX_{SHARE|MAX} that are used to set devlink rate
shared/max tx rate values. Extend devlink ops with new callbacks
rate_leaf_tx_{share|max}_set() to allow supporting drivers to implement
rate control through devlink.

New attributes are optional. Driver implementations are allowed to
support either or both of them.

Shared rate example:

$ devlink port function rate set netdevsim/netdevsim10/0 tx_share 10mbit

$ devlink port function rate show netdevsim/netdevsim10/0
netdevsim/netdevsim10/0: type leaf tx_share 10mbit

Max rate example:

$ devlink port function rate set netdevsim/netdevsim10/0 tx_max 100mbit

$ devlink port function rate show netdevsim/netdevsim10/0
netdevsim/netdevsim10/0: type leaf tx_max 100mbit

Co-developed-by: default avatarVlad Buslov <vladbu@nvidia.com>
Signed-off-by: default avatarVlad Buslov <vladbu@nvidia.com>
Signed-off-by: default avatarDmytro Linkin <dlinkin@nvidia.com>
Reviewed-by: default avatarJiri Pirko <jiri@nvidia.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent a27d8e35
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -139,6 +139,8 @@ struct devlink_rate {
	enum devlink_rate_type type;
	struct devlink *devlink;
	void *priv;
	u64 tx_share;
	u64 tx_max;

	struct devlink_port *devlink_port;
};
@@ -1465,6 +1467,14 @@ struct devlink_ops {
				 struct devlink_port *port,
				 enum devlink_port_fn_state state,
				 struct netlink_ext_ack *extack);

	/**
	 * Rate control callbacks.
	 */
	int (*rate_leaf_tx_share_set)(struct devlink_rate *devlink_rate, void *priv,
				      u64 tx_share, struct netlink_ext_ack *extack);
	int (*rate_leaf_tx_max_set)(struct devlink_rate *devlink_rate, void *priv,
				    u64 tx_max, struct netlink_ext_ack *extack);
};

static inline void *devlink_priv(struct devlink *devlink)
+2 −0
Original line number Diff line number Diff line
@@ -545,6 +545,8 @@ enum devlink_attr {
	DEVLINK_ATTR_PORT_PCI_SF_NUMBER,	/* u32 */

	DEVLINK_ATTR_RATE_TYPE,			/* u16 */
	DEVLINK_ATTR_RATE_TX_SHARE,		/* u64 */
	DEVLINK_ATTR_RATE_TX_MAX,		/* u64 */
	/* add new attributes above here, update the policy in devlink.c */

	__DEVLINK_ATTR_MAX,
+86 −0
Original line number Diff line number Diff line
@@ -803,6 +803,14 @@ 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))
		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;

	genlmsg_end(msg, hdr);
	return 0;

@@ -1495,6 +1503,76 @@ static int devlink_nl_cmd_port_del_doit(struct sk_buff *skb,
	return devlink->ops->port_del(devlink, port_index, extack);
}

static int devlink_nl_rate_set(struct devlink_rate *devlink_rate,
			       const struct devlink_ops *ops,
			       struct genl_info *info)
{
	struct nlattr **attrs = info->attrs;
	u64 rate;
	int err;

	if (attrs[DEVLINK_ATTR_RATE_TX_SHARE]) {
		rate = nla_get_u64(attrs[DEVLINK_ATTR_RATE_TX_SHARE]);
		err = ops->rate_leaf_tx_share_set(devlink_rate, devlink_rate->priv,
						  rate, info->extack);
		if (err)
			return err;
		devlink_rate->tx_share = rate;
	}

	if (attrs[DEVLINK_ATTR_RATE_TX_MAX]) {
		rate = nla_get_u64(attrs[DEVLINK_ATTR_RATE_TX_MAX]);
		err = ops->rate_leaf_tx_max_set(devlink_rate, devlink_rate->priv,
						rate, info->extack);
		if (err)
			return err;
		devlink_rate->tx_max = rate;
	}

	return 0;
}

static bool devlink_rate_set_ops_supported(const struct devlink_ops *ops,
					   struct genl_info *info,
					   enum devlink_rate_type type)
{
	struct nlattr **attrs = info->attrs;

	if (type == DEVLINK_RATE_TYPE_LEAF) {
		if (attrs[DEVLINK_ATTR_RATE_TX_SHARE] && !ops->rate_leaf_tx_share_set) {
			NL_SET_ERR_MSG_MOD(info->extack, "TX share set isn't supported for the leafs");
			return false;
		}
		if (attrs[DEVLINK_ATTR_RATE_TX_MAX] && !ops->rate_leaf_tx_max_set) {
			NL_SET_ERR_MSG_MOD(info->extack, "TX max set isn't supported for the leafs");
			return false;
		}
	} else {
		WARN_ON("Unknown type of rate object");
		return false;
	}

	return true;
}

static int devlink_nl_cmd_rate_set_doit(struct sk_buff *skb,
					struct genl_info *info)
{
	struct devlink_rate *devlink_rate = info->user_ptr[1];
	struct devlink *devlink = devlink_rate->devlink;
	const struct devlink_ops *ops = devlink->ops;
	int err;

	if (!ops || !devlink_rate_set_ops_supported(ops, info, devlink_rate->type))
		return -EOPNOTSUPP;

	err = devlink_nl_rate_set(devlink_rate, ops, info);

	if (!err)
		devlink_rate_notify(devlink_rate, DEVLINK_CMD_RATE_NEW);
	return err;
}

static int devlink_nl_sb_fill(struct sk_buff *msg, struct devlink *devlink,
			      struct devlink_sb *devlink_sb,
			      enum devlink_command cmd, u32 portid,
@@ -7958,6 +8036,8 @@ static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
	[DEVLINK_ATTR_PORT_PCI_SF_NUMBER] = { .type = NLA_U32 },
	[DEVLINK_ATTR_PORT_CONTROLLER_NUMBER] = { .type = NLA_U32 },
	[DEVLINK_ATTR_RATE_TYPE] = { .type = NLA_U16 },
	[DEVLINK_ATTR_RATE_TX_SHARE] = { .type = NLA_U64 },
	[DEVLINK_ATTR_RATE_TX_MAX] = { .type = NLA_U64 },
};

static const struct genl_small_ops devlink_nl_ops[] = {
@@ -7990,6 +8070,12 @@ static const struct genl_small_ops devlink_nl_ops[] = {
		.internal_flags = DEVLINK_NL_FLAG_NEED_RATE,
		/* can be retrieved by unprivileged users */
	},
	{
		.cmd = DEVLINK_CMD_RATE_SET,
		.doit = devlink_nl_cmd_rate_set_doit,
		.flags = GENL_ADMIN_PERM,
		.internal_flags = DEVLINK_NL_FLAG_NEED_RATE,
	},
	{
		.cmd = DEVLINK_CMD_PORT_SPLIT,
		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,