[PATCH v4 net-next 06/12] net-shapers: implement delete support for NODE scope shaper
From: Paolo Abeni <pabeni@redhat.com>
Date: 2024-08-20 15:13:26
Subsystem:
networking [general], the rest · Maintainers:
"David S. Miller", Eric Dumazet, Jakub Kicinski, Paolo Abeni, Linus Torvalds
Leverage the previously introduced group operation to implement the removal of NODE scope shaper, re-linking its leaves under the the parent node before actually deleting the specified NODE scope shaper. Signed-off-by: Paolo Abeni <pabeni@redhat.com> --- net/shaper/shaper.c | 98 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 86 insertions(+), 12 deletions(-)
diff --git a/net/shaper/shaper.c b/net/shaper/shaper.c
index c4228f98b416..e5282c5bebe1 100644
--- a/net/shaper/shaper.c
+++ b/net/shaper/shaper.c@@ -675,7 +675,8 @@ static int __net_shaper_delete(struct net_device *dev, return 0; } -static int __net_shaper_group(struct net_device *dev, int leaves_count, +static int __net_shaper_group(struct net_device *dev, + bool cache_root, int leaves_count, const struct net_shaper_handle *leaves_handles, struct net_shaper_info *leaves, struct net_shaper_handle *root_handle,
@@ -710,12 +711,14 @@ static int __net_shaper_group(struct net_device *dev, int leaves_count, } } - /* For newly created node scope shaper, the following will update - * the handle, due to id allocation. - */ - ret = net_shaper_cache_pre_insert(dev, root_handle, extack); - if (ret) - return ret; + if (cache_root) { + /* For newly created node scope shaper, the following will + * update the handle, due to id allocation. + */ + ret = net_shaper_cache_pre_insert(dev, root_handle, extack); + if (ret) + return ret; + } for (i = 0; i < leaves_count; ++i) { leaf_handle = leaves_handles[i];
@@ -750,7 +753,8 @@ static int __net_shaper_group(struct net_device *dev, int leaves_count, if (parent) parent->leaves++; - net_shaper_cache_commit(dev, 1, root_handle, root); + if (cache_root) + net_shaper_cache_commit(dev, 1, root_handle, root); net_shaper_cache_commit(dev, leaves_count, leaves_handles, leaves); return 0;
@@ -758,6 +762,76 @@ static int __net_shaper_group(struct net_device *dev, int leaves_count, net_shaper_cache_rollback(dev); return ret; } + +static int __net_shaper_pre_del_node(struct net_device *dev, + const struct net_shaper_handle *handle, + const struct net_shaper_info *shaper, + struct netlink_ext_ack *extack) +{ + struct net_shaper_handle *leaves_handles, root_handle; + struct xarray *xa = net_shaper_cache_container(dev); + struct net_shaper_info *cur, *leaves, root = {}; + int ret, leaves_count = 0; + unsigned long index; + bool cache_root; + + if (!shaper->leaves) + return 0; + + if (WARN_ON_ONCE(!xa)) + return -EINVAL; + + /* Fetch the new root information. */ + root_handle = shaper->parent; + cur = net_shaper_cache_lookup(dev, &root_handle); + if (cur) { + root = *cur; + } else { + /* A scope NODE shaper can be nested only to the NETDEV scope + * shaper without creating the latter, this check may fail only + * if the cache is in inconsistent status. + */ + if (WARN_ON_ONCE(root_handle.scope != NET_SHAPER_SCOPE_NETDEV)) + return -EINVAL; + } + + leaves = kcalloc(shaper->leaves, + sizeof(struct net_shaper_info) + + sizeof(struct net_shaper_handle), GFP_KERNEL); + if (!leaves) + return -ENOMEM; + + leaves_handles = (struct net_shaper_handle *)&leaves[shaper->leaves]; + + /* Build the leaves arrays. */ + xa_for_each(xa, index, cur) { + if (cur->parent.scope != handle->scope || + cur->parent.id != handle->id) + continue; + + if (WARN_ON_ONCE(leaves_count == shaper->leaves)) { + ret = -EINVAL; + goto free; + } + + net_shaper_index_to_handle(index, + &leaves_handles[leaves_count]); + leaves[leaves_count++] = *cur; + } + + /* When re-linking to the netdev shaper, avoid the eventual, implicit, + * creation of the new root, would be surprising since the user is + * doing a delete operation. + */ + cache_root = root_handle.scope != NET_SHAPER_SCOPE_NETDEV; + ret = __net_shaper_group(dev, cache_root, leaves_count, leaves_handles, + leaves, &root_handle, &root, extack); + +free: + kfree(leaves); + return ret; +} + static int net_shaper_delete(struct net_device *dev, const struct net_shaper_handle *handle, struct netlink_ext_ack *extack)
@@ -780,9 +854,9 @@ static int net_shaper_delete(struct net_device *dev, } if (handle->scope == NET_SHAPER_SCOPE_NODE) { - /* TODO: implement support for scope NODE delete. */ - ret = -EINVAL; - goto unlock; + ret = __net_shaper_pre_del_node(dev, handle, shaper, extack); + if (ret) + goto unlock; } ret = __net_shaper_delete(dev, handle, shaper, extack);
@@ -843,7 +917,7 @@ static int net_shaper_group(struct net_device *dev, int leaves_count, old_roots[old_roots_count++] = leaves[i].parent; mutex_lock(lock); - ret = __net_shaper_group(dev, leaves_count, leaves_handles, + ret = __net_shaper_group(dev, true, leaves_count, leaves_handles, leaves, root_handle, root, extack); /* Check if we need to delete any NODE left alone by the new leaves
--
2.45.2