提交 16b25d1a 编写于 作者: D 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

This batch contains Netfilter updates for net-next:

1) Add nft_setelem_parse_key() helper function.

2) Add NFTA_SET_ELEM_KEY_END to specify a range with one single element.

3) Add NFTA_SET_DESC_CONCAT to describe the set element concatenation,
   from Stefano Brivio.

4) Add bitmap_cut() to copy n-bits from source to destination,
   from Stefano Brivio.

5) Add set to match on arbitrary concatenations, from Stefano Brivio.

6) Add selftest for this new set type. An extract of Stefano's
   description follows:

"Existing nftables set implementations allow matching entries with
interval expressions (rbtree), e.g. 192.0.2.1-192.0.2.4, entries
specifying field concatenation (hash, rhash), e.g. 192.0.2.1:22,
but not both.

In other words, none of the set types allows matching on range
expressions for more than one packet field at a time, such as ipset
does with types bitmap:ip,mac, and, to a more limited extent
(netmasks, not arbitrary ranges), with types hash:net,net,
hash:net,port, hash:ip,port,net, and hash:net,port,net.

As a pure hash-based approach is unsuitable for matching on ranges,
and "proxying" the existing red-black tree type looks impractical as
elements would need to be shared and managed across all employed
trees, this new set implementation intends to fill the functionality
gap by employing a relatively novel approach.

The fundamental idea, illustrated in deeper detail in patch 5/9, is to
use lookup tables classifying a small number of grouped bits from each
field, and map the lookup results in a way that yields a verdict for
the full set of specified fields.

The grouping bit aspect is loosely inspired by the Grouper algorithm,
by Jay Ligatti, Josh Kuhn, and Chris Gage (see patch 5/9 for the full
reference).

A reference, stand-alone implementation of the algorithm itself is
available at:
        https://pipapo.lameexcu.se

Some notes about possible future optimisations are also mentioned
there. This algorithm reduces the matching problem to, essentially,
a repetitive sequence of simple bitwise operations, and is
particularly suitable to be optimised by leveraging SIMD instruction
sets."
====================
Signed-off-by: NDavid S. Miller <davem@davemloft.net>
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
* bitmap_find_next_zero_area_off(buf, len, pos, n, mask) as above * bitmap_find_next_zero_area_off(buf, len, pos, n, mask) as above
* bitmap_shift_right(dst, src, n, nbits) *dst = *src >> n * bitmap_shift_right(dst, src, n, nbits) *dst = *src >> n
* bitmap_shift_left(dst, src, n, nbits) *dst = *src << n * bitmap_shift_left(dst, src, n, nbits) *dst = *src << n
* bitmap_cut(dst, src, first, n, nbits) Cut n bits from first, copy rest
* bitmap_replace(dst, old, new, mask, nbits) *dst = (*old & ~(*mask)) | (*new & *mask) * bitmap_replace(dst, old, new, mask, nbits) *dst = (*old & ~(*mask)) | (*new & *mask)
* bitmap_remap(dst, src, old, new, nbits) *dst = map(old, new)(src) * bitmap_remap(dst, src, old, new, nbits) *dst = map(old, new)(src)
* bitmap_bitremap(oldbit, old, new, nbits) newbit = map(old, new)(oldbit) * bitmap_bitremap(oldbit, old, new, nbits) newbit = map(old, new)(oldbit)
...@@ -133,6 +134,9 @@ extern void __bitmap_shift_right(unsigned long *dst, const unsigned long *src, ...@@ -133,6 +134,9 @@ extern void __bitmap_shift_right(unsigned long *dst, const unsigned long *src,
unsigned int shift, unsigned int nbits); unsigned int shift, unsigned int nbits);
extern void __bitmap_shift_left(unsigned long *dst, const unsigned long *src, extern void __bitmap_shift_left(unsigned long *dst, const unsigned long *src,
unsigned int shift, unsigned int nbits); unsigned int shift, unsigned int nbits);
extern void bitmap_cut(unsigned long *dst, const unsigned long *src,
unsigned int first, unsigned int cut,
unsigned int nbits);
extern int __bitmap_and(unsigned long *dst, const unsigned long *bitmap1, extern int __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
const unsigned long *bitmap2, unsigned int nbits); const unsigned long *bitmap2, unsigned int nbits);
extern void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1, extern void __bitmap_or(unsigned long *dst, const unsigned long *bitmap1,
......
...@@ -231,6 +231,7 @@ struct nft_userdata { ...@@ -231,6 +231,7 @@ struct nft_userdata {
* struct nft_set_elem - generic representation of set elements * struct nft_set_elem - generic representation of set elements
* *
* @key: element key * @key: element key
* @key_end: closing element key
* @priv: element private data and extensions * @priv: element private data and extensions
*/ */
struct nft_set_elem { struct nft_set_elem {
...@@ -238,6 +239,10 @@ struct nft_set_elem { ...@@ -238,6 +239,10 @@ struct nft_set_elem {
u32 buf[NFT_DATA_VALUE_MAXLEN / sizeof(u32)]; u32 buf[NFT_DATA_VALUE_MAXLEN / sizeof(u32)];
struct nft_data val; struct nft_data val;
} key; } key;
union {
u32 buf[NFT_DATA_VALUE_MAXLEN / sizeof(u32)];
struct nft_data val;
} key_end;
void *priv; void *priv;
}; };
...@@ -259,11 +264,15 @@ struct nft_set_iter { ...@@ -259,11 +264,15 @@ struct nft_set_iter {
* @klen: key length * @klen: key length
* @dlen: data length * @dlen: data length
* @size: number of set elements * @size: number of set elements
* @field_len: length of each field in concatenation, bytes
* @field_count: number of concatenated fields in element
*/ */
struct nft_set_desc { struct nft_set_desc {
unsigned int klen; unsigned int klen;
unsigned int dlen; unsigned int dlen;
unsigned int size; unsigned int size;
u8 field_len[NFT_REG32_COUNT];
u8 field_count;
}; };
/** /**
...@@ -404,6 +413,8 @@ void nft_unregister_set(struct nft_set_type *type); ...@@ -404,6 +413,8 @@ void nft_unregister_set(struct nft_set_type *type);
* @dtype: data type (verdict or numeric type defined by userspace) * @dtype: data type (verdict or numeric type defined by userspace)
* @objtype: object type (see NFT_OBJECT_* definitions) * @objtype: object type (see NFT_OBJECT_* definitions)
* @size: maximum set size * @size: maximum set size
* @field_len: length of each field in concatenation, bytes
* @field_count: number of concatenated fields in element
* @use: number of rules references to this set * @use: number of rules references to this set
* @nelems: number of elements * @nelems: number of elements
* @ndeact: number of deactivated elements queued for removal * @ndeact: number of deactivated elements queued for removal
...@@ -430,6 +441,8 @@ struct nft_set { ...@@ -430,6 +441,8 @@ struct nft_set {
u32 dtype; u32 dtype;
u32 objtype; u32 objtype;
u32 size; u32 size;
u8 field_len[NFT_REG32_COUNT];
u8 field_count;
u32 use; u32 use;
atomic_t nelems; atomic_t nelems;
u32 ndeact; u32 ndeact;
...@@ -502,6 +515,7 @@ void nf_tables_destroy_set(const struct nft_ctx *ctx, struct nft_set *set); ...@@ -502,6 +515,7 @@ void nf_tables_destroy_set(const struct nft_ctx *ctx, struct nft_set *set);
* enum nft_set_extensions - set extension type IDs * enum nft_set_extensions - set extension type IDs
* *
* @NFT_SET_EXT_KEY: element key * @NFT_SET_EXT_KEY: element key
* @NFT_SET_EXT_KEY_END: upper bound element key, for ranges
* @NFT_SET_EXT_DATA: mapping data * @NFT_SET_EXT_DATA: mapping data
* @NFT_SET_EXT_FLAGS: element flags * @NFT_SET_EXT_FLAGS: element flags
* @NFT_SET_EXT_TIMEOUT: element timeout * @NFT_SET_EXT_TIMEOUT: element timeout
...@@ -513,6 +527,7 @@ void nf_tables_destroy_set(const struct nft_ctx *ctx, struct nft_set *set); ...@@ -513,6 +527,7 @@ void nf_tables_destroy_set(const struct nft_ctx *ctx, struct nft_set *set);
*/ */
enum nft_set_extensions { enum nft_set_extensions {
NFT_SET_EXT_KEY, NFT_SET_EXT_KEY,
NFT_SET_EXT_KEY_END,
NFT_SET_EXT_DATA, NFT_SET_EXT_DATA,
NFT_SET_EXT_FLAGS, NFT_SET_EXT_FLAGS,
NFT_SET_EXT_TIMEOUT, NFT_SET_EXT_TIMEOUT,
...@@ -606,6 +621,11 @@ static inline struct nft_data *nft_set_ext_key(const struct nft_set_ext *ext) ...@@ -606,6 +621,11 @@ static inline struct nft_data *nft_set_ext_key(const struct nft_set_ext *ext)
return nft_set_ext(ext, NFT_SET_EXT_KEY); return nft_set_ext(ext, NFT_SET_EXT_KEY);
} }
static inline struct nft_data *nft_set_ext_key_end(const struct nft_set_ext *ext)
{
return nft_set_ext(ext, NFT_SET_EXT_KEY_END);
}
static inline struct nft_data *nft_set_ext_data(const struct nft_set_ext *ext) static inline struct nft_data *nft_set_ext_data(const struct nft_set_ext *ext)
{ {
return nft_set_ext(ext, NFT_SET_EXT_DATA); return nft_set_ext(ext, NFT_SET_EXT_DATA);
...@@ -655,7 +675,7 @@ static inline struct nft_object **nft_set_ext_obj(const struct nft_set_ext *ext) ...@@ -655,7 +675,7 @@ static inline struct nft_object **nft_set_ext_obj(const struct nft_set_ext *ext)
void *nft_set_elem_init(const struct nft_set *set, void *nft_set_elem_init(const struct nft_set *set,
const struct nft_set_ext_tmpl *tmpl, const struct nft_set_ext_tmpl *tmpl,
const u32 *key, const u32 *data, const u32 *key, const u32 *key_end, const u32 *data,
u64 timeout, u64 expiration, gfp_t gfp); u64 timeout, u64 expiration, gfp_t gfp);
void nft_set_elem_destroy(const struct nft_set *set, void *elem, void nft_set_elem_destroy(const struct nft_set *set, void *elem,
bool destroy_expr); bool destroy_expr);
......
...@@ -74,6 +74,7 @@ extern struct nft_set_type nft_set_hash_type; ...@@ -74,6 +74,7 @@ extern struct nft_set_type nft_set_hash_type;
extern struct nft_set_type nft_set_hash_fast_type; extern struct nft_set_type nft_set_hash_fast_type;
extern struct nft_set_type nft_set_rbtree_type; extern struct nft_set_type nft_set_rbtree_type;
extern struct nft_set_type nft_set_bitmap_type; extern struct nft_set_type nft_set_bitmap_type;
extern struct nft_set_type nft_set_pipapo_type;
struct nft_expr; struct nft_expr;
struct nft_regs; struct nft_regs;
......
...@@ -48,6 +48,7 @@ enum nft_registers { ...@@ -48,6 +48,7 @@ enum nft_registers {
#define NFT_REG_SIZE 16 #define NFT_REG_SIZE 16
#define NFT_REG32_SIZE 4 #define NFT_REG32_SIZE 4
#define NFT_REG32_COUNT (NFT_REG32_15 - NFT_REG32_00 + 1)
/** /**
* enum nft_verdicts - nf_tables internal verdicts * enum nft_verdicts - nf_tables internal verdicts
...@@ -301,14 +302,28 @@ enum nft_set_policies { ...@@ -301,14 +302,28 @@ enum nft_set_policies {
* enum nft_set_desc_attributes - set element description * enum nft_set_desc_attributes - set element description
* *
* @NFTA_SET_DESC_SIZE: number of elements in set (NLA_U32) * @NFTA_SET_DESC_SIZE: number of elements in set (NLA_U32)
* @NFTA_SET_DESC_CONCAT: description of field concatenation (NLA_NESTED)
*/ */
enum nft_set_desc_attributes { enum nft_set_desc_attributes {
NFTA_SET_DESC_UNSPEC, NFTA_SET_DESC_UNSPEC,
NFTA_SET_DESC_SIZE, NFTA_SET_DESC_SIZE,
NFTA_SET_DESC_CONCAT,
__NFTA_SET_DESC_MAX __NFTA_SET_DESC_MAX
}; };
#define NFTA_SET_DESC_MAX (__NFTA_SET_DESC_MAX - 1) #define NFTA_SET_DESC_MAX (__NFTA_SET_DESC_MAX - 1)
/**
* enum nft_set_field_attributes - attributes of concatenated fields
*
* @NFTA_SET_FIELD_LEN: length of single field, in bits (NLA_U32)
*/
enum nft_set_field_attributes {
NFTA_SET_FIELD_UNSPEC,
NFTA_SET_FIELD_LEN,
__NFTA_SET_FIELD_MAX
};
#define NFTA_SET_FIELD_MAX (__NFTA_SET_FIELD_MAX - 1)
/** /**
* enum nft_set_attributes - nf_tables set netlink attributes * enum nft_set_attributes - nf_tables set netlink attributes
* *
...@@ -370,6 +385,7 @@ enum nft_set_elem_flags { ...@@ -370,6 +385,7 @@ enum nft_set_elem_flags {
* @NFTA_SET_ELEM_USERDATA: user data (NLA_BINARY) * @NFTA_SET_ELEM_USERDATA: user data (NLA_BINARY)
* @NFTA_SET_ELEM_EXPR: expression (NLA_NESTED: nft_expr_attributes) * @NFTA_SET_ELEM_EXPR: expression (NLA_NESTED: nft_expr_attributes)
* @NFTA_SET_ELEM_OBJREF: stateful object reference (NLA_STRING) * @NFTA_SET_ELEM_OBJREF: stateful object reference (NLA_STRING)
* @NFTA_SET_ELEM_KEY_END: closing key value (NLA_NESTED: nft_data)
*/ */
enum nft_set_elem_attributes { enum nft_set_elem_attributes {
NFTA_SET_ELEM_UNSPEC, NFTA_SET_ELEM_UNSPEC,
...@@ -382,6 +398,7 @@ enum nft_set_elem_attributes { ...@@ -382,6 +398,7 @@ enum nft_set_elem_attributes {
NFTA_SET_ELEM_EXPR, NFTA_SET_ELEM_EXPR,
NFTA_SET_ELEM_PAD, NFTA_SET_ELEM_PAD,
NFTA_SET_ELEM_OBJREF, NFTA_SET_ELEM_OBJREF,
NFTA_SET_ELEM_KEY_END,
__NFTA_SET_ELEM_MAX __NFTA_SET_ELEM_MAX
}; };
#define NFTA_SET_ELEM_MAX (__NFTA_SET_ELEM_MAX - 1) #define NFTA_SET_ELEM_MAX (__NFTA_SET_ELEM_MAX - 1)
......
...@@ -168,6 +168,72 @@ void __bitmap_shift_left(unsigned long *dst, const unsigned long *src, ...@@ -168,6 +168,72 @@ void __bitmap_shift_left(unsigned long *dst, const unsigned long *src,
} }
EXPORT_SYMBOL(__bitmap_shift_left); EXPORT_SYMBOL(__bitmap_shift_left);
/**
* bitmap_cut() - remove bit region from bitmap and right shift remaining bits
* @dst: destination bitmap, might overlap with src
* @src: source bitmap
* @first: start bit of region to be removed
* @cut: number of bits to remove
* @nbits: bitmap size, in bits
*
* Set the n-th bit of @dst iff the n-th bit of @src is set and
* n is less than @first, or the m-th bit of @src is set for any
* m such that @first <= n < nbits, and m = n + @cut.
*
* In pictures, example for a big-endian 32-bit architecture:
*
* @src:
* 31 63
* | |
* 10000000 11000001 11110010 00010101 10000000 11000001 01110010 00010101
* | | | |
* 16 14 0 32
*
* if @cut is 3, and @first is 14, bits 14-16 in @src are cut and @dst is:
*
* 31 63
* | |
* 10110000 00011000 00110010 00010101 00010000 00011000 00101110 01000010
* | | |
* 14 (bit 17 0 32
* from @src)
*
* Note that @dst and @src might overlap partially or entirely.
*
* This is implemented in the obvious way, with a shift and carry
* step for each moved bit. Optimisation is left as an exercise
* for the compiler.
*/
void bitmap_cut(unsigned long *dst, const unsigned long *src,
unsigned int first, unsigned int cut, unsigned int nbits)
{
unsigned int len = BITS_TO_LONGS(nbits);
unsigned long keep = 0, carry;
int i;
memmove(dst, src, len * sizeof(*dst));
if (first % BITS_PER_LONG) {
keep = src[first / BITS_PER_LONG] &
(~0UL >> (BITS_PER_LONG - first % BITS_PER_LONG));
}
while (cut--) {
for (i = first / BITS_PER_LONG; i < len; i++) {
if (i < len - 1)
carry = dst[i + 1] & 1UL;
else
carry = 0;
dst[i] = (dst[i] >> 1) | (carry << (BITS_PER_LONG - 1));
}
}
dst[first / BITS_PER_LONG] &= ~0UL << (first % BITS_PER_LONG);
dst[first / BITS_PER_LONG] |= keep;
}
EXPORT_SYMBOL(bitmap_cut);
int __bitmap_and(unsigned long *dst, const unsigned long *bitmap1, int __bitmap_and(unsigned long *dst, const unsigned long *bitmap1,
const unsigned long *bitmap2, unsigned int bits) const unsigned long *bitmap2, unsigned int bits)
{ {
......
...@@ -81,7 +81,8 @@ nf_tables-objs := nf_tables_core.o nf_tables_api.o nft_chain_filter.o \ ...@@ -81,7 +81,8 @@ nf_tables-objs := nf_tables_core.o nf_tables_api.o nft_chain_filter.o \
nft_chain_route.o nf_tables_offload.o nft_chain_route.o nf_tables_offload.o
nf_tables_set-objs := nf_tables_set_core.o \ nf_tables_set-objs := nf_tables_set_core.o \
nft_set_hash.o nft_set_bitmap.o nft_set_rbtree.o nft_set_hash.o nft_set_bitmap.o nft_set_rbtree.o \
nft_set_pipapo.o
obj-$(CONFIG_NF_TABLES) += nf_tables.o obj-$(CONFIG_NF_TABLES) += nf_tables.o
obj-$(CONFIG_NF_TABLES_SET) += nf_tables_set.o obj-$(CONFIG_NF_TABLES_SET) += nf_tables_set.o
......
...@@ -3391,6 +3391,7 @@ static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = { ...@@ -3391,6 +3391,7 @@ static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = {
static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = { static const struct nla_policy nft_set_desc_policy[NFTA_SET_DESC_MAX + 1] = {
[NFTA_SET_DESC_SIZE] = { .type = NLA_U32 }, [NFTA_SET_DESC_SIZE] = { .type = NLA_U32 },
[NFTA_SET_DESC_CONCAT] = { .type = NLA_NESTED },
}; };
static int nft_ctx_init_from_setattr(struct nft_ctx *ctx, struct net *net, static int nft_ctx_init_from_setattr(struct nft_ctx *ctx, struct net *net,
...@@ -3557,6 +3558,33 @@ static __be64 nf_jiffies64_to_msecs(u64 input) ...@@ -3557,6 +3558,33 @@ static __be64 nf_jiffies64_to_msecs(u64 input)
return cpu_to_be64(jiffies64_to_msecs(input)); return cpu_to_be64(jiffies64_to_msecs(input));
} }
static int nf_tables_fill_set_concat(struct sk_buff *skb,
const struct nft_set *set)
{
struct nlattr *concat, *field;
int i;
concat = nla_nest_start_noflag(skb, NFTA_SET_DESC_CONCAT);
if (!concat)
return -ENOMEM;
for (i = 0; i < set->field_count; i++) {
field = nla_nest_start_noflag(skb, NFTA_LIST_ELEM);
if (!field)
return -ENOMEM;
if (nla_put_be32(skb, NFTA_SET_FIELD_LEN,
htonl(set->field_len[i])))
return -ENOMEM;
nla_nest_end(skb, field);
}
nla_nest_end(skb, concat);
return 0;
}
static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx, static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
const struct nft_set *set, u16 event, u16 flags) const struct nft_set *set, u16 event, u16 flags)
{ {
...@@ -3620,11 +3648,17 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx, ...@@ -3620,11 +3648,17 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
goto nla_put_failure; goto nla_put_failure;
desc = nla_nest_start_noflag(skb, NFTA_SET_DESC); desc = nla_nest_start_noflag(skb, NFTA_SET_DESC);
if (desc == NULL) if (desc == NULL)
goto nla_put_failure; goto nla_put_failure;
if (set->size && if (set->size &&
nla_put_be32(skb, NFTA_SET_DESC_SIZE, htonl(set->size))) nla_put_be32(skb, NFTA_SET_DESC_SIZE, htonl(set->size)))
goto nla_put_failure; goto nla_put_failure;
if (set->field_count > 1 &&
nf_tables_fill_set_concat(skb, set))
goto nla_put_failure;
nla_nest_end(skb, desc); nla_nest_end(skb, desc);
nlmsg_end(skb, nlh); nlmsg_end(skb, nlh);
...@@ -3797,6 +3831,53 @@ static int nf_tables_getset(struct net *net, struct sock *nlsk, ...@@ -3797,6 +3831,53 @@ static int nf_tables_getset(struct net *net, struct sock *nlsk,
return err; return err;
} }
static const struct nla_policy nft_concat_policy[NFTA_SET_FIELD_MAX + 1] = {
[NFTA_SET_FIELD_LEN] = { .type = NLA_U32 },
};
static int nft_set_desc_concat_parse(const struct nlattr *attr,
struct nft_set_desc *desc)
{
struct nlattr *tb[NFTA_SET_FIELD_MAX + 1];
u32 len;
int err;
err = nla_parse_nested_deprecated(tb, NFTA_SET_FIELD_MAX, attr,
nft_concat_policy, NULL);
if (err < 0)
return err;
if (!tb[NFTA_SET_FIELD_LEN])
return -EINVAL;
len = ntohl(nla_get_be32(tb[NFTA_SET_FIELD_LEN]));
if (len * BITS_PER_BYTE / 32 > NFT_REG32_COUNT)
return -E2BIG;
desc->field_len[desc->field_count++] = len;
return 0;
}
static int nft_set_desc_concat(struct nft_set_desc *desc,
const struct nlattr *nla)
{
struct nlattr *attr;
int rem, err;
nla_for_each_nested(attr, nla, rem) {
if (nla_type(attr) != NFTA_LIST_ELEM)
return -EINVAL;
err = nft_set_desc_concat_parse(attr, desc);
if (err < 0)
return err;
}
return 0;
}
static int nf_tables_set_desc_parse(struct nft_set_desc *desc, static int nf_tables_set_desc_parse(struct nft_set_desc *desc,
const struct nlattr *nla) const struct nlattr *nla)
{ {
...@@ -3810,8 +3891,10 @@ static int nf_tables_set_desc_parse(struct nft_set_desc *desc, ...@@ -3810,8 +3891,10 @@ static int nf_tables_set_desc_parse(struct nft_set_desc *desc,
if (da[NFTA_SET_DESC_SIZE] != NULL) if (da[NFTA_SET_DESC_SIZE] != NULL)
desc->size = ntohl(nla_get_be32(da[NFTA_SET_DESC_SIZE])); desc->size = ntohl(nla_get_be32(da[NFTA_SET_DESC_SIZE]));
if (da[NFTA_SET_DESC_CONCAT])
err = nft_set_desc_concat(desc, da[NFTA_SET_DESC_CONCAT]);
return 0; return err;
} }
static int nf_tables_newset(struct net *net, struct sock *nlsk, static int nf_tables_newset(struct net *net, struct sock *nlsk,
...@@ -3834,6 +3917,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk, ...@@ -3834,6 +3917,7 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
unsigned char *udata; unsigned char *udata;
u16 udlen; u16 udlen;
int err; int err;
int i;
if (nla[NFTA_SET_TABLE] == NULL || if (nla[NFTA_SET_TABLE] == NULL ||
nla[NFTA_SET_NAME] == NULL || nla[NFTA_SET_NAME] == NULL ||
...@@ -4012,6 +4096,10 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk, ...@@ -4012,6 +4096,10 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
set->gc_int = gc_int; set->gc_int = gc_int;
set->handle = nf_tables_alloc_handle(table); set->handle = nf_tables_alloc_handle(table);
set->field_count = desc.field_count;
for (i = 0; i < desc.field_count; i++)
set->field_len[i] = desc.field_len[i];
err = ops->init(set, &desc, nla); err = ops->init(set, &desc, nla);
if (err < 0) if (err < 0)
goto err3; goto err3;
...@@ -4215,6 +4303,9 @@ const struct nft_set_ext_type nft_set_ext_types[] = { ...@@ -4215,6 +4303,9 @@ const struct nft_set_ext_type nft_set_ext_types[] = {
.len = sizeof(struct nft_userdata), .len = sizeof(struct nft_userdata),
.align = __alignof__(struct nft_userdata), .align = __alignof__(struct nft_userdata),
}, },
[NFT_SET_EXT_KEY_END] = {
.align = __alignof__(u32),
},
}; };
EXPORT_SYMBOL_GPL(nft_set_ext_types); EXPORT_SYMBOL_GPL(nft_set_ext_types);
...@@ -4233,6 +4324,7 @@ static const struct nla_policy nft_set_elem_policy[NFTA_SET_ELEM_MAX + 1] = { ...@@ -4233,6 +4324,7 @@ static const struct nla_policy nft_set_elem_policy[NFTA_SET_ELEM_MAX + 1] = {
[NFTA_SET_ELEM_EXPR] = { .type = NLA_NESTED }, [NFTA_SET_ELEM_EXPR] = { .type = NLA_NESTED },
[NFTA_SET_ELEM_OBJREF] = { .type = NLA_STRING, [NFTA_SET_ELEM_OBJREF] = { .type = NLA_STRING,
.len = NFT_OBJ_MAXNAMELEN - 1 }, .len = NFT_OBJ_MAXNAMELEN - 1 },
[NFTA_SET_ELEM_KEY_END] = { .type = NLA_NESTED },
}; };
static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX + 1] = { static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX + 1] = {
...@@ -4282,6 +4374,11 @@ static int nf_tables_fill_setelem(struct sk_buff *skb, ...@@ -4282,6 +4374,11 @@ static int nf_tables_fill_setelem(struct sk_buff *skb,
NFT_DATA_VALUE, set->klen) < 0) NFT_DATA_VALUE, set->klen) < 0)
goto nla_put_failure; goto nla_put_failure;
if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY_END) &&
nft_data_dump(skb, NFTA_SET_ELEM_KEY_END, nft_set_ext_key_end(ext),
NFT_DATA_VALUE, set->klen) < 0)
goto nla_put_failure;
if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA) && if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA) &&
nft_data_dump(skb, NFTA_SET_ELEM_DATA, nft_set_ext_data(ext), nft_data_dump(skb, NFTA_SET_ELEM_DATA, nft_set_ext_data(ext),
set->dtype == NFT_DATA_VERDICT ? NFT_DATA_VERDICT : NFT_DATA_VALUE, set->dtype == NFT_DATA_VERDICT ? NFT_DATA_VERDICT : NFT_DATA_VALUE,
...@@ -4524,11 +4621,28 @@ static int nft_setelem_parse_flags(const struct nft_set *set, ...@@ -4524,11 +4621,28 @@ static int nft_setelem_parse_flags(const struct nft_set *set,
return 0; return 0;
} }
static int nft_setelem_parse_key(struct nft_ctx *ctx, struct nft_set *set,
struct nft_data *key, struct nlattr *attr)
{
struct nft_data_desc desc;
int err;
err = nft_data_init(ctx, key, NFT_DATA_VALUE_MAXLEN, &desc, attr);
if (err < 0)
return err;
if (desc.type != NFT_DATA_VALUE || desc.len != set->klen) {
nft_data_release(key, desc.type);
return -EINVAL;
}
return 0;
}
static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set, static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set,
const struct nlattr *attr) const struct nlattr *attr)
{ {
struct nlattr *nla[NFTA_SET_ELEM_MAX + 1]; struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
struct nft_data_desc desc;
struct nft_set_elem elem; struct nft_set_elem elem;
struct sk_buff *skb; struct sk_buff *skb;
uint32_t flags = 0; uint32_t flags = 0;
...@@ -4547,15 +4661,16 @@ static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -4547,15 +4661,16 @@ static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set,
if (err < 0) if (err < 0)
return err; return err;
err = nft_data_init(ctx, &elem.key.val, sizeof(elem.key), &desc, err = nft_setelem_parse_key(ctx, set, &elem.key.val,
nla[NFTA_SET_ELEM_KEY]); nla[NFTA_SET_ELEM_KEY]);
if (err < 0) if (err < 0)
return err; return err;
err = -EINVAL; if (nla[NFTA_SET_ELEM_KEY_END]) {
if (desc.type != NFT_DATA_VALUE || desc.len != set->klen) { err = nft_setelem_parse_key(ctx, set, &elem.key_end.val,
nft_data_release(&elem.key.val, desc.type); nla[NFTA_SET_ELEM_KEY_END]);
return err; if (err < 0)
return err;
} }
priv = set->ops->get(ctx->net, set, &elem, flags); priv = set->ops->get(ctx->net, set, &elem, flags);
...@@ -4683,8 +4798,8 @@ static struct nft_trans *nft_trans_elem_alloc(struct nft_ctx *ctx, ...@@ -4683,8 +4798,8 @@ static struct nft_trans *nft_trans_elem_alloc(struct nft_ctx *ctx,
void *nft_set_elem_init(const struct nft_set *set, void *nft_set_elem_init(const struct nft_set *set,
const struct nft_set_ext_tmpl *tmpl, const struct nft_set_ext_tmpl *tmpl,
const u32 *key, const u32 *data, const u32 *key, const u32 *key_end,
u64 timeout, u64 expiration, gfp_t gfp) const u32 *data, u64 timeout, u64 expiration, gfp_t gfp)
{ {
struct nft_set_ext *ext; struct nft_set_ext *ext;
void *elem; void *elem;
...@@ -4697,6 +4812,8 @@ void *nft_set_elem_init(const struct nft_set *set, ...@@ -4697,6 +4812,8 @@ void *nft_set_elem_init(const struct nft_set *set,
nft_set_ext_init(ext, tmpl); nft_set_ext_init(ext, tmpl);
memcpy(nft_set_ext_key(ext), key, set->klen); memcpy(nft_set_ext_key(ext), key, set->klen);
if (nft_set_ext_exists(ext, NFT_SET_EXT_KEY_END))
memcpy(nft_set_ext_key_end(ext), key_end, set->klen);
if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA)) if (nft_set_ext_exists(ext, NFT_SET_EXT_DATA))
memcpy(nft_set_ext_data(ext), data, set->dlen); memcpy(nft_set_ext_data(ext), data, set->dlen);
if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION)) { if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION)) {
...@@ -4756,13 +4873,13 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -4756,13 +4873,13 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
{ {
struct nlattr *nla[NFTA_SET_ELEM_MAX + 1]; struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
u8 genmask = nft_genmask_next(ctx->net); u8 genmask = nft_genmask_next(ctx->net);
struct nft_data_desc d1, d2;
struct nft_set_ext_tmpl tmpl; struct nft_set_ext_tmpl tmpl;
struct nft_set_ext *ext, *ext2; struct nft_set_ext *ext, *ext2;
struct nft_set_elem elem; struct nft_set_elem elem;
struct nft_set_binding *binding; struct nft_set_binding *binding;
struct nft_object *obj = NULL; struct nft_object *obj = NULL;
struct nft_userdata *udata; struct nft_userdata *udata;
struct nft_data_desc desc;
struct nft_data data; struct nft_data data;
enum nft_registers dreg; enum nft_registers dreg;
struct nft_trans *trans; struct nft_trans *trans;
...@@ -4828,15 +4945,22 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -4828,15 +4945,22 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
return err; return err;
} }
err = nft_data_init(ctx, &elem.key.val, sizeof(elem.key), &d1, err = nft_setelem_parse_key(ctx, set, &elem.key.val,
nla[NFTA_SET_ELEM_KEY]); nla[NFTA_SET_ELEM_KEY]);
if (err < 0) if (err < 0)
goto err1; return err;
err = -EINVAL;
if (d1.type != NFT_DATA_VALUE || d1.len != set->klen) nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
goto err2;
if (nla[NFTA_SET_ELEM_KEY_END]) {
err = nft_setelem_parse_key(ctx, set, &elem.key_end.val,
nla[NFTA_SET_ELEM_KEY_END]);
if (err < 0)
goto err_parse_key;
nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY_END, set->klen);
}
nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, d1.len);
if (timeout > 0) { if (timeout > 0) {
nft_set_ext_add(&tmpl, NFT_SET_EXT_EXPIRATION); nft_set_ext_add(&tmpl, NFT_SET_EXT_EXPIRATION);
if (timeout != set->timeout) if (timeout != set->timeout)
...@@ -4846,27 +4970,27 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -4846,27 +4970,27 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
if (nla[NFTA_SET_ELEM_OBJREF] != NULL) { if (nla[NFTA_SET_ELEM_OBJREF] != NULL) {
if (!(set->flags & NFT_SET_OBJECT)) { if (!(set->flags & NFT_SET_OBJECT)) {
err = -EINVAL; err = -EINVAL;
goto err2; goto err_parse_key_end;
} }
obj = nft_obj_lookup(ctx->net, ctx->table, obj = nft_obj_lookup(ctx->net, ctx->table,
nla[NFTA_SET_ELEM_OBJREF], nla[NFTA_SET_ELEM_OBJREF],
set->objtype, genmask); set->objtype, genmask);
if (IS_ERR(obj)) { if (IS_ERR(obj)) {
err = PTR_ERR(obj); err = PTR_ERR(obj);
goto err2; goto err_parse_key_end;
} }
nft_set_ext_add(&tmpl, NFT_SET_EXT_OBJREF); nft_set_ext_add(&tmpl, NFT_SET_EXT_OBJREF);
} }
if (nla[NFTA_SET_ELEM_DATA] != NULL) { if (nla[NFTA_SET_ELEM_DATA] != NULL) {
err = nft_data_init(ctx, &data, sizeof(data), &d2, err = nft_data_init(ctx, &data, sizeof(data), &desc,
nla[NFTA_SET_ELEM_DATA]); nla[NFTA_SET_ELEM_DATA]);
if (err < 0) if (err < 0)
goto err2; goto err_parse_key_end;
err = -EINVAL; err = -EINVAL;
if (set->dtype != NFT_DATA_VERDICT && d2.len != set->dlen) if (set->dtype != NFT_DATA_VERDICT && desc.len != set->dlen)
goto err3; goto err_parse_data;
dreg = nft_type_to_reg(set->dtype); dreg = nft_type_to_reg(set->dtype);
list_for_each_entry(binding, &set->bindings, list) { list_for_each_entry(binding, &set->bindings, list) {
...@@ -4882,18 +5006,18 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -4882,18 +5006,18 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
err = nft_validate_register_store(&bind_ctx, dreg, err = nft_validate_register_store(&bind_ctx, dreg,
&data, &data,
d2.type, d2.len); desc.type, desc.len);
if (err < 0) if (err < 0)
goto err3; goto err_parse_data;
if (d2.type == NFT_DATA_VERDICT && if (desc.type == NFT_DATA_VERDICT &&
(data.verdict.code == NFT_GOTO || (data.verdict.code == NFT_GOTO ||
data.verdict.code == NFT_JUMP)) data.verdict.code == NFT_JUMP))
nft_validate_state_update(ctx->net, nft_validate_state_update(ctx->net,
NFT_VALIDATE_NEED); NFT_VALIDATE_NEED);
} }
nft_set_ext_add_length(&tmpl, NFT_SET_EXT_DATA, d2.len); nft_set_ext_add_length(&tmpl, NFT_SET_EXT_DATA, desc.len);
} }
/* The full maximum length of userdata can exceed the maximum /* The full maximum length of userdata can exceed the maximum
...@@ -4909,10 +5033,11 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -4909,10 +5033,11 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
} }
err = -ENOMEM; err = -ENOMEM;
elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data, data.data, elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data,
elem.key_end.val.data, data.data,
timeout, expiration, GFP_KERNEL); timeout, expiration, GFP_KERNEL);
if (elem.priv == NULL) if (elem.priv == NULL)
goto err3; goto err_parse_data;
ext = nft_set_elem_ext(set, elem.priv); ext = nft_set_elem_ext(set, elem.priv);
if (flags) if (flags)
...@@ -4929,7 +5054,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -4929,7 +5054,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
trans = nft_trans_elem_alloc(ctx, NFT_MSG_NEWSETELEM, set); trans = nft_trans_elem_alloc(ctx, NFT_MSG_NEWSETELEM, set);
if (trans == NULL) if (trans == NULL)
goto err4; goto err_trans;
ext->genmask = nft_genmask_cur(ctx->net) | NFT_SET_ELEM_BUSY_MASK; ext->genmask = nft_genmask_cur(ctx->net) | NFT_SET_ELEM_BUSY_MASK;
err = set->ops->insert(ctx->net, set, &elem, &ext2); err = set->ops->insert(ctx->net, set, &elem, &ext2);
...@@ -4940,7 +5065,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -4940,7 +5065,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF) ^ nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF) ^
nft_set_ext_exists(ext2, NFT_SET_EXT_OBJREF)) { nft_set_ext_exists(ext2, NFT_SET_EXT_OBJREF)) {
err = -EBUSY; err = -EBUSY;
goto err5; goto err_element_clash;
} }
if ((nft_set_ext_exists(ext, NFT_SET_EXT_DATA) && if ((nft_set_ext_exists(ext, NFT_SET_EXT_DATA) &&
nft_set_ext_exists(ext2, NFT_SET_EXT_DATA) && nft_set_ext_exists(ext2, NFT_SET_EXT_DATA) &&
...@@ -4953,33 +5078,35 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -4953,33 +5078,35 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
else if (!(nlmsg_flags & NLM_F_EXCL)) else if (!(nlmsg_flags & NLM_F_EXCL))
err = 0; err = 0;
} }
goto err5; goto err_element_clash;
} }
if (set->size && if (set->size &&
!atomic_add_unless(&set->nelems, 1, set->size + set->ndeact)) { !atomic_add_unless(&set->nelems, 1, set->size + set->ndeact)) {
err = -ENFILE; err = -ENFILE;
goto err6; goto err_set_full;
} }
nft_trans_elem(trans) = elem; nft_trans_elem(trans) = elem;
list_add_tail(&trans->list, &ctx->net->nft.commit_list); list_add_tail(&trans->list, &ctx->net->nft.commit_list);
return 0; return 0;
err6: err_set_full:
set->ops->remove(ctx->net, set, &elem); set->ops->remove(ctx->net, set, &elem);
err5: err_element_clash:
kfree(trans); kfree(trans);
err4: err_trans:
if (obj) if (obj)
obj->use--; obj->use--;
kfree(elem.priv); kfree(elem.priv);
err3: err_parse_data:
if (nla[NFTA_SET_ELEM_DATA] != NULL) if (nla[NFTA_SET_ELEM_DATA] != NULL)
nft_data_release(&data, d2.type); nft_data_release(&data, desc.type);
err2: err_parse_key_end:
nft_data_release(&elem.key.val, d1.type); nft_data_release(&elem.key_end.val, NFT_DATA_VALUE);
err1: err_parse_key:
nft_data_release(&elem.key.val, NFT_DATA_VALUE);
return err; return err;
} }
...@@ -5074,7 +5201,6 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -5074,7 +5201,6 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
{ {
struct nlattr *nla[NFTA_SET_ELEM_MAX + 1]; struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
struct nft_set_ext_tmpl tmpl; struct nft_set_ext_tmpl tmpl;
struct nft_data_desc desc;
struct nft_set_elem elem; struct nft_set_elem elem;
struct nft_set_ext *ext; struct nft_set_ext *ext;
struct nft_trans *trans; struct nft_trans *trans;
...@@ -5085,11 +5211,10 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -5085,11 +5211,10 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
err = nla_parse_nested_deprecated(nla, NFTA_SET_ELEM_MAX, attr, err = nla_parse_nested_deprecated(nla, NFTA_SET_ELEM_MAX, attr,
nft_set_elem_policy, NULL); nft_set_elem_policy, NULL);
if (err < 0) if (err < 0)
goto err1; return err;
err = -EINVAL;
if (nla[NFTA_SET_ELEM_KEY] == NULL) if (nla[NFTA_SET_ELEM_KEY] == NULL)
goto err1; return -EINVAL;
nft_set_ext_prepare(&tmpl); nft_set_ext_prepare(&tmpl);
...@@ -5099,37 +5224,41 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -5099,37 +5224,41 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
if (flags != 0) if (flags != 0)
nft_set_ext_add(&tmpl, NFT_SET_EXT_FLAGS); nft_set_ext_add(&tmpl, NFT_SET_EXT_FLAGS);
err = nft_data_init(ctx, &elem.key.val, sizeof(elem.key), &desc, err = nft_setelem_parse_key(ctx, set, &elem.key.val,
nla[NFTA_SET_ELEM_KEY]); nla[NFTA_SET_ELEM_KEY]);
if (err < 0) if (err < 0)
goto err1; return err;
err = -EINVAL; nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, set->klen);
if (desc.type != NFT_DATA_VALUE || desc.len != set->klen)
goto err2;
nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY, desc.len); if (nla[NFTA_SET_ELEM_KEY_END]) {
err = nft_setelem_parse_key(ctx, set, &elem.key_end.val,
nla[NFTA_SET_ELEM_KEY_END]);
if (err < 0)
return err;
nft_set_ext_add_length(&tmpl, NFT_SET_EXT_KEY_END, set->klen);
}
err = -ENOMEM; err = -ENOMEM;
elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data, NULL, 0, elem.priv = nft_set_elem_init(set, &tmpl, elem.key.val.data,
0, GFP_KERNEL); elem.key_end.val.data, NULL, 0, 0,
GFP_KERNEL);
if (elem.priv == NULL) if (elem.priv == NULL)
goto err2; goto fail_elem;
ext = nft_set_elem_ext(set, elem.priv); ext = nft_set_elem_ext(set, elem.priv);
if (flags) if (flags)
*nft_set_ext_flags(ext) = flags; *nft_set_ext_flags(ext) = flags;
trans = nft_trans_elem_alloc(ctx, NFT_MSG_DELSETELEM, set); trans = nft_trans_elem_alloc(ctx, NFT_MSG_DELSETELEM, set);
if (trans == NULL) { if (trans == NULL)
err = -ENOMEM; goto fail_trans;
goto err3;
}
priv = set->ops->deactivate(ctx->net, set, &elem); priv = set->ops->deactivate(ctx->net, set, &elem);
if (priv == NULL) { if (priv == NULL) {
err = -ENOENT; err = -ENOENT;
goto err4; goto fail_ops;
} }
kfree(elem.priv); kfree(elem.priv);
elem.priv = priv; elem.priv = priv;
...@@ -5140,13 +5269,12 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set, ...@@ -5140,13 +5269,12 @@ static int nft_del_setelem(struct nft_ctx *ctx, struct nft_set *set,
list_add_tail(&trans->list, &ctx->net->nft.commit_list); list_add_tail(&trans->list, &ctx->net->nft.commit_list);
return 0; return 0;
err4: fail_ops:
kfree(trans); kfree(trans);
err3: fail_trans:
kfree(elem.priv); kfree(elem.priv);
err2: fail_elem:
nft_data_release(&elem.key.val, desc.type); nft_data_release(&elem.key.val, NFT_DATA_VALUE);
err1:
return err; return err;
} }
......
...@@ -9,12 +9,14 @@ static int __init nf_tables_set_module_init(void) ...@@ -9,12 +9,14 @@ static int __init nf_tables_set_module_init(void)
nft_register_set(&nft_set_rhash_type); nft_register_set(&nft_set_rhash_type);
nft_register_set(&nft_set_bitmap_type); nft_register_set(&nft_set_bitmap_type);
nft_register_set(&nft_set_rbtree_type); nft_register_set(&nft_set_rbtree_type);
nft_register_set(&nft_set_pipapo_type);
return 0; return 0;
} }
static void __exit nf_tables_set_module_exit(void) static void __exit nf_tables_set_module_exit(void)
{ {
nft_unregister_set(&nft_set_pipapo_type);
nft_unregister_set(&nft_set_rbtree_type); nft_unregister_set(&nft_set_rbtree_type);
nft_unregister_set(&nft_set_bitmap_type); nft_unregister_set(&nft_set_bitmap_type);
nft_unregister_set(&nft_set_rhash_type); nft_unregister_set(&nft_set_rhash_type);
......
...@@ -54,7 +54,7 @@ static void *nft_dynset_new(struct nft_set *set, const struct nft_expr *expr, ...@@ -54,7 +54,7 @@ static void *nft_dynset_new(struct nft_set *set, const struct nft_expr *expr,
timeout = priv->timeout ? : set->timeout; timeout = priv->timeout ? : set->timeout;
elem = nft_set_elem_init(set, &priv->tmpl, elem = nft_set_elem_init(set, &priv->tmpl,
&regs->data[priv->sreg_key], &regs->data[priv->sreg_key], NULL,
&regs->data[priv->sreg_data], &regs->data[priv->sreg_data],
timeout, 0, GFP_ATOMIC); timeout, 0, GFP_ATOMIC);
if (elem == NULL) if (elem == NULL)
......
此差异已折叠。
...@@ -466,6 +466,9 @@ static void nft_rbtree_destroy(const struct nft_set *set) ...@@ -466,6 +466,9 @@ static void nft_rbtree_destroy(const struct nft_set *set)
static bool nft_rbtree_estimate(const struct nft_set_desc *desc, u32 features, static bool nft_rbtree_estimate(const struct nft_set_desc *desc, u32 features,
struct nft_set_estimate *est) struct nft_set_estimate *est)
{ {
if (desc->field_count > 1)
return false;
if (desc->size) if (desc->size)
est->size = sizeof(struct nft_rbtree) + est->size = sizeof(struct nft_rbtree) +
desc->size * sizeof(struct nft_rbtree_elem); desc->size * sizeof(struct nft_rbtree_elem);
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
# Makefile for netfilter selftests # Makefile for netfilter selftests
TEST_PROGS := nft_trans_stress.sh nft_nat.sh bridge_brouter.sh \ TEST_PROGS := nft_trans_stress.sh nft_nat.sh bridge_brouter.sh \
conntrack_icmp_related.sh nft_flowtable.sh ipvs.sh conntrack_icmp_related.sh nft_flowtable.sh ipvs.sh \
nft_concat_range.sh
include ../lib.mk include ../lib.mk
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册