Skip to content

Commit d755598

Browse files
DmytroLinkindavem330
authored andcommitted
devlink: Allow setting parent node of rate objects
Refactor DEVLINK_CMD_RATE_{GET|SET} command handlers to support setting a node as a parent for another rate object (leaf or node) by means of new attribute DEVLINK_ATTR_RATE_PARENT_NODE_NAME. Extend devlink ops with new callbacks rate_{leaf|node}_parent_set() to set node as a parent for rate object to allow supporting drivers to implement rate grouping through devlink. Driver implementations are allowed to support leafs or node children only. Invoking callback with NULL as parent should be threated by the driver as unset parent action. Extend rate object struct with reference counter to disallow deleting a node with any child pointing to it. User should unset parent for the child explicitly. Example: $ devlink port function rate add netdevsim/netdevsim10/group1 $ devlink port function rate add netdevsim/netdevsim10/group2 $ devlink port function rate set netdevsim/netdevsim10/group1 parent group2 $ devlink port function rate show netdevsim/netdevsim10/group1 netdevsim/netdevsim10/group1: type node parent group2 $ devlink port function rate set netdevsim/netdevsim10/group1 noparent Co-developed-by: Vlad Buslov <vladbu@nvidia.com> Signed-off-by: Vlad Buslov <vladbu@nvidia.com> Signed-off-by: Dmytro Linkin <dlinkin@nvidia.com> Reviewed-by: Jiri Pirko <jiri@nvidia.com> Signed-off-by: David S. Miller <davem@davemloft.net>
1 parent 413ee94 commit d755598

File tree

3 files changed

+137
-3
lines changed

3 files changed

+137
-3
lines changed

include/net/devlink.h

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,13 @@ struct devlink_rate {
142142
u64 tx_share;
143143
u64 tx_max;
144144

145+
struct devlink_rate *parent;
145146
union {
146147
struct devlink_port *devlink_port;
147-
char *name;
148+
struct {
149+
char *name;
150+
refcount_t refcnt;
151+
};
148152
};
149153
};
150154

@@ -1486,6 +1490,14 @@ struct devlink_ops {
14861490
struct netlink_ext_ack *extack);
14871491
int (*rate_node_del)(struct devlink_rate *rate_node, void *priv,
14881492
struct netlink_ext_ack *extack);
1493+
int (*rate_leaf_parent_set)(struct devlink_rate *child,
1494+
struct devlink_rate *parent,
1495+
void *priv_child, void *priv_parent,
1496+
struct netlink_ext_ack *extack);
1497+
int (*rate_node_parent_set)(struct devlink_rate *child,
1498+
struct devlink_rate *parent,
1499+
void *priv_child, void *priv_parent,
1500+
struct netlink_ext_ack *extack);
14891501
};
14901502

14911503
static inline void *devlink_priv(struct devlink *devlink)

include/uapi/linux/devlink.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,7 @@ enum devlink_attr {
549549
DEVLINK_ATTR_RATE_TX_SHARE, /* u64 */
550550
DEVLINK_ATTR_RATE_TX_MAX, /* u64 */
551551
DEVLINK_ATTR_RATE_NODE_NAME, /* string */
552+
DEVLINK_ATTR_RATE_PARENT_NODE_NAME, /* string */
552553

553554
/* add new attributes above here, update the policy in devlink.c */
554555

net/core/devlink.c

Lines changed: 123 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,11 @@ static int devlink_nl_rate_fill(struct sk_buff *msg,
880880
devlink_rate->tx_max, DEVLINK_ATTR_PAD))
881881
goto nla_put_failure;
882882

883+
if (devlink_rate->parent)
884+
if (nla_put_string(msg, DEVLINK_ATTR_RATE_PARENT_NODE_NAME,
885+
devlink_rate->parent->name))
886+
goto nla_put_failure;
887+
883888
genlmsg_end(msg, hdr);
884889
return 0;
885890

@@ -1152,6 +1157,18 @@ static int devlink_nl_cmd_rate_get_doit(struct sk_buff *skb,
11521157
return genlmsg_reply(msg, info);
11531158
}
11541159

1160+
static bool
1161+
devlink_rate_is_parent_node(struct devlink_rate *devlink_rate,
1162+
struct devlink_rate *parent)
1163+
{
1164+
while (parent) {
1165+
if (parent == devlink_rate)
1166+
return true;
1167+
parent = parent->parent;
1168+
}
1169+
return false;
1170+
}
1171+
11551172
static int devlink_nl_cmd_get_doit(struct sk_buff *skb, struct genl_info *info)
11561173
{
11571174
struct devlink *devlink = info->user_ptr[0];
@@ -1572,11 +1589,75 @@ static int devlink_nl_cmd_port_del_doit(struct sk_buff *skb,
15721589
return devlink->ops->port_del(devlink, port_index, extack);
15731590
}
15741591

1592+
static int
1593+
devlink_nl_rate_parent_node_set(struct devlink_rate *devlink_rate,
1594+
struct genl_info *info,
1595+
struct nlattr *nla_parent)
1596+
{
1597+
struct devlink *devlink = devlink_rate->devlink;
1598+
const char *parent_name = nla_data(nla_parent);
1599+
const struct devlink_ops *ops = devlink->ops;
1600+
size_t len = strlen(parent_name);
1601+
struct devlink_rate *parent;
1602+
int err = -EOPNOTSUPP;
1603+
1604+
parent = devlink_rate->parent;
1605+
if (parent && len) {
1606+
NL_SET_ERR_MSG_MOD(info->extack, "Rate object already has parent.");
1607+
return -EBUSY;
1608+
} else if (parent && !len) {
1609+
if (devlink_rate_is_leaf(devlink_rate))
1610+
err = ops->rate_leaf_parent_set(devlink_rate, NULL,
1611+
devlink_rate->priv, NULL,
1612+
info->extack);
1613+
else if (devlink_rate_is_node(devlink_rate))
1614+
err = ops->rate_node_parent_set(devlink_rate, NULL,
1615+
devlink_rate->priv, NULL,
1616+
info->extack);
1617+
if (err)
1618+
return err;
1619+
1620+
refcount_dec(&parent->refcnt);
1621+
devlink_rate->parent = NULL;
1622+
} else if (!parent && len) {
1623+
parent = devlink_rate_node_get_by_name(devlink, parent_name);
1624+
if (IS_ERR(parent))
1625+
return -ENODEV;
1626+
1627+
if (parent == devlink_rate) {
1628+
NL_SET_ERR_MSG_MOD(info->extack, "Parent to self is not allowed");
1629+
return -EINVAL;
1630+
}
1631+
1632+
if (devlink_rate_is_node(devlink_rate) &&
1633+
devlink_rate_is_parent_node(devlink_rate, parent->parent)) {
1634+
NL_SET_ERR_MSG_MOD(info->extack, "Node is already a parent of parent node.");
1635+
return -EEXIST;
1636+
}
1637+
1638+
if (devlink_rate_is_leaf(devlink_rate))
1639+
err = ops->rate_leaf_parent_set(devlink_rate, parent,
1640+
devlink_rate->priv, parent->priv,
1641+
info->extack);
1642+
else if (devlink_rate_is_node(devlink_rate))
1643+
err = ops->rate_node_parent_set(devlink_rate, parent,
1644+
devlink_rate->priv, parent->priv,
1645+
info->extack);
1646+
if (err)
1647+
return err;
1648+
1649+
refcount_inc(&parent->refcnt);
1650+
devlink_rate->parent = parent;
1651+
}
1652+
1653+
return 0;
1654+
}
1655+
15751656
static int devlink_nl_rate_set(struct devlink_rate *devlink_rate,
15761657
const struct devlink_ops *ops,
15771658
struct genl_info *info)
15781659
{
1579-
struct nlattr **attrs = info->attrs;
1660+
struct nlattr *nla_parent, **attrs = info->attrs;
15801661
int err = -EOPNOTSUPP;
15811662
u64 rate;
15821663

@@ -1606,6 +1687,14 @@ static int devlink_nl_rate_set(struct devlink_rate *devlink_rate,
16061687
devlink_rate->tx_max = rate;
16071688
}
16081689

1690+
nla_parent = attrs[DEVLINK_ATTR_RATE_PARENT_NODE_NAME];
1691+
if (nla_parent) {
1692+
err = devlink_nl_rate_parent_node_set(devlink_rate, info,
1693+
nla_parent);
1694+
if (err)
1695+
return err;
1696+
}
1697+
16091698
return 0;
16101699
}
16111700

@@ -1624,6 +1713,11 @@ static bool devlink_rate_set_ops_supported(const struct devlink_ops *ops,
16241713
NL_SET_ERR_MSG_MOD(info->extack, "TX max set isn't supported for the leafs");
16251714
return false;
16261715
}
1716+
if (attrs[DEVLINK_ATTR_RATE_PARENT_NODE_NAME] &&
1717+
!ops->rate_leaf_parent_set) {
1718+
NL_SET_ERR_MSG_MOD(info->extack, "Parent set isn't supported for the leafs");
1719+
return false;
1720+
}
16271721
} else if (type == DEVLINK_RATE_TYPE_NODE) {
16281722
if (attrs[DEVLINK_ATTR_RATE_TX_SHARE] && !ops->rate_node_tx_share_set) {
16291723
NL_SET_ERR_MSG_MOD(info->extack, "TX share set isn't supported for the nodes");
@@ -1633,6 +1727,11 @@ static bool devlink_rate_set_ops_supported(const struct devlink_ops *ops,
16331727
NL_SET_ERR_MSG_MOD(info->extack, "TX max set isn't supported for the nodes");
16341728
return false;
16351729
}
1730+
if (attrs[DEVLINK_ATTR_RATE_PARENT_NODE_NAME] &&
1731+
!ops->rate_node_parent_set) {
1732+
NL_SET_ERR_MSG_MOD(info->extack, "Parent set isn't supported for the nodes");
1733+
return false;
1734+
}
16361735
} else {
16371736
WARN_ON("Unknown type of rate object");
16381737
return false;
@@ -1702,6 +1801,7 @@ static int devlink_nl_cmd_rate_new_doit(struct sk_buff *skb,
17021801
if (err)
17031802
goto err_rate_set;
17041803

1804+
refcount_set(&rate_node->refcnt, 1);
17051805
list_add(&rate_node->list, &devlink->rate_list);
17061806
devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_NEW);
17071807
return 0;
@@ -1723,8 +1823,15 @@ static int devlink_nl_cmd_rate_del_doit(struct sk_buff *skb,
17231823
const struct devlink_ops *ops = devlink->ops;
17241824
int err;
17251825

1826+
if (refcount_read(&rate_node->refcnt) > 1) {
1827+
NL_SET_ERR_MSG_MOD(info->extack, "Node has children. Cannot delete node.");
1828+
return -EBUSY;
1829+
}
1830+
17261831
devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_DEL);
17271832
err = ops->rate_node_del(rate_node, rate_node->priv, info->extack);
1833+
if (rate_node->parent)
1834+
refcount_dec(&rate_node->parent->refcnt);
17281835
list_del(&rate_node->list);
17291836
kfree(rate_node->name);
17301837
kfree(rate_node);
@@ -8224,6 +8331,7 @@ static const struct nla_policy devlink_nl_policy[DEVLINK_ATTR_MAX + 1] = {
82248331
[DEVLINK_ATTR_RATE_TX_SHARE] = { .type = NLA_U64 },
82258332
[DEVLINK_ATTR_RATE_TX_MAX] = { .type = NLA_U64 },
82268333
[DEVLINK_ATTR_RATE_NODE_NAME] = { .type = NLA_NUL_STRING },
8334+
[DEVLINK_ATTR_RATE_PARENT_NODE_NAME] = { .type = NLA_NUL_STRING },
82278335
};
82288336

82298337
static const struct genl_small_ops devlink_nl_ops[] = {
@@ -9135,7 +9243,8 @@ EXPORT_SYMBOL_GPL(devlink_rate_leaf_destroy);
91359243
*
91369244
* @devlink: devlink instance
91379245
*
9138-
* Destroy all rate nodes on specified device
9246+
* Unset parent for all rate objects and destroy all rate nodes
9247+
* on specified device.
91399248
*
91409249
* Context: Takes and release devlink->lock <mutex>.
91419250
*/
@@ -9145,6 +9254,18 @@ void devlink_rate_nodes_destroy(struct devlink *devlink)
91459254
const struct devlink_ops *ops = devlink->ops;
91469255

91479256
mutex_lock(&devlink->lock);
9257+
list_for_each_entry(devlink_rate, &devlink->rate_list, list) {
9258+
if (!devlink_rate->parent)
9259+
continue;
9260+
9261+
refcount_dec(&devlink_rate->parent->refcnt);
9262+
if (devlink_rate_is_leaf(devlink_rate))
9263+
ops->rate_leaf_parent_set(devlink_rate, NULL, devlink_rate->priv,
9264+
NULL, NULL);
9265+
else if (devlink_rate_is_node(devlink_rate))
9266+
ops->rate_node_parent_set(devlink_rate, NULL, devlink_rate->priv,
9267+
NULL, NULL);
9268+
}
91489269
list_for_each_entry_safe(devlink_rate, tmp, &devlink->rate_list, list) {
91499270
if (devlink_rate_is_node(devlink_rate)) {
91509271
ops->rate_node_del(devlink_rate, devlink_rate->priv, NULL);

0 commit comments

Comments
 (0)