Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4ef295e0 authored by David S. Miller's avatar David S. Miller
Browse files


Pablo Neira Ayuso says:

====================
Netfilter updates for net-next

The following patchset contains Netfilter updates for your net-next tree.
Basically, nf_tables updates to add the set extension infrastructure and finish
the transaction for sets from Patrick McHardy. More specifically, they are:

1) Move netns to basechain and use recently added possible_net_t, from
   Patrick McHardy.

2) Use LOGLEVEL_<FOO> from nf_log infrastructure, from Joe Perches.

3) Restore nf_log_trace that was accidentally removed during conflict
   resolution.

4) nft_queue does not depend on NETFILTER_XTABLES, starting from here
   all patches from Patrick McHardy.

5) Use raw_smp_processor_id() in nft_meta.

Then, several patches to prepare ground for the new set extension
infrastructure:

6) Pass object length to the hash callback in rhashtable as needed by
   the new set extension infrastructure.

7) Cleanup patch to restore struct nft_hash as wrapper for struct
   rhashtable

8) Another small source code readability cleanup for nft_hash.

9) Convert nft_hash to rhashtable callbacks.

And finally...

10) Add the new set extension infrastructure.

11) Convert the nft_hash and nft_rbtree sets to use it.

12) Batch set element release to avoid several RCU grace period in a row
    and add new function nft_set_elem_destroy() to consolidate set element
    release.

13) Return the set extension data area from nft_lookup.

14) Refactor existing transaction code to add some helper functions
    and document it.

15) Complete the set transaction support, using similar approach to what we
    already use, to activate/deactivate elements in an atomic fashion.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents ae7633c8 cc02e457
Loading
Loading
Loading
Loading
+4 −2
Original line number Diff line number Diff line
@@ -88,7 +88,7 @@ struct rhashtable_compare_arg {
};

typedef u32 (*rht_hashfn_t)(const void *data, u32 len, u32 seed);
typedef u32 (*rht_obj_hashfn_t)(const void *data, u32 seed);
typedef u32 (*rht_obj_hashfn_t)(const void *data, u32 len, u32 seed);
typedef int (*rht_obj_cmpfn_t)(struct rhashtable_compare_arg *arg,
			       const void *obj);

@@ -242,7 +242,9 @@ static inline unsigned int rht_head_hashfn(
	const char *ptr = rht_obj(ht, he);

	return likely(params.obj_hashfn) ?
	       rht_bucket_index(tbl, params.obj_hashfn(ptr, tbl->hash_rnd)) :
	       rht_bucket_index(tbl, params.obj_hashfn(ptr, params.key_len ?:
							    ht->p.key_len,
						       tbl->hash_rnd)) :
	       rht_key_hashfn(ht, tbl, ptr + params.key_offset, params);
}

