@@ -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+
11551172static 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+
15751656static 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
82298337static 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