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