+176 −14
Original line number Diff line number Diff line
@@ -138,19 +138,12 @@ struct nft_userdata {
/**
 *	struct nft_set_elem - generic representation of set elements
 *
 *	@cookie: implementation specific element cookie
 *	@key: element key
 *	@data: element data (maps only)
 *	@flags: element flags (end of interval)
 *
 *	The cookie can be used to store a handle to the element for subsequent
 *	removal.
 *	@priv: element private data and extensions
 */
struct nft_set_elem {
	void			*cookie;
	struct nft_data		key;
	struct nft_data		data;
	u32			flags;
	void			*priv;
};

struct nft_set;
@@ -202,11 +195,15 @@ struct nft_set_estimate {
	enum nft_set_class	class;
};

struct nft_set_ext;

/**
 *	struct nft_set_ops - nf_tables set operations
 *
 *	@lookup: look up an element within the set
 *	@insert: insert new element into set
 *	@activate: activate new element in the next generation
 *	@deactivate: deactivate element in the next generation
 *	@remove: remove element from set
 *	@walk: iterate over all set elemeennts
 *	@privsize: function to return size of set private data
@@ -214,16 +211,19 @@ struct nft_set_estimate {
 *	@destroy: destroy private data of set instance
 *	@list: nf_tables_set_ops list node
 *	@owner: module reference
 *	@elemsize: element private size
 *	@features: features supported by the implementation
 */
struct nft_set_ops {
	bool				(*lookup)(const struct nft_set *set,
						  const struct nft_data *key,
						  struct nft_data *data);
	int				(*get)(const struct nft_set *set,
					       struct nft_set_elem *elem);
						  const struct nft_set_ext **ext);
	int				(*insert)(const struct nft_set *set,
						  const struct nft_set_elem *elem);
	void				(*activate)(const struct nft_set *set,
						    const struct nft_set_elem *elem);
	void *				(*deactivate)(const struct nft_set *set,
						      const struct nft_set_elem *elem);
	void				(*remove)(const struct nft_set *set,
						  const struct nft_set_elem *elem);
	void				(*walk)(const struct nft_ctx *ctx,
@@ -241,6 +241,7 @@ struct nft_set_ops {

	struct list_head		list;
	struct module			*owner;
	unsigned int			elemsize;
	u32				features;
};

@@ -259,6 +260,7 @@ void nft_unregister_set(struct nft_set_ops *ops);
 * 	@nelems: number of elements
 *	@policy: set parameterization (see enum nft_set_policies)
 * 	@ops: set ops
 * 	@pnet: network namespace
 * 	@flags: set flags
 * 	@klen: key length
 * 	@dlen: data length
@@ -275,6 +277,7 @@ struct nft_set {
	u16				policy;
	/* runtime data below here */
	const struct nft_set_ops	*ops ____cacheline_aligned;
	possible_net_t			pnet;
	u16				flags;
	u8				klen;
	u8				dlen;
@@ -311,6 +314,121 @@ int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
			  struct nft_set_binding *binding);

/**
 *	enum nft_set_extensions - set extension type IDs
 *
 *	@NFT_SET_EXT_KEY: element key
 *	@NFT_SET_EXT_DATA: mapping data
 *	@NFT_SET_EXT_FLAGS: element flags
 *	@NFT_SET_EXT_NUM: number of extension types
 */
enum nft_set_extensions {
	NFT_SET_EXT_KEY,
	NFT_SET_EXT_DATA,
	NFT_SET_EXT_FLAGS,
	NFT_SET_EXT_NUM
};

/**
 *	struct nft_set_ext_type - set extension type
 *
 * 	@len: fixed part length of the extension
 * 	@align: alignment requirements of the extension
 */
struct nft_set_ext_type {
	u8	len;
	u8	align;
};

extern const struct nft_set_ext_type nft_set_ext_types[];

/**
 *	struct nft_set_ext_tmpl - set extension template
 *
 *	@len: length of extension area
 *	@offset: offsets of individual extension types
 */
struct nft_set_ext_tmpl {
	u16	len;
	u8	offset[NFT_SET_EXT_NUM];
};

/**
 *	struct nft_set_ext - set extensions
 *
 *	@genmask: generation mask
 *	@offset: offsets of individual extension types
 *	@data: beginning of extension data
 */
struct nft_set_ext {
	u8	genmask;
	u8	offset[NFT_SET_EXT_NUM];
	char	data[0];
};

static inline void nft_set_ext_prepare(struct nft_set_ext_tmpl *tmpl)
{
	memset(tmpl, 0, sizeof(*tmpl));
	tmpl->len = sizeof(struct nft_set_ext);
}

static inline void nft_set_ext_add_length(struct nft_set_ext_tmpl *tmpl, u8 id,
					  unsigned int len)
{
	tmpl->len	 = ALIGN(tmpl->len, nft_set_ext_types[id].align);
	BUG_ON(tmpl->len > U8_MAX);
	tmpl->offset[id] = tmpl->len;
	tmpl->len	+= nft_set_ext_types[id].len + len;
}

static inline void nft_set_ext_add(struct nft_set_ext_tmpl *tmpl, u8 id)
{
	nft_set_ext_add_length(tmpl, id, 0);
}

static inline void nft_set_ext_init(struct nft_set_ext *ext,
				    const struct nft_set_ext_tmpl *tmpl)
{
	memcpy(ext->offset, tmpl->offset, sizeof(ext->offset));
}

static inline bool __nft_set_ext_exists(const struct nft_set_ext *ext, u8 id)
{
	return !!ext->offset[id];
}

static inline bool nft_set_ext_exists(const struct nft_set_ext *ext, u8 id)
{
	return ext && __nft_set_ext_exists(ext, id);
}

static inline void *nft_set_ext(const struct nft_set_ext *ext, u8 id)
{
	return (void *)ext + ext->offset[id];
}

static inline struct nft_data *nft_set_ext_key(const struct nft_set_ext *ext)
{
	return nft_set_ext(ext, NFT_SET_EXT_KEY);
}

static inline struct nft_data *nft_set_ext_data(const struct nft_set_ext *ext)
{
	return nft_set_ext(ext, NFT_SET_EXT_DATA);
}

static inline u8 *nft_set_ext_flags(const struct nft_set_ext *ext)
{
	return nft_set_ext(ext, NFT_SET_EXT_FLAGS);
}

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

void nft_set_elem_destroy(const struct nft_set *set, void *elem);

/**
 *	struct nft_expr_type - nf_tables expression type
@@ -449,7 +567,6 @@ enum nft_chain_flags {
 *
 *	@rules: list of rules in the chain
 *	@list: used internally
 *	@net: net namespace that this chain belongs to
 *	@table: table that this chain belongs to
 *	@handle: chain handle
 *	@use: number of jump references to this chain
@@ -460,7 +577,6 @@ enum nft_chain_flags {
struct nft_chain {
	struct list_head		rules;
	struct list_head		list;
	struct net			*net;
	struct nft_table		*table;
	u64				handle;
	u32				use;
@@ -512,6 +628,7 @@ struct nft_stats {
 *	struct nft_base_chain - nf_tables base chain
 *
 *	@ops: netfilter hook ops
 *	@pnet: net namespace that this chain belongs to
 *	@type: chain type
 *	@policy: default policy
 *	@stats: per-cpu chain stats
@@ -519,6 +636,7 @@ struct nft_stats {
 */
struct nft_base_chain {
	struct nf_hook_ops		ops[NFT_HOOK_OPS_MAX];
	possible_net_t			pnet;
	const struct nf_chain_type	*type;
	u8				policy;
	struct nft_stats __percpu	*stats;
@@ -605,6 +723,50 @@ void nft_unregister_expr(struct nft_expr_type *);
#define MODULE_ALIAS_NFT_SET() \
	MODULE_ALIAS("nft-set")

/*
 * The gencursor defines two generations, the currently active and the
 * next one. Objects contain a bitmask of 2 bits specifying the generations
 * they're active in. A set bit means they're inactive in the generation
 * represented by that bit.
 *
 * New objects start out as inactive in the current and active in the
 * next generation. When committing the ruleset the bitmask is cleared,
 * meaning they're active in all generations. When removing an object,
 * it is set inactive in the next generation. After committing the ruleset,
 * the objects are removed.
 */
static inline unsigned int nft_gencursor_next(const struct net *net)
{
	return net->nft.gencursor + 1 == 1 ? 1 : 0;
}

static inline u8 nft_genmask_next(const struct net *net)
{
	return 1 << nft_gencursor_next(net);
}

static inline u8 nft_genmask_cur(const struct net *net)
{
	/* Use ACCESS_ONCE() to prevent refetching the value for atomicity */
	return 1 << ACCESS_ONCE(net->nft.gencursor);
}

/*
 * Set element transaction helpers
 */

static inline bool nft_set_elem_active(const struct nft_set_ext *ext,
				       u8 genmask)
{
	return !(ext->genmask & genmask);
}

static inline void nft_set_elem_change_active(const struct nft_set *set,
					      struct nft_set_ext *ext)
{
	ext->genmask ^= nft_genmask_next(read_pnet(&set->pnet));
}

/**
 *	struct nft_trans - nf_tables object update in transaction
 *
+1 −1
Original line number Diff line number Diff line
@@ -691,7 +691,7 @@ static u32 rhashtable_jhash2(const void *key, u32 length, u32 seed)
 *	struct rhash_head	node;
 * };
 *
 * u32 my_hash_fn(const void *data, u32 seed)
 * u32 my_hash_fn(const void *data, u32 len, u32 seed)
 * {
 *	struct test_obj *obj = data;
 *
+3 −1
Original line number Diff line number Diff line
@@ -10,8 +10,10 @@
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/skbuff.h>
@@ -27,7 +29,7 @@ static struct nf_loginfo default_loginfo = {
	.type	= NF_LOG_TYPE_LOG,
	.u = {
		.log = {
			.level	  = 5,
			.level	  = LOGLEVEL_NOTICE,
			.logflags = NF_LOG_MASK,
		},
	},
+3 −1
Original line number Diff line number Diff line
@@ -5,8 +5,10 @@
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include <linux/skbuff.h>
@@ -26,7 +28,7 @@ static struct nf_loginfo default_loginfo = {
	.type	= NF_LOG_TYPE_LOG,
	.u = {
		.log = {
			.level	  = 5,
			.level	  = LOGLEVEL_NOTICE,
			.logflags = NF_LOG_MASK,
		},
	},
Loading