Commit bf230c49 authored by Paolo Abeni's avatar Paolo Abeni Committed by Jakub Kicinski
Browse files

net-shapers: implement delete support for NODE scope shaper



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.

Reviewed-by: default avatarJiri Pirko <jiri@nvidia.com>
Signed-off-by: default avatarPaolo Abeni <pabeni@redhat.com>
Link: https://patch.msgid.link/763d484b5b69e365acccfd8031b183c647a367a4.1728460186.git.pabeni@redhat.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent 5d5d4700
Loading
Loading
Loading
Loading
+74 −12
Original line number Diff line number Diff line
@@ -785,7 +785,8 @@ static int net_shaper_parent_from_leaves(int leaves_count,
}

static int __net_shaper_group(struct net_shaper_binding *binding,
			      int leaves_count, struct net_shaper *leaves,
			      bool update_node, int leaves_count,
			      struct net_shaper *leaves,
			      struct net_shaper *node,
			      struct netlink_ext_ack *extack)
{
@@ -831,12 +832,14 @@ static int __net_shaper_group(struct net_shaper_binding *binding,
		}
	}

	/* For newly created node scope shaper, the following will update
	 * the handle, due to id allocation.
	if (update_node) {
		/* For newly created node scope shaper, the following will
		 * update the handle, due to id allocation.
		 */
		ret = net_shaper_pre_insert(binding, &node->handle, extack);
		if (ret)
			return ret;
	}

	for (i = 0; i < leaves_count; ++i) {
		leaf_handle = leaves[i].handle;
@@ -864,6 +867,7 @@ static int __net_shaper_group(struct net_shaper_binding *binding,
	 */
	if (new_node && parent)
		parent->leaves++;
	if (update_node)
		net_shaper_commit(binding, 1, node);
	net_shaper_commit(binding, leaves_count, leaves);
	return 0;
@@ -873,6 +877,64 @@ static int __net_shaper_group(struct net_shaper_binding *binding,
	return ret;
}

static int net_shaper_pre_del_node(struct net_shaper_binding *binding,
				   const struct net_shaper *shaper,
				   struct netlink_ext_ack *extack)
{
	struct net_shaper_hierarchy *hierarchy = net_shaper_hierarchy(binding);
	struct net_shaper *cur, *leaves, node = {};
	int ret, leaves_count = 0;
	unsigned long index;
	bool update_node;

	if (!shaper->leaves)
		return 0;

	/* Fetch the new node information. */
	node.handle = shaper->parent;
	cur = net_shaper_lookup(binding, &node.handle);
	if (cur) {
		node = *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 data is in inconsistent status.
		 */
		if (WARN_ON_ONCE(node.handle.scope != NET_SHAPER_SCOPE_NETDEV))
			return -EINVAL;
	}

	leaves = kcalloc(shaper->leaves, sizeof(struct net_shaper),
			 GFP_KERNEL);
	if (!leaves)
		return -ENOMEM;

	/* Build the leaves arrays. */
	xa_for_each(&hierarchy->shapers, index, cur) {
		if (net_shaper_handle_cmp(&cur->parent, &shaper->handle))
			continue;

		if (WARN_ON_ONCE(leaves_count == shaper->leaves)) {
			ret = -EINVAL;
			goto free;
		}

		leaves[leaves_count++] = *cur;
	}

	/* When re-linking to the netdev shaper, avoid the eventual, implicit,
	 * creation of the new node, would be surprising since the user is
	 * doing a delete operation.
	 */
	update_node = node.handle.scope != NET_SHAPER_SCOPE_NETDEV;
	ret = __net_shaper_group(binding, update_node, leaves_count,
				 leaves, &node, extack);

free:
	kfree(leaves);
	return ret;
}

int net_shaper_nl_delete_doit(struct sk_buff *skb, struct genl_info *info)
{
	struct net_shaper_hierarchy *hierarchy;
@@ -905,8 +967,8 @@ int net_shaper_nl_delete_doit(struct sk_buff *skb, struct genl_info *info)
	}

	if (handle.scope == NET_SHAPER_SCOPE_NODE) {
		/* TODO: implement support for scope NODE delete. */
		ret = -EINVAL;
		ret = net_shaper_pre_del_node(binding, shaper, info->extack);
		if (ret)
			goto unlock;
	}

@@ -1027,7 +1089,7 @@ int net_shaper_nl_group_doit(struct sk_buff *skb, struct genl_info *info)
		}
	}

	ret = __net_shaper_group(binding, leaves_count, leaves, &node,
	ret = __net_shaper_group(binding, true, leaves_count, leaves, &node,
				 info->extack);
	if (ret)
		goto free_msg;