xref: /openbmc/linux/net/devlink/rate.c (revision 7cc7194e)
1*7cc7194eSJiri Pirko // SPDX-License-Identifier: GPL-2.0-or-later
2*7cc7194eSJiri Pirko /*
3*7cc7194eSJiri Pirko  * Copyright (c) 2016 Mellanox Technologies. All rights reserved.
4*7cc7194eSJiri Pirko  * Copyright (c) 2016 Jiri Pirko <jiri@mellanox.com>
5*7cc7194eSJiri Pirko  */
6*7cc7194eSJiri Pirko 
7*7cc7194eSJiri Pirko #include "devl_internal.h"
8*7cc7194eSJiri Pirko 
9*7cc7194eSJiri Pirko static inline bool
devlink_rate_is_leaf(struct devlink_rate * devlink_rate)10*7cc7194eSJiri Pirko devlink_rate_is_leaf(struct devlink_rate *devlink_rate)
11*7cc7194eSJiri Pirko {
12*7cc7194eSJiri Pirko 	return devlink_rate->type == DEVLINK_RATE_TYPE_LEAF;
13*7cc7194eSJiri Pirko }
14*7cc7194eSJiri Pirko 
15*7cc7194eSJiri Pirko static inline bool
devlink_rate_is_node(struct devlink_rate * devlink_rate)16*7cc7194eSJiri Pirko devlink_rate_is_node(struct devlink_rate *devlink_rate)
17*7cc7194eSJiri Pirko {
18*7cc7194eSJiri Pirko 	return devlink_rate->type == DEVLINK_RATE_TYPE_NODE;
19*7cc7194eSJiri Pirko }
20*7cc7194eSJiri Pirko 
21*7cc7194eSJiri Pirko static struct devlink_rate *
devlink_rate_leaf_get_from_info(struct devlink * devlink,struct genl_info * info)22*7cc7194eSJiri Pirko devlink_rate_leaf_get_from_info(struct devlink *devlink, struct genl_info *info)
23*7cc7194eSJiri Pirko {
24*7cc7194eSJiri Pirko 	struct devlink_rate *devlink_rate;
25*7cc7194eSJiri Pirko 	struct devlink_port *devlink_port;
26*7cc7194eSJiri Pirko 
27*7cc7194eSJiri Pirko 	devlink_port = devlink_port_get_from_attrs(devlink, info->attrs);
28*7cc7194eSJiri Pirko 	if (IS_ERR(devlink_port))
29*7cc7194eSJiri Pirko 		return ERR_CAST(devlink_port);
30*7cc7194eSJiri Pirko 	devlink_rate = devlink_port->devlink_rate;
31*7cc7194eSJiri Pirko 	return devlink_rate ?: ERR_PTR(-ENODEV);
32*7cc7194eSJiri Pirko }
33*7cc7194eSJiri Pirko 
34*7cc7194eSJiri Pirko static struct devlink_rate *
devlink_rate_node_get_by_name(struct devlink * devlink,const char * node_name)35*7cc7194eSJiri Pirko devlink_rate_node_get_by_name(struct devlink *devlink, const char *node_name)
36*7cc7194eSJiri Pirko {
37*7cc7194eSJiri Pirko 	static struct devlink_rate *devlink_rate;
38*7cc7194eSJiri Pirko 
39*7cc7194eSJiri Pirko 	list_for_each_entry(devlink_rate, &devlink->rate_list, list) {
40*7cc7194eSJiri Pirko 		if (devlink_rate_is_node(devlink_rate) &&
41*7cc7194eSJiri Pirko 		    !strcmp(node_name, devlink_rate->name))
42*7cc7194eSJiri Pirko 			return devlink_rate;
43*7cc7194eSJiri Pirko 	}
44*7cc7194eSJiri Pirko 	return ERR_PTR(-ENODEV);
45*7cc7194eSJiri Pirko }
46*7cc7194eSJiri Pirko 
47*7cc7194eSJiri Pirko static struct devlink_rate *
devlink_rate_node_get_from_attrs(struct devlink * devlink,struct nlattr ** attrs)48*7cc7194eSJiri Pirko devlink_rate_node_get_from_attrs(struct devlink *devlink, struct nlattr **attrs)
49*7cc7194eSJiri Pirko {
50*7cc7194eSJiri Pirko 	const char *rate_node_name;
51*7cc7194eSJiri Pirko 	size_t len;
52*7cc7194eSJiri Pirko 
53*7cc7194eSJiri Pirko 	if (!attrs[DEVLINK_ATTR_RATE_NODE_NAME])
54*7cc7194eSJiri Pirko 		return ERR_PTR(-EINVAL);
55*7cc7194eSJiri Pirko 	rate_node_name = nla_data(attrs[DEVLINK_ATTR_RATE_NODE_NAME]);
56*7cc7194eSJiri Pirko 	len = strlen(rate_node_name);
57*7cc7194eSJiri Pirko 	/* Name cannot be empty or decimal number */
58*7cc7194eSJiri Pirko 	if (!len || strspn(rate_node_name, "0123456789") == len)
59*7cc7194eSJiri Pirko 		return ERR_PTR(-EINVAL);
60*7cc7194eSJiri Pirko 
61*7cc7194eSJiri Pirko 	return devlink_rate_node_get_by_name(devlink, rate_node_name);
62*7cc7194eSJiri Pirko }
63*7cc7194eSJiri Pirko 
64*7cc7194eSJiri Pirko static struct devlink_rate *
devlink_rate_node_get_from_info(struct devlink * devlink,struct genl_info * info)65*7cc7194eSJiri Pirko devlink_rate_node_get_from_info(struct devlink *devlink, struct genl_info *info)
66*7cc7194eSJiri Pirko {
67*7cc7194eSJiri Pirko 	return devlink_rate_node_get_from_attrs(devlink, info->attrs);
68*7cc7194eSJiri Pirko }
69*7cc7194eSJiri Pirko 
70*7cc7194eSJiri Pirko static struct devlink_rate *
devlink_rate_get_from_info(struct devlink * devlink,struct genl_info * info)71*7cc7194eSJiri Pirko devlink_rate_get_from_info(struct devlink *devlink, struct genl_info *info)
72*7cc7194eSJiri Pirko {
73*7cc7194eSJiri Pirko 	struct nlattr **attrs = info->attrs;
74*7cc7194eSJiri Pirko 
75*7cc7194eSJiri Pirko 	if (attrs[DEVLINK_ATTR_PORT_INDEX])
76*7cc7194eSJiri Pirko 		return devlink_rate_leaf_get_from_info(devlink, info);
77*7cc7194eSJiri Pirko 	else if (attrs[DEVLINK_ATTR_RATE_NODE_NAME])
78*7cc7194eSJiri Pirko 		return devlink_rate_node_get_from_info(devlink, info);
79*7cc7194eSJiri Pirko 	else
80*7cc7194eSJiri Pirko 		return ERR_PTR(-EINVAL);
81*7cc7194eSJiri Pirko }
82*7cc7194eSJiri Pirko 
devlink_nl_rate_fill(struct sk_buff * msg,struct devlink_rate * devlink_rate,enum devlink_command cmd,u32 portid,u32 seq,int flags,struct netlink_ext_ack * extack)83*7cc7194eSJiri Pirko static int devlink_nl_rate_fill(struct sk_buff *msg,
84*7cc7194eSJiri Pirko 				struct devlink_rate *devlink_rate,
85*7cc7194eSJiri Pirko 				enum devlink_command cmd, u32 portid, u32 seq,
86*7cc7194eSJiri Pirko 				int flags, struct netlink_ext_ack *extack)
87*7cc7194eSJiri Pirko {
88*7cc7194eSJiri Pirko 	struct devlink *devlink = devlink_rate->devlink;
89*7cc7194eSJiri Pirko 	void *hdr;
90*7cc7194eSJiri Pirko 
91*7cc7194eSJiri Pirko 	hdr = genlmsg_put(msg, portid, seq, &devlink_nl_family, flags, cmd);
92*7cc7194eSJiri Pirko 	if (!hdr)
93*7cc7194eSJiri Pirko 		return -EMSGSIZE;
94*7cc7194eSJiri Pirko 
95*7cc7194eSJiri Pirko 	if (devlink_nl_put_handle(msg, devlink))
96*7cc7194eSJiri Pirko 		goto nla_put_failure;
97*7cc7194eSJiri Pirko 
98*7cc7194eSJiri Pirko 	if (nla_put_u16(msg, DEVLINK_ATTR_RATE_TYPE, devlink_rate->type))
99*7cc7194eSJiri Pirko 		goto nla_put_failure;
100*7cc7194eSJiri Pirko 
101*7cc7194eSJiri Pirko 	if (devlink_rate_is_leaf(devlink_rate)) {
102*7cc7194eSJiri Pirko 		if (nla_put_u32(msg, DEVLINK_ATTR_PORT_INDEX,
103*7cc7194eSJiri Pirko 				devlink_rate->devlink_port->index))
104*7cc7194eSJiri Pirko 			goto nla_put_failure;
105*7cc7194eSJiri Pirko 	} else if (devlink_rate_is_node(devlink_rate)) {
106*7cc7194eSJiri Pirko 		if (nla_put_string(msg, DEVLINK_ATTR_RATE_NODE_NAME,
107*7cc7194eSJiri Pirko 				   devlink_rate->name))
108*7cc7194eSJiri Pirko 			goto nla_put_failure;
109*7cc7194eSJiri Pirko 	}
110*7cc7194eSJiri Pirko 
111*7cc7194eSJiri Pirko 	if (nla_put_u64_64bit(msg, DEVLINK_ATTR_RATE_TX_SHARE,
112*7cc7194eSJiri Pirko 			      devlink_rate->tx_share, DEVLINK_ATTR_PAD))
113*7cc7194eSJiri Pirko 		goto nla_put_failure;
114*7cc7194eSJiri Pirko 
115*7cc7194eSJiri Pirko 	if (nla_put_u64_64bit(msg, DEVLINK_ATTR_RATE_TX_MAX,
116*7cc7194eSJiri Pirko 			      devlink_rate->tx_max, DEVLINK_ATTR_PAD))
117*7cc7194eSJiri Pirko 		goto nla_put_failure;
118*7cc7194eSJiri Pirko 
119*7cc7194eSJiri Pirko 	if (nla_put_u32(msg, DEVLINK_ATTR_RATE_TX_PRIORITY,
120*7cc7194eSJiri Pirko 			devlink_rate->tx_priority))
121*7cc7194eSJiri Pirko 		goto nla_put_failure;
122*7cc7194eSJiri Pirko 
123*7cc7194eSJiri Pirko 	if (nla_put_u32(msg, DEVLINK_ATTR_RATE_TX_WEIGHT,
124*7cc7194eSJiri Pirko 			devlink_rate->tx_weight))
125*7cc7194eSJiri Pirko 		goto nla_put_failure;
126*7cc7194eSJiri Pirko 
127*7cc7194eSJiri Pirko 	if (devlink_rate->parent)
128*7cc7194eSJiri Pirko 		if (nla_put_string(msg, DEVLINK_ATTR_RATE_PARENT_NODE_NAME,
129*7cc7194eSJiri Pirko 				   devlink_rate->parent->name))
130*7cc7194eSJiri Pirko 			goto nla_put_failure;
131*7cc7194eSJiri Pirko 
132*7cc7194eSJiri Pirko 	genlmsg_end(msg, hdr);
133*7cc7194eSJiri Pirko 	return 0;
134*7cc7194eSJiri Pirko 
135*7cc7194eSJiri Pirko nla_put_failure:
136*7cc7194eSJiri Pirko 	genlmsg_cancel(msg, hdr);
137*7cc7194eSJiri Pirko 	return -EMSGSIZE;
138*7cc7194eSJiri Pirko }
139*7cc7194eSJiri Pirko 
devlink_rate_notify(struct devlink_rate * devlink_rate,enum devlink_command cmd)140*7cc7194eSJiri Pirko static void devlink_rate_notify(struct devlink_rate *devlink_rate,
141*7cc7194eSJiri Pirko 				enum devlink_command cmd)
142*7cc7194eSJiri Pirko {
143*7cc7194eSJiri Pirko 	struct devlink *devlink = devlink_rate->devlink;
144*7cc7194eSJiri Pirko 	struct sk_buff *msg;
145*7cc7194eSJiri Pirko 	int err;
146*7cc7194eSJiri Pirko 
147*7cc7194eSJiri Pirko 	WARN_ON(cmd != DEVLINK_CMD_RATE_NEW && cmd != DEVLINK_CMD_RATE_DEL);
148*7cc7194eSJiri Pirko 
149*7cc7194eSJiri Pirko 	if (!xa_get_mark(&devlinks, devlink->index, DEVLINK_REGISTERED))
150*7cc7194eSJiri Pirko 		return;
151*7cc7194eSJiri Pirko 
152*7cc7194eSJiri Pirko 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
153*7cc7194eSJiri Pirko 	if (!msg)
154*7cc7194eSJiri Pirko 		return;
155*7cc7194eSJiri Pirko 
156*7cc7194eSJiri Pirko 	err = devlink_nl_rate_fill(msg, devlink_rate, cmd, 0, 0, 0, NULL);
157*7cc7194eSJiri Pirko 	if (err) {
158*7cc7194eSJiri Pirko 		nlmsg_free(msg);
159*7cc7194eSJiri Pirko 		return;
160*7cc7194eSJiri Pirko 	}
161*7cc7194eSJiri Pirko 
162*7cc7194eSJiri Pirko 	genlmsg_multicast_netns(&devlink_nl_family, devlink_net(devlink), msg,
163*7cc7194eSJiri Pirko 				0, DEVLINK_MCGRP_CONFIG, GFP_KERNEL);
164*7cc7194eSJiri Pirko }
165*7cc7194eSJiri Pirko 
devlink_rates_notify_register(struct devlink * devlink)166*7cc7194eSJiri Pirko void devlink_rates_notify_register(struct devlink *devlink)
167*7cc7194eSJiri Pirko {
168*7cc7194eSJiri Pirko 	struct devlink_rate *rate_node;
169*7cc7194eSJiri Pirko 
170*7cc7194eSJiri Pirko 	list_for_each_entry(rate_node, &devlink->rate_list, list)
171*7cc7194eSJiri Pirko 		devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_NEW);
172*7cc7194eSJiri Pirko }
173*7cc7194eSJiri Pirko 
devlink_rates_notify_unregister(struct devlink * devlink)174*7cc7194eSJiri Pirko void devlink_rates_notify_unregister(struct devlink *devlink)
175*7cc7194eSJiri Pirko {
176*7cc7194eSJiri Pirko 	struct devlink_rate *rate_node;
177*7cc7194eSJiri Pirko 
178*7cc7194eSJiri Pirko 	list_for_each_entry_reverse(rate_node, &devlink->rate_list, list)
179*7cc7194eSJiri Pirko 		devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_DEL);
180*7cc7194eSJiri Pirko }
181*7cc7194eSJiri Pirko 
182*7cc7194eSJiri Pirko static int
devlink_nl_rate_get_dump_one(struct sk_buff * msg,struct devlink * devlink,struct netlink_callback * cb,int flags)183*7cc7194eSJiri Pirko devlink_nl_rate_get_dump_one(struct sk_buff *msg, struct devlink *devlink,
184*7cc7194eSJiri Pirko 			     struct netlink_callback *cb, int flags)
185*7cc7194eSJiri Pirko {
186*7cc7194eSJiri Pirko 	struct devlink_nl_dump_state *state = devlink_dump_state(cb);
187*7cc7194eSJiri Pirko 	struct devlink_rate *devlink_rate;
188*7cc7194eSJiri Pirko 	int idx = 0;
189*7cc7194eSJiri Pirko 	int err = 0;
190*7cc7194eSJiri Pirko 
191*7cc7194eSJiri Pirko 	list_for_each_entry(devlink_rate, &devlink->rate_list, list) {
192*7cc7194eSJiri Pirko 		enum devlink_command cmd = DEVLINK_CMD_RATE_NEW;
193*7cc7194eSJiri Pirko 		u32 id = NETLINK_CB(cb->skb).portid;
194*7cc7194eSJiri Pirko 
195*7cc7194eSJiri Pirko 		if (idx < state->idx) {
196*7cc7194eSJiri Pirko 			idx++;
197*7cc7194eSJiri Pirko 			continue;
198*7cc7194eSJiri Pirko 		}
199*7cc7194eSJiri Pirko 		err = devlink_nl_rate_fill(msg, devlink_rate, cmd, id,
200*7cc7194eSJiri Pirko 					   cb->nlh->nlmsg_seq, flags, NULL);
201*7cc7194eSJiri Pirko 		if (err) {
202*7cc7194eSJiri Pirko 			state->idx = idx;
203*7cc7194eSJiri Pirko 			break;
204*7cc7194eSJiri Pirko 		}
205*7cc7194eSJiri Pirko 		idx++;
206*7cc7194eSJiri Pirko 	}
207*7cc7194eSJiri Pirko 
208*7cc7194eSJiri Pirko 	return err;
209*7cc7194eSJiri Pirko }
210*7cc7194eSJiri Pirko 
devlink_nl_rate_get_dumpit(struct sk_buff * skb,struct netlink_callback * cb)211*7cc7194eSJiri Pirko int devlink_nl_rate_get_dumpit(struct sk_buff *skb, struct netlink_callback *cb)
212*7cc7194eSJiri Pirko {
213*7cc7194eSJiri Pirko 	return devlink_nl_dumpit(skb, cb, devlink_nl_rate_get_dump_one);
214*7cc7194eSJiri Pirko }
215*7cc7194eSJiri Pirko 
devlink_nl_rate_get_doit(struct sk_buff * skb,struct genl_info * info)216*7cc7194eSJiri Pirko int devlink_nl_rate_get_doit(struct sk_buff *skb, struct genl_info *info)
217*7cc7194eSJiri Pirko {
218*7cc7194eSJiri Pirko 	struct devlink *devlink = info->user_ptr[0];
219*7cc7194eSJiri Pirko 	struct devlink_rate *devlink_rate;
220*7cc7194eSJiri Pirko 	struct sk_buff *msg;
221*7cc7194eSJiri Pirko 	int err;
222*7cc7194eSJiri Pirko 
223*7cc7194eSJiri Pirko 	devlink_rate = devlink_rate_get_from_info(devlink, info);
224*7cc7194eSJiri Pirko 	if (IS_ERR(devlink_rate))
225*7cc7194eSJiri Pirko 		return PTR_ERR(devlink_rate);
226*7cc7194eSJiri Pirko 
227*7cc7194eSJiri Pirko 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
228*7cc7194eSJiri Pirko 	if (!msg)
229*7cc7194eSJiri Pirko 		return -ENOMEM;
230*7cc7194eSJiri Pirko 
231*7cc7194eSJiri Pirko 	err = devlink_nl_rate_fill(msg, devlink_rate, DEVLINK_CMD_RATE_NEW,
232*7cc7194eSJiri Pirko 				   info->snd_portid, info->snd_seq, 0,
233*7cc7194eSJiri Pirko 				   info->extack);
234*7cc7194eSJiri Pirko 	if (err) {
235*7cc7194eSJiri Pirko 		nlmsg_free(msg);
236*7cc7194eSJiri Pirko 		return err;
237*7cc7194eSJiri Pirko 	}
238*7cc7194eSJiri Pirko 
239*7cc7194eSJiri Pirko 	return genlmsg_reply(msg, info);
240*7cc7194eSJiri Pirko }
241*7cc7194eSJiri Pirko 
242*7cc7194eSJiri Pirko static bool
devlink_rate_is_parent_node(struct devlink_rate * devlink_rate,struct devlink_rate * parent)243*7cc7194eSJiri Pirko devlink_rate_is_parent_node(struct devlink_rate *devlink_rate,
244*7cc7194eSJiri Pirko 			    struct devlink_rate *parent)
245*7cc7194eSJiri Pirko {
246*7cc7194eSJiri Pirko 	while (parent) {
247*7cc7194eSJiri Pirko 		if (parent == devlink_rate)
248*7cc7194eSJiri Pirko 			return true;
249*7cc7194eSJiri Pirko 		parent = parent->parent;
250*7cc7194eSJiri Pirko 	}
251*7cc7194eSJiri Pirko 	return false;
252*7cc7194eSJiri Pirko }
253*7cc7194eSJiri Pirko 
254*7cc7194eSJiri Pirko static int
devlink_nl_rate_parent_node_set(struct devlink_rate * devlink_rate,struct genl_info * info,struct nlattr * nla_parent)255*7cc7194eSJiri Pirko devlink_nl_rate_parent_node_set(struct devlink_rate *devlink_rate,
256*7cc7194eSJiri Pirko 				struct genl_info *info,
257*7cc7194eSJiri Pirko 				struct nlattr *nla_parent)
258*7cc7194eSJiri Pirko {
259*7cc7194eSJiri Pirko 	struct devlink *devlink = devlink_rate->devlink;
260*7cc7194eSJiri Pirko 	const char *parent_name = nla_data(nla_parent);
261*7cc7194eSJiri Pirko 	const struct devlink_ops *ops = devlink->ops;
262*7cc7194eSJiri Pirko 	size_t len = strlen(parent_name);
263*7cc7194eSJiri Pirko 	struct devlink_rate *parent;
264*7cc7194eSJiri Pirko 	int err = -EOPNOTSUPP;
265*7cc7194eSJiri Pirko 
266*7cc7194eSJiri Pirko 	parent = devlink_rate->parent;
267*7cc7194eSJiri Pirko 
268*7cc7194eSJiri Pirko 	if (parent && !len) {
269*7cc7194eSJiri Pirko 		if (devlink_rate_is_leaf(devlink_rate))
270*7cc7194eSJiri Pirko 			err = ops->rate_leaf_parent_set(devlink_rate, NULL,
271*7cc7194eSJiri Pirko 							devlink_rate->priv, NULL,
272*7cc7194eSJiri Pirko 							info->extack);
273*7cc7194eSJiri Pirko 		else if (devlink_rate_is_node(devlink_rate))
274*7cc7194eSJiri Pirko 			err = ops->rate_node_parent_set(devlink_rate, NULL,
275*7cc7194eSJiri Pirko 							devlink_rate->priv, NULL,
276*7cc7194eSJiri Pirko 							info->extack);
277*7cc7194eSJiri Pirko 		if (err)
278*7cc7194eSJiri Pirko 			return err;
279*7cc7194eSJiri Pirko 
280*7cc7194eSJiri Pirko 		refcount_dec(&parent->refcnt);
281*7cc7194eSJiri Pirko 		devlink_rate->parent = NULL;
282*7cc7194eSJiri Pirko 	} else if (len) {
283*7cc7194eSJiri Pirko 		parent = devlink_rate_node_get_by_name(devlink, parent_name);
284*7cc7194eSJiri Pirko 		if (IS_ERR(parent))
285*7cc7194eSJiri Pirko 			return -ENODEV;
286*7cc7194eSJiri Pirko 
287*7cc7194eSJiri Pirko 		if (parent == devlink_rate) {
288*7cc7194eSJiri Pirko 			NL_SET_ERR_MSG(info->extack, "Parent to self is not allowed");
289*7cc7194eSJiri Pirko 			return -EINVAL;
290*7cc7194eSJiri Pirko 		}
291*7cc7194eSJiri Pirko 
292*7cc7194eSJiri Pirko 		if (devlink_rate_is_node(devlink_rate) &&
293*7cc7194eSJiri Pirko 		    devlink_rate_is_parent_node(devlink_rate, parent->parent)) {
294*7cc7194eSJiri Pirko 			NL_SET_ERR_MSG(info->extack, "Node is already a parent of parent node.");
295*7cc7194eSJiri Pirko 			return -EEXIST;
296*7cc7194eSJiri Pirko 		}
297*7cc7194eSJiri Pirko 
298*7cc7194eSJiri Pirko 		if (devlink_rate_is_leaf(devlink_rate))
299*7cc7194eSJiri Pirko 			err = ops->rate_leaf_parent_set(devlink_rate, parent,
300*7cc7194eSJiri Pirko 							devlink_rate->priv, parent->priv,
301*7cc7194eSJiri Pirko 							info->extack);
302*7cc7194eSJiri Pirko 		else if (devlink_rate_is_node(devlink_rate))
303*7cc7194eSJiri Pirko 			err = ops->rate_node_parent_set(devlink_rate, parent,
304*7cc7194eSJiri Pirko 							devlink_rate->priv, parent->priv,
305*7cc7194eSJiri Pirko 							info->extack);
306*7cc7194eSJiri Pirko 		if (err)
307*7cc7194eSJiri Pirko 			return err;
308*7cc7194eSJiri Pirko 
309*7cc7194eSJiri Pirko 		if (devlink_rate->parent)
310*7cc7194eSJiri Pirko 			/* we're reassigning to other parent in this case */
311*7cc7194eSJiri Pirko 			refcount_dec(&devlink_rate->parent->refcnt);
312*7cc7194eSJiri Pirko 
313*7cc7194eSJiri Pirko 		refcount_inc(&parent->refcnt);
314*7cc7194eSJiri Pirko 		devlink_rate->parent = parent;
315*7cc7194eSJiri Pirko 	}
316*7cc7194eSJiri Pirko 
317*7cc7194eSJiri Pirko 	return 0;
318*7cc7194eSJiri Pirko }
319*7cc7194eSJiri Pirko 
devlink_nl_rate_set(struct devlink_rate * devlink_rate,const struct devlink_ops * ops,struct genl_info * info)320*7cc7194eSJiri Pirko static int devlink_nl_rate_set(struct devlink_rate *devlink_rate,
321*7cc7194eSJiri Pirko 			       const struct devlink_ops *ops,
322*7cc7194eSJiri Pirko 			       struct genl_info *info)
323*7cc7194eSJiri Pirko {
324*7cc7194eSJiri Pirko 	struct nlattr *nla_parent, **attrs = info->attrs;
325*7cc7194eSJiri Pirko 	int err = -EOPNOTSUPP;
326*7cc7194eSJiri Pirko 	u32 priority;
327*7cc7194eSJiri Pirko 	u32 weight;
328*7cc7194eSJiri Pirko 	u64 rate;
329*7cc7194eSJiri Pirko 
330*7cc7194eSJiri Pirko 	if (attrs[DEVLINK_ATTR_RATE_TX_SHARE]) {
331*7cc7194eSJiri Pirko 		rate = nla_get_u64(attrs[DEVLINK_ATTR_RATE_TX_SHARE]);
332*7cc7194eSJiri Pirko 		if (devlink_rate_is_leaf(devlink_rate))
333*7cc7194eSJiri Pirko 			err = ops->rate_leaf_tx_share_set(devlink_rate, devlink_rate->priv,
334*7cc7194eSJiri Pirko 							  rate, info->extack);
335*7cc7194eSJiri Pirko 		else if (devlink_rate_is_node(devlink_rate))
336*7cc7194eSJiri Pirko 			err = ops->rate_node_tx_share_set(devlink_rate, devlink_rate->priv,
337*7cc7194eSJiri Pirko 							  rate, info->extack);
338*7cc7194eSJiri Pirko 		if (err)
339*7cc7194eSJiri Pirko 			return err;
340*7cc7194eSJiri Pirko 		devlink_rate->tx_share = rate;
341*7cc7194eSJiri Pirko 	}
342*7cc7194eSJiri Pirko 
343*7cc7194eSJiri Pirko 	if (attrs[DEVLINK_ATTR_RATE_TX_MAX]) {
344*7cc7194eSJiri Pirko 		rate = nla_get_u64(attrs[DEVLINK_ATTR_RATE_TX_MAX]);
345*7cc7194eSJiri Pirko 		if (devlink_rate_is_leaf(devlink_rate))
346*7cc7194eSJiri Pirko 			err = ops->rate_leaf_tx_max_set(devlink_rate, devlink_rate->priv,
347*7cc7194eSJiri Pirko 							rate, info->extack);
348*7cc7194eSJiri Pirko 		else if (devlink_rate_is_node(devlink_rate))
349*7cc7194eSJiri Pirko 			err = ops->rate_node_tx_max_set(devlink_rate, devlink_rate->priv,
350*7cc7194eSJiri Pirko 							rate, info->extack);
351*7cc7194eSJiri Pirko 		if (err)
352*7cc7194eSJiri Pirko 			return err;
353*7cc7194eSJiri Pirko 		devlink_rate->tx_max = rate;
354*7cc7194eSJiri Pirko 	}
355*7cc7194eSJiri Pirko 
356*7cc7194eSJiri Pirko 	if (attrs[DEVLINK_ATTR_RATE_TX_PRIORITY]) {
357*7cc7194eSJiri Pirko 		priority = nla_get_u32(attrs[DEVLINK_ATTR_RATE_TX_PRIORITY]);
358*7cc7194eSJiri Pirko 		if (devlink_rate_is_leaf(devlink_rate))
359*7cc7194eSJiri Pirko 			err = ops->rate_leaf_tx_priority_set(devlink_rate, devlink_rate->priv,
360*7cc7194eSJiri Pirko 							     priority, info->extack);
361*7cc7194eSJiri Pirko 		else if (devlink_rate_is_node(devlink_rate))
362*7cc7194eSJiri Pirko 			err = ops->rate_node_tx_priority_set(devlink_rate, devlink_rate->priv,
363*7cc7194eSJiri Pirko 							     priority, info->extack);
364*7cc7194eSJiri Pirko 
365*7cc7194eSJiri Pirko 		if (err)
366*7cc7194eSJiri Pirko 			return err;
367*7cc7194eSJiri Pirko 		devlink_rate->tx_priority = priority;
368*7cc7194eSJiri Pirko 	}
369*7cc7194eSJiri Pirko 
370*7cc7194eSJiri Pirko 	if (attrs[DEVLINK_ATTR_RATE_TX_WEIGHT]) {
371*7cc7194eSJiri Pirko 		weight = nla_get_u32(attrs[DEVLINK_ATTR_RATE_TX_WEIGHT]);
372*7cc7194eSJiri Pirko 		if (devlink_rate_is_leaf(devlink_rate))
373*7cc7194eSJiri Pirko 			err = ops->rate_leaf_tx_weight_set(devlink_rate, devlink_rate->priv,
374*7cc7194eSJiri Pirko 							   weight, info->extack);
375*7cc7194eSJiri Pirko 		else if (devlink_rate_is_node(devlink_rate))
376*7cc7194eSJiri Pirko 			err = ops->rate_node_tx_weight_set(devlink_rate, devlink_rate->priv,
377*7cc7194eSJiri Pirko 							   weight, info->extack);
378*7cc7194eSJiri Pirko 
379*7cc7194eSJiri Pirko 		if (err)
380*7cc7194eSJiri Pirko 			return err;
381*7cc7194eSJiri Pirko 		devlink_rate->tx_weight = weight;
382*7cc7194eSJiri Pirko 	}
383*7cc7194eSJiri Pirko 
384*7cc7194eSJiri Pirko 	nla_parent = attrs[DEVLINK_ATTR_RATE_PARENT_NODE_NAME];
385*7cc7194eSJiri Pirko 	if (nla_parent) {
386*7cc7194eSJiri Pirko 		err = devlink_nl_rate_parent_node_set(devlink_rate, info,
387*7cc7194eSJiri Pirko 						      nla_parent);
388*7cc7194eSJiri Pirko 		if (err)
389*7cc7194eSJiri Pirko 			return err;
390*7cc7194eSJiri Pirko 	}
391*7cc7194eSJiri Pirko 
392*7cc7194eSJiri Pirko 	return 0;
393*7cc7194eSJiri Pirko }
394*7cc7194eSJiri Pirko 
devlink_rate_set_ops_supported(const struct devlink_ops * ops,struct genl_info * info,enum devlink_rate_type type)395*7cc7194eSJiri Pirko static bool devlink_rate_set_ops_supported(const struct devlink_ops *ops,
396*7cc7194eSJiri Pirko 					   struct genl_info *info,
397*7cc7194eSJiri Pirko 					   enum devlink_rate_type type)
398*7cc7194eSJiri Pirko {
399*7cc7194eSJiri Pirko 	struct nlattr **attrs = info->attrs;
400*7cc7194eSJiri Pirko 
401*7cc7194eSJiri Pirko 	if (type == DEVLINK_RATE_TYPE_LEAF) {
402*7cc7194eSJiri Pirko 		if (attrs[DEVLINK_ATTR_RATE_TX_SHARE] && !ops->rate_leaf_tx_share_set) {
403*7cc7194eSJiri Pirko 			NL_SET_ERR_MSG(info->extack, "TX share set isn't supported for the leafs");
404*7cc7194eSJiri Pirko 			return false;
405*7cc7194eSJiri Pirko 		}
406*7cc7194eSJiri Pirko 		if (attrs[DEVLINK_ATTR_RATE_TX_MAX] && !ops->rate_leaf_tx_max_set) {
407*7cc7194eSJiri Pirko 			NL_SET_ERR_MSG(info->extack, "TX max set isn't supported for the leafs");
408*7cc7194eSJiri Pirko 			return false;
409*7cc7194eSJiri Pirko 		}
410*7cc7194eSJiri Pirko 		if (attrs[DEVLINK_ATTR_RATE_PARENT_NODE_NAME] &&
411*7cc7194eSJiri Pirko 		    !ops->rate_leaf_parent_set) {
412*7cc7194eSJiri Pirko 			NL_SET_ERR_MSG(info->extack, "Parent set isn't supported for the leafs");
413*7cc7194eSJiri Pirko 			return false;
414*7cc7194eSJiri Pirko 		}
415*7cc7194eSJiri Pirko 		if (attrs[DEVLINK_ATTR_RATE_TX_PRIORITY] && !ops->rate_leaf_tx_priority_set) {
416*7cc7194eSJiri Pirko 			NL_SET_ERR_MSG_ATTR(info->extack,
417*7cc7194eSJiri Pirko 					    attrs[DEVLINK_ATTR_RATE_TX_PRIORITY],
418*7cc7194eSJiri Pirko 					    "TX priority set isn't supported for the leafs");
419*7cc7194eSJiri Pirko 			return false;
420*7cc7194eSJiri Pirko 		}
421*7cc7194eSJiri Pirko 		if (attrs[DEVLINK_ATTR_RATE_TX_WEIGHT] && !ops->rate_leaf_tx_weight_set) {
422*7cc7194eSJiri Pirko 			NL_SET_ERR_MSG_ATTR(info->extack,
423*7cc7194eSJiri Pirko 					    attrs[DEVLINK_ATTR_RATE_TX_WEIGHT],
424*7cc7194eSJiri Pirko 					    "TX weight set isn't supported for the leafs");
425*7cc7194eSJiri Pirko 			return false;
426*7cc7194eSJiri Pirko 		}
427*7cc7194eSJiri Pirko 	} else if (type == DEVLINK_RATE_TYPE_NODE) {
428*7cc7194eSJiri Pirko 		if (attrs[DEVLINK_ATTR_RATE_TX_SHARE] && !ops->rate_node_tx_share_set) {
429*7cc7194eSJiri Pirko 			NL_SET_ERR_MSG(info->extack, "TX share set isn't supported for the nodes");
430*7cc7194eSJiri Pirko 			return false;
431*7cc7194eSJiri Pirko 		}
432*7cc7194eSJiri Pirko 		if (attrs[DEVLINK_ATTR_RATE_TX_MAX] && !ops->rate_node_tx_max_set) {
433*7cc7194eSJiri Pirko 			NL_SET_ERR_MSG(info->extack, "TX max set isn't supported for the nodes");
434*7cc7194eSJiri Pirko 			return false;
435*7cc7194eSJiri Pirko 		}
436*7cc7194eSJiri Pirko 		if (attrs[DEVLINK_ATTR_RATE_PARENT_NODE_NAME] &&
437*7cc7194eSJiri Pirko 		    !ops->rate_node_parent_set) {
438*7cc7194eSJiri Pirko 			NL_SET_ERR_MSG(info->extack, "Parent set isn't supported for the nodes");
439*7cc7194eSJiri Pirko 			return false;
440*7cc7194eSJiri Pirko 		}
441*7cc7194eSJiri Pirko 		if (attrs[DEVLINK_ATTR_RATE_TX_PRIORITY] && !ops->rate_node_tx_priority_set) {
442*7cc7194eSJiri Pirko 			NL_SET_ERR_MSG_ATTR(info->extack,
443*7cc7194eSJiri Pirko 					    attrs[DEVLINK_ATTR_RATE_TX_PRIORITY],
444*7cc7194eSJiri Pirko 					    "TX priority set isn't supported for the nodes");
445*7cc7194eSJiri Pirko 			return false;
446*7cc7194eSJiri Pirko 		}
447*7cc7194eSJiri Pirko 		if (attrs[DEVLINK_ATTR_RATE_TX_WEIGHT] && !ops->rate_node_tx_weight_set) {
448*7cc7194eSJiri Pirko 			NL_SET_ERR_MSG_ATTR(info->extack,
449*7cc7194eSJiri Pirko 					    attrs[DEVLINK_ATTR_RATE_TX_WEIGHT],
450*7cc7194eSJiri Pirko 					    "TX weight set isn't supported for the nodes");
451*7cc7194eSJiri Pirko 			return false;
452*7cc7194eSJiri Pirko 		}
453*7cc7194eSJiri Pirko 	} else {
454*7cc7194eSJiri Pirko 		WARN(1, "Unknown type of rate object");
455*7cc7194eSJiri Pirko 		return false;
456*7cc7194eSJiri Pirko 	}
457*7cc7194eSJiri Pirko 
458*7cc7194eSJiri Pirko 	return true;
459*7cc7194eSJiri Pirko }
460*7cc7194eSJiri Pirko 
devlink_nl_cmd_rate_set_doit(struct sk_buff * skb,struct genl_info * info)461*7cc7194eSJiri Pirko int devlink_nl_cmd_rate_set_doit(struct sk_buff *skb, struct genl_info *info)
462*7cc7194eSJiri Pirko {
463*7cc7194eSJiri Pirko 	struct devlink *devlink = info->user_ptr[0];
464*7cc7194eSJiri Pirko 	struct devlink_rate *devlink_rate;
465*7cc7194eSJiri Pirko 	const struct devlink_ops *ops;
466*7cc7194eSJiri Pirko 	int err;
467*7cc7194eSJiri Pirko 
468*7cc7194eSJiri Pirko 	devlink_rate = devlink_rate_get_from_info(devlink, info);
469*7cc7194eSJiri Pirko 	if (IS_ERR(devlink_rate))
470*7cc7194eSJiri Pirko 		return PTR_ERR(devlink_rate);
471*7cc7194eSJiri Pirko 
472*7cc7194eSJiri Pirko 	ops = devlink->ops;
473*7cc7194eSJiri Pirko 	if (!ops || !devlink_rate_set_ops_supported(ops, info, devlink_rate->type))
474*7cc7194eSJiri Pirko 		return -EOPNOTSUPP;
475*7cc7194eSJiri Pirko 
476*7cc7194eSJiri Pirko 	err = devlink_nl_rate_set(devlink_rate, ops, info);
477*7cc7194eSJiri Pirko 
478*7cc7194eSJiri Pirko 	if (!err)
479*7cc7194eSJiri Pirko 		devlink_rate_notify(devlink_rate, DEVLINK_CMD_RATE_NEW);
480*7cc7194eSJiri Pirko 	return err;
481*7cc7194eSJiri Pirko }
482*7cc7194eSJiri Pirko 
devlink_nl_cmd_rate_new_doit(struct sk_buff * skb,struct genl_info * info)483*7cc7194eSJiri Pirko int devlink_nl_cmd_rate_new_doit(struct sk_buff *skb, struct genl_info *info)
484*7cc7194eSJiri Pirko {
485*7cc7194eSJiri Pirko 	struct devlink *devlink = info->user_ptr[0];
486*7cc7194eSJiri Pirko 	struct devlink_rate *rate_node;
487*7cc7194eSJiri Pirko 	const struct devlink_ops *ops;
488*7cc7194eSJiri Pirko 	int err;
489*7cc7194eSJiri Pirko 
490*7cc7194eSJiri Pirko 	ops = devlink->ops;
491*7cc7194eSJiri Pirko 	if (!ops || !ops->rate_node_new || !ops->rate_node_del) {
492*7cc7194eSJiri Pirko 		NL_SET_ERR_MSG(info->extack, "Rate nodes aren't supported");
493*7cc7194eSJiri Pirko 		return -EOPNOTSUPP;
494*7cc7194eSJiri Pirko 	}
495*7cc7194eSJiri Pirko 
496*7cc7194eSJiri Pirko 	if (!devlink_rate_set_ops_supported(ops, info, DEVLINK_RATE_TYPE_NODE))
497*7cc7194eSJiri Pirko 		return -EOPNOTSUPP;
498*7cc7194eSJiri Pirko 
499*7cc7194eSJiri Pirko 	rate_node = devlink_rate_node_get_from_attrs(devlink, info->attrs);
500*7cc7194eSJiri Pirko 	if (!IS_ERR(rate_node))
501*7cc7194eSJiri Pirko 		return -EEXIST;
502*7cc7194eSJiri Pirko 	else if (rate_node == ERR_PTR(-EINVAL))
503*7cc7194eSJiri Pirko 		return -EINVAL;
504*7cc7194eSJiri Pirko 
505*7cc7194eSJiri Pirko 	rate_node = kzalloc(sizeof(*rate_node), GFP_KERNEL);
506*7cc7194eSJiri Pirko 	if (!rate_node)
507*7cc7194eSJiri Pirko 		return -ENOMEM;
508*7cc7194eSJiri Pirko 
509*7cc7194eSJiri Pirko 	rate_node->devlink = devlink;
510*7cc7194eSJiri Pirko 	rate_node->type = DEVLINK_RATE_TYPE_NODE;
511*7cc7194eSJiri Pirko 	rate_node->name = nla_strdup(info->attrs[DEVLINK_ATTR_RATE_NODE_NAME], GFP_KERNEL);
512*7cc7194eSJiri Pirko 	if (!rate_node->name) {
513*7cc7194eSJiri Pirko 		err = -ENOMEM;
514*7cc7194eSJiri Pirko 		goto err_strdup;
515*7cc7194eSJiri Pirko 	}
516*7cc7194eSJiri Pirko 
517*7cc7194eSJiri Pirko 	err = ops->rate_node_new(rate_node, &rate_node->priv, info->extack);
518*7cc7194eSJiri Pirko 	if (err)
519*7cc7194eSJiri Pirko 		goto err_node_new;
520*7cc7194eSJiri Pirko 
521*7cc7194eSJiri Pirko 	err = devlink_nl_rate_set(rate_node, ops, info);
522*7cc7194eSJiri Pirko 	if (err)
523*7cc7194eSJiri Pirko 		goto err_rate_set;
524*7cc7194eSJiri Pirko 
525*7cc7194eSJiri Pirko 	refcount_set(&rate_node->refcnt, 1);
526*7cc7194eSJiri Pirko 	list_add(&rate_node->list, &devlink->rate_list);
527*7cc7194eSJiri Pirko 	devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_NEW);
528*7cc7194eSJiri Pirko 	return 0;
529*7cc7194eSJiri Pirko 
530*7cc7194eSJiri Pirko err_rate_set:
531*7cc7194eSJiri Pirko 	ops->rate_node_del(rate_node, rate_node->priv, info->extack);
532*7cc7194eSJiri Pirko err_node_new:
533*7cc7194eSJiri Pirko 	kfree(rate_node->name);
534*7cc7194eSJiri Pirko err_strdup:
535*7cc7194eSJiri Pirko 	kfree(rate_node);
536*7cc7194eSJiri Pirko 	return err;
537*7cc7194eSJiri Pirko }
538*7cc7194eSJiri Pirko 
devlink_nl_cmd_rate_del_doit(struct sk_buff * skb,struct genl_info * info)539*7cc7194eSJiri Pirko int devlink_nl_cmd_rate_del_doit(struct sk_buff *skb, struct genl_info *info)
540*7cc7194eSJiri Pirko {
541*7cc7194eSJiri Pirko 	struct devlink *devlink = info->user_ptr[0];
542*7cc7194eSJiri Pirko 	struct devlink_rate *rate_node;
543*7cc7194eSJiri Pirko 	int err;
544*7cc7194eSJiri Pirko 
545*7cc7194eSJiri Pirko 	rate_node = devlink_rate_node_get_from_info(devlink, info);
546*7cc7194eSJiri Pirko 	if (IS_ERR(rate_node))
547*7cc7194eSJiri Pirko 		return PTR_ERR(rate_node);
548*7cc7194eSJiri Pirko 
549*7cc7194eSJiri Pirko 	if (refcount_read(&rate_node->refcnt) > 1) {
550*7cc7194eSJiri Pirko 		NL_SET_ERR_MSG(info->extack, "Node has children. Cannot delete node.");
551*7cc7194eSJiri Pirko 		return -EBUSY;
552*7cc7194eSJiri Pirko 	}
553*7cc7194eSJiri Pirko 
554*7cc7194eSJiri Pirko 	devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_DEL);
555*7cc7194eSJiri Pirko 	err = devlink->ops->rate_node_del(rate_node, rate_node->priv,
556*7cc7194eSJiri Pirko 					  info->extack);
557*7cc7194eSJiri Pirko 	if (rate_node->parent)
558*7cc7194eSJiri Pirko 		refcount_dec(&rate_node->parent->refcnt);
559*7cc7194eSJiri Pirko 	list_del(&rate_node->list);
560*7cc7194eSJiri Pirko 	kfree(rate_node->name);
561*7cc7194eSJiri Pirko 	kfree(rate_node);
562*7cc7194eSJiri Pirko 	return err;
563*7cc7194eSJiri Pirko }
564*7cc7194eSJiri Pirko 
devlink_rate_nodes_check(struct devlink * devlink,u16 mode,struct netlink_ext_ack * extack)565*7cc7194eSJiri Pirko int devlink_rate_nodes_check(struct devlink *devlink, u16 mode,
566*7cc7194eSJiri Pirko 			     struct netlink_ext_ack *extack)
567*7cc7194eSJiri Pirko {
568*7cc7194eSJiri Pirko 	struct devlink_rate *devlink_rate;
569*7cc7194eSJiri Pirko 
570*7cc7194eSJiri Pirko 	list_for_each_entry(devlink_rate, &devlink->rate_list, list)
571*7cc7194eSJiri Pirko 		if (devlink_rate_is_node(devlink_rate)) {
572*7cc7194eSJiri Pirko 			NL_SET_ERR_MSG(extack, "Rate node(s) exists.");
573*7cc7194eSJiri Pirko 			return -EBUSY;
574*7cc7194eSJiri Pirko 		}
575*7cc7194eSJiri Pirko 	return 0;
576*7cc7194eSJiri Pirko }
577*7cc7194eSJiri Pirko 
578*7cc7194eSJiri Pirko /**
579*7cc7194eSJiri Pirko  * devl_rate_node_create - create devlink rate node
580*7cc7194eSJiri Pirko  * @devlink: devlink instance
581*7cc7194eSJiri Pirko  * @priv: driver private data
582*7cc7194eSJiri Pirko  * @node_name: name of the resulting node
583*7cc7194eSJiri Pirko  * @parent: parent devlink_rate struct
584*7cc7194eSJiri Pirko  *
585*7cc7194eSJiri Pirko  * Create devlink rate object of type node
586*7cc7194eSJiri Pirko  */
587*7cc7194eSJiri Pirko struct devlink_rate *
devl_rate_node_create(struct devlink * devlink,void * priv,char * node_name,struct devlink_rate * parent)588*7cc7194eSJiri Pirko devl_rate_node_create(struct devlink *devlink, void *priv, char *node_name,
589*7cc7194eSJiri Pirko 		      struct devlink_rate *parent)
590*7cc7194eSJiri Pirko {
591*7cc7194eSJiri Pirko 	struct devlink_rate *rate_node;
592*7cc7194eSJiri Pirko 
593*7cc7194eSJiri Pirko 	rate_node = devlink_rate_node_get_by_name(devlink, node_name);
594*7cc7194eSJiri Pirko 	if (!IS_ERR(rate_node))
595*7cc7194eSJiri Pirko 		return ERR_PTR(-EEXIST);
596*7cc7194eSJiri Pirko 
597*7cc7194eSJiri Pirko 	rate_node = kzalloc(sizeof(*rate_node), GFP_KERNEL);
598*7cc7194eSJiri Pirko 	if (!rate_node)
599*7cc7194eSJiri Pirko 		return ERR_PTR(-ENOMEM);
600*7cc7194eSJiri Pirko 
601*7cc7194eSJiri Pirko 	if (parent) {
602*7cc7194eSJiri Pirko 		rate_node->parent = parent;
603*7cc7194eSJiri Pirko 		refcount_inc(&rate_node->parent->refcnt);
604*7cc7194eSJiri Pirko 	}
605*7cc7194eSJiri Pirko 
606*7cc7194eSJiri Pirko 	rate_node->type = DEVLINK_RATE_TYPE_NODE;
607*7cc7194eSJiri Pirko 	rate_node->devlink = devlink;
608*7cc7194eSJiri Pirko 	rate_node->priv = priv;
609*7cc7194eSJiri Pirko 
610*7cc7194eSJiri Pirko 	rate_node->name = kstrdup(node_name, GFP_KERNEL);
611*7cc7194eSJiri Pirko 	if (!rate_node->name) {
612*7cc7194eSJiri Pirko 		kfree(rate_node);
613*7cc7194eSJiri Pirko 		return ERR_PTR(-ENOMEM);
614*7cc7194eSJiri Pirko 	}
615*7cc7194eSJiri Pirko 
616*7cc7194eSJiri Pirko 	refcount_set(&rate_node->refcnt, 1);
617*7cc7194eSJiri Pirko 	list_add(&rate_node->list, &devlink->rate_list);
618*7cc7194eSJiri Pirko 	devlink_rate_notify(rate_node, DEVLINK_CMD_RATE_NEW);
619*7cc7194eSJiri Pirko 	return rate_node;
620*7cc7194eSJiri Pirko }
621*7cc7194eSJiri Pirko EXPORT_SYMBOL_GPL(devl_rate_node_create);
622*7cc7194eSJiri Pirko 
623*7cc7194eSJiri Pirko /**
624*7cc7194eSJiri Pirko  * devl_rate_leaf_create - create devlink rate leaf
625*7cc7194eSJiri Pirko  * @devlink_port: devlink port object to create rate object on
626*7cc7194eSJiri Pirko  * @priv: driver private data
627*7cc7194eSJiri Pirko  * @parent: parent devlink_rate struct
628*7cc7194eSJiri Pirko  *
629*7cc7194eSJiri Pirko  * Create devlink rate object of type leaf on provided @devlink_port.
630*7cc7194eSJiri Pirko  */
devl_rate_leaf_create(struct devlink_port * devlink_port,void * priv,struct devlink_rate * parent)631*7cc7194eSJiri Pirko int devl_rate_leaf_create(struct devlink_port *devlink_port, void *priv,
632*7cc7194eSJiri Pirko 			  struct devlink_rate *parent)
633*7cc7194eSJiri Pirko {
634*7cc7194eSJiri Pirko 	struct devlink *devlink = devlink_port->devlink;
635*7cc7194eSJiri Pirko 	struct devlink_rate *devlink_rate;
636*7cc7194eSJiri Pirko 
637*7cc7194eSJiri Pirko 	devl_assert_locked(devlink_port->devlink);
638*7cc7194eSJiri Pirko 
639*7cc7194eSJiri Pirko 	if (WARN_ON(devlink_port->devlink_rate))
640*7cc7194eSJiri Pirko 		return -EBUSY;
641*7cc7194eSJiri Pirko 
642*7cc7194eSJiri Pirko 	devlink_rate = kzalloc(sizeof(*devlink_rate), GFP_KERNEL);
643*7cc7194eSJiri Pirko 	if (!devlink_rate)
644*7cc7194eSJiri Pirko 		return -ENOMEM;
645*7cc7194eSJiri Pirko 
646*7cc7194eSJiri Pirko 	if (parent) {
647*7cc7194eSJiri Pirko 		devlink_rate->parent = parent;
648*7cc7194eSJiri Pirko 		refcount_inc(&devlink_rate->parent->refcnt);
649*7cc7194eSJiri Pirko 	}
650*7cc7194eSJiri Pirko 
651*7cc7194eSJiri Pirko 	devlink_rate->type = DEVLINK_RATE_TYPE_LEAF;
652*7cc7194eSJiri Pirko 	devlink_rate->devlink = devlink;
653*7cc7194eSJiri Pirko 	devlink_rate->devlink_port = devlink_port;
654*7cc7194eSJiri Pirko 	devlink_rate->priv = priv;
655*7cc7194eSJiri Pirko 	list_add_tail(&devlink_rate->list, &devlink->rate_list);
656*7cc7194eSJiri Pirko 	devlink_port->devlink_rate = devlink_rate;
657*7cc7194eSJiri Pirko 	devlink_rate_notify(devlink_rate, DEVLINK_CMD_RATE_NEW);
658*7cc7194eSJiri Pirko 
659*7cc7194eSJiri Pirko 	return 0;
660*7cc7194eSJiri Pirko }
661*7cc7194eSJiri Pirko EXPORT_SYMBOL_GPL(devl_rate_leaf_create);
662*7cc7194eSJiri Pirko 
663*7cc7194eSJiri Pirko /**
664*7cc7194eSJiri Pirko  * devl_rate_leaf_destroy - destroy devlink rate leaf
665*7cc7194eSJiri Pirko  *
666*7cc7194eSJiri Pirko  * @devlink_port: devlink port linked to the rate object
667*7cc7194eSJiri Pirko  *
668*7cc7194eSJiri Pirko  * Destroy the devlink rate object of type leaf on provided @devlink_port.
669*7cc7194eSJiri Pirko  */
devl_rate_leaf_destroy(struct devlink_port * devlink_port)670*7cc7194eSJiri Pirko void devl_rate_leaf_destroy(struct devlink_port *devlink_port)
671*7cc7194eSJiri Pirko {
672*7cc7194eSJiri Pirko 	struct devlink_rate *devlink_rate = devlink_port->devlink_rate;
673*7cc7194eSJiri Pirko 
674*7cc7194eSJiri Pirko 	devl_assert_locked(devlink_port->devlink);
675*7cc7194eSJiri Pirko 	if (!devlink_rate)
676*7cc7194eSJiri Pirko 		return;
677*7cc7194eSJiri Pirko 
678*7cc7194eSJiri Pirko 	devlink_rate_notify(devlink_rate, DEVLINK_CMD_RATE_DEL);
679*7cc7194eSJiri Pirko 	if (devlink_rate->parent)
680*7cc7194eSJiri Pirko 		refcount_dec(&devlink_rate->parent->refcnt);
681*7cc7194eSJiri Pirko 	list_del(&devlink_rate->list);
682*7cc7194eSJiri Pirko 	devlink_port->devlink_rate = NULL;
683*7cc7194eSJiri Pirko 	kfree(devlink_rate);
684*7cc7194eSJiri Pirko }
685*7cc7194eSJiri Pirko EXPORT_SYMBOL_GPL(devl_rate_leaf_destroy);
686*7cc7194eSJiri Pirko 
687*7cc7194eSJiri Pirko /**
688*7cc7194eSJiri Pirko  * devl_rate_nodes_destroy - destroy all devlink rate nodes on device
689*7cc7194eSJiri Pirko  * @devlink: devlink instance
690*7cc7194eSJiri Pirko  *
691*7cc7194eSJiri Pirko  * Unset parent for all rate objects and destroy all rate nodes
692*7cc7194eSJiri Pirko  * on specified device.
693*7cc7194eSJiri Pirko  */
devl_rate_nodes_destroy(struct devlink * devlink)694*7cc7194eSJiri Pirko void devl_rate_nodes_destroy(struct devlink *devlink)
695*7cc7194eSJiri Pirko {
696*7cc7194eSJiri Pirko 	static struct devlink_rate *devlink_rate, *tmp;
697*7cc7194eSJiri Pirko 	const struct devlink_ops *ops = devlink->ops;
698*7cc7194eSJiri Pirko 
699*7cc7194eSJiri Pirko 	devl_assert_locked(devlink);
700*7cc7194eSJiri Pirko 
701*7cc7194eSJiri Pirko 	list_for_each_entry(devlink_rate, &devlink->rate_list, list) {
702*7cc7194eSJiri Pirko 		if (!devlink_rate->parent)
703*7cc7194eSJiri Pirko 			continue;
704*7cc7194eSJiri Pirko 
705*7cc7194eSJiri Pirko 		refcount_dec(&devlink_rate->parent->refcnt);
706*7cc7194eSJiri Pirko 		if (devlink_rate_is_leaf(devlink_rate))
707*7cc7194eSJiri Pirko 			ops->rate_leaf_parent_set(devlink_rate, NULL, devlink_rate->priv,
708*7cc7194eSJiri Pirko 						  NULL, NULL);
709*7cc7194eSJiri Pirko 		else if (devlink_rate_is_node(devlink_rate))
710*7cc7194eSJiri Pirko 			ops->rate_node_parent_set(devlink_rate, NULL, devlink_rate->priv,
711*7cc7194eSJiri Pirko 						  NULL, NULL);
712*7cc7194eSJiri Pirko 	}
713*7cc7194eSJiri Pirko 	list_for_each_entry_safe(devlink_rate, tmp, &devlink->rate_list, list) {
714*7cc7194eSJiri Pirko 		if (devlink_rate_is_node(devlink_rate)) {
715*7cc7194eSJiri Pirko 			ops->rate_node_del(devlink_rate, devlink_rate->priv, NULL);
716*7cc7194eSJiri Pirko 			list_del(&devlink_rate->list);
717*7cc7194eSJiri Pirko 			kfree(devlink_rate->name);
718*7cc7194eSJiri Pirko 			kfree(devlink_rate);
719*7cc7194eSJiri Pirko 		}
720*7cc7194eSJiri Pirko 	}
721*7cc7194eSJiri Pirko }
722*7cc7194eSJiri Pirko EXPORT_SYMBOL_GPL(devl_rate_nodes_destroy);
723