xref: /linux/net/shaper/shaper.c (revision 1260ed77798502de9c98020040d2995008de10cc)
104e65df9SPaolo Abeni // SPDX-License-Identifier: GPL-2.0-or-later
204e65df9SPaolo Abeni 
34b623f9fSPaolo Abeni #include <linux/bits.h>
44b623f9fSPaolo Abeni #include <linux/bitfield.h>
54b623f9fSPaolo Abeni #include <linux/idr.h>
604e65df9SPaolo Abeni #include <linux/kernel.h>
74b623f9fSPaolo Abeni #include <linux/netdevice.h>
84b623f9fSPaolo Abeni #include <linux/netlink.h>
904e65df9SPaolo Abeni #include <linux/skbuff.h>
104b623f9fSPaolo Abeni #include <linux/xarray.h>
114b623f9fSPaolo Abeni #include <net/devlink.h>
124b623f9fSPaolo Abeni #include <net/net_shaper.h>
1304e65df9SPaolo Abeni 
1404e65df9SPaolo Abeni #include "shaper_nl_gen.h"
1504e65df9SPaolo Abeni 
164b623f9fSPaolo Abeni #include "../core/dev.h"
174b623f9fSPaolo Abeni 
184b623f9fSPaolo Abeni #define NET_SHAPER_SCOPE_SHIFT	26
194b623f9fSPaolo Abeni #define NET_SHAPER_ID_MASK	GENMASK(NET_SHAPER_SCOPE_SHIFT - 1, 0)
204b623f9fSPaolo Abeni #define NET_SHAPER_SCOPE_MASK	GENMASK(31, NET_SHAPER_SCOPE_SHIFT)
214b623f9fSPaolo Abeni 
224b623f9fSPaolo Abeni #define NET_SHAPER_ID_UNSPEC NET_SHAPER_ID_MASK
234b623f9fSPaolo Abeni 
244b623f9fSPaolo Abeni struct net_shaper_hierarchy {
254b623f9fSPaolo Abeni 	struct xarray shapers;
264b623f9fSPaolo Abeni };
274b623f9fSPaolo Abeni 
284b623f9fSPaolo Abeni struct net_shaper_nl_ctx {
294b623f9fSPaolo Abeni 	struct net_shaper_binding binding;
304b623f9fSPaolo Abeni 	netdevice_tracker dev_tracker;
314b623f9fSPaolo Abeni 	unsigned long start_index;
324b623f9fSPaolo Abeni };
334b623f9fSPaolo Abeni 
344b623f9fSPaolo Abeni static struct net_shaper_binding *net_shaper_binding_from_ctx(void *ctx)
354b623f9fSPaolo Abeni {
364b623f9fSPaolo Abeni 	return &((struct net_shaper_nl_ctx *)ctx)->binding;
374b623f9fSPaolo Abeni }
384b623f9fSPaolo Abeni 
3993954b40SPaolo Abeni static void net_shaper_lock(struct net_shaper_binding *binding)
4093954b40SPaolo Abeni {
4193954b40SPaolo Abeni 	switch (binding->type) {
4293954b40SPaolo Abeni 	case NET_SHAPER_BINDING_TYPE_NETDEV:
43*ebda2f0bSJakub Kicinski 		netdev_lock(binding->netdev);
4493954b40SPaolo Abeni 		break;
4593954b40SPaolo Abeni 	}
4693954b40SPaolo Abeni }
4793954b40SPaolo Abeni 
4893954b40SPaolo Abeni static void net_shaper_unlock(struct net_shaper_binding *binding)
4993954b40SPaolo Abeni {
5093954b40SPaolo Abeni 	switch (binding->type) {
5193954b40SPaolo Abeni 	case NET_SHAPER_BINDING_TYPE_NETDEV:
52*ebda2f0bSJakub Kicinski 		netdev_unlock(binding->netdev);
5393954b40SPaolo Abeni 		break;
5493954b40SPaolo Abeni 	}
5593954b40SPaolo Abeni }
5693954b40SPaolo Abeni 
574b623f9fSPaolo Abeni static struct net_shaper_hierarchy *
584b623f9fSPaolo Abeni net_shaper_hierarchy(struct net_shaper_binding *binding)
594b623f9fSPaolo Abeni {
604b623f9fSPaolo Abeni 	/* Pairs with WRITE_ONCE() in net_shaper_hierarchy_setup. */
614b623f9fSPaolo Abeni 	if (binding->type == NET_SHAPER_BINDING_TYPE_NETDEV)
624b623f9fSPaolo Abeni 		return READ_ONCE(binding->netdev->net_shaper_hierarchy);
634b623f9fSPaolo Abeni 
644b623f9fSPaolo Abeni 	/* No other type supported yet. */
654b623f9fSPaolo Abeni 	return NULL;
664b623f9fSPaolo Abeni }
674b623f9fSPaolo Abeni 
6893954b40SPaolo Abeni static const struct net_shaper_ops *
6993954b40SPaolo Abeni net_shaper_ops(struct net_shaper_binding *binding)
7093954b40SPaolo Abeni {
7193954b40SPaolo Abeni 	if (binding->type == NET_SHAPER_BINDING_TYPE_NETDEV)
7293954b40SPaolo Abeni 		return binding->netdev->netdev_ops->net_shaper_ops;
7393954b40SPaolo Abeni 
7493954b40SPaolo Abeni 	/* No other type supported yet. */
7593954b40SPaolo Abeni 	return NULL;
7693954b40SPaolo Abeni }
7793954b40SPaolo Abeni 
785d5d4700SPaolo Abeni /* Count the number of [multi] attributes of the given type. */
795d5d4700SPaolo Abeni static int net_shaper_list_len(struct genl_info *info, int type)
805d5d4700SPaolo Abeni {
815d5d4700SPaolo Abeni 	struct nlattr *attr;
825d5d4700SPaolo Abeni 	int rem, cnt = 0;
835d5d4700SPaolo Abeni 
845d5d4700SPaolo Abeni 	nla_for_each_attr_type(attr, type, genlmsg_data(info->genlhdr),
855d5d4700SPaolo Abeni 			       genlmsg_len(info->genlhdr), rem)
865d5d4700SPaolo Abeni 		cnt++;
875d5d4700SPaolo Abeni 	return cnt;
885d5d4700SPaolo Abeni }
895d5d4700SPaolo Abeni 
905d5d4700SPaolo Abeni static int net_shaper_handle_size(void)
915d5d4700SPaolo Abeni {
925d5d4700SPaolo Abeni 	return nla_total_size(nla_total_size(sizeof(u32)) +
935d5d4700SPaolo Abeni 			      nla_total_size(sizeof(u32)));
945d5d4700SPaolo Abeni }
955d5d4700SPaolo Abeni 
964b623f9fSPaolo Abeni static int net_shaper_fill_binding(struct sk_buff *msg,
974b623f9fSPaolo Abeni 				   const struct net_shaper_binding *binding,
984b623f9fSPaolo Abeni 				   u32 type)
994b623f9fSPaolo Abeni {
1004b623f9fSPaolo Abeni 	/* Should never happen, as currently only NETDEV is supported. */
1014b623f9fSPaolo Abeni 	if (WARN_ON_ONCE(binding->type != NET_SHAPER_BINDING_TYPE_NETDEV))
1024b623f9fSPaolo Abeni 		return -EINVAL;
1034b623f9fSPaolo Abeni 
1044b623f9fSPaolo Abeni 	if (nla_put_u32(msg, type, binding->netdev->ifindex))
1054b623f9fSPaolo Abeni 		return -EMSGSIZE;
1064b623f9fSPaolo Abeni 
1074b623f9fSPaolo Abeni 	return 0;
1084b623f9fSPaolo Abeni }
1094b623f9fSPaolo Abeni 
1104b623f9fSPaolo Abeni static int net_shaper_fill_handle(struct sk_buff *msg,
1114b623f9fSPaolo Abeni 				  const struct net_shaper_handle *handle,
1124b623f9fSPaolo Abeni 				  u32 type)
1134b623f9fSPaolo Abeni {
1144b623f9fSPaolo Abeni 	struct nlattr *handle_attr;
1154b623f9fSPaolo Abeni 
1164b623f9fSPaolo Abeni 	if (handle->scope == NET_SHAPER_SCOPE_UNSPEC)
1174b623f9fSPaolo Abeni 		return 0;
1184b623f9fSPaolo Abeni 
1194b623f9fSPaolo Abeni 	handle_attr = nla_nest_start(msg, type);
1204b623f9fSPaolo Abeni 	if (!handle_attr)
1214b623f9fSPaolo Abeni 		return -EMSGSIZE;
1224b623f9fSPaolo Abeni 
1234b623f9fSPaolo Abeni 	if (nla_put_u32(msg, NET_SHAPER_A_HANDLE_SCOPE, handle->scope) ||
1244b623f9fSPaolo Abeni 	    (handle->scope >= NET_SHAPER_SCOPE_QUEUE &&
1254b623f9fSPaolo Abeni 	     nla_put_u32(msg, NET_SHAPER_A_HANDLE_ID, handle->id)))
1264b623f9fSPaolo Abeni 		goto handle_nest_cancel;
1274b623f9fSPaolo Abeni 
1284b623f9fSPaolo Abeni 	nla_nest_end(msg, handle_attr);
1294b623f9fSPaolo Abeni 	return 0;
1304b623f9fSPaolo Abeni 
1314b623f9fSPaolo Abeni handle_nest_cancel:
1324b623f9fSPaolo Abeni 	nla_nest_cancel(msg, handle_attr);
1334b623f9fSPaolo Abeni 	return -EMSGSIZE;
1344b623f9fSPaolo Abeni }
1354b623f9fSPaolo Abeni 
1364b623f9fSPaolo Abeni static int
1374b623f9fSPaolo Abeni net_shaper_fill_one(struct sk_buff *msg,
1384b623f9fSPaolo Abeni 		    const struct net_shaper_binding *binding,
1394b623f9fSPaolo Abeni 		    const struct net_shaper *shaper,
1404b623f9fSPaolo Abeni 		    const struct genl_info *info)
1414b623f9fSPaolo Abeni {
1424b623f9fSPaolo Abeni 	void *hdr;
1434b623f9fSPaolo Abeni 
1444b623f9fSPaolo Abeni 	hdr = genlmsg_iput(msg, info);
1454b623f9fSPaolo Abeni 	if (!hdr)
1464b623f9fSPaolo Abeni 		return -EMSGSIZE;
1474b623f9fSPaolo Abeni 
1484b623f9fSPaolo Abeni 	if (net_shaper_fill_binding(msg, binding, NET_SHAPER_A_IFINDEX) ||
1494b623f9fSPaolo Abeni 	    net_shaper_fill_handle(msg, &shaper->parent,
1504b623f9fSPaolo Abeni 				   NET_SHAPER_A_PARENT) ||
1514b623f9fSPaolo Abeni 	    net_shaper_fill_handle(msg, &shaper->handle,
1524b623f9fSPaolo Abeni 				   NET_SHAPER_A_HANDLE) ||
1534b623f9fSPaolo Abeni 	    ((shaper->bw_min || shaper->bw_max || shaper->burst) &&
1544b623f9fSPaolo Abeni 	     nla_put_u32(msg, NET_SHAPER_A_METRIC, shaper->metric)) ||
1554b623f9fSPaolo Abeni 	    (shaper->bw_min &&
1564b623f9fSPaolo Abeni 	     nla_put_uint(msg, NET_SHAPER_A_BW_MIN, shaper->bw_min)) ||
1574b623f9fSPaolo Abeni 	    (shaper->bw_max &&
1584b623f9fSPaolo Abeni 	     nla_put_uint(msg, NET_SHAPER_A_BW_MAX, shaper->bw_max)) ||
1594b623f9fSPaolo Abeni 	    (shaper->burst &&
1604b623f9fSPaolo Abeni 	     nla_put_uint(msg, NET_SHAPER_A_BURST, shaper->burst)) ||
1614b623f9fSPaolo Abeni 	    (shaper->priority &&
1624b623f9fSPaolo Abeni 	     nla_put_u32(msg, NET_SHAPER_A_PRIORITY, shaper->priority)) ||
1634b623f9fSPaolo Abeni 	    (shaper->weight &&
1644b623f9fSPaolo Abeni 	     nla_put_u32(msg, NET_SHAPER_A_WEIGHT, shaper->weight)))
1654b623f9fSPaolo Abeni 		goto nla_put_failure;
1664b623f9fSPaolo Abeni 
1674b623f9fSPaolo Abeni 	genlmsg_end(msg, hdr);
1684b623f9fSPaolo Abeni 
1694b623f9fSPaolo Abeni 	return 0;
1704b623f9fSPaolo Abeni 
1714b623f9fSPaolo Abeni nla_put_failure:
1724b623f9fSPaolo Abeni 	genlmsg_cancel(msg, hdr);
1734b623f9fSPaolo Abeni 	return -EMSGSIZE;
1744b623f9fSPaolo Abeni }
1754b623f9fSPaolo Abeni 
1764b623f9fSPaolo Abeni /* Initialize the context fetching the relevant device and
1774b623f9fSPaolo Abeni  * acquiring a reference to it.
1784b623f9fSPaolo Abeni  */
1794b623f9fSPaolo Abeni static int net_shaper_ctx_setup(const struct genl_info *info, int type,
1804b623f9fSPaolo Abeni 				struct net_shaper_nl_ctx *ctx)
1814b623f9fSPaolo Abeni {
1824b623f9fSPaolo Abeni 	struct net *ns = genl_info_net(info);
1834b623f9fSPaolo Abeni 	struct net_device *dev;
1844b623f9fSPaolo Abeni 	int ifindex;
1854b623f9fSPaolo Abeni 
1864b623f9fSPaolo Abeni 	if (GENL_REQ_ATTR_CHECK(info, type))
1874b623f9fSPaolo Abeni 		return -EINVAL;
1884b623f9fSPaolo Abeni 
1894b623f9fSPaolo Abeni 	ifindex = nla_get_u32(info->attrs[type]);
1904b623f9fSPaolo Abeni 	dev = netdev_get_by_index(ns, ifindex, &ctx->dev_tracker, GFP_KERNEL);
1914b623f9fSPaolo Abeni 	if (!dev) {
1924b623f9fSPaolo Abeni 		NL_SET_BAD_ATTR(info->extack, info->attrs[type]);
1934b623f9fSPaolo Abeni 		return -ENOENT;
1944b623f9fSPaolo Abeni 	}
1954b623f9fSPaolo Abeni 
1964b623f9fSPaolo Abeni 	if (!dev->netdev_ops->net_shaper_ops) {
1974b623f9fSPaolo Abeni 		NL_SET_BAD_ATTR(info->extack, info->attrs[type]);
1984b623f9fSPaolo Abeni 		netdev_put(dev, &ctx->dev_tracker);
1994b623f9fSPaolo Abeni 		return -EOPNOTSUPP;
2004b623f9fSPaolo Abeni 	}
2014b623f9fSPaolo Abeni 
2024b623f9fSPaolo Abeni 	ctx->binding.type = NET_SHAPER_BINDING_TYPE_NETDEV;
2034b623f9fSPaolo Abeni 	ctx->binding.netdev = dev;
2044b623f9fSPaolo Abeni 	return 0;
2054b623f9fSPaolo Abeni }
2064b623f9fSPaolo Abeni 
2074b623f9fSPaolo Abeni static void net_shaper_ctx_cleanup(struct net_shaper_nl_ctx *ctx)
2084b623f9fSPaolo Abeni {
2094b623f9fSPaolo Abeni 	if (ctx->binding.type == NET_SHAPER_BINDING_TYPE_NETDEV)
2104b623f9fSPaolo Abeni 		netdev_put(ctx->binding.netdev, &ctx->dev_tracker);
2114b623f9fSPaolo Abeni }
2124b623f9fSPaolo Abeni 
2134b623f9fSPaolo Abeni static u32 net_shaper_handle_to_index(const struct net_shaper_handle *handle)
2144b623f9fSPaolo Abeni {
2154b623f9fSPaolo Abeni 	return FIELD_PREP(NET_SHAPER_SCOPE_MASK, handle->scope) |
2164b623f9fSPaolo Abeni 		FIELD_PREP(NET_SHAPER_ID_MASK, handle->id);
2174b623f9fSPaolo Abeni }
2184b623f9fSPaolo Abeni 
21993954b40SPaolo Abeni static void net_shaper_index_to_handle(u32 index,
22093954b40SPaolo Abeni 				       struct net_shaper_handle *handle)
22193954b40SPaolo Abeni {
22293954b40SPaolo Abeni 	handle->scope = FIELD_GET(NET_SHAPER_SCOPE_MASK, index);
22393954b40SPaolo Abeni 	handle->id = FIELD_GET(NET_SHAPER_ID_MASK, index);
22493954b40SPaolo Abeni }
22593954b40SPaolo Abeni 
22693954b40SPaolo Abeni static void net_shaper_default_parent(const struct net_shaper_handle *handle,
22793954b40SPaolo Abeni 				      struct net_shaper_handle *parent)
22893954b40SPaolo Abeni {
22993954b40SPaolo Abeni 	switch (handle->scope) {
23093954b40SPaolo Abeni 	case NET_SHAPER_SCOPE_UNSPEC:
23193954b40SPaolo Abeni 	case NET_SHAPER_SCOPE_NETDEV:
23293954b40SPaolo Abeni 	case __NET_SHAPER_SCOPE_MAX:
23393954b40SPaolo Abeni 		parent->scope = NET_SHAPER_SCOPE_UNSPEC;
23493954b40SPaolo Abeni 		break;
23593954b40SPaolo Abeni 
23693954b40SPaolo Abeni 	case NET_SHAPER_SCOPE_QUEUE:
23793954b40SPaolo Abeni 	case NET_SHAPER_SCOPE_NODE:
23893954b40SPaolo Abeni 		parent->scope = NET_SHAPER_SCOPE_NETDEV;
23993954b40SPaolo Abeni 		break;
24093954b40SPaolo Abeni 	}
24193954b40SPaolo Abeni 	parent->id = 0;
24293954b40SPaolo Abeni }
24393954b40SPaolo Abeni 
24493954b40SPaolo Abeni /*
24593954b40SPaolo Abeni  * MARK_0 is already in use due to XA_FLAGS_ALLOC, can't reuse such flag as
24693954b40SPaolo Abeni  * it's cleared by xa_store().
24793954b40SPaolo Abeni  */
24893954b40SPaolo Abeni #define NET_SHAPER_NOT_VALID XA_MARK_1
24993954b40SPaolo Abeni 
2504b623f9fSPaolo Abeni static struct net_shaper *
2514b623f9fSPaolo Abeni net_shaper_lookup(struct net_shaper_binding *binding,
2524b623f9fSPaolo Abeni 		  const struct net_shaper_handle *handle)
2534b623f9fSPaolo Abeni {
2544b623f9fSPaolo Abeni 	struct net_shaper_hierarchy *hierarchy = net_shaper_hierarchy(binding);
2554b623f9fSPaolo Abeni 	u32 index = net_shaper_handle_to_index(handle);
2564b623f9fSPaolo Abeni 
25793954b40SPaolo Abeni 	if (!hierarchy || xa_get_mark(&hierarchy->shapers, index,
25893954b40SPaolo Abeni 				      NET_SHAPER_NOT_VALID))
25993954b40SPaolo Abeni 		return NULL;
26093954b40SPaolo Abeni 
26193954b40SPaolo Abeni 	return xa_load(&hierarchy->shapers, index);
26293954b40SPaolo Abeni }
26393954b40SPaolo Abeni 
26493954b40SPaolo Abeni /* Allocate on demand the per device shaper's hierarchy container.
26593954b40SPaolo Abeni  * Called under the net shaper lock
26693954b40SPaolo Abeni  */
26793954b40SPaolo Abeni static struct net_shaper_hierarchy *
26893954b40SPaolo Abeni net_shaper_hierarchy_setup(struct net_shaper_binding *binding)
26993954b40SPaolo Abeni {
27093954b40SPaolo Abeni 	struct net_shaper_hierarchy *hierarchy = net_shaper_hierarchy(binding);
27193954b40SPaolo Abeni 
27293954b40SPaolo Abeni 	if (hierarchy)
27393954b40SPaolo Abeni 		return hierarchy;
27493954b40SPaolo Abeni 
27593954b40SPaolo Abeni 	hierarchy = kmalloc(sizeof(*hierarchy), GFP_KERNEL);
27693954b40SPaolo Abeni 	if (!hierarchy)
27793954b40SPaolo Abeni 		return NULL;
27893954b40SPaolo Abeni 
27993954b40SPaolo Abeni 	/* The flag is required for ID allocation */
28093954b40SPaolo Abeni 	xa_init_flags(&hierarchy->shapers, XA_FLAGS_ALLOC);
28193954b40SPaolo Abeni 
28293954b40SPaolo Abeni 	switch (binding->type) {
28393954b40SPaolo Abeni 	case NET_SHAPER_BINDING_TYPE_NETDEV:
28493954b40SPaolo Abeni 		/* Pairs with READ_ONCE in net_shaper_hierarchy. */
28593954b40SPaolo Abeni 		WRITE_ONCE(binding->netdev->net_shaper_hierarchy, hierarchy);
28693954b40SPaolo Abeni 		break;
28793954b40SPaolo Abeni 	}
28893954b40SPaolo Abeni 	return hierarchy;
28993954b40SPaolo Abeni }
29093954b40SPaolo Abeni 
29193954b40SPaolo Abeni /* Prepare the hierarchy container to actually insert the given shaper, doing
29293954b40SPaolo Abeni  * in advance the needed allocations.
29393954b40SPaolo Abeni  */
29493954b40SPaolo Abeni static int net_shaper_pre_insert(struct net_shaper_binding *binding,
29593954b40SPaolo Abeni 				 struct net_shaper_handle *handle,
29693954b40SPaolo Abeni 				 struct netlink_ext_ack *extack)
29793954b40SPaolo Abeni {
29893954b40SPaolo Abeni 	struct net_shaper_hierarchy *hierarchy = net_shaper_hierarchy(binding);
29993954b40SPaolo Abeni 	struct net_shaper *prev, *cur;
30093954b40SPaolo Abeni 	bool id_allocated = false;
30193954b40SPaolo Abeni 	int ret, index;
30293954b40SPaolo Abeni 
30393954b40SPaolo Abeni 	if (!hierarchy)
30493954b40SPaolo Abeni 		return -ENOMEM;
30593954b40SPaolo Abeni 
30693954b40SPaolo Abeni 	index = net_shaper_handle_to_index(handle);
30793954b40SPaolo Abeni 	cur = xa_load(&hierarchy->shapers, index);
30893954b40SPaolo Abeni 	if (cur)
30993954b40SPaolo Abeni 		return 0;
31093954b40SPaolo Abeni 
31193954b40SPaolo Abeni 	/* Allocated a new id, if needed. */
31293954b40SPaolo Abeni 	if (handle->scope == NET_SHAPER_SCOPE_NODE &&
31393954b40SPaolo Abeni 	    handle->id == NET_SHAPER_ID_UNSPEC) {
31493954b40SPaolo Abeni 		u32 min, max;
31593954b40SPaolo Abeni 
31693954b40SPaolo Abeni 		handle->id = NET_SHAPER_ID_MASK - 1;
31793954b40SPaolo Abeni 		max = net_shaper_handle_to_index(handle);
31893954b40SPaolo Abeni 		handle->id = 0;
31993954b40SPaolo Abeni 		min = net_shaper_handle_to_index(handle);
32093954b40SPaolo Abeni 
32193954b40SPaolo Abeni 		ret = xa_alloc(&hierarchy->shapers, &index, NULL,
32293954b40SPaolo Abeni 			       XA_LIMIT(min, max), GFP_KERNEL);
32393954b40SPaolo Abeni 		if (ret < 0) {
32493954b40SPaolo Abeni 			NL_SET_ERR_MSG(extack, "Can't allocate new id for NODE shaper");
32593954b40SPaolo Abeni 			return ret;
32693954b40SPaolo Abeni 		}
32793954b40SPaolo Abeni 
32893954b40SPaolo Abeni 		net_shaper_index_to_handle(index, handle);
32993954b40SPaolo Abeni 		id_allocated = true;
33093954b40SPaolo Abeni 	}
33193954b40SPaolo Abeni 
33293954b40SPaolo Abeni 	cur = kzalloc(sizeof(*cur), GFP_KERNEL);
33393954b40SPaolo Abeni 	if (!cur) {
33493954b40SPaolo Abeni 		ret = -ENOMEM;
33593954b40SPaolo Abeni 		goto free_id;
33693954b40SPaolo Abeni 	}
33793954b40SPaolo Abeni 
33893954b40SPaolo Abeni 	/* Mark 'tentative' shaper inside the hierarchy container.
33993954b40SPaolo Abeni 	 * xa_set_mark is a no-op if the previous store fails.
34093954b40SPaolo Abeni 	 */
34193954b40SPaolo Abeni 	xa_lock(&hierarchy->shapers);
34293954b40SPaolo Abeni 	prev = __xa_store(&hierarchy->shapers, index, cur, GFP_KERNEL);
34393954b40SPaolo Abeni 	__xa_set_mark(&hierarchy->shapers, index, NET_SHAPER_NOT_VALID);
34493954b40SPaolo Abeni 	xa_unlock(&hierarchy->shapers);
34593954b40SPaolo Abeni 	if (xa_err(prev)) {
34693954b40SPaolo Abeni 		NL_SET_ERR_MSG(extack, "Can't insert shaper into device store");
34793954b40SPaolo Abeni 		kfree_rcu(cur, rcu);
34893954b40SPaolo Abeni 		ret = xa_err(prev);
34993954b40SPaolo Abeni 		goto free_id;
35093954b40SPaolo Abeni 	}
35193954b40SPaolo Abeni 	return 0;
35293954b40SPaolo Abeni 
35393954b40SPaolo Abeni free_id:
35493954b40SPaolo Abeni 	if (id_allocated)
35593954b40SPaolo Abeni 		xa_erase(&hierarchy->shapers, index);
35693954b40SPaolo Abeni 	return ret;
35793954b40SPaolo Abeni }
35893954b40SPaolo Abeni 
35993954b40SPaolo Abeni /* Commit the tentative insert with the actual values.
36093954b40SPaolo Abeni  * Must be called only after a successful net_shaper_pre_insert().
36193954b40SPaolo Abeni  */
36293954b40SPaolo Abeni static void net_shaper_commit(struct net_shaper_binding *binding,
36393954b40SPaolo Abeni 			      int nr_shapers, const struct net_shaper *shapers)
36493954b40SPaolo Abeni {
36593954b40SPaolo Abeni 	struct net_shaper_hierarchy *hierarchy = net_shaper_hierarchy(binding);
36693954b40SPaolo Abeni 	struct net_shaper *cur;
36793954b40SPaolo Abeni 	int index;
36893954b40SPaolo Abeni 	int i;
36993954b40SPaolo Abeni 
37093954b40SPaolo Abeni 	xa_lock(&hierarchy->shapers);
37193954b40SPaolo Abeni 	for (i = 0; i < nr_shapers; ++i) {
37293954b40SPaolo Abeni 		index = net_shaper_handle_to_index(&shapers[i].handle);
37393954b40SPaolo Abeni 
37493954b40SPaolo Abeni 		cur = xa_load(&hierarchy->shapers, index);
37593954b40SPaolo Abeni 		if (WARN_ON_ONCE(!cur))
37693954b40SPaolo Abeni 			continue;
37793954b40SPaolo Abeni 
37893954b40SPaolo Abeni 		/* Successful update: drop the tentative mark
37993954b40SPaolo Abeni 		 * and update the hierarchy container.
38093954b40SPaolo Abeni 		 */
38193954b40SPaolo Abeni 		__xa_clear_mark(&hierarchy->shapers, index,
38293954b40SPaolo Abeni 				NET_SHAPER_NOT_VALID);
38393954b40SPaolo Abeni 		*cur = shapers[i];
38493954b40SPaolo Abeni 	}
38593954b40SPaolo Abeni 	xa_unlock(&hierarchy->shapers);
38693954b40SPaolo Abeni }
38793954b40SPaolo Abeni 
38893954b40SPaolo Abeni /* Rollback all the tentative inserts from the hierarchy. */
38993954b40SPaolo Abeni static void net_shaper_rollback(struct net_shaper_binding *binding)
39093954b40SPaolo Abeni {
39193954b40SPaolo Abeni 	struct net_shaper_hierarchy *hierarchy = net_shaper_hierarchy(binding);
39293954b40SPaolo Abeni 	struct net_shaper *cur;
39393954b40SPaolo Abeni 	unsigned long index;
39493954b40SPaolo Abeni 
39593954b40SPaolo Abeni 	if (!hierarchy)
39693954b40SPaolo Abeni 		return;
39793954b40SPaolo Abeni 
39893954b40SPaolo Abeni 	xa_lock(&hierarchy->shapers);
39993954b40SPaolo Abeni 	xa_for_each_marked(&hierarchy->shapers, index, cur,
40093954b40SPaolo Abeni 			   NET_SHAPER_NOT_VALID) {
40193954b40SPaolo Abeni 		__xa_erase(&hierarchy->shapers, index);
40293954b40SPaolo Abeni 		kfree(cur);
40393954b40SPaolo Abeni 	}
40493954b40SPaolo Abeni 	xa_unlock(&hierarchy->shapers);
4054b623f9fSPaolo Abeni }
4064b623f9fSPaolo Abeni 
4074b623f9fSPaolo Abeni static int net_shaper_parse_handle(const struct nlattr *attr,
4084b623f9fSPaolo Abeni 				   const struct genl_info *info,
4094b623f9fSPaolo Abeni 				   struct net_shaper_handle *handle)
4104b623f9fSPaolo Abeni {
4114b623f9fSPaolo Abeni 	struct nlattr *tb[NET_SHAPER_A_HANDLE_MAX + 1];
4124b623f9fSPaolo Abeni 	struct nlattr *id_attr;
4134b623f9fSPaolo Abeni 	u32 id = 0;
4144b623f9fSPaolo Abeni 	int ret;
4154b623f9fSPaolo Abeni 
4164b623f9fSPaolo Abeni 	ret = nla_parse_nested(tb, NET_SHAPER_A_HANDLE_MAX, attr,
4174b623f9fSPaolo Abeni 			       net_shaper_handle_nl_policy, info->extack);
4184b623f9fSPaolo Abeni 	if (ret < 0)
4194b623f9fSPaolo Abeni 		return ret;
4204b623f9fSPaolo Abeni 
4214b623f9fSPaolo Abeni 	if (NL_REQ_ATTR_CHECK(info->extack, attr, tb,
4224b623f9fSPaolo Abeni 			      NET_SHAPER_A_HANDLE_SCOPE))
4234b623f9fSPaolo Abeni 		return -EINVAL;
4244b623f9fSPaolo Abeni 
4254b623f9fSPaolo Abeni 	handle->scope = nla_get_u32(tb[NET_SHAPER_A_HANDLE_SCOPE]);
4264b623f9fSPaolo Abeni 
4274b623f9fSPaolo Abeni 	/* The default id for NODE scope shapers is an invalid one
4284b623f9fSPaolo Abeni 	 * to help the 'group' operation discriminate between new
4294b623f9fSPaolo Abeni 	 * NODE shaper creation (ID_UNSPEC) and reuse of existing
4304b623f9fSPaolo Abeni 	 * shaper (any other value).
4314b623f9fSPaolo Abeni 	 */
4324b623f9fSPaolo Abeni 	id_attr = tb[NET_SHAPER_A_HANDLE_ID];
4334b623f9fSPaolo Abeni 	if (id_attr)
4344b623f9fSPaolo Abeni 		id = nla_get_u32(id_attr);
4354b623f9fSPaolo Abeni 	else if (handle->scope == NET_SHAPER_SCOPE_NODE)
4364b623f9fSPaolo Abeni 		id = NET_SHAPER_ID_UNSPEC;
4374b623f9fSPaolo Abeni 
4384b623f9fSPaolo Abeni 	handle->id = id;
4394b623f9fSPaolo Abeni 	return 0;
4404b623f9fSPaolo Abeni }
4414b623f9fSPaolo Abeni 
442ecd82cfeSPaolo Abeni static int net_shaper_validate_caps(struct net_shaper_binding *binding,
443ecd82cfeSPaolo Abeni 				    struct nlattr **tb,
444ecd82cfeSPaolo Abeni 				    const struct genl_info *info,
445ecd82cfeSPaolo Abeni 				    struct net_shaper *shaper)
446ecd82cfeSPaolo Abeni {
447ecd82cfeSPaolo Abeni 	const struct net_shaper_ops *ops = net_shaper_ops(binding);
448ecd82cfeSPaolo Abeni 	struct nlattr *bad = NULL;
449ecd82cfeSPaolo Abeni 	unsigned long caps = 0;
450ecd82cfeSPaolo Abeni 
451ecd82cfeSPaolo Abeni 	ops->capabilities(binding, shaper->handle.scope, &caps);
452ecd82cfeSPaolo Abeni 
453ecd82cfeSPaolo Abeni 	if (tb[NET_SHAPER_A_PRIORITY] &&
454ecd82cfeSPaolo Abeni 	    !(caps & BIT(NET_SHAPER_A_CAPS_SUPPORT_PRIORITY)))
455ecd82cfeSPaolo Abeni 		bad = tb[NET_SHAPER_A_PRIORITY];
456ecd82cfeSPaolo Abeni 	if (tb[NET_SHAPER_A_WEIGHT] &&
457ecd82cfeSPaolo Abeni 	    !(caps & BIT(NET_SHAPER_A_CAPS_SUPPORT_WEIGHT)))
458ecd82cfeSPaolo Abeni 		bad = tb[NET_SHAPER_A_WEIGHT];
459ecd82cfeSPaolo Abeni 	if (tb[NET_SHAPER_A_BW_MIN] &&
460ecd82cfeSPaolo Abeni 	    !(caps & BIT(NET_SHAPER_A_CAPS_SUPPORT_BW_MIN)))
461ecd82cfeSPaolo Abeni 		bad = tb[NET_SHAPER_A_BW_MIN];
462ecd82cfeSPaolo Abeni 	if (tb[NET_SHAPER_A_BW_MAX] &&
463ecd82cfeSPaolo Abeni 	    !(caps & BIT(NET_SHAPER_A_CAPS_SUPPORT_BW_MAX)))
464ecd82cfeSPaolo Abeni 		bad = tb[NET_SHAPER_A_BW_MAX];
465ecd82cfeSPaolo Abeni 	if (tb[NET_SHAPER_A_BURST] &&
466ecd82cfeSPaolo Abeni 	    !(caps & BIT(NET_SHAPER_A_CAPS_SUPPORT_BURST)))
467ecd82cfeSPaolo Abeni 		bad = tb[NET_SHAPER_A_BURST];
468ecd82cfeSPaolo Abeni 
469ecd82cfeSPaolo Abeni 	if (!caps)
470ecd82cfeSPaolo Abeni 		bad = tb[NET_SHAPER_A_HANDLE];
471ecd82cfeSPaolo Abeni 
472ecd82cfeSPaolo Abeni 	if (bad) {
473ecd82cfeSPaolo Abeni 		NL_SET_BAD_ATTR(info->extack, bad);
474ecd82cfeSPaolo Abeni 		return -EOPNOTSUPP;
475ecd82cfeSPaolo Abeni 	}
476ecd82cfeSPaolo Abeni 
477ecd82cfeSPaolo Abeni 	if (shaper->handle.scope == NET_SHAPER_SCOPE_QUEUE &&
478ecd82cfeSPaolo Abeni 	    binding->type == NET_SHAPER_BINDING_TYPE_NETDEV &&
479ecd82cfeSPaolo Abeni 	    shaper->handle.id >= binding->netdev->real_num_tx_queues) {
480ecd82cfeSPaolo Abeni 		NL_SET_ERR_MSG_FMT(info->extack,
481ecd82cfeSPaolo Abeni 				   "Not existing queue id %d max %d",
482ecd82cfeSPaolo Abeni 				   shaper->handle.id,
483ecd82cfeSPaolo Abeni 				   binding->netdev->real_num_tx_queues);
484ecd82cfeSPaolo Abeni 		return -ENOENT;
485ecd82cfeSPaolo Abeni 	}
486ecd82cfeSPaolo Abeni 
487ecd82cfeSPaolo Abeni 	/* The metric is really used only if there is *any* rate-related
488ecd82cfeSPaolo Abeni 	 * setting, either in current attributes set or in pre-existing
489ecd82cfeSPaolo Abeni 	 * values.
490ecd82cfeSPaolo Abeni 	 */
491ecd82cfeSPaolo Abeni 	if (shaper->burst || shaper->bw_min || shaper->bw_max) {
492ecd82cfeSPaolo Abeni 		u32 metric_cap = NET_SHAPER_A_CAPS_SUPPORT_METRIC_BPS +
493ecd82cfeSPaolo Abeni 				 shaper->metric;
494ecd82cfeSPaolo Abeni 
495ecd82cfeSPaolo Abeni 		/* The metric test can fail even when the user did not
496ecd82cfeSPaolo Abeni 		 * specify the METRIC attribute. Pointing to rate related
497ecd82cfeSPaolo Abeni 		 * attribute will be confusing, as the attribute itself
498ecd82cfeSPaolo Abeni 		 * could be indeed supported, with a different metric.
499ecd82cfeSPaolo Abeni 		 * Be more specific.
500ecd82cfeSPaolo Abeni 		 */
501ecd82cfeSPaolo Abeni 		if (!(caps & BIT(metric_cap))) {
502ecd82cfeSPaolo Abeni 			NL_SET_ERR_MSG_FMT(info->extack, "Bad metric %d",
503ecd82cfeSPaolo Abeni 					   shaper->metric);
504ecd82cfeSPaolo Abeni 			return -EOPNOTSUPP;
505ecd82cfeSPaolo Abeni 		}
506ecd82cfeSPaolo Abeni 	}
507ecd82cfeSPaolo Abeni 	return 0;
508ecd82cfeSPaolo Abeni }
509ecd82cfeSPaolo Abeni 
51093954b40SPaolo Abeni static int net_shaper_parse_info(struct net_shaper_binding *binding,
51193954b40SPaolo Abeni 				 struct nlattr **tb,
51293954b40SPaolo Abeni 				 const struct genl_info *info,
51393954b40SPaolo Abeni 				 struct net_shaper *shaper,
51493954b40SPaolo Abeni 				 bool *exists)
51593954b40SPaolo Abeni {
51693954b40SPaolo Abeni 	struct net_shaper *old;
51793954b40SPaolo Abeni 	int ret;
51893954b40SPaolo Abeni 
51993954b40SPaolo Abeni 	/* The shaper handle is the only mandatory attribute. */
52093954b40SPaolo Abeni 	if (NL_REQ_ATTR_CHECK(info->extack, NULL, tb, NET_SHAPER_A_HANDLE))
52193954b40SPaolo Abeni 		return -EINVAL;
52293954b40SPaolo Abeni 
52393954b40SPaolo Abeni 	ret = net_shaper_parse_handle(tb[NET_SHAPER_A_HANDLE], info,
52493954b40SPaolo Abeni 				      &shaper->handle);
52593954b40SPaolo Abeni 	if (ret)
52693954b40SPaolo Abeni 		return ret;
52793954b40SPaolo Abeni 
52893954b40SPaolo Abeni 	if (shaper->handle.scope == NET_SHAPER_SCOPE_UNSPEC) {
52993954b40SPaolo Abeni 		NL_SET_BAD_ATTR(info->extack, tb[NET_SHAPER_A_HANDLE]);
53093954b40SPaolo Abeni 		return -EINVAL;
53193954b40SPaolo Abeni 	}
53293954b40SPaolo Abeni 
53393954b40SPaolo Abeni 	/* Fetch existing hierarchy, if any, so that user provide info will
53493954b40SPaolo Abeni 	 * incrementally update the existing shaper configuration.
53593954b40SPaolo Abeni 	 */
53693954b40SPaolo Abeni 	old = net_shaper_lookup(binding, &shaper->handle);
53793954b40SPaolo Abeni 	if (old)
53893954b40SPaolo Abeni 		*shaper = *old;
53993954b40SPaolo Abeni 	*exists = !!old;
54093954b40SPaolo Abeni 
54193954b40SPaolo Abeni 	if (tb[NET_SHAPER_A_METRIC])
54293954b40SPaolo Abeni 		shaper->metric = nla_get_u32(tb[NET_SHAPER_A_METRIC]);
54393954b40SPaolo Abeni 
54493954b40SPaolo Abeni 	if (tb[NET_SHAPER_A_BW_MIN])
54593954b40SPaolo Abeni 		shaper->bw_min = nla_get_uint(tb[NET_SHAPER_A_BW_MIN]);
54693954b40SPaolo Abeni 
54793954b40SPaolo Abeni 	if (tb[NET_SHAPER_A_BW_MAX])
54893954b40SPaolo Abeni 		shaper->bw_max = nla_get_uint(tb[NET_SHAPER_A_BW_MAX]);
54993954b40SPaolo Abeni 
55093954b40SPaolo Abeni 	if (tb[NET_SHAPER_A_BURST])
55193954b40SPaolo Abeni 		shaper->burst = nla_get_uint(tb[NET_SHAPER_A_BURST]);
55293954b40SPaolo Abeni 
55393954b40SPaolo Abeni 	if (tb[NET_SHAPER_A_PRIORITY])
55493954b40SPaolo Abeni 		shaper->priority = nla_get_u32(tb[NET_SHAPER_A_PRIORITY]);
55593954b40SPaolo Abeni 
55693954b40SPaolo Abeni 	if (tb[NET_SHAPER_A_WEIGHT])
55793954b40SPaolo Abeni 		shaper->weight = nla_get_u32(tb[NET_SHAPER_A_WEIGHT]);
558ecd82cfeSPaolo Abeni 
559ecd82cfeSPaolo Abeni 	ret = net_shaper_validate_caps(binding, tb, info, shaper);
560ecd82cfeSPaolo Abeni 	if (ret < 0)
561ecd82cfeSPaolo Abeni 		return ret;
562ecd82cfeSPaolo Abeni 
563ecd82cfeSPaolo Abeni 	return 0;
564ecd82cfeSPaolo Abeni }
565ecd82cfeSPaolo Abeni 
566ecd82cfeSPaolo Abeni static int net_shaper_validate_nesting(struct net_shaper_binding *binding,
567ecd82cfeSPaolo Abeni 				       const struct net_shaper *shaper,
568ecd82cfeSPaolo Abeni 				       struct netlink_ext_ack *extack)
569ecd82cfeSPaolo Abeni {
570ecd82cfeSPaolo Abeni 	const struct net_shaper_ops *ops = net_shaper_ops(binding);
571ecd82cfeSPaolo Abeni 	unsigned long caps = 0;
572ecd82cfeSPaolo Abeni 
573ecd82cfeSPaolo Abeni 	ops->capabilities(binding, shaper->handle.scope, &caps);
574ecd82cfeSPaolo Abeni 	if (!(caps & BIT(NET_SHAPER_A_CAPS_SUPPORT_NESTING))) {
575ecd82cfeSPaolo Abeni 		NL_SET_ERR_MSG_FMT(extack,
576ecd82cfeSPaolo Abeni 				   "Nesting not supported for scope %d",
577ecd82cfeSPaolo Abeni 				   shaper->handle.scope);
578ecd82cfeSPaolo Abeni 		return -EOPNOTSUPP;
579ecd82cfeSPaolo Abeni 	}
58093954b40SPaolo Abeni 	return 0;
58193954b40SPaolo Abeni }
58293954b40SPaolo Abeni 
5835d5d4700SPaolo Abeni /* Fetch the existing leaf and update it with the user-provided
5845d5d4700SPaolo Abeni  * attributes.
5855d5d4700SPaolo Abeni  */
5865d5d4700SPaolo Abeni static int net_shaper_parse_leaf(struct net_shaper_binding *binding,
5875d5d4700SPaolo Abeni 				 const struct nlattr *attr,
5885d5d4700SPaolo Abeni 				 const struct genl_info *info,
5895d5d4700SPaolo Abeni 				 const struct net_shaper *node,
5905d5d4700SPaolo Abeni 				 struct net_shaper *shaper)
5915d5d4700SPaolo Abeni {
5925d5d4700SPaolo Abeni 	struct nlattr *tb[NET_SHAPER_A_WEIGHT + 1];
5935d5d4700SPaolo Abeni 	bool exists;
5945d5d4700SPaolo Abeni 	int ret;
5955d5d4700SPaolo Abeni 
5965d5d4700SPaolo Abeni 	ret = nla_parse_nested(tb, NET_SHAPER_A_WEIGHT, attr,
5975d5d4700SPaolo Abeni 			       net_shaper_leaf_info_nl_policy, info->extack);
5985d5d4700SPaolo Abeni 	if (ret < 0)
5995d5d4700SPaolo Abeni 		return ret;
6005d5d4700SPaolo Abeni 
6015d5d4700SPaolo Abeni 	ret = net_shaper_parse_info(binding, tb, info, shaper, &exists);
6025d5d4700SPaolo Abeni 	if (ret < 0)
6035d5d4700SPaolo Abeni 		return ret;
6045d5d4700SPaolo Abeni 
6055d5d4700SPaolo Abeni 	if (shaper->handle.scope != NET_SHAPER_SCOPE_QUEUE) {
6065d5d4700SPaolo Abeni 		NL_SET_BAD_ATTR(info->extack, tb[NET_SHAPER_A_HANDLE]);
6075d5d4700SPaolo Abeni 		return -EINVAL;
6085d5d4700SPaolo Abeni 	}
6095d5d4700SPaolo Abeni 
610ecd82cfeSPaolo Abeni 	if (node->handle.scope == NET_SHAPER_SCOPE_NODE) {
611ecd82cfeSPaolo Abeni 		ret = net_shaper_validate_nesting(binding, shaper,
612ecd82cfeSPaolo Abeni 						  info->extack);
613ecd82cfeSPaolo Abeni 		if (ret < 0)
614ecd82cfeSPaolo Abeni 			return ret;
615ecd82cfeSPaolo Abeni 	}
616ecd82cfeSPaolo Abeni 
6175d5d4700SPaolo Abeni 	if (!exists)
6185d5d4700SPaolo Abeni 		net_shaper_default_parent(&shaper->handle, &shaper->parent);
6195d5d4700SPaolo Abeni 	return 0;
6205d5d4700SPaolo Abeni }
6215d5d4700SPaolo Abeni 
6225d5d4700SPaolo Abeni /* Alike net_parse_shaper_info(), but additionally allow the user specifying
6235d5d4700SPaolo Abeni  * the shaper's parent handle.
6245d5d4700SPaolo Abeni  */
6255d5d4700SPaolo Abeni static int net_shaper_parse_node(struct net_shaper_binding *binding,
6265d5d4700SPaolo Abeni 				 struct nlattr **tb,
6275d5d4700SPaolo Abeni 				 const struct genl_info *info,
6285d5d4700SPaolo Abeni 				 struct net_shaper *shaper)
6295d5d4700SPaolo Abeni {
6305d5d4700SPaolo Abeni 	bool exists;
6315d5d4700SPaolo Abeni 	int ret;
6325d5d4700SPaolo Abeni 
6335d5d4700SPaolo Abeni 	ret = net_shaper_parse_info(binding, tb, info, shaper, &exists);
6345d5d4700SPaolo Abeni 	if (ret)
6355d5d4700SPaolo Abeni 		return ret;
6365d5d4700SPaolo Abeni 
6375d5d4700SPaolo Abeni 	if (shaper->handle.scope != NET_SHAPER_SCOPE_NODE &&
6385d5d4700SPaolo Abeni 	    shaper->handle.scope != NET_SHAPER_SCOPE_NETDEV) {
6395d5d4700SPaolo Abeni 		NL_SET_BAD_ATTR(info->extack, tb[NET_SHAPER_A_HANDLE]);
6405d5d4700SPaolo Abeni 		return -EINVAL;
6415d5d4700SPaolo Abeni 	}
6425d5d4700SPaolo Abeni 
6435d5d4700SPaolo Abeni 	if (tb[NET_SHAPER_A_PARENT]) {
6445d5d4700SPaolo Abeni 		ret = net_shaper_parse_handle(tb[NET_SHAPER_A_PARENT], info,
6455d5d4700SPaolo Abeni 					      &shaper->parent);
6465d5d4700SPaolo Abeni 		if (ret)
6475d5d4700SPaolo Abeni 			return ret;
6485d5d4700SPaolo Abeni 
6495d5d4700SPaolo Abeni 		if (shaper->parent.scope != NET_SHAPER_SCOPE_NODE &&
6505d5d4700SPaolo Abeni 		    shaper->parent.scope != NET_SHAPER_SCOPE_NETDEV) {
6515d5d4700SPaolo Abeni 			NL_SET_BAD_ATTR(info->extack, tb[NET_SHAPER_A_PARENT]);
6525d5d4700SPaolo Abeni 			return -EINVAL;
6535d5d4700SPaolo Abeni 		}
6545d5d4700SPaolo Abeni 	}
6555d5d4700SPaolo Abeni 	return 0;
6565d5d4700SPaolo Abeni }
6575d5d4700SPaolo Abeni 
6584b623f9fSPaolo Abeni static int net_shaper_generic_pre(struct genl_info *info, int type)
6594b623f9fSPaolo Abeni {
6604b623f9fSPaolo Abeni 	struct net_shaper_nl_ctx *ctx = (struct net_shaper_nl_ctx *)info->ctx;
6614b623f9fSPaolo Abeni 
6624b623f9fSPaolo Abeni 	BUILD_BUG_ON(sizeof(*ctx) > sizeof(info->ctx));
6634b623f9fSPaolo Abeni 
6644b623f9fSPaolo Abeni 	return net_shaper_ctx_setup(info, type, ctx);
6654b623f9fSPaolo Abeni }
6664b623f9fSPaolo Abeni 
66704e65df9SPaolo Abeni int net_shaper_nl_pre_doit(const struct genl_split_ops *ops,
66804e65df9SPaolo Abeni 			   struct sk_buff *skb, struct genl_info *info)
66904e65df9SPaolo Abeni {
6704b623f9fSPaolo Abeni 	return net_shaper_generic_pre(info, NET_SHAPER_A_IFINDEX);
6714b623f9fSPaolo Abeni }
6724b623f9fSPaolo Abeni 
6734b623f9fSPaolo Abeni static void net_shaper_generic_post(struct genl_info *info)
6744b623f9fSPaolo Abeni {
6754b623f9fSPaolo Abeni 	net_shaper_ctx_cleanup((struct net_shaper_nl_ctx *)info->ctx);
67604e65df9SPaolo Abeni }
67704e65df9SPaolo Abeni 
67804e65df9SPaolo Abeni void net_shaper_nl_post_doit(const struct genl_split_ops *ops,
67904e65df9SPaolo Abeni 			     struct sk_buff *skb, struct genl_info *info)
68004e65df9SPaolo Abeni {
6814b623f9fSPaolo Abeni 	net_shaper_generic_post(info);
6824b623f9fSPaolo Abeni }
6834b623f9fSPaolo Abeni 
6844b623f9fSPaolo Abeni int net_shaper_nl_pre_dumpit(struct netlink_callback *cb)
6854b623f9fSPaolo Abeni {
6864b623f9fSPaolo Abeni 	struct net_shaper_nl_ctx *ctx = (struct net_shaper_nl_ctx *)cb->ctx;
6874b623f9fSPaolo Abeni 	const struct genl_info *info = genl_info_dump(cb);
6884b623f9fSPaolo Abeni 
6894b623f9fSPaolo Abeni 	return net_shaper_ctx_setup(info, NET_SHAPER_A_IFINDEX, ctx);
6904b623f9fSPaolo Abeni }
6914b623f9fSPaolo Abeni 
6924b623f9fSPaolo Abeni int net_shaper_nl_post_dumpit(struct netlink_callback *cb)
6934b623f9fSPaolo Abeni {
6944b623f9fSPaolo Abeni 	net_shaper_ctx_cleanup((struct net_shaper_nl_ctx *)cb->ctx);
6954b623f9fSPaolo Abeni 	return 0;
69604e65df9SPaolo Abeni }
69704e65df9SPaolo Abeni 
69814bba928SPaolo Abeni int net_shaper_nl_cap_pre_doit(const struct genl_split_ops *ops,
69914bba928SPaolo Abeni 			       struct sk_buff *skb, struct genl_info *info)
70014bba928SPaolo Abeni {
701553ea9f1SPaolo Abeni 	return net_shaper_generic_pre(info, NET_SHAPER_A_CAPS_IFINDEX);
70214bba928SPaolo Abeni }
70314bba928SPaolo Abeni 
70414bba928SPaolo Abeni void net_shaper_nl_cap_post_doit(const struct genl_split_ops *ops,
70514bba928SPaolo Abeni 				 struct sk_buff *skb, struct genl_info *info)
70614bba928SPaolo Abeni {
707553ea9f1SPaolo Abeni 	net_shaper_generic_post(info);
70814bba928SPaolo Abeni }
70914bba928SPaolo Abeni 
71014bba928SPaolo Abeni int net_shaper_nl_cap_pre_dumpit(struct netlink_callback *cb)
71114bba928SPaolo Abeni {
712553ea9f1SPaolo Abeni 	struct net_shaper_nl_ctx *ctx = (struct net_shaper_nl_ctx *)cb->ctx;
713553ea9f1SPaolo Abeni 
714553ea9f1SPaolo Abeni 	return net_shaper_ctx_setup(genl_info_dump(cb),
715553ea9f1SPaolo Abeni 				    NET_SHAPER_A_CAPS_IFINDEX, ctx);
71614bba928SPaolo Abeni }
71714bba928SPaolo Abeni 
71814bba928SPaolo Abeni int net_shaper_nl_cap_post_dumpit(struct netlink_callback *cb)
71914bba928SPaolo Abeni {
720553ea9f1SPaolo Abeni 	struct net_shaper_nl_ctx *ctx = (struct net_shaper_nl_ctx *)cb->ctx;
721553ea9f1SPaolo Abeni 
722553ea9f1SPaolo Abeni 	net_shaper_ctx_cleanup(ctx);
723553ea9f1SPaolo Abeni 	return 0;
72414bba928SPaolo Abeni }
72514bba928SPaolo Abeni 
72604e65df9SPaolo Abeni int net_shaper_nl_get_doit(struct sk_buff *skb, struct genl_info *info)
72704e65df9SPaolo Abeni {
7284b623f9fSPaolo Abeni 	struct net_shaper_binding *binding;
7294b623f9fSPaolo Abeni 	struct net_shaper_handle handle;
7304b623f9fSPaolo Abeni 	struct net_shaper *shaper;
7314b623f9fSPaolo Abeni 	struct sk_buff *msg;
7324b623f9fSPaolo Abeni 	int ret;
7334b623f9fSPaolo Abeni 
7344b623f9fSPaolo Abeni 	if (GENL_REQ_ATTR_CHECK(info, NET_SHAPER_A_HANDLE))
7354b623f9fSPaolo Abeni 		return -EINVAL;
7364b623f9fSPaolo Abeni 
7374b623f9fSPaolo Abeni 	binding = net_shaper_binding_from_ctx(info->ctx);
7384b623f9fSPaolo Abeni 	ret = net_shaper_parse_handle(info->attrs[NET_SHAPER_A_HANDLE], info,
7394b623f9fSPaolo Abeni 				      &handle);
7404b623f9fSPaolo Abeni 	if (ret < 0)
7414b623f9fSPaolo Abeni 		return ret;
7424b623f9fSPaolo Abeni 
7434b623f9fSPaolo Abeni 	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
7444b623f9fSPaolo Abeni 	if (!msg)
7454b623f9fSPaolo Abeni 		return -ENOMEM;
7464b623f9fSPaolo Abeni 
7474b623f9fSPaolo Abeni 	rcu_read_lock();
7484b623f9fSPaolo Abeni 	shaper = net_shaper_lookup(binding, &handle);
7494b623f9fSPaolo Abeni 	if (!shaper) {
7504b623f9fSPaolo Abeni 		NL_SET_BAD_ATTR(info->extack,
7514b623f9fSPaolo Abeni 				info->attrs[NET_SHAPER_A_HANDLE]);
7524b623f9fSPaolo Abeni 		rcu_read_unlock();
7534b623f9fSPaolo Abeni 		ret = -ENOENT;
7544b623f9fSPaolo Abeni 		goto free_msg;
7554b623f9fSPaolo Abeni 	}
7564b623f9fSPaolo Abeni 
7574b623f9fSPaolo Abeni 	ret = net_shaper_fill_one(msg, binding, shaper, info);
7584b623f9fSPaolo Abeni 	rcu_read_unlock();
7594b623f9fSPaolo Abeni 	if (ret)
7604b623f9fSPaolo Abeni 		goto free_msg;
7614b623f9fSPaolo Abeni 
7624b623f9fSPaolo Abeni 	ret = genlmsg_reply(msg, info);
7634b623f9fSPaolo Abeni 	if (ret)
7644b623f9fSPaolo Abeni 		goto free_msg;
7654b623f9fSPaolo Abeni 
7664b623f9fSPaolo Abeni 	return 0;
7674b623f9fSPaolo Abeni 
7684b623f9fSPaolo Abeni free_msg:
7694b623f9fSPaolo Abeni 	nlmsg_free(msg);
7704b623f9fSPaolo Abeni 	return ret;
77104e65df9SPaolo Abeni }
77204e65df9SPaolo Abeni 
77304e65df9SPaolo Abeni int net_shaper_nl_get_dumpit(struct sk_buff *skb,
77404e65df9SPaolo Abeni 			     struct netlink_callback *cb)
77504e65df9SPaolo Abeni {
7764b623f9fSPaolo Abeni 	struct net_shaper_nl_ctx *ctx = (struct net_shaper_nl_ctx *)cb->ctx;
7774b623f9fSPaolo Abeni 	const struct genl_info *info = genl_info_dump(cb);
7784b623f9fSPaolo Abeni 	struct net_shaper_hierarchy *hierarchy;
7794b623f9fSPaolo Abeni 	struct net_shaper_binding *binding;
7804b623f9fSPaolo Abeni 	struct net_shaper *shaper;
7814b623f9fSPaolo Abeni 	int ret = 0;
7824b623f9fSPaolo Abeni 
7834b623f9fSPaolo Abeni 	/* Don't error out dumps performed before any set operation. */
7844b623f9fSPaolo Abeni 	binding = net_shaper_binding_from_ctx(ctx);
7854b623f9fSPaolo Abeni 	hierarchy = net_shaper_hierarchy(binding);
7864b623f9fSPaolo Abeni 	if (!hierarchy)
7874b623f9fSPaolo Abeni 		return 0;
7884b623f9fSPaolo Abeni 
7894b623f9fSPaolo Abeni 	rcu_read_lock();
7904b623f9fSPaolo Abeni 	for (; (shaper = xa_find(&hierarchy->shapers, &ctx->start_index,
7914b623f9fSPaolo Abeni 				 U32_MAX, XA_PRESENT)); ctx->start_index++) {
7924b623f9fSPaolo Abeni 		ret = net_shaper_fill_one(skb, binding, shaper, info);
7934b623f9fSPaolo Abeni 		if (ret)
7944b623f9fSPaolo Abeni 			break;
7954b623f9fSPaolo Abeni 	}
7964b623f9fSPaolo Abeni 	rcu_read_unlock();
7974b623f9fSPaolo Abeni 
7984b623f9fSPaolo Abeni 	return ret;
79904e65df9SPaolo Abeni }
80004e65df9SPaolo Abeni 
80104e65df9SPaolo Abeni int net_shaper_nl_set_doit(struct sk_buff *skb, struct genl_info *info)
80204e65df9SPaolo Abeni {
80393954b40SPaolo Abeni 	struct net_shaper_hierarchy *hierarchy;
80493954b40SPaolo Abeni 	struct net_shaper_binding *binding;
80593954b40SPaolo Abeni 	const struct net_shaper_ops *ops;
80693954b40SPaolo Abeni 	struct net_shaper_handle handle;
80793954b40SPaolo Abeni 	struct net_shaper shaper = {};
80893954b40SPaolo Abeni 	bool exists;
80993954b40SPaolo Abeni 	int ret;
81093954b40SPaolo Abeni 
81193954b40SPaolo Abeni 	binding = net_shaper_binding_from_ctx(info->ctx);
81293954b40SPaolo Abeni 
81393954b40SPaolo Abeni 	net_shaper_lock(binding);
81493954b40SPaolo Abeni 	ret = net_shaper_parse_info(binding, info->attrs, info, &shaper,
81593954b40SPaolo Abeni 				    &exists);
81693954b40SPaolo Abeni 	if (ret)
81793954b40SPaolo Abeni 		goto unlock;
81893954b40SPaolo Abeni 
81993954b40SPaolo Abeni 	if (!exists)
82093954b40SPaolo Abeni 		net_shaper_default_parent(&shaper.handle, &shaper.parent);
82193954b40SPaolo Abeni 
82293954b40SPaolo Abeni 	hierarchy = net_shaper_hierarchy_setup(binding);
82393954b40SPaolo Abeni 	if (!hierarchy) {
82493954b40SPaolo Abeni 		ret = -ENOMEM;
82593954b40SPaolo Abeni 		goto unlock;
82693954b40SPaolo Abeni 	}
82793954b40SPaolo Abeni 
82893954b40SPaolo Abeni 	/* The 'set' operation can't create node-scope shapers. */
82993954b40SPaolo Abeni 	handle = shaper.handle;
83093954b40SPaolo Abeni 	if (handle.scope == NET_SHAPER_SCOPE_NODE &&
83193954b40SPaolo Abeni 	    !net_shaper_lookup(binding, &handle)) {
83293954b40SPaolo Abeni 		ret = -ENOENT;
83393954b40SPaolo Abeni 		goto unlock;
83493954b40SPaolo Abeni 	}
83593954b40SPaolo Abeni 
83693954b40SPaolo Abeni 	ret = net_shaper_pre_insert(binding, &handle, info->extack);
83793954b40SPaolo Abeni 	if (ret)
83893954b40SPaolo Abeni 		goto unlock;
83993954b40SPaolo Abeni 
84093954b40SPaolo Abeni 	ops = net_shaper_ops(binding);
84193954b40SPaolo Abeni 	ret = ops->set(binding, &shaper, info->extack);
84293954b40SPaolo Abeni 	if (ret) {
84393954b40SPaolo Abeni 		net_shaper_rollback(binding);
84493954b40SPaolo Abeni 		goto unlock;
84593954b40SPaolo Abeni 	}
84693954b40SPaolo Abeni 
84793954b40SPaolo Abeni 	net_shaper_commit(binding, 1, &shaper);
84893954b40SPaolo Abeni 
84993954b40SPaolo Abeni unlock:
85093954b40SPaolo Abeni 	net_shaper_unlock(binding);
85193954b40SPaolo Abeni 	return ret;
85293954b40SPaolo Abeni }
85393954b40SPaolo Abeni 
85493954b40SPaolo Abeni static int __net_shaper_delete(struct net_shaper_binding *binding,
85593954b40SPaolo Abeni 			       struct net_shaper *shaper,
85693954b40SPaolo Abeni 			       struct netlink_ext_ack *extack)
85793954b40SPaolo Abeni {
85893954b40SPaolo Abeni 	struct net_shaper_hierarchy *hierarchy = net_shaper_hierarchy(binding);
85993954b40SPaolo Abeni 	struct net_shaper_handle parent_handle, handle = shaper->handle;
86093954b40SPaolo Abeni 	const struct net_shaper_ops *ops = net_shaper_ops(binding);
86193954b40SPaolo Abeni 	int ret;
86293954b40SPaolo Abeni 
86393954b40SPaolo Abeni again:
86493954b40SPaolo Abeni 	parent_handle = shaper->parent;
86593954b40SPaolo Abeni 
86693954b40SPaolo Abeni 	ret = ops->delete(binding, &handle, extack);
86793954b40SPaolo Abeni 	if (ret < 0)
86893954b40SPaolo Abeni 		return ret;
86993954b40SPaolo Abeni 
87093954b40SPaolo Abeni 	xa_erase(&hierarchy->shapers, net_shaper_handle_to_index(&handle));
87193954b40SPaolo Abeni 	kfree_rcu(shaper, rcu);
87293954b40SPaolo Abeni 
87393954b40SPaolo Abeni 	/* Eventually delete the parent, if it is left over with no leaves. */
87493954b40SPaolo Abeni 	if (parent_handle.scope == NET_SHAPER_SCOPE_NODE) {
87593954b40SPaolo Abeni 		shaper = net_shaper_lookup(binding, &parent_handle);
87693954b40SPaolo Abeni 		if (shaper && !--shaper->leaves) {
87793954b40SPaolo Abeni 			handle = parent_handle;
87893954b40SPaolo Abeni 			goto again;
87993954b40SPaolo Abeni 		}
88093954b40SPaolo Abeni 	}
88193954b40SPaolo Abeni 	return 0;
88204e65df9SPaolo Abeni }
88304e65df9SPaolo Abeni 
8845d5d4700SPaolo Abeni static int net_shaper_handle_cmp(const struct net_shaper_handle *a,
8855d5d4700SPaolo Abeni 				 const struct net_shaper_handle *b)
8865d5d4700SPaolo Abeni {
8875d5d4700SPaolo Abeni 	/* Must avoid holes in struct net_shaper_handle. */
8885d5d4700SPaolo Abeni 	BUILD_BUG_ON(sizeof(*a) != 8);
8895d5d4700SPaolo Abeni 
8905d5d4700SPaolo Abeni 	return memcmp(a, b, sizeof(*a));
8915d5d4700SPaolo Abeni }
8925d5d4700SPaolo Abeni 
8935d5d4700SPaolo Abeni static int net_shaper_parent_from_leaves(int leaves_count,
8945d5d4700SPaolo Abeni 					 const struct net_shaper *leaves,
8955d5d4700SPaolo Abeni 					 struct net_shaper *node,
8965d5d4700SPaolo Abeni 					 struct netlink_ext_ack *extack)
8975d5d4700SPaolo Abeni {
8985d5d4700SPaolo Abeni 	struct net_shaper_handle parent = leaves[0].parent;
8995d5d4700SPaolo Abeni 	int i;
9005d5d4700SPaolo Abeni 
9015d5d4700SPaolo Abeni 	for (i = 1; i < leaves_count; ++i) {
9025d5d4700SPaolo Abeni 		if (net_shaper_handle_cmp(&leaves[i].parent, &parent)) {
9035d5d4700SPaolo Abeni 			NL_SET_ERR_MSG_FMT(extack, "All the leaves shapers must have the same old parent");
9045d5d4700SPaolo Abeni 			return -EINVAL;
9055d5d4700SPaolo Abeni 		}
9065d5d4700SPaolo Abeni 	}
9075d5d4700SPaolo Abeni 
9085d5d4700SPaolo Abeni 	node->parent = parent;
9095d5d4700SPaolo Abeni 	return 0;
9105d5d4700SPaolo Abeni }
9115d5d4700SPaolo Abeni 
9125d5d4700SPaolo Abeni static int __net_shaper_group(struct net_shaper_binding *binding,
913bf230c49SPaolo Abeni 			      bool update_node, int leaves_count,
914bf230c49SPaolo Abeni 			      struct net_shaper *leaves,
9155d5d4700SPaolo Abeni 			      struct net_shaper *node,
9165d5d4700SPaolo Abeni 			      struct netlink_ext_ack *extack)
9175d5d4700SPaolo Abeni {
9185d5d4700SPaolo Abeni 	const struct net_shaper_ops *ops = net_shaper_ops(binding);
9195d5d4700SPaolo Abeni 	struct net_shaper_handle leaf_handle;
9205d5d4700SPaolo Abeni 	struct net_shaper *parent = NULL;
9215d5d4700SPaolo Abeni 	bool new_node = false;
9225d5d4700SPaolo Abeni 	int i, ret;
9235d5d4700SPaolo Abeni 
9245d5d4700SPaolo Abeni 	if (node->handle.scope == NET_SHAPER_SCOPE_NODE) {
9255d5d4700SPaolo Abeni 		new_node = node->handle.id == NET_SHAPER_ID_UNSPEC;
9265d5d4700SPaolo Abeni 
9275d5d4700SPaolo Abeni 		if (!new_node && !net_shaper_lookup(binding, &node->handle)) {
9285d5d4700SPaolo Abeni 			/* The related attribute is not available when
9295d5d4700SPaolo Abeni 			 * reaching here from the delete() op.
9305d5d4700SPaolo Abeni 			 */
9315d5d4700SPaolo Abeni 			NL_SET_ERR_MSG_FMT(extack, "Node shaper %d:%d does not exists",
9325d5d4700SPaolo Abeni 					   node->handle.scope, node->handle.id);
9335d5d4700SPaolo Abeni 			return -ENOENT;
9345d5d4700SPaolo Abeni 		}
9355d5d4700SPaolo Abeni 
9365d5d4700SPaolo Abeni 		/* When unspecified, the node parent scope is inherited from
9375d5d4700SPaolo Abeni 		 * the leaves.
9385d5d4700SPaolo Abeni 		 */
9395d5d4700SPaolo Abeni 		if (node->parent.scope == NET_SHAPER_SCOPE_UNSPEC) {
9405d5d4700SPaolo Abeni 			ret = net_shaper_parent_from_leaves(leaves_count,
9415d5d4700SPaolo Abeni 							    leaves, node,
9425d5d4700SPaolo Abeni 							    extack);
9435d5d4700SPaolo Abeni 			if (ret)
9445d5d4700SPaolo Abeni 				return ret;
9455d5d4700SPaolo Abeni 		}
9465d5d4700SPaolo Abeni 
9475d5d4700SPaolo Abeni 	} else {
9485d5d4700SPaolo Abeni 		net_shaper_default_parent(&node->handle, &node->parent);
9495d5d4700SPaolo Abeni 	}
9505d5d4700SPaolo Abeni 
9515d5d4700SPaolo Abeni 	if (node->parent.scope == NET_SHAPER_SCOPE_NODE) {
9525d5d4700SPaolo Abeni 		parent = net_shaper_lookup(binding, &node->parent);
9535d5d4700SPaolo Abeni 		if (!parent) {
9545d5d4700SPaolo Abeni 			NL_SET_ERR_MSG_FMT(extack, "Node parent shaper %d:%d does not exists",
9555d5d4700SPaolo Abeni 					   node->parent.scope, node->parent.id);
9565d5d4700SPaolo Abeni 			return -ENOENT;
9575d5d4700SPaolo Abeni 		}
958ecd82cfeSPaolo Abeni 
959ecd82cfeSPaolo Abeni 		ret = net_shaper_validate_nesting(binding, node, extack);
960ecd82cfeSPaolo Abeni 		if (ret < 0)
961ecd82cfeSPaolo Abeni 			return ret;
9625d5d4700SPaolo Abeni 	}
9635d5d4700SPaolo Abeni 
964bf230c49SPaolo Abeni 	if (update_node) {
965bf230c49SPaolo Abeni 		/* For newly created node scope shaper, the following will
966bf230c49SPaolo Abeni 		 * update the handle, due to id allocation.
9675d5d4700SPaolo Abeni 		 */
9685d5d4700SPaolo Abeni 		ret = net_shaper_pre_insert(binding, &node->handle, extack);
9695d5d4700SPaolo Abeni 		if (ret)
9705d5d4700SPaolo Abeni 			return ret;
971bf230c49SPaolo Abeni 	}
9725d5d4700SPaolo Abeni 
9735d5d4700SPaolo Abeni 	for (i = 0; i < leaves_count; ++i) {
9745d5d4700SPaolo Abeni 		leaf_handle = leaves[i].handle;
9755d5d4700SPaolo Abeni 
9765d5d4700SPaolo Abeni 		ret = net_shaper_pre_insert(binding, &leaf_handle, extack);
9775d5d4700SPaolo Abeni 		if (ret)
9785d5d4700SPaolo Abeni 			goto rollback;
9795d5d4700SPaolo Abeni 
9805d5d4700SPaolo Abeni 		if (!net_shaper_handle_cmp(&leaves[i].parent, &node->handle))
9815d5d4700SPaolo Abeni 			continue;
9825d5d4700SPaolo Abeni 
9835d5d4700SPaolo Abeni 		/* The leaves shapers will be nested to the node, update the
9845d5d4700SPaolo Abeni 		 * linking accordingly.
9855d5d4700SPaolo Abeni 		 */
9865d5d4700SPaolo Abeni 		leaves[i].parent = node->handle;
9875d5d4700SPaolo Abeni 		node->leaves++;
9885d5d4700SPaolo Abeni 	}
9895d5d4700SPaolo Abeni 
9905d5d4700SPaolo Abeni 	ret = ops->group(binding, leaves_count, leaves, node, extack);
9915d5d4700SPaolo Abeni 	if (ret < 0)
9925d5d4700SPaolo Abeni 		goto rollback;
9935d5d4700SPaolo Abeni 
9945d5d4700SPaolo Abeni 	/* The node's parent gains a new leaf only when the node itself
9955d5d4700SPaolo Abeni 	 * is created by this group operation
9965d5d4700SPaolo Abeni 	 */
9975d5d4700SPaolo Abeni 	if (new_node && parent)
9985d5d4700SPaolo Abeni 		parent->leaves++;
999bf230c49SPaolo Abeni 	if (update_node)
10005d5d4700SPaolo Abeni 		net_shaper_commit(binding, 1, node);
10015d5d4700SPaolo Abeni 	net_shaper_commit(binding, leaves_count, leaves);
10025d5d4700SPaolo Abeni 	return 0;
10035d5d4700SPaolo Abeni 
10045d5d4700SPaolo Abeni rollback:
10055d5d4700SPaolo Abeni 	net_shaper_rollback(binding);
10065d5d4700SPaolo Abeni 	return ret;
10075d5d4700SPaolo Abeni }
10085d5d4700SPaolo Abeni 
1009bf230c49SPaolo Abeni static int net_shaper_pre_del_node(struct net_shaper_binding *binding,
1010bf230c49SPaolo Abeni 				   const struct net_shaper *shaper,
1011bf230c49SPaolo Abeni 				   struct netlink_ext_ack *extack)
1012bf230c49SPaolo Abeni {
1013bf230c49SPaolo Abeni 	struct net_shaper_hierarchy *hierarchy = net_shaper_hierarchy(binding);
1014bf230c49SPaolo Abeni 	struct net_shaper *cur, *leaves, node = {};
1015bf230c49SPaolo Abeni 	int ret, leaves_count = 0;
1016bf230c49SPaolo Abeni 	unsigned long index;
1017bf230c49SPaolo Abeni 	bool update_node;
1018bf230c49SPaolo Abeni 
1019bf230c49SPaolo Abeni 	if (!shaper->leaves)
1020bf230c49SPaolo Abeni 		return 0;
1021bf230c49SPaolo Abeni 
1022bf230c49SPaolo Abeni 	/* Fetch the new node information. */
1023bf230c49SPaolo Abeni 	node.handle = shaper->parent;
1024bf230c49SPaolo Abeni 	cur = net_shaper_lookup(binding, &node.handle);
1025bf230c49SPaolo Abeni 	if (cur) {
1026bf230c49SPaolo Abeni 		node = *cur;
1027bf230c49SPaolo Abeni 	} else {
1028bf230c49SPaolo Abeni 		/* A scope NODE shaper can be nested only to the NETDEV scope
1029bf230c49SPaolo Abeni 		 * shaper without creating the latter, this check may fail only
1030bf230c49SPaolo Abeni 		 * if the data is in inconsistent status.
1031bf230c49SPaolo Abeni 		 */
1032bf230c49SPaolo Abeni 		if (WARN_ON_ONCE(node.handle.scope != NET_SHAPER_SCOPE_NETDEV))
1033bf230c49SPaolo Abeni 			return -EINVAL;
1034bf230c49SPaolo Abeni 	}
1035bf230c49SPaolo Abeni 
1036bf230c49SPaolo Abeni 	leaves = kcalloc(shaper->leaves, sizeof(struct net_shaper),
1037bf230c49SPaolo Abeni 			 GFP_KERNEL);
1038bf230c49SPaolo Abeni 	if (!leaves)
1039bf230c49SPaolo Abeni 		return -ENOMEM;
1040bf230c49SPaolo Abeni 
1041bf230c49SPaolo Abeni 	/* Build the leaves arrays. */
1042bf230c49SPaolo Abeni 	xa_for_each(&hierarchy->shapers, index, cur) {
1043bf230c49SPaolo Abeni 		if (net_shaper_handle_cmp(&cur->parent, &shaper->handle))
1044bf230c49SPaolo Abeni 			continue;
1045bf230c49SPaolo Abeni 
1046bf230c49SPaolo Abeni 		if (WARN_ON_ONCE(leaves_count == shaper->leaves)) {
1047bf230c49SPaolo Abeni 			ret = -EINVAL;
1048bf230c49SPaolo Abeni 			goto free;
1049bf230c49SPaolo Abeni 		}
1050bf230c49SPaolo Abeni 
1051bf230c49SPaolo Abeni 		leaves[leaves_count++] = *cur;
1052bf230c49SPaolo Abeni 	}
1053bf230c49SPaolo Abeni 
1054bf230c49SPaolo Abeni 	/* When re-linking to the netdev shaper, avoid the eventual, implicit,
1055bf230c49SPaolo Abeni 	 * creation of the new node, would be surprising since the user is
1056bf230c49SPaolo Abeni 	 * doing a delete operation.
1057bf230c49SPaolo Abeni 	 */
1058bf230c49SPaolo Abeni 	update_node = node.handle.scope != NET_SHAPER_SCOPE_NETDEV;
1059bf230c49SPaolo Abeni 	ret = __net_shaper_group(binding, update_node, leaves_count,
1060bf230c49SPaolo Abeni 				 leaves, &node, extack);
1061bf230c49SPaolo Abeni 
1062bf230c49SPaolo Abeni free:
1063bf230c49SPaolo Abeni 	kfree(leaves);
1064bf230c49SPaolo Abeni 	return ret;
1065bf230c49SPaolo Abeni }
1066bf230c49SPaolo Abeni 
106704e65df9SPaolo Abeni int net_shaper_nl_delete_doit(struct sk_buff *skb, struct genl_info *info)
106804e65df9SPaolo Abeni {
106993954b40SPaolo Abeni 	struct net_shaper_hierarchy *hierarchy;
107093954b40SPaolo Abeni 	struct net_shaper_binding *binding;
107193954b40SPaolo Abeni 	struct net_shaper_handle handle;
107293954b40SPaolo Abeni 	struct net_shaper *shaper;
107393954b40SPaolo Abeni 	int ret;
107493954b40SPaolo Abeni 
107593954b40SPaolo Abeni 	if (GENL_REQ_ATTR_CHECK(info, NET_SHAPER_A_HANDLE))
107693954b40SPaolo Abeni 		return -EINVAL;
107793954b40SPaolo Abeni 
107893954b40SPaolo Abeni 	binding = net_shaper_binding_from_ctx(info->ctx);
107993954b40SPaolo Abeni 
108093954b40SPaolo Abeni 	net_shaper_lock(binding);
108193954b40SPaolo Abeni 	ret = net_shaper_parse_handle(info->attrs[NET_SHAPER_A_HANDLE], info,
108293954b40SPaolo Abeni 				      &handle);
108393954b40SPaolo Abeni 	if (ret)
108493954b40SPaolo Abeni 		goto unlock;
108593954b40SPaolo Abeni 
108693954b40SPaolo Abeni 	hierarchy = net_shaper_hierarchy(binding);
108793954b40SPaolo Abeni 	if (!hierarchy) {
108893954b40SPaolo Abeni 		ret = -ENOENT;
108993954b40SPaolo Abeni 		goto unlock;
109093954b40SPaolo Abeni 	}
109193954b40SPaolo Abeni 
109293954b40SPaolo Abeni 	shaper = net_shaper_lookup(binding, &handle);
109393954b40SPaolo Abeni 	if (!shaper) {
109493954b40SPaolo Abeni 		ret = -ENOENT;
109593954b40SPaolo Abeni 		goto unlock;
109693954b40SPaolo Abeni 	}
109793954b40SPaolo Abeni 
109893954b40SPaolo Abeni 	if (handle.scope == NET_SHAPER_SCOPE_NODE) {
1099bf230c49SPaolo Abeni 		ret = net_shaper_pre_del_node(binding, shaper, info->extack);
1100bf230c49SPaolo Abeni 		if (ret)
110193954b40SPaolo Abeni 			goto unlock;
110293954b40SPaolo Abeni 	}
110393954b40SPaolo Abeni 
110493954b40SPaolo Abeni 	ret = __net_shaper_delete(binding, shaper, info->extack);
110593954b40SPaolo Abeni 
110693954b40SPaolo Abeni unlock:
110793954b40SPaolo Abeni 	net_shaper_unlock(binding);
110893954b40SPaolo Abeni 	return ret;
110904e65df9SPaolo Abeni }
111004e65df9SPaolo Abeni 
11115d5d4700SPaolo Abeni static int net_shaper_group_send_reply(struct net_shaper_binding *binding,
11125d5d4700SPaolo Abeni 				       const struct net_shaper_handle *handle,
11135d5d4700SPaolo Abeni 				       struct genl_info *info,
11145d5d4700SPaolo Abeni 				       struct sk_buff *msg)
11155d5d4700SPaolo Abeni {
11165d5d4700SPaolo Abeni 	void *hdr;
11175d5d4700SPaolo Abeni 
11185d5d4700SPaolo Abeni 	hdr = genlmsg_iput(msg, info);
11195d5d4700SPaolo Abeni 	if (!hdr)
11205d5d4700SPaolo Abeni 		goto free_msg;
11215d5d4700SPaolo Abeni 
11225d5d4700SPaolo Abeni 	if (net_shaper_fill_binding(msg, binding, NET_SHAPER_A_IFINDEX) ||
11235d5d4700SPaolo Abeni 	    net_shaper_fill_handle(msg, handle, NET_SHAPER_A_HANDLE))
11245d5d4700SPaolo Abeni 		goto free_msg;
11255d5d4700SPaolo Abeni 
11265d5d4700SPaolo Abeni 	genlmsg_end(msg, hdr);
11275d5d4700SPaolo Abeni 
11285d5d4700SPaolo Abeni 	return genlmsg_reply(msg, info);
11295d5d4700SPaolo Abeni 
11305d5d4700SPaolo Abeni free_msg:
11315d5d4700SPaolo Abeni 	/* Should never happen as msg is pre-allocated with enough space. */
11325d5d4700SPaolo Abeni 	WARN_ONCE(true, "calculated message payload length (%d)",
11335d5d4700SPaolo Abeni 		  net_shaper_handle_size());
11345d5d4700SPaolo Abeni 	nlmsg_free(msg);
11355d5d4700SPaolo Abeni 	return -EMSGSIZE;
11365d5d4700SPaolo Abeni }
11375d5d4700SPaolo Abeni 
11385d5d4700SPaolo Abeni int net_shaper_nl_group_doit(struct sk_buff *skb, struct genl_info *info)
11395d5d4700SPaolo Abeni {
11405d5d4700SPaolo Abeni 	struct net_shaper **old_nodes, *leaves, node = {};
11415d5d4700SPaolo Abeni 	struct net_shaper_hierarchy *hierarchy;
11425d5d4700SPaolo Abeni 	struct net_shaper_binding *binding;
11435d5d4700SPaolo Abeni 	int i, ret, rem, leaves_count;
11445d5d4700SPaolo Abeni 	int old_nodes_count = 0;
11455d5d4700SPaolo Abeni 	struct sk_buff *msg;
11465d5d4700SPaolo Abeni 	struct nlattr *attr;
11475d5d4700SPaolo Abeni 
11485d5d4700SPaolo Abeni 	if (GENL_REQ_ATTR_CHECK(info, NET_SHAPER_A_LEAVES))
11495d5d4700SPaolo Abeni 		return -EINVAL;
11505d5d4700SPaolo Abeni 
11515d5d4700SPaolo Abeni 	binding = net_shaper_binding_from_ctx(info->ctx);
11525d5d4700SPaolo Abeni 
11535d5d4700SPaolo Abeni 	/* The group operation is optional. */
11545d5d4700SPaolo Abeni 	if (!net_shaper_ops(binding)->group)
11555d5d4700SPaolo Abeni 		return -EOPNOTSUPP;
11565d5d4700SPaolo Abeni 
11575d5d4700SPaolo Abeni 	net_shaper_lock(binding);
11585d5d4700SPaolo Abeni 	leaves_count = net_shaper_list_len(info, NET_SHAPER_A_LEAVES);
11595d5d4700SPaolo Abeni 	if (!leaves_count) {
11605d5d4700SPaolo Abeni 		NL_SET_BAD_ATTR(info->extack,
11615d5d4700SPaolo Abeni 				info->attrs[NET_SHAPER_A_LEAVES]);
11625d5d4700SPaolo Abeni 		ret = -EINVAL;
11635d5d4700SPaolo Abeni 		goto unlock;
11645d5d4700SPaolo Abeni 	}
11655d5d4700SPaolo Abeni 
11665d5d4700SPaolo Abeni 	leaves = kcalloc(leaves_count, sizeof(struct net_shaper) +
11675d5d4700SPaolo Abeni 			 sizeof(struct net_shaper *), GFP_KERNEL);
11685d5d4700SPaolo Abeni 	if (!leaves) {
11695d5d4700SPaolo Abeni 		ret = -ENOMEM;
11705d5d4700SPaolo Abeni 		goto unlock;
11715d5d4700SPaolo Abeni 	}
11725d5d4700SPaolo Abeni 	old_nodes = (void *)&leaves[leaves_count];
11735d5d4700SPaolo Abeni 
11745d5d4700SPaolo Abeni 	ret = net_shaper_parse_node(binding, info->attrs, info, &node);
11755d5d4700SPaolo Abeni 	if (ret)
11765d5d4700SPaolo Abeni 		goto free_leaves;
11775d5d4700SPaolo Abeni 
11785d5d4700SPaolo Abeni 	i = 0;
11795d5d4700SPaolo Abeni 	nla_for_each_attr_type(attr, NET_SHAPER_A_LEAVES,
11805d5d4700SPaolo Abeni 			       genlmsg_data(info->genlhdr),
11815d5d4700SPaolo Abeni 			       genlmsg_len(info->genlhdr), rem) {
11825d5d4700SPaolo Abeni 		if (WARN_ON_ONCE(i >= leaves_count))
11835d5d4700SPaolo Abeni 			goto free_leaves;
11845d5d4700SPaolo Abeni 
11855d5d4700SPaolo Abeni 		ret = net_shaper_parse_leaf(binding, attr, info,
11865d5d4700SPaolo Abeni 					    &node, &leaves[i]);
11875d5d4700SPaolo Abeni 		if (ret)
11885d5d4700SPaolo Abeni 			goto free_leaves;
11895d5d4700SPaolo Abeni 		i++;
11905d5d4700SPaolo Abeni 	}
11915d5d4700SPaolo Abeni 
11925d5d4700SPaolo Abeni 	/* Prepare the msg reply in advance, to avoid device operation
11935d5d4700SPaolo Abeni 	 * rollback on allocation failure.
11945d5d4700SPaolo Abeni 	 */
11955d5d4700SPaolo Abeni 	msg = genlmsg_new(net_shaper_handle_size(), GFP_KERNEL);
11965d5d4700SPaolo Abeni 	if (!msg)
11975d5d4700SPaolo Abeni 		goto free_leaves;
11985d5d4700SPaolo Abeni 
11995d5d4700SPaolo Abeni 	hierarchy = net_shaper_hierarchy_setup(binding);
12005d5d4700SPaolo Abeni 	if (!hierarchy) {
12015d5d4700SPaolo Abeni 		ret = -ENOMEM;
12025d5d4700SPaolo Abeni 		goto free_msg;
12035d5d4700SPaolo Abeni 	}
12045d5d4700SPaolo Abeni 
12055d5d4700SPaolo Abeni 	/* Record the node shapers that this group() operation can make
12065d5d4700SPaolo Abeni 	 * childless for later cleanup.
12075d5d4700SPaolo Abeni 	 */
12085d5d4700SPaolo Abeni 	for (i = 0; i < leaves_count; i++) {
12095d5d4700SPaolo Abeni 		if (leaves[i].parent.scope == NET_SHAPER_SCOPE_NODE &&
12105d5d4700SPaolo Abeni 		    net_shaper_handle_cmp(&leaves[i].parent, &node.handle)) {
12115d5d4700SPaolo Abeni 			struct net_shaper *tmp;
12125d5d4700SPaolo Abeni 
12135d5d4700SPaolo Abeni 			tmp = net_shaper_lookup(binding, &leaves[i].parent);
12145d5d4700SPaolo Abeni 			if (!tmp)
12155d5d4700SPaolo Abeni 				continue;
12165d5d4700SPaolo Abeni 
12175d5d4700SPaolo Abeni 			old_nodes[old_nodes_count++] = tmp;
12185d5d4700SPaolo Abeni 		}
12195d5d4700SPaolo Abeni 	}
12205d5d4700SPaolo Abeni 
1221bf230c49SPaolo Abeni 	ret = __net_shaper_group(binding, true, leaves_count, leaves, &node,
12225d5d4700SPaolo Abeni 				 info->extack);
12235d5d4700SPaolo Abeni 	if (ret)
12245d5d4700SPaolo Abeni 		goto free_msg;
12255d5d4700SPaolo Abeni 
12265d5d4700SPaolo Abeni 	/* Check if we need to delete any node left alone by the new leaves
12275d5d4700SPaolo Abeni 	 * linkage.
12285d5d4700SPaolo Abeni 	 */
12295d5d4700SPaolo Abeni 	for (i = 0; i < old_nodes_count; ++i) {
12305d5d4700SPaolo Abeni 		struct net_shaper *tmp = old_nodes[i];
12315d5d4700SPaolo Abeni 
12325d5d4700SPaolo Abeni 		if (--tmp->leaves > 0)
12335d5d4700SPaolo Abeni 			continue;
12345d5d4700SPaolo Abeni 
12355d5d4700SPaolo Abeni 		/* Errors here are not fatal: the grouping operation is
12365d5d4700SPaolo Abeni 		 * completed, and user-space can still explicitly clean-up
12375d5d4700SPaolo Abeni 		 * left-over nodes.
12385d5d4700SPaolo Abeni 		 */
12395d5d4700SPaolo Abeni 		__net_shaper_delete(binding, tmp, info->extack);
12405d5d4700SPaolo Abeni 	}
12415d5d4700SPaolo Abeni 
12425d5d4700SPaolo Abeni 	ret = net_shaper_group_send_reply(binding, &node.handle, info, msg);
12435d5d4700SPaolo Abeni 	if (ret)
12445d5d4700SPaolo Abeni 		GENL_SET_ERR_MSG_FMT(info, "Can't send reply");
12455d5d4700SPaolo Abeni 
12465d5d4700SPaolo Abeni free_leaves:
12475d5d4700SPaolo Abeni 	kfree(leaves);
12485d5d4700SPaolo Abeni 
12495d5d4700SPaolo Abeni unlock:
12505d5d4700SPaolo Abeni 	net_shaper_unlock(binding);
12515d5d4700SPaolo Abeni 	return ret;
12525d5d4700SPaolo Abeni 
12535d5d4700SPaolo Abeni free_msg:
12545d5d4700SPaolo Abeni 	kfree_skb(msg);
12555d5d4700SPaolo Abeni 	goto free_leaves;
12565d5d4700SPaolo Abeni }
12575d5d4700SPaolo Abeni 
1258553ea9f1SPaolo Abeni static int
1259553ea9f1SPaolo Abeni net_shaper_cap_fill_one(struct sk_buff *msg,
1260553ea9f1SPaolo Abeni 			struct net_shaper_binding *binding,
1261553ea9f1SPaolo Abeni 			enum net_shaper_scope scope, unsigned long flags,
1262553ea9f1SPaolo Abeni 			const struct genl_info *info)
1263553ea9f1SPaolo Abeni {
1264553ea9f1SPaolo Abeni 	unsigned long cur;
1265553ea9f1SPaolo Abeni 	void *hdr;
1266553ea9f1SPaolo Abeni 
1267553ea9f1SPaolo Abeni 	hdr = genlmsg_iput(msg, info);
1268553ea9f1SPaolo Abeni 	if (!hdr)
1269553ea9f1SPaolo Abeni 		return -EMSGSIZE;
1270553ea9f1SPaolo Abeni 
1271553ea9f1SPaolo Abeni 	if (net_shaper_fill_binding(msg, binding, NET_SHAPER_A_CAPS_IFINDEX) ||
1272553ea9f1SPaolo Abeni 	    nla_put_u32(msg, NET_SHAPER_A_CAPS_SCOPE, scope))
1273553ea9f1SPaolo Abeni 		goto nla_put_failure;
1274553ea9f1SPaolo Abeni 
1275553ea9f1SPaolo Abeni 	for (cur = NET_SHAPER_A_CAPS_SUPPORT_METRIC_BPS;
1276553ea9f1SPaolo Abeni 	     cur <= NET_SHAPER_A_CAPS_MAX; ++cur) {
1277553ea9f1SPaolo Abeni 		if (flags & BIT(cur) && nla_put_flag(msg, cur))
1278553ea9f1SPaolo Abeni 			goto nla_put_failure;
1279553ea9f1SPaolo Abeni 	}
1280553ea9f1SPaolo Abeni 
1281553ea9f1SPaolo Abeni 	genlmsg_end(msg, hdr);
1282553ea9f1SPaolo Abeni 
1283553ea9f1SPaolo Abeni 	return 0;
1284553ea9f1SPaolo Abeni 
1285553ea9f1SPaolo Abeni nla_put_failure:
1286553ea9f1SPaolo Abeni 	genlmsg_cancel(msg, hdr);
1287553ea9f1SPaolo Abeni 	return -EMSGSIZE;
1288553ea9f1SPaolo Abeni }
1289553ea9f1SPaolo Abeni 
129014bba928SPaolo Abeni int net_shaper_nl_cap_get_doit(struct sk_buff *skb, struct genl_info *info)
129114bba928SPaolo Abeni {
1292553ea9f1SPaolo Abeni 	struct net_shaper_binding *binding;
1293553ea9f1SPaolo Abeni 	const struct net_shaper_ops *ops;
1294553ea9f1SPaolo Abeni 	enum net_shaper_scope scope;
1295553ea9f1SPaolo Abeni 	unsigned long flags = 0;
1296553ea9f1SPaolo Abeni 	struct sk_buff *msg;
1297553ea9f1SPaolo Abeni 	int ret;
1298553ea9f1SPaolo Abeni 
1299553ea9f1SPaolo Abeni 	if (GENL_REQ_ATTR_CHECK(info, NET_SHAPER_A_CAPS_SCOPE))
1300553ea9f1SPaolo Abeni 		return -EINVAL;
1301553ea9f1SPaolo Abeni 
1302553ea9f1SPaolo Abeni 	binding = net_shaper_binding_from_ctx(info->ctx);
1303553ea9f1SPaolo Abeni 	scope = nla_get_u32(info->attrs[NET_SHAPER_A_CAPS_SCOPE]);
1304553ea9f1SPaolo Abeni 	ops = net_shaper_ops(binding);
1305553ea9f1SPaolo Abeni 	ops->capabilities(binding, scope, &flags);
1306553ea9f1SPaolo Abeni 	if (!flags)
1307553ea9f1SPaolo Abeni 		return -EOPNOTSUPP;
1308553ea9f1SPaolo Abeni 
1309553ea9f1SPaolo Abeni 	msg = genlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
1310553ea9f1SPaolo Abeni 	if (!msg)
1311553ea9f1SPaolo Abeni 		return -ENOMEM;
1312553ea9f1SPaolo Abeni 
1313553ea9f1SPaolo Abeni 	ret = net_shaper_cap_fill_one(msg, binding, scope, flags, info);
1314553ea9f1SPaolo Abeni 	if (ret)
1315553ea9f1SPaolo Abeni 		goto free_msg;
1316553ea9f1SPaolo Abeni 
1317553ea9f1SPaolo Abeni 	ret =  genlmsg_reply(msg, info);
1318553ea9f1SPaolo Abeni 	if (ret)
1319553ea9f1SPaolo Abeni 		goto free_msg;
132014bba928SPaolo Abeni 	return 0;
1321553ea9f1SPaolo Abeni 
1322553ea9f1SPaolo Abeni free_msg:
1323553ea9f1SPaolo Abeni 	nlmsg_free(msg);
1324553ea9f1SPaolo Abeni 	return ret;
132514bba928SPaolo Abeni }
132614bba928SPaolo Abeni 
132714bba928SPaolo Abeni int net_shaper_nl_cap_get_dumpit(struct sk_buff *skb,
132814bba928SPaolo Abeni 				 struct netlink_callback *cb)
132914bba928SPaolo Abeni {
1330553ea9f1SPaolo Abeni 	const struct genl_info *info = genl_info_dump(cb);
1331553ea9f1SPaolo Abeni 	struct net_shaper_binding *binding;
1332553ea9f1SPaolo Abeni 	const struct net_shaper_ops *ops;
1333553ea9f1SPaolo Abeni 	enum net_shaper_scope scope;
1334553ea9f1SPaolo Abeni 	int ret;
1335553ea9f1SPaolo Abeni 
1336553ea9f1SPaolo Abeni 	binding = net_shaper_binding_from_ctx(cb->ctx);
1337553ea9f1SPaolo Abeni 	ops = net_shaper_ops(binding);
1338553ea9f1SPaolo Abeni 	for (scope = 0; scope <= NET_SHAPER_SCOPE_MAX; ++scope) {
1339553ea9f1SPaolo Abeni 		unsigned long flags = 0;
1340553ea9f1SPaolo Abeni 
1341553ea9f1SPaolo Abeni 		ops->capabilities(binding, scope, &flags);
1342553ea9f1SPaolo Abeni 		if (!flags)
1343553ea9f1SPaolo Abeni 			continue;
1344553ea9f1SPaolo Abeni 
1345553ea9f1SPaolo Abeni 		ret = net_shaper_cap_fill_one(skb, binding, scope, flags,
1346553ea9f1SPaolo Abeni 					      info);
1347553ea9f1SPaolo Abeni 		if (ret)
1348553ea9f1SPaolo Abeni 			return ret;
1349553ea9f1SPaolo Abeni 	}
1350553ea9f1SPaolo Abeni 
135114bba928SPaolo Abeni 	return 0;
135214bba928SPaolo Abeni }
135314bba928SPaolo Abeni 
13544b623f9fSPaolo Abeni static void net_shaper_flush(struct net_shaper_binding *binding)
135504e65df9SPaolo Abeni {
13564b623f9fSPaolo Abeni 	struct net_shaper_hierarchy *hierarchy = net_shaper_hierarchy(binding);
13574b623f9fSPaolo Abeni 	struct net_shaper *cur;
13584b623f9fSPaolo Abeni 	unsigned long index;
13594b623f9fSPaolo Abeni 
13604b623f9fSPaolo Abeni 	if (!hierarchy)
13614b623f9fSPaolo Abeni 		return;
13624b623f9fSPaolo Abeni 
136393954b40SPaolo Abeni 	net_shaper_lock(binding);
13644b623f9fSPaolo Abeni 	xa_lock(&hierarchy->shapers);
13654b623f9fSPaolo Abeni 	xa_for_each(&hierarchy->shapers, index, cur) {
13664b623f9fSPaolo Abeni 		__xa_erase(&hierarchy->shapers, index);
13674b623f9fSPaolo Abeni 		kfree(cur);
13684b623f9fSPaolo Abeni 	}
13694b623f9fSPaolo Abeni 	xa_unlock(&hierarchy->shapers);
137093954b40SPaolo Abeni 	net_shaper_unlock(binding);
137193954b40SPaolo Abeni 
13724b623f9fSPaolo Abeni 	kfree(hierarchy);
137304e65df9SPaolo Abeni }
137404e65df9SPaolo Abeni 
13754b623f9fSPaolo Abeni void net_shaper_flush_netdev(struct net_device *dev)
137604e65df9SPaolo Abeni {
13774b623f9fSPaolo Abeni 	struct net_shaper_binding binding = {
13784b623f9fSPaolo Abeni 		.type = NET_SHAPER_BINDING_TYPE_NETDEV,
13794b623f9fSPaolo Abeni 		.netdev = dev,
13804b623f9fSPaolo Abeni 	};
13814b623f9fSPaolo Abeni 
13824b623f9fSPaolo Abeni 	net_shaper_flush(&binding);
138304e65df9SPaolo Abeni }
138404e65df9SPaolo Abeni 
1385ff7d4debSPaolo Abeni void net_shaper_set_real_num_tx_queues(struct net_device *dev,
1386ff7d4debSPaolo Abeni 				       unsigned int txq)
1387ff7d4debSPaolo Abeni {
1388ff7d4debSPaolo Abeni 	struct net_shaper_hierarchy *hierarchy;
1389ff7d4debSPaolo Abeni 	struct net_shaper_binding binding;
1390ff7d4debSPaolo Abeni 	int i;
1391ff7d4debSPaolo Abeni 
1392ff7d4debSPaolo Abeni 	binding.type = NET_SHAPER_BINDING_TYPE_NETDEV;
1393ff7d4debSPaolo Abeni 	binding.netdev = dev;
1394ff7d4debSPaolo Abeni 	hierarchy = net_shaper_hierarchy(&binding);
1395ff7d4debSPaolo Abeni 	if (!hierarchy)
1396ff7d4debSPaolo Abeni 		return;
1397ff7d4debSPaolo Abeni 
1398ff7d4debSPaolo Abeni 	/* Only drivers implementing shapers support ensure
1399ff7d4debSPaolo Abeni 	 * the lock is acquired in advance.
1400ff7d4debSPaolo Abeni 	 */
1401*ebda2f0bSJakub Kicinski 	netdev_assert_locked(dev);
1402ff7d4debSPaolo Abeni 
1403ff7d4debSPaolo Abeni 	/* Take action only when decreasing the tx queue number. */
1404ff7d4debSPaolo Abeni 	for (i = txq; i < dev->real_num_tx_queues; ++i) {
1405ff7d4debSPaolo Abeni 		struct net_shaper_handle handle, parent_handle;
1406ff7d4debSPaolo Abeni 		struct net_shaper *shaper;
1407ff7d4debSPaolo Abeni 		u32 index;
1408ff7d4debSPaolo Abeni 
1409ff7d4debSPaolo Abeni 		handle.scope = NET_SHAPER_SCOPE_QUEUE;
1410ff7d4debSPaolo Abeni 		handle.id = i;
1411ff7d4debSPaolo Abeni 		shaper = net_shaper_lookup(&binding, &handle);
1412ff7d4debSPaolo Abeni 		if (!shaper)
1413ff7d4debSPaolo Abeni 			continue;
1414ff7d4debSPaolo Abeni 
1415ff7d4debSPaolo Abeni 		/* Don't touch the H/W for the queue shaper, the drivers already
1416ff7d4debSPaolo Abeni 		 * deleted the queue and related resources.
1417ff7d4debSPaolo Abeni 		 */
1418ff7d4debSPaolo Abeni 		parent_handle = shaper->parent;
1419ff7d4debSPaolo Abeni 		index = net_shaper_handle_to_index(&handle);
1420ff7d4debSPaolo Abeni 		xa_erase(&hierarchy->shapers, index);
1421ff7d4debSPaolo Abeni 		kfree_rcu(shaper, rcu);
1422ff7d4debSPaolo Abeni 
1423ff7d4debSPaolo Abeni 		/* The recursion on parent does the full job. */
1424ff7d4debSPaolo Abeni 		if (parent_handle.scope != NET_SHAPER_SCOPE_NODE)
1425ff7d4debSPaolo Abeni 			continue;
1426ff7d4debSPaolo Abeni 
1427ff7d4debSPaolo Abeni 		shaper = net_shaper_lookup(&binding, &parent_handle);
1428ff7d4debSPaolo Abeni 		if (shaper && !--shaper->leaves)
1429ff7d4debSPaolo Abeni 			__net_shaper_delete(&binding, shaper, NULL);
1430ff7d4debSPaolo Abeni 	}
1431ff7d4debSPaolo Abeni }
1432ff7d4debSPaolo Abeni 
143304e65df9SPaolo Abeni static int __init shaper_init(void)
143404e65df9SPaolo Abeni {
143504e65df9SPaolo Abeni 	return genl_register_family(&net_shaper_nl_family);
143604e65df9SPaolo Abeni }
143704e65df9SPaolo Abeni 
143804e65df9SPaolo Abeni subsys_initcall(shaper_init);
1439