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

Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next

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
...@@ -88,7 +88,7 @@ struct rhashtable_compare_arg { ...@@ -88,7 +88,7 @@ struct rhashtable_compare_arg {
}; };
typedef u32 (*rht_hashfn_t)(const void *data, u32 len, u32 seed); 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, typedef int (*rht_obj_cmpfn_t)(struct rhashtable_compare_arg *arg,
const void *obj); const void *obj);
...@@ -242,7 +242,9 @@ static inline unsigned int rht_head_hashfn( ...@@ -242,7 +242,9 @@ static inline unsigned int rht_head_hashfn(
const char *ptr = rht_obj(ht, he); const char *ptr = rht_obj(ht, he);
return likely(params.obj_hashfn) ? 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); rht_key_hashfn(ht, tbl, ptr + params.key_offset, params);
} }
......
...@@ -138,19 +138,12 @@ struct nft_userdata { ...@@ -138,19 +138,12 @@ struct nft_userdata {
/** /**
* struct nft_set_elem - generic representation of set elements * struct nft_set_elem - generic representation of set elements
* *
* @cookie: implementation specific element cookie
* @key: element key * @key: element key
* @data: element data (maps only) * @priv: element private data and extensions
* @flags: element flags (end of interval)
*
* The cookie can be used to store a handle to the element for subsequent
* removal.
*/ */
struct nft_set_elem { struct nft_set_elem {
void *cookie;
struct nft_data key; struct nft_data key;
struct nft_data data; void *priv;
u32 flags;
}; };
struct nft_set; struct nft_set;
...@@ -202,11 +195,15 @@ struct nft_set_estimate { ...@@ -202,11 +195,15 @@ struct nft_set_estimate {
enum nft_set_class class; enum nft_set_class class;
}; };
struct nft_set_ext;
/** /**
* struct nft_set_ops - nf_tables set operations * struct nft_set_ops - nf_tables set operations
* *
* @lookup: look up an element within the set * @lookup: look up an element within the set
* @insert: insert new element into 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 * @remove: remove element from set
* @walk: iterate over all set elemeennts * @walk: iterate over all set elemeennts
* @privsize: function to return size of set private data * @privsize: function to return size of set private data
...@@ -214,16 +211,19 @@ struct nft_set_estimate { ...@@ -214,16 +211,19 @@ struct nft_set_estimate {
* @destroy: destroy private data of set instance * @destroy: destroy private data of set instance
* @list: nf_tables_set_ops list node * @list: nf_tables_set_ops list node
* @owner: module reference * @owner: module reference
* @elemsize: element private size
* @features: features supported by the implementation * @features: features supported by the implementation
*/ */
struct nft_set_ops { struct nft_set_ops {
bool (*lookup)(const struct nft_set *set, bool (*lookup)(const struct nft_set *set,
const struct nft_data *key, const struct nft_data *key,
struct nft_data *data); const struct nft_set_ext **ext);
int (*get)(const struct nft_set *set,
struct nft_set_elem *elem);
int (*insert)(const struct nft_set *set, int (*insert)(const struct nft_set *set,
const struct nft_set_elem *elem); 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, void (*remove)(const struct nft_set *set,
const struct nft_set_elem *elem); const struct nft_set_elem *elem);
void (*walk)(const struct nft_ctx *ctx, void (*walk)(const struct nft_ctx *ctx,
...@@ -241,6 +241,7 @@ struct nft_set_ops { ...@@ -241,6 +241,7 @@ struct nft_set_ops {
struct list_head list; struct list_head list;
struct module *owner; struct module *owner;
unsigned int elemsize;
u32 features; u32 features;
}; };
...@@ -259,6 +260,7 @@ void nft_unregister_set(struct nft_set_ops *ops); ...@@ -259,6 +260,7 @@ void nft_unregister_set(struct nft_set_ops *ops);
* @nelems: number of elements * @nelems: number of elements
* @policy: set parameterization (see enum nft_set_policies) * @policy: set parameterization (see enum nft_set_policies)
* @ops: set ops * @ops: set ops
* @pnet: network namespace
* @flags: set flags * @flags: set flags
* @klen: key length * @klen: key length
* @dlen: data length * @dlen: data length
...@@ -275,6 +277,7 @@ struct nft_set { ...@@ -275,6 +277,7 @@ struct nft_set {
u16 policy; u16 policy;
/* runtime data below here */ /* runtime data below here */
const struct nft_set_ops *ops ____cacheline_aligned; const struct nft_set_ops *ops ____cacheline_aligned;
possible_net_t pnet;
u16 flags; u16 flags;
u8 klen; u8 klen;
u8 dlen; u8 dlen;
...@@ -311,6 +314,121 @@ int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set, ...@@ -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, void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
struct nft_set_binding *binding); 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 * struct nft_expr_type - nf_tables expression type
...@@ -449,7 +567,6 @@ enum nft_chain_flags { ...@@ -449,7 +567,6 @@ enum nft_chain_flags {
* *
* @rules: list of rules in the chain * @rules: list of rules in the chain
* @list: used internally * @list: used internally
* @net: net namespace that this chain belongs to
* @table: table that this chain belongs to * @table: table that this chain belongs to
* @handle: chain handle * @handle: chain handle
* @use: number of jump references to this chain * @use: number of jump references to this chain
...@@ -460,7 +577,6 @@ enum nft_chain_flags { ...@@ -460,7 +577,6 @@ enum nft_chain_flags {
struct nft_chain { struct nft_chain {
struct list_head rules; struct list_head rules;
struct list_head list; struct list_head list;
struct net *net;
struct nft_table *table; struct nft_table *table;
u64 handle; u64 handle;
u32 use; u32 use;
...@@ -512,6 +628,7 @@ struct nft_stats { ...@@ -512,6 +628,7 @@ struct nft_stats {
* struct nft_base_chain - nf_tables base chain * struct nft_base_chain - nf_tables base chain
* *
* @ops: netfilter hook ops * @ops: netfilter hook ops
* @pnet: net namespace that this chain belongs to
* @type: chain type * @type: chain type
* @policy: default policy * @policy: default policy
* @stats: per-cpu chain stats * @stats: per-cpu chain stats
...@@ -519,6 +636,7 @@ struct nft_stats { ...@@ -519,6 +636,7 @@ struct nft_stats {
*/ */
struct nft_base_chain { struct nft_base_chain {
struct nf_hook_ops ops[NFT_HOOK_OPS_MAX]; struct nf_hook_ops ops[NFT_HOOK_OPS_MAX];
possible_net_t pnet;
const struct nf_chain_type *type; const struct nf_chain_type *type;
u8 policy; u8 policy;
struct nft_stats __percpu *stats; struct nft_stats __percpu *stats;
...@@ -605,6 +723,50 @@ void nft_unregister_expr(struct nft_expr_type *); ...@@ -605,6 +723,50 @@ void nft_unregister_expr(struct nft_expr_type *);
#define MODULE_ALIAS_NFT_SET() \ #define MODULE_ALIAS_NFT_SET() \
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 * struct nft_trans - nf_tables object update in transaction
* *
......
...@@ -691,7 +691,7 @@ static u32 rhashtable_jhash2(const void *key, u32 length, u32 seed) ...@@ -691,7 +691,7 @@ static u32 rhashtable_jhash2(const void *key, u32 length, u32 seed)
* struct rhash_head node; * 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; * struct test_obj *obj = data;
* *
......
...@@ -10,8 +10,10 @@ ...@@ -10,8 +10,10 @@
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
...@@ -27,7 +29,7 @@ static struct nf_loginfo default_loginfo = { ...@@ -27,7 +29,7 @@ static struct nf_loginfo default_loginfo = {
.type = NF_LOG_TYPE_LOG, .type = NF_LOG_TYPE_LOG,
.u = { .u = {
.log = { .log = {
.level = 5, .level = LOGLEVEL_NOTICE,
.logflags = NF_LOG_MASK, .logflags = NF_LOG_MASK,
}, },
}, },
......
...@@ -5,8 +5,10 @@ ...@@ -5,8 +5,10 @@
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
...@@ -26,7 +28,7 @@ static struct nf_loginfo default_loginfo = { ...@@ -26,7 +28,7 @@ static struct nf_loginfo default_loginfo = {
.type = NF_LOG_TYPE_LOG, .type = NF_LOG_TYPE_LOG,
.u = { .u = {
.log = { .log = {
.level = 5, .level = LOGLEVEL_NOTICE,
.logflags = NF_LOG_MASK, .logflags = NF_LOG_MASK,
}, },
}, },
......
...@@ -9,7 +9,10 @@ ...@@ -9,7 +9,10 @@
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/capability.h> #include <linux/capability.h>
#include <linux/in.h> #include <linux/in.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
...@@ -234,7 +237,7 @@ static struct nf_loginfo trace_loginfo = { ...@@ -234,7 +237,7 @@ static struct nf_loginfo trace_loginfo = {
.type = NF_LOG_TYPE_LOG, .type = NF_LOG_TYPE_LOG,
.u = { .u = {
.log = { .log = {
.level = 4, .level = LOGLEVEL_WARNING,
.logflags = NF_LOG_MASK, .logflags = NF_LOG_MASK,
}, },
}, },
......
...@@ -5,8 +5,10 @@ ...@@ -5,8 +5,10 @@
* it under the terms of the GNU General Public License version 2 as * it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
...@@ -27,7 +29,7 @@ static struct nf_loginfo default_loginfo = { ...@@ -27,7 +29,7 @@ static struct nf_loginfo default_loginfo = {
.type = NF_LOG_TYPE_LOG, .type = NF_LOG_TYPE_LOG,
.u = { .u = {
.log = { .log = {
.level = 5, .level = LOGLEVEL_NOTICE,
.logflags = NF_LOG_MASK, .logflags = NF_LOG_MASK,
}, },
}, },
......
...@@ -522,7 +522,6 @@ config NFT_NAT ...@@ -522,7 +522,6 @@ config NFT_NAT
typical Network Address Translation (NAT) packet transformations. typical Network Address Translation (NAT) packet transformations.
config NFT_QUEUE config NFT_QUEUE
depends on NETFILTER_XTABLES
depends on NETFILTER_NETLINK_QUEUE depends on NETFILTER_NETLINK_QUEUE
tristate "Netfilter nf_tables queue module" tristate "Netfilter nf_tables queue module"
help help
......
This diff is collapsed.
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
* Development of this code funded by Astaro AG (http://www.astaro.com/) * Development of this code funded by Astaro AG (http://www.astaro.com/)
*/ */
#include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/list.h> #include <linux/list.h>
...@@ -37,7 +38,7 @@ static struct nf_loginfo trace_loginfo = { ...@@ -37,7 +38,7 @@ static struct nf_loginfo trace_loginfo = {
.type = NF_LOG_TYPE_LOG, .type = NF_LOG_TYPE_LOG,
.u = { .u = {
.log = { .log = {
.level = 4, .level = LOGLEVEL_WARNING,
.logflags = NF_LOG_MASK, .logflags = NF_LOG_MASK,
}, },
}, },
...@@ -49,10 +50,10 @@ static void __nft_trace_packet(const struct nft_pktinfo *pkt, ...@@ -49,10 +50,10 @@ static void __nft_trace_packet(const struct nft_pktinfo *pkt,
{ {
struct net *net = dev_net(pkt->in ? pkt->in : pkt->out); struct net *net = dev_net(pkt->in ? pkt->in : pkt->out);
nf_log_packet(net, pkt->xt.family, pkt->ops->hooknum, pkt->skb, pkt->in, nf_log_trace(net, pkt->xt.family, pkt->ops->hooknum, pkt->skb, pkt->in,
pkt->out, &trace_loginfo, "TRACE: %s:%s:%s:%u ", pkt->out, &trace_loginfo, "TRACE: %s:%s:%s:%u ",
chain->table->name, chain->name, comments[type], chain->table->name, chain->name, comments[type],
rulenum); rulenum);
} }
static inline void nft_trace_packet(const struct nft_pktinfo *pkt, static inline void nft_trace_packet(const struct nft_pktinfo *pkt,
...@@ -112,6 +113,7 @@ unsigned int ...@@ -112,6 +113,7 @@ unsigned int
nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops) nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops)
{ {
const struct nft_chain *chain = ops->priv, *basechain = chain; const struct nft_chain *chain = ops->priv, *basechain = chain;
const struct net *net = read_pnet(&nft_base_chain(basechain)->pnet);
const struct nft_rule *rule; const struct nft_rule *rule;
const struct nft_expr *expr, *last; const struct nft_expr *expr, *last;
struct nft_data data[NFT_REG_MAX + 1]; struct nft_data data[NFT_REG_MAX + 1];
...@@ -119,11 +121,7 @@ nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops) ...@@ -119,11 +121,7 @@ nft_do_chain(struct nft_pktinfo *pkt, const struct nf_hook_ops *ops)
struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE]; struct nft_jumpstack jumpstack[NFT_JUMP_STACK_SIZE];
struct nft_stats *stats; struct nft_stats *stats;
int rulenum; int rulenum;
/* unsigned int gencursor = nft_genmask_cur(net);
* Cache cursor to avoid problems in case that the cursor is updated
* while traversing the ruleset.
*/
unsigned int gencursor = ACCESS_ONCE(chain->net->nft.gencursor);
do_chain: do_chain:
rulenum = 0; rulenum = 0;
......
...@@ -23,104 +23,130 @@ ...@@ -23,104 +23,130 @@
/* We target a hash table size of 4, element hint is 75% of final size */ /* We target a hash table size of 4, element hint is 75% of final size */
#define NFT_HASH_ELEMENT_HINT 3 #define NFT_HASH_ELEMENT_HINT 3
struct nft_hash {
struct rhashtable ht;
};
struct nft_hash_elem { struct nft_hash_elem {
struct rhash_head node; struct rhash_head node;
struct nft_data key; struct nft_set_ext ext;
struct nft_data data[]; };
struct nft_hash_cmp_arg {
const struct nft_set *set;
const struct nft_data *key;
u8 genmask;
}; };
static const struct rhashtable_params nft_hash_params; static const struct rhashtable_params nft_hash_params;
static bool nft_hash_lookup(const struct nft_set *set, static inline u32 nft_hash_key(const void *data, u32 len, u32 seed)
const struct nft_data *key,
struct nft_data *data)
{ {
struct rhashtable *priv = nft_set_priv(set); const struct nft_hash_cmp_arg *arg = data;
const struct nft_hash_elem *he;
he = rhashtable_lookup_fast(priv, key, nft_hash_params);
if (he && set->flags & NFT_SET_MAP)
nft_data_copy(data, he->data);
return !!he; return jhash(arg->key, len, seed);
} }
static int nft_hash_insert(const struct nft_set *set, static inline u32 nft_hash_obj(const void *data, u32 len, u32 seed)
const struct nft_set_elem *elem)
{ {
struct rhashtable *priv = nft_set_priv(set); const struct nft_hash_elem *he = data;
struct nft_hash_elem *he;
unsigned int size;
int err;
if (elem->flags != 0) return jhash(nft_set_ext_key(&he->ext), len, seed);
return -EINVAL; }
size = sizeof(*he); static inline int nft_hash_cmp(struct rhashtable_compare_arg *arg,
if (set->flags & NFT_SET_MAP) const void *ptr)
size += sizeof(he->data[0]); {
const struct nft_hash_cmp_arg *x = arg->key;
const struct nft_hash_elem *he = ptr;
he = kzalloc(size, GFP_KERNEL); if (nft_data_cmp(nft_set_ext_key(&he->ext), x->key, x->set->klen))
if (he == NULL) return 1;
return -ENOMEM; if (!nft_set_elem_active(&he->ext, x->genmask))
return 1;
return 0;
}
nft_data_copy(&he->key, &elem->key); static bool nft_hash_lookup(const struct nft_set *set,
if (set->flags & NFT_SET_MAP) const struct nft_data *key,
nft_data_copy(he->data, &elem->data); const struct nft_set_ext **ext)
{
struct nft_hash *priv = nft_set_priv(set);
const struct nft_hash_elem *he;
struct nft_hash_cmp_arg arg = {
.genmask = nft_genmask_cur(read_pnet(&set->pnet)),
.set = set,
.key = key,
};
err = rhashtable_insert_fast(priv, &he->node, nft_hash_params); he = rhashtable_lookup_fast(&priv->ht, &arg, nft_hash_params);
if (err) if (he != NULL)
kfree(he); *ext = &he->ext;
return err; return !!he;
} }
static void nft_hash_elem_destroy(const struct nft_set *set, static int nft_hash_insert(const struct nft_set *set,
struct nft_hash_elem *he) const struct nft_set_elem *elem)
{ {
nft_data_uninit(&he->key, NFT_DATA_VALUE); struct nft_hash *priv = nft_set_priv(set);
if (set->flags & NFT_SET_MAP) struct nft_hash_elem *he = elem->priv;
nft_data_uninit(he->data, set->dtype); struct nft_hash_cmp_arg arg = {
kfree(he); .genmask = nft_genmask_next(read_pnet(&set->pnet)),
.set = set,
.key = &elem->key,
};
return rhashtable_lookup_insert_key(&priv->ht, &arg, &he->node,
nft_hash_params);
} }
static void nft_hash_remove(const struct nft_set *set, static void nft_hash_activate(const struct nft_set *set,
const struct nft_set_elem *elem) const struct nft_set_elem *elem)
{ {
struct rhashtable *priv = nft_set_priv(set); struct nft_hash_elem *he = elem->priv;
rhashtable_remove_fast(priv, elem->cookie, nft_hash_params); nft_set_elem_change_active(set, &he->ext);
synchronize_rcu();
kfree(elem->cookie);
} }
static int nft_hash_get(const struct nft_set *set, struct nft_set_elem *elem) static void *nft_hash_deactivate(const struct nft_set *set,
const struct nft_set_elem *elem)
{ {
struct rhashtable *priv = nft_set_priv(set); struct nft_hash *priv = nft_set_priv(set);
struct nft_hash_elem *he; struct nft_hash_elem *he;
struct nft_hash_cmp_arg arg = {
.genmask = nft_genmask_next(read_pnet(&set->pnet)),
.set = set,
.key = &elem->key,
};
he = rhashtable_lookup_fast(priv, &elem->key, nft_hash_params); he = rhashtable_lookup_fast(&priv->ht, &arg, nft_hash_params);
if (!he) if (he != NULL)
return -ENOENT; nft_set_elem_change_active(set, &he->ext);
elem->cookie = he; return he;
elem->flags = 0; }
if (set->flags & NFT_SET_MAP)
nft_data_copy(&elem->data, he->data);
return 0; static void nft_hash_remove(const struct nft_set *set,
const struct nft_set_elem *elem)
{
struct nft_hash *priv = nft_set_priv(set);
struct nft_hash_elem *he = elem->priv;
rhashtable_remove_fast(&priv->ht, &he->node, nft_hash_params);
} }
static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set, static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set,
struct nft_set_iter *iter) struct nft_set_iter *iter)
{ {
struct rhashtable *priv = nft_set_priv(set); struct nft_hash *priv = nft_set_priv(set);
const struct nft_hash_elem *he; struct nft_hash_elem *he;
struct rhashtable_iter hti; struct rhashtable_iter hti;
struct nft_set_elem elem; struct nft_set_elem elem;
u8 genmask = nft_genmask_cur(read_pnet(&set->pnet));
int err; int err;
err = rhashtable_walk_init(priv, &hti); err = rhashtable_walk_init(&priv->ht, &hti);
iter->err = err; iter->err = err;
if (err) if (err)
return; return;
...@@ -144,11 +170,10 @@ static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set, ...@@ -144,11 +170,10 @@ static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set,
if (iter->count < iter->skip) if (iter->count < iter->skip)
goto cont; goto cont;
if (!nft_set_elem_active(&he->ext, genmask))
goto cont;
memcpy(&elem.key, &he->key, sizeof(elem.key)); elem.priv = he;
if (set->flags & NFT_SET_MAP)
memcpy(&elem.data, he->data, sizeof(elem.data));
elem.flags = 0;
iter->err = iter->fn(ctx, set, iter, &elem); iter->err = iter->fn(ctx, set, iter, &elem);
if (iter->err < 0) if (iter->err < 0)
...@@ -165,37 +190,40 @@ static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set, ...@@ -165,37 +190,40 @@ static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set,
static unsigned int nft_hash_privsize(const struct nlattr * const nla[]) static unsigned int nft_hash_privsize(const struct nlattr * const nla[])
{ {
return sizeof(struct rhashtable); return sizeof(struct nft_hash);
} }
static const struct rhashtable_params nft_hash_params = { static const struct rhashtable_params nft_hash_params = {
.head_offset = offsetof(struct nft_hash_elem, node), .head_offset = offsetof(struct nft_hash_elem, node),
.key_offset = offsetof(struct nft_hash_elem, key), .hashfn = nft_hash_key,
.hashfn = jhash, .obj_hashfn = nft_hash_obj,
.automatic_shrinking = true, .obj_cmpfn = nft_hash_cmp,
.automatic_shrinking = true,
}; };
static int nft_hash_init(const struct nft_set *set, static int nft_hash_init(const struct nft_set *set,
const struct nft_set_desc *desc, const struct nft_set_desc *desc,
const struct nlattr * const tb[]) const struct nlattr * const tb[])
{ {
struct rhashtable *priv = nft_set_priv(set); struct nft_hash *priv = nft_set_priv(set);
struct rhashtable_params params = nft_hash_params; struct rhashtable_params params = nft_hash_params;
params.nelem_hint = desc->size ?: NFT_HASH_ELEMENT_HINT; params.nelem_hint = desc->size ?: NFT_HASH_ELEMENT_HINT;
params.key_len = set->klen; params.key_len = set->klen;
return rhashtable_init(priv, &params); return rhashtable_init(&priv->ht, &params);
} }
static void nft_free_element(void *ptr, void *arg) static void nft_hash_elem_destroy(void *ptr, void *arg)
{ {
nft_hash_elem_destroy((const struct nft_set *)arg, ptr); nft_set_elem_destroy((const struct nft_set *)arg, ptr);
} }
static void nft_hash_destroy(const struct nft_set *set) static void nft_hash_destroy(const struct nft_set *set)
{ {
rhashtable_free_and_destroy(nft_set_priv(set), nft_free_element, struct nft_hash *priv = nft_set_priv(set);
rhashtable_free_and_destroy(&priv->ht, nft_hash_elem_destroy,
(void *)set); (void *)set);
} }
...@@ -205,11 +233,8 @@ static bool nft_hash_estimate(const struct nft_set_desc *desc, u32 features, ...@@ -205,11 +233,8 @@ static bool nft_hash_estimate(const struct nft_set_desc *desc, u32 features,
unsigned int esize; unsigned int esize;
esize = sizeof(struct nft_hash_elem); esize = sizeof(struct nft_hash_elem);
if (features & NFT_SET_MAP)
esize += FIELD_SIZEOF(struct nft_hash_elem, data[0]);
if (desc->size) { if (desc->size) {
est->size = sizeof(struct rhashtable) + est->size = sizeof(struct nft_hash) +
roundup_pow_of_two(desc->size * 4 / 3) * roundup_pow_of_two(desc->size * 4 / 3) *
sizeof(struct nft_hash_elem *) + sizeof(struct nft_hash_elem *) +
desc->size * esize; desc->size * esize;
...@@ -229,11 +254,13 @@ static bool nft_hash_estimate(const struct nft_set_desc *desc, u32 features, ...@@ -229,11 +254,13 @@ static bool nft_hash_estimate(const struct nft_set_desc *desc, u32 features,
static struct nft_set_ops nft_hash_ops __read_mostly = { static struct nft_set_ops nft_hash_ops __read_mostly = {
.privsize = nft_hash_privsize, .privsize = nft_hash_privsize,
.elemsize = offsetof(struct nft_hash_elem, ext),
.estimate = nft_hash_estimate, .estimate = nft_hash_estimate,
.init = nft_hash_init, .init = nft_hash_init,
.destroy = nft_hash_destroy, .destroy = nft_hash_destroy,
.get = nft_hash_get,
.insert = nft_hash_insert, .insert = nft_hash_insert,
.activate = nft_hash_activate,
.deactivate = nft_hash_deactivate,
.remove = nft_hash_remove, .remove = nft_hash_remove,
.lookup = nft_hash_lookup, .lookup = nft_hash_lookup,
.walk = nft_hash_walk, .walk = nft_hash_walk,
......
...@@ -78,7 +78,7 @@ static int nft_log_init(const struct nft_ctx *ctx, ...@@ -78,7 +78,7 @@ static int nft_log_init(const struct nft_ctx *ctx,
li->u.log.level = li->u.log.level =
ntohl(nla_get_be32(tb[NFTA_LOG_LEVEL])); ntohl(nla_get_be32(tb[NFTA_LOG_LEVEL]));
} else { } else {
li->u.log.level = 4; li->u.log.level = LOGLEVEL_WARNING;
} }
if (tb[NFTA_LOG_FLAGS] != NULL) { if (tb[NFTA_LOG_FLAGS] != NULL) {
li->u.log.logflags = li->u.log.logflags =
......
...@@ -31,9 +31,13 @@ static void nft_lookup_eval(const struct nft_expr *expr, ...@@ -31,9 +31,13 @@ static void nft_lookup_eval(const struct nft_expr *expr,
{ {
const struct nft_lookup *priv = nft_expr_priv(expr); const struct nft_lookup *priv = nft_expr_priv(expr);
const struct nft_set *set = priv->set; const struct nft_set *set = priv->set;
const struct nft_set_ext *ext;
if (set->ops->lookup(set, &data[priv->sreg], &data[priv->dreg])) if (set->ops->lookup(set, &data[priv->sreg], &ext)) {
if (set->flags & NFT_SET_MAP)
nft_data_copy(&data[priv->dreg], nft_set_ext_data(ext));
return; return;
}
data[NFT_REG_VERDICT].verdict = NFT_BREAK; data[NFT_REG_VERDICT].verdict = NFT_BREAK;
} }
......
...@@ -153,7 +153,7 @@ void nft_meta_get_eval(const struct nft_expr *expr, ...@@ -153,7 +153,7 @@ void nft_meta_get_eval(const struct nft_expr *expr,
} }
break; break;
case NFT_META_CPU: case NFT_META_CPU:
dest->data[0] = smp_processor_id(); dest->data[0] = raw_smp_processor_id();
break; break;
case NFT_META_IIFGROUP: case NFT_META_IIFGROUP:
if (in == NULL) if (in == NULL)
......
...@@ -26,18 +26,18 @@ struct nft_rbtree { ...@@ -26,18 +26,18 @@ struct nft_rbtree {
struct nft_rbtree_elem { struct nft_rbtree_elem {
struct rb_node node; struct rb_node node;
u16 flags; struct nft_set_ext ext;
struct nft_data key;
struct nft_data data[];
}; };
static bool nft_rbtree_lookup(const struct nft_set *set, static bool nft_rbtree_lookup(const struct nft_set *set,
const struct nft_data *key, const struct nft_data *key,
struct nft_data *data) const struct nft_set_ext **ext)
{ {
const struct nft_rbtree *priv = nft_set_priv(set); const struct nft_rbtree *priv = nft_set_priv(set);
const struct nft_rbtree_elem *rbe, *interval = NULL; const struct nft_rbtree_elem *rbe, *interval = NULL;
const struct rb_node *parent; const struct rb_node *parent;
u8 genmask = nft_genmask_cur(read_pnet(&set->pnet));
int d; int d;
spin_lock_bh(&nft_rbtree_lock); spin_lock_bh(&nft_rbtree_lock);
...@@ -45,7 +45,7 @@ static bool nft_rbtree_lookup(const struct nft_set *set, ...@@ -45,7 +45,7 @@ static bool nft_rbtree_lookup(const struct nft_set *set,
while (parent != NULL) { while (parent != NULL) {
rbe = rb_entry(parent, struct nft_rbtree_elem, node); rbe = rb_entry(parent, struct nft_rbtree_elem, node);
d = nft_data_cmp(&rbe->key, key, set->klen); d = nft_data_cmp(nft_set_ext_key(&rbe->ext), key, set->klen);
if (d < 0) { if (d < 0) {
parent = parent->rb_left; parent = parent->rb_left;
interval = rbe; interval = rbe;
...@@ -53,12 +53,17 @@ static bool nft_rbtree_lookup(const struct nft_set *set, ...@@ -53,12 +53,17 @@ static bool nft_rbtree_lookup(const struct nft_set *set,
parent = parent->rb_right; parent = parent->rb_right;
else { else {
found: found:
if (rbe->flags & NFT_SET_ELEM_INTERVAL_END) if (!nft_set_elem_active(&rbe->ext, genmask)) {
parent = parent->rb_left;
continue;
}
if (nft_set_ext_exists(&rbe->ext, NFT_SET_EXT_FLAGS) &&
*nft_set_ext_flags(&rbe->ext) &
NFT_SET_ELEM_INTERVAL_END)
goto out; goto out;
if (set->flags & NFT_SET_MAP)
nft_data_copy(data, rbe->data);
spin_unlock_bh(&nft_rbtree_lock); spin_unlock_bh(&nft_rbtree_lock);
*ext = &rbe->ext;
return true; return true;
} }
} }
...@@ -72,23 +77,13 @@ static bool nft_rbtree_lookup(const struct nft_set *set, ...@@ -72,23 +77,13 @@ static bool nft_rbtree_lookup(const struct nft_set *set,
return false; return false;
} }
static void nft_rbtree_elem_destroy(const struct nft_set *set,
struct nft_rbtree_elem *rbe)
{
nft_data_uninit(&rbe->key, NFT_DATA_VALUE);
if (set->flags & NFT_SET_MAP &&
!(rbe->flags & NFT_SET_ELEM_INTERVAL_END))
nft_data_uninit(rbe->data, set->dtype);
kfree(rbe);
}
static int __nft_rbtree_insert(const struct nft_set *set, static int __nft_rbtree_insert(const struct nft_set *set,
struct nft_rbtree_elem *new) struct nft_rbtree_elem *new)
{ {
struct nft_rbtree *priv = nft_set_priv(set); struct nft_rbtree *priv = nft_set_priv(set);
struct nft_rbtree_elem *rbe; struct nft_rbtree_elem *rbe;
struct rb_node *parent, **p; struct rb_node *parent, **p;
u8 genmask = nft_genmask_next(read_pnet(&set->pnet));
int d; int d;
parent = NULL; parent = NULL;
...@@ -96,13 +91,18 @@ static int __nft_rbtree_insert(const struct nft_set *set, ...@@ -96,13 +91,18 @@ static int __nft_rbtree_insert(const struct nft_set *set,
while (*p != NULL) { while (*p != NULL) {
parent = *p; parent = *p;
rbe = rb_entry(parent, struct nft_rbtree_elem, node); rbe = rb_entry(parent, struct nft_rbtree_elem, node);
d = nft_data_cmp(&rbe->key, &new->key, set->klen); d = nft_data_cmp(nft_set_ext_key(&rbe->ext),
nft_set_ext_key(&new->ext),
set->klen);
if (d < 0) if (d < 0)
p = &parent->rb_left; p = &parent->rb_left;
else if (d > 0) else if (d > 0)
p = &parent->rb_right; p = &parent->rb_right;
else else {
return -EEXIST; if (nft_set_elem_active(&rbe->ext, genmask))
return -EEXIST;
p = &parent->rb_left;
}
} }
rb_link_node(&new->node, parent, p); rb_link_node(&new->node, parent, p);
rb_insert_color(&new->node, &priv->root); rb_insert_color(&new->node, &priv->root);
...@@ -112,31 +112,13 @@ static int __nft_rbtree_insert(const struct nft_set *set, ...@@ -112,31 +112,13 @@ static int __nft_rbtree_insert(const struct nft_set *set,
static int nft_rbtree_insert(const struct nft_set *set, static int nft_rbtree_insert(const struct nft_set *set,
const struct nft_set_elem *elem) const struct nft_set_elem *elem)
{ {
struct nft_rbtree_elem *rbe; struct nft_rbtree_elem *rbe = elem->priv;
unsigned int size;
int err; int err;
size = sizeof(*rbe);
if (set->flags & NFT_SET_MAP &&
!(elem->flags & NFT_SET_ELEM_INTERVAL_END))
size += sizeof(rbe->data[0]);
rbe = kzalloc(size, GFP_KERNEL);
if (rbe == NULL)
return -ENOMEM;
rbe->flags = elem->flags;
nft_data_copy(&rbe->key, &elem->key);
if (set->flags & NFT_SET_MAP &&
!(rbe->flags & NFT_SET_ELEM_INTERVAL_END))
nft_data_copy(rbe->data, &elem->data);
spin_lock_bh(&nft_rbtree_lock); spin_lock_bh(&nft_rbtree_lock);
err = __nft_rbtree_insert(set, rbe); err = __nft_rbtree_insert(set, rbe);
if (err < 0)
kfree(rbe);
spin_unlock_bh(&nft_rbtree_lock); spin_unlock_bh(&nft_rbtree_lock);
return err; return err;
} }
...@@ -144,39 +126,49 @@ static void nft_rbtree_remove(const struct nft_set *set, ...@@ -144,39 +126,49 @@ static void nft_rbtree_remove(const struct nft_set *set,
const struct nft_set_elem *elem) const struct nft_set_elem *elem)
{ {
struct nft_rbtree *priv = nft_set_priv(set); struct nft_rbtree *priv = nft_set_priv(set);
struct nft_rbtree_elem *rbe = elem->cookie; struct nft_rbtree_elem *rbe = elem->priv;
spin_lock_bh(&nft_rbtree_lock); spin_lock_bh(&nft_rbtree_lock);
rb_erase(&rbe->node, &priv->root); rb_erase(&rbe->node, &priv->root);
spin_unlock_bh(&nft_rbtree_lock); spin_unlock_bh(&nft_rbtree_lock);
kfree(rbe);
} }
static int nft_rbtree_get(const struct nft_set *set, struct nft_set_elem *elem) static void nft_rbtree_activate(const struct nft_set *set,
const struct nft_set_elem *elem)
{
struct nft_rbtree_elem *rbe = elem->priv;
nft_set_elem_change_active(set, &rbe->ext);
}
static void *nft_rbtree_deactivate(const struct nft_set *set,
const struct nft_set_elem *elem)
{ {
const struct nft_rbtree *priv = nft_set_priv(set); const struct nft_rbtree *priv = nft_set_priv(set);
const struct rb_node *parent = priv->root.rb_node; const struct rb_node *parent = priv->root.rb_node;
struct nft_rbtree_elem *rbe; struct nft_rbtree_elem *rbe;
u8 genmask = nft_genmask_cur(read_pnet(&set->pnet));
int d; int d;
while (parent != NULL) { while (parent != NULL) {
rbe = rb_entry(parent, struct nft_rbtree_elem, node); rbe = rb_entry(parent, struct nft_rbtree_elem, node);
d = nft_data_cmp(&rbe->key, &elem->key, set->klen); d = nft_data_cmp(nft_set_ext_key(&rbe->ext), &elem->key,
set->klen);
if (d < 0) if (d < 0)
parent = parent->rb_left; parent = parent->rb_left;
else if (d > 0) else if (d > 0)
parent = parent->rb_right; parent = parent->rb_right;
else { else {
elem->cookie = rbe; if (!nft_set_elem_active(&rbe->ext, genmask)) {
if (set->flags & NFT_SET_MAP && parent = parent->rb_left;
!(rbe->flags & NFT_SET_ELEM_INTERVAL_END)) continue;
nft_data_copy(&elem->data, rbe->data); }
elem->flags = rbe->flags; nft_set_elem_change_active(set, &rbe->ext);
return 0; return rbe;
} }
} }
return -ENOENT; return NULL;
} }
static void nft_rbtree_walk(const struct nft_ctx *ctx, static void nft_rbtree_walk(const struct nft_ctx *ctx,
...@@ -184,21 +176,21 @@ static void nft_rbtree_walk(const struct nft_ctx *ctx, ...@@ -184,21 +176,21 @@ static void nft_rbtree_walk(const struct nft_ctx *ctx,
struct nft_set_iter *iter) struct nft_set_iter *iter)
{ {
const struct nft_rbtree *priv = nft_set_priv(set); const struct nft_rbtree *priv = nft_set_priv(set);
const struct nft_rbtree_elem *rbe; struct nft_rbtree_elem *rbe;
struct nft_set_elem elem; struct nft_set_elem elem;
struct rb_node *node; struct rb_node *node;
u8 genmask = nft_genmask_cur(read_pnet(&set->pnet));
spin_lock_bh(&nft_rbtree_lock); spin_lock_bh(&nft_rbtree_lock);
for (node = rb_first(&priv->root); node != NULL; node = rb_next(node)) { for (node = rb_first(&priv->root); node != NULL; node = rb_next(node)) {
rbe = rb_entry(node, struct nft_rbtree_elem, node);
if (iter->count < iter->skip) if (iter->count < iter->skip)
goto cont; goto cont;
if (!nft_set_elem_active(&rbe->ext, genmask))
goto cont;
rbe = rb_entry(node, struct nft_rbtree_elem, node); elem.priv = rbe;
nft_data_copy(&elem.key, &rbe->key);
if (set->flags & NFT_SET_MAP &&
!(rbe->flags & NFT_SET_ELEM_INTERVAL_END))
nft_data_copy(&elem.data, rbe->data);
elem.flags = rbe->flags;
iter->err = iter->fn(ctx, set, iter, &elem); iter->err = iter->fn(ctx, set, iter, &elem);
if (iter->err < 0) { if (iter->err < 0) {
...@@ -235,7 +227,7 @@ static void nft_rbtree_destroy(const struct nft_set *set) ...@@ -235,7 +227,7 @@ static void nft_rbtree_destroy(const struct nft_set *set)
while ((node = priv->root.rb_node) != NULL) { while ((node = priv->root.rb_node) != NULL) {
rb_erase(node, &priv->root); rb_erase(node, &priv->root);
rbe = rb_entry(node, struct nft_rbtree_elem, node); rbe = rb_entry(node, struct nft_rbtree_elem, node);
nft_rbtree_elem_destroy(set, rbe); nft_set_elem_destroy(set, rbe);
} }
} }
...@@ -245,9 +237,6 @@ static bool nft_rbtree_estimate(const struct nft_set_desc *desc, u32 features, ...@@ -245,9 +237,6 @@ static bool nft_rbtree_estimate(const struct nft_set_desc *desc, u32 features,
unsigned int nsize; unsigned int nsize;
nsize = sizeof(struct nft_rbtree_elem); nsize = sizeof(struct nft_rbtree_elem);
if (features & NFT_SET_MAP)
nsize += FIELD_SIZEOF(struct nft_rbtree_elem, data[0]);
if (desc->size) if (desc->size)
est->size = sizeof(struct nft_rbtree) + desc->size * nsize; est->size = sizeof(struct nft_rbtree) + desc->size * nsize;
else else
...@@ -260,12 +249,14 @@ static bool nft_rbtree_estimate(const struct nft_set_desc *desc, u32 features, ...@@ -260,12 +249,14 @@ static bool nft_rbtree_estimate(const struct nft_set_desc *desc, u32 features,
static struct nft_set_ops nft_rbtree_ops __read_mostly = { static struct nft_set_ops nft_rbtree_ops __read_mostly = {
.privsize = nft_rbtree_privsize, .privsize = nft_rbtree_privsize,
.elemsize = offsetof(struct nft_rbtree_elem, ext),
.estimate = nft_rbtree_estimate, .estimate = nft_rbtree_estimate,
.init = nft_rbtree_init, .init = nft_rbtree_init,
.destroy = nft_rbtree_destroy, .destroy = nft_rbtree_destroy,
.insert = nft_rbtree_insert, .insert = nft_rbtree_insert,
.remove = nft_rbtree_remove, .remove = nft_rbtree_remove,
.get = nft_rbtree_get, .deactivate = nft_rbtree_deactivate,
.activate = nft_rbtree_activate,
.lookup = nft_rbtree_lookup, .lookup = nft_rbtree_lookup,
.walk = nft_rbtree_walk, .walk = nft_rbtree_walk,
.features = NFT_SET_INTERVAL | NFT_SET_MAP, .features = NFT_SET_INTERVAL | NFT_SET_MAP,
......
...@@ -3127,7 +3127,7 @@ static struct pernet_operations __net_initdata netlink_net_ops = { ...@@ -3127,7 +3127,7 @@ static struct pernet_operations __net_initdata netlink_net_ops = {
.exit = netlink_net_exit, .exit = netlink_net_exit,
}; };
static inline u32 netlink_hash(const void *data, u32 seed) static inline u32 netlink_hash(const void *data, u32 len, u32 seed)
{ {
const struct netlink_sock *nlk = data; const struct netlink_sock *nlk = data;
struct netlink_compare_arg arg; struct netlink_compare_arg arg;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment