Commit 9dad402b authored by Pablo Neira Ayuso's avatar Pablo Neira Ayuso
Browse files

netfilter: nf_tables: expose opaque set element as struct nft_elem_priv



Add placeholder structure and place it at the beginning of each struct
nft_*_elem for each existing set backend, instead of exposing elements
as void type to the frontend which defeats compiler type checks. Use
this pointer to this new type to replace void *.

This patch updates the following set backend API to use this new struct
nft_elem_priv placeholder structure:

- update
- deactivate
- flush
- get

as well as the following helper functions:

- nft_set_elem_ext()
- nft_set_elem_init()
- nft_set_elem_destroy()
- nf_tables_set_elem_destroy()

This patch adds nft_elem_priv_cast() to cast struct nft_elem_priv to
native element representation from the corresponding set backend.
BUILD_BUG_ON() makes sure this .priv placeholder is always at the top
of the opaque set element representation.

Suggested-by: default avatarFlorian Westphal <fw@strlen.de>
Signed-off-by: default avatarPablo Neira Ayuso <pablo@netfilter.org>
parent 6509a2e4
Loading
Loading
Loading
Loading
+25 −13
Original line number Diff line number Diff line
@@ -274,6 +274,9 @@ struct nft_userdata {
	unsigned char		data[];
};

/* placeholder structure for opaque set element backend representation. */
struct nft_elem_priv { };

/**
 *	struct nft_set_elem - generic representation of set elements
 *
@@ -294,9 +297,14 @@ struct nft_set_elem {
		u32		buf[NFT_DATA_VALUE_MAXLEN / sizeof(u32)];
		struct nft_data val;
	} data;
	void			*priv;
	struct nft_elem_priv	*priv;
};

static inline void *nft_elem_priv_cast(const struct nft_elem_priv *priv)
{
	return (void *)priv;
}

struct nft_set;
struct nft_set_iter {
	u8		genmask;
@@ -430,7 +438,8 @@ struct nft_set_ops {
						  const struct nft_set_ext **ext);
	bool				(*update)(struct nft_set *set,
						  const u32 *key,
						  void *(*new)(struct nft_set *,
						  struct nft_elem_priv *
							(*new)(struct nft_set *,
							       const struct nft_expr *,
							       struct nft_regs *),
						  const struct nft_expr *expr,
@@ -446,19 +455,19 @@ struct nft_set_ops {
	void				(*activate)(const struct net *net,
						    const struct nft_set *set,
						    const struct nft_set_elem *elem);
	void *				(*deactivate)(const struct net *net,
	struct nft_elem_priv *		(*deactivate)(const struct net *net,
						      const struct nft_set *set,
						      const struct nft_set_elem *elem);
	void				(*flush)(const struct net *net,
						 const struct nft_set *set,
						 void *priv);
						 struct nft_elem_priv *priv);
	void				(*remove)(const struct net *net,
						  const struct nft_set *set,
						  const struct nft_set_elem *elem);
	void				(*walk)(const struct nft_ctx *ctx,
						struct nft_set *set,
						struct nft_set_iter *iter);
	void *				(*get)(const struct net *net,
	struct nft_elem_priv *		(*get)(const struct net *net,
					       const struct nft_set *set,
					       const struct nft_set_elem *elem,
					       unsigned int flags);
@@ -796,9 +805,9 @@ static inline bool nft_set_elem_expired(const struct nft_set_ext *ext)
}

static inline struct nft_set_ext *nft_set_elem_ext(const struct nft_set *set,
						   void *elem)
						   const struct nft_elem_priv *elem_priv)
{
	return elem + set->ops->elemsize;
	return (void *)elem_priv + set->ops->elemsize;
}

static inline struct nft_object **nft_set_ext_obj(const struct nft_set_ext *ext)
@@ -810,16 +819,19 @@ struct nft_expr *nft_set_elem_expr_alloc(const struct nft_ctx *ctx,
					 const struct nft_set *set,
					 const struct nlattr *attr);

void *nft_set_elem_init(const struct nft_set *set,
struct nft_elem_priv *nft_set_elem_init(const struct nft_set *set,
					const struct nft_set_ext_tmpl *tmpl,
			const u32 *key, const u32 *key_end, const u32 *data,
					const u32 *key, const u32 *key_end,
					const u32 *data,
					u64 timeout, u64 expiration, gfp_t gfp);
int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set,
			    struct nft_expr *expr_array[]);
void nft_set_elem_destroy(const struct nft_set *set, void *elem,
void nft_set_elem_destroy(const struct nft_set *set,
			  const struct nft_elem_priv *elem_priv,
			  bool destroy_expr);
void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
				const struct nft_set *set, void *elem);
				const struct nft_set *set,
				const struct nft_elem_priv *elem_priv);

struct nft_expr_ops;
/**
+15 −12
Original line number Diff line number Diff line
@@ -601,7 +601,7 @@ static int nft_mapelem_deactivate(const struct nft_ctx *ctx,
struct nft_set_elem_catchall {
	struct list_head	list;
	struct rcu_head		rcu;
	void			*elem;
	struct nft_elem_priv	*elem;
};

static void nft_map_catchall_deactivate(const struct nft_ctx *ctx,
@@ -6218,10 +6218,11 @@ static int nft_set_ext_memcpy(const struct nft_set_ext_tmpl *tmpl, u8 id,
	return 0;
}

void *nft_set_elem_init(const struct nft_set *set,
struct nft_elem_priv *nft_set_elem_init(const struct nft_set *set,
					const struct nft_set_ext_tmpl *tmpl,
					const u32 *key, const u32 *key_end,
			const u32 *data, u64 timeout, u64 expiration, gfp_t gfp)
					const u32 *data,
					u64 timeout, u64 expiration, gfp_t gfp)
{
	struct nft_set_ext *ext;
	void *elem;
@@ -6286,10 +6287,11 @@ static void nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
}

/* Drop references and destroy. Called from gc, dynset and abort path. */
void nft_set_elem_destroy(const struct nft_set *set, void *elem,
void nft_set_elem_destroy(const struct nft_set *set,
			  const struct nft_elem_priv *elem_priv,
			  bool destroy_expr)
{
	struct nft_set_ext *ext = nft_set_elem_ext(set, elem);
	struct nft_set_ext *ext = nft_set_elem_ext(set, elem_priv);
	struct nft_ctx ctx = {
		.net	= read_pnet(&set->net),
		.family	= set->table->family,
@@ -6300,10 +6302,10 @@ void nft_set_elem_destroy(const struct nft_set *set, void *elem,
		nft_data_release(nft_set_ext_data(ext), set->dtype);
	if (destroy_expr && nft_set_ext_exists(ext, NFT_SET_EXT_EXPRESSIONS))
		nft_set_elem_expr_destroy(&ctx, nft_set_ext_expr(ext));

	if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF))
		nft_use_dec(&(*nft_set_ext_obj(ext))->use);
	kfree(elem);

	kfree(elem_priv);
}
EXPORT_SYMBOL_GPL(nft_set_elem_destroy);

@@ -6311,14 +6313,15 @@ EXPORT_SYMBOL_GPL(nft_set_elem_destroy);
 * path via nft_setelem_data_deactivate().
 */
void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
				const struct nft_set *set, void *elem)
				const struct nft_set *set,
				const struct nft_elem_priv *elem_priv)
{
	struct nft_set_ext *ext = nft_set_elem_ext(set, elem);
	struct nft_set_ext *ext = nft_set_elem_ext(set, elem_priv);

	if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPRESSIONS))
		nft_set_elem_expr_destroy(ctx, nft_set_ext_expr(ext));

	kfree(elem);
	kfree(elem_priv);
}

int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set,
+12 −11
Original line number Diff line number Diff line
@@ -44,33 +44,34 @@ static int nft_dynset_expr_setup(const struct nft_dynset *priv,
	return 0;
}

static void *nft_dynset_new(struct nft_set *set, const struct nft_expr *expr,
static struct nft_elem_priv *nft_dynset_new(struct nft_set *set,
					    const struct nft_expr *expr,
					    struct nft_regs *regs)
{
	const struct nft_dynset *priv = nft_expr_priv(expr);
	struct nft_set_ext *ext;
	void *elem_priv;
	u64 timeout;
	void *elem;

	if (!atomic_add_unless(&set->nelems, 1, set->size))
		return NULL;

	timeout = priv->timeout ? : set->timeout;
	elem = nft_set_elem_init(set, &priv->tmpl,
	elem_priv = nft_set_elem_init(set, &priv->tmpl,
				      &regs->data[priv->sreg_key], NULL,
				      &regs->data[priv->sreg_data],
				      timeout, 0, GFP_ATOMIC);
	if (IS_ERR(elem))
	if (IS_ERR(elem_priv))
		goto err1;

	ext = nft_set_elem_ext(set, elem);
	ext = nft_set_elem_ext(set, elem_priv);
	if (priv->num_exprs && nft_dynset_expr_setup(priv, ext) < 0)
		goto err2;

	return elem;
	return elem_priv;

err2:
	nft_set_elem_destroy(set, elem, false);
	nft_set_elem_destroy(set, elem_priv, false);
err1:
	if (set->size)
		atomic_dec(&set->nelems);
+20 −15
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include <net/netfilter/nf_tables_core.h>

struct nft_bitmap_elem {
	struct nft_elem_priv	priv;
	struct list_head	head;
	struct nft_set_ext	ext;
};
@@ -104,7 +105,8 @@ nft_bitmap_elem_find(const struct nft_set *set, struct nft_bitmap_elem *this,
	return NULL;
}

static void *nft_bitmap_get(const struct net *net, const struct nft_set *set,
static struct nft_elem_priv *
nft_bitmap_get(const struct net *net, const struct nft_set *set,
	       const struct nft_set_elem *elem, unsigned int flags)
{
	const struct nft_bitmap *priv = nft_set_priv(set);
@@ -116,7 +118,7 @@ static void *nft_bitmap_get(const struct net *net, const struct nft_set *set,
		    !nft_set_elem_active(&be->ext, genmask))
			continue;

		return be;
		return &be->priv;
	}
	return ERR_PTR(-ENOENT);
}
@@ -125,8 +127,8 @@ static int nft_bitmap_insert(const struct net *net, const struct nft_set *set,
			     const struct nft_set_elem *elem,
			     struct nft_set_ext **ext)
{
	struct nft_bitmap_elem *new = nft_elem_priv_cast(elem->priv), *be;
	struct nft_bitmap *priv = nft_set_priv(set);
	struct nft_bitmap_elem *new = elem->priv, *be;
	u8 genmask = nft_genmask_next(net);
	u32 idx, off;

@@ -148,8 +150,8 @@ static void nft_bitmap_remove(const struct net *net,
			      const struct nft_set *set,
			      const struct nft_set_elem *elem)
{
	struct nft_bitmap_elem *be = nft_elem_priv_cast(elem->priv);
	struct nft_bitmap *priv = nft_set_priv(set);
	struct nft_bitmap_elem *be = elem->priv;
	u8 genmask = nft_genmask_next(net);
	u32 idx, off;

@@ -163,8 +165,8 @@ static void nft_bitmap_activate(const struct net *net,
				const struct nft_set *set,
				const struct nft_set_elem *elem)
{
	struct nft_bitmap_elem *be = nft_elem_priv_cast(elem->priv);
	struct nft_bitmap *priv = nft_set_priv(set);
	struct nft_bitmap_elem *be = elem->priv;
	u8 genmask = nft_genmask_next(net);
	u32 idx, off;

@@ -175,11 +177,12 @@ static void nft_bitmap_activate(const struct net *net,
}

static void nft_bitmap_flush(const struct net *net,
			     const struct nft_set *set, void *_be)
			     const struct nft_set *set,
			     struct nft_elem_priv *elem_priv)
{
	struct nft_bitmap_elem *be = nft_elem_priv_cast(elem_priv);
	struct nft_bitmap *priv = nft_set_priv(set);
	u8 genmask = nft_genmask_next(net);
	struct nft_bitmap_elem *be = _be;
	u32 idx, off;

	nft_bitmap_location(set, nft_set_ext_key(&be->ext), &idx, &off);
@@ -188,12 +191,12 @@ static void nft_bitmap_flush(const struct net *net,
	nft_set_elem_change_active(net, set, &be->ext);
}

static void *nft_bitmap_deactivate(const struct net *net,
				   const struct nft_set *set,
static struct nft_elem_priv *
nft_bitmap_deactivate(const struct net *net, const struct nft_set *set,
		      const struct nft_set_elem *elem)
{
	struct nft_bitmap_elem *this = nft_elem_priv_cast(elem->priv), *be;
	struct nft_bitmap *priv = nft_set_priv(set);
	struct nft_bitmap_elem *this = elem->priv, *be;
	u8 genmask = nft_genmask_next(net);
	u32 idx, off;

@@ -207,7 +210,7 @@ static void *nft_bitmap_deactivate(const struct net *net,
	priv->bitmap[idx] &= ~(genmask << off);
	nft_set_elem_change_active(net, set, &be->ext);

	return be;
	return &be->priv;
}

static void nft_bitmap_walk(const struct nft_ctx *ctx,
@@ -224,7 +227,7 @@ static void nft_bitmap_walk(const struct nft_ctx *ctx,
		if (!nft_set_elem_active(&be->ext, iter->genmask))
			goto cont;

		elem.priv = be;
		elem.priv = &be->priv;

		iter->err = iter->fn(ctx, set, iter, &elem);

@@ -263,6 +266,8 @@ static int nft_bitmap_init(const struct nft_set *set,
{
	struct nft_bitmap *priv = nft_set_priv(set);

	BUILD_BUG_ON(offsetof(struct nft_bitmap_elem, priv) != 0);

	INIT_LIST_HEAD(&priv->list);
	priv->bitmap_size = nft_bitmap_size(set->klen);

@@ -276,7 +281,7 @@ static void nft_bitmap_destroy(const struct nft_ctx *ctx,
	struct nft_bitmap_elem *be, *n;

	list_for_each_entry_safe(be, n, &priv->list, head)
		nf_tables_set_elem_destroy(ctx, set, be);
		nf_tables_set_elem_destroy(ctx, set, &be->priv);
}

static bool nft_bitmap_estimate(const struct nft_set_desc *desc, u32 features,
+46 −34
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ struct nft_rhash {
};

struct nft_rhash_elem {
	struct nft_elem_priv		priv;
	struct rhash_head		node;
	struct nft_set_ext		ext;
};
@@ -95,7 +96,8 @@ bool nft_rhash_lookup(const struct net *net, const struct nft_set *set,
	return !!he;
}

static void *nft_rhash_get(const struct net *net, const struct nft_set *set,
static struct nft_elem_priv *
nft_rhash_get(const struct net *net, const struct nft_set *set,
	      const struct nft_set_elem *elem, unsigned int flags)
{
	struct nft_rhash *priv = nft_set_priv(set);
@@ -108,13 +110,14 @@ static void *nft_rhash_get(const struct net *net, const struct nft_set *set,

	he = rhashtable_lookup(&priv->ht, &arg, nft_rhash_params);
	if (he != NULL)
		return he;
		return &he->priv;

	return ERR_PTR(-ENOENT);
}

static bool nft_rhash_update(struct nft_set *set, const u32 *key,
			     void *(*new)(struct nft_set *,
			     struct nft_elem_priv *
				   (*new)(struct nft_set *,
					  const struct nft_expr *,
					  struct nft_regs *regs),
			     const struct nft_expr *expr,
@@ -123,6 +126,7 @@ static bool nft_rhash_update(struct nft_set *set, const u32 *key,
{
	struct nft_rhash *priv = nft_set_priv(set);
	struct nft_rhash_elem *he, *prev;
	struct nft_elem_priv *elem_priv;
	struct nft_rhash_cmp_arg arg = {
		.genmask = NFT_GENMASK_ANY,
		.set	 = set,
@@ -133,10 +137,11 @@ static bool nft_rhash_update(struct nft_set *set, const u32 *key,
	if (he != NULL)
		goto out;

	he = new(set, expr, regs);
	if (he == NULL)
	elem_priv = new(set, expr, regs);
	if (!elem_priv)
		goto err1;

	he = nft_elem_priv_cast(elem_priv);
	prev = rhashtable_lookup_get_insert_key(&priv->ht, &arg, &he->node,
						nft_rhash_params);
	if (IS_ERR(prev))
@@ -144,7 +149,7 @@ static bool nft_rhash_update(struct nft_set *set, const u32 *key,

	/* Another cpu may race to insert the element with the same key */
	if (prev) {
		nft_set_elem_destroy(set, he, true);
		nft_set_elem_destroy(set, &he->priv, true);
		atomic_dec(&set->nelems);
		he = prev;
	}
@@ -154,7 +159,7 @@ static bool nft_rhash_update(struct nft_set *set, const u32 *key,
	return true;

err2:
	nft_set_elem_destroy(set, he, true);
	nft_set_elem_destroy(set, &he->priv, true);
	atomic_dec(&set->nelems);
err1:
	return false;
@@ -164,8 +169,8 @@ static int nft_rhash_insert(const struct net *net, const struct nft_set *set,
			    const struct nft_set_elem *elem,
			    struct nft_set_ext **ext)
{
	struct nft_rhash_elem *he = nft_elem_priv_cast(elem->priv);
	struct nft_rhash *priv = nft_set_priv(set);
	struct nft_rhash_elem *he = elem->priv;
	struct nft_rhash_cmp_arg arg = {
		.genmask = nft_genmask_next(net),
		.set	 = set,
@@ -187,21 +192,22 @@ static int nft_rhash_insert(const struct net *net, const struct nft_set *set,
static void nft_rhash_activate(const struct net *net, const struct nft_set *set,
			       const struct nft_set_elem *elem)
{
	struct nft_rhash_elem *he = elem->priv;
	struct nft_rhash_elem *he = nft_elem_priv_cast(elem->priv);

	nft_set_elem_change_active(net, set, &he->ext);
}

static void nft_rhash_flush(const struct net *net,
			    const struct nft_set *set, void *priv)
			    const struct nft_set *set,
			    struct nft_elem_priv *elem_priv)
{
	struct nft_rhash_elem *he = priv;
	struct nft_rhash_elem *he = nft_elem_priv_cast(elem_priv);

	nft_set_elem_change_active(net, set, &he->ext);
}

static void *nft_rhash_deactivate(const struct net *net,
				  const struct nft_set *set,
static struct nft_elem_priv *
nft_rhash_deactivate(const struct net *net, const struct nft_set *set,
		     const struct nft_set_elem *elem)
{
	struct nft_rhash *priv = nft_set_priv(set);
@@ -219,15 +225,15 @@ static void *nft_rhash_deactivate(const struct net *net,

	rcu_read_unlock();

	return he;
	return &he->priv;
}

static void nft_rhash_remove(const struct net *net,
			     const struct nft_set *set,
			     const struct nft_set_elem *elem)
{
	struct nft_rhash_elem *he = nft_elem_priv_cast(elem->priv);
	struct nft_rhash *priv = nft_set_priv(set);
	struct nft_rhash_elem *he = elem->priv;

	rhashtable_remove_fast(&priv->ht, &he->node, nft_rhash_params);
}
@@ -278,7 +284,7 @@ static void nft_rhash_walk(const struct nft_ctx *ctx, struct nft_set *set,
		if (!nft_set_elem_active(&he->ext, iter->genmask))
			goto cont;

		elem.priv = he;
		elem.priv = &he->priv;

		iter->err = iter->fn(ctx, set, iter, &elem);
		if (iter->err < 0)
@@ -404,6 +410,8 @@ static int nft_rhash_init(const struct nft_set *set,
	struct rhashtable_params params = nft_rhash_params;
	int err;

	BUILD_BUG_ON(offsetof(struct nft_rhash_elem, priv) != 0);

	params.nelem_hint = desc->size ?: NFT_RHASH_ELEMENT_HINT;
	params.key_len	  = set->klen;

@@ -426,8 +434,9 @@ struct nft_rhash_ctx {
static void nft_rhash_elem_destroy(void *ptr, void *arg)
{
	struct nft_rhash_ctx *rhash_ctx = arg;
	struct nft_rhash_elem *he = ptr;

	nf_tables_set_elem_destroy(&rhash_ctx->ctx, rhash_ctx->set, ptr);
	nf_tables_set_elem_destroy(&rhash_ctx->ctx, rhash_ctx->set, &he->priv);
}

static void nft_rhash_destroy(const struct nft_ctx *ctx,
@@ -474,6 +483,7 @@ struct nft_hash {
};

struct nft_hash_elem {
	struct nft_elem_priv		priv;
	struct hlist_node		node;
	struct nft_set_ext		ext;
};
@@ -499,7 +509,8 @@ bool nft_hash_lookup(const struct net *net, const struct nft_set *set,
	return false;
}

static void *nft_hash_get(const struct net *net, const struct nft_set *set,
static struct nft_elem_priv *
nft_hash_get(const struct net *net, const struct nft_set *set,
	     const struct nft_set_elem *elem, unsigned int flags)
{
	struct nft_hash *priv = nft_set_priv(set);
@@ -512,7 +523,7 @@ static void *nft_hash_get(const struct net *net, const struct nft_set *set,
	hlist_for_each_entry_rcu(he, &priv->table[hash], node) {
		if (!memcmp(nft_set_ext_key(&he->ext), elem->key.val.data, set->klen) &&
		    nft_set_elem_active(&he->ext, genmask))
			return he;
			return &he->priv;
	}
	return ERR_PTR(-ENOENT);
}
@@ -562,7 +573,7 @@ static int nft_hash_insert(const struct net *net, const struct nft_set *set,
			   const struct nft_set_elem *elem,
			   struct nft_set_ext **ext)
{
	struct nft_hash_elem *this = elem->priv, *he;
	struct nft_hash_elem *this = nft_elem_priv_cast(elem->priv), *he;
	struct nft_hash *priv = nft_set_priv(set);
	u8 genmask = nft_genmask_next(net);
	u32 hash;
@@ -583,25 +594,26 @@ static int nft_hash_insert(const struct net *net, const struct nft_set *set,
static void nft_hash_activate(const struct net *net, const struct nft_set *set,
			      const struct nft_set_elem *elem)
{
	struct nft_hash_elem *he = elem->priv;
	struct nft_hash_elem *he = nft_elem_priv_cast(elem->priv);

	nft_set_elem_change_active(net, set, &he->ext);
}

static void nft_hash_flush(const struct net *net,
			   const struct nft_set *set, void *priv)
			   const struct nft_set *set,
			   struct nft_elem_priv *elem_priv)
{
	struct nft_hash_elem *he = priv;
	struct nft_hash_elem *he = nft_elem_priv_cast(elem_priv);

	nft_set_elem_change_active(net, set, &he->ext);
}

static void *nft_hash_deactivate(const struct net *net,
				 const struct nft_set *set,
static struct nft_elem_priv *
nft_hash_deactivate(const struct net *net, const struct nft_set *set,
		    const struct nft_set_elem *elem)
{
	struct nft_hash_elem *this = nft_elem_priv_cast(elem->priv), *he;
	struct nft_hash *priv = nft_set_priv(set);
	struct nft_hash_elem *this = elem->priv, *he;
	u8 genmask = nft_genmask_next(net);
	u32 hash;

@@ -611,7 +623,7 @@ static void *nft_hash_deactivate(const struct net *net,
			    set->klen) &&
		    nft_set_elem_active(&he->ext, genmask)) {
			nft_set_elem_change_active(net, set, &he->ext);
			return he;
			return &he->priv;
		}
	}
	return NULL;
@@ -621,7 +633,7 @@ static void nft_hash_remove(const struct net *net,
			    const struct nft_set *set,
			    const struct nft_set_elem *elem)
{
	struct nft_hash_elem *he = elem->priv;
	struct nft_hash_elem *he = nft_elem_priv_cast(elem->priv);

	hlist_del_rcu(&he->node);
}
@@ -641,7 +653,7 @@ static void nft_hash_walk(const struct nft_ctx *ctx, struct nft_set *set,
			if (!nft_set_elem_active(&he->ext, iter->genmask))
				goto cont;

			elem.priv = he;
			elem.priv = &he->priv;

			iter->err = iter->fn(ctx, set, iter, &elem);
			if (iter->err < 0)
@@ -682,7 +694,7 @@ static void nft_hash_destroy(const struct nft_ctx *ctx,
	for (i = 0; i < priv->buckets; i++) {
		hlist_for_each_entry_safe(he, next, &priv->table[i], node) {
			hlist_del_rcu(&he->node);
			nf_tables_set_elem_destroy(ctx, set, he);
			nf_tables_set_elem_destroy(ctx, set, &he->priv);
		}
	}
}
Loading