Skip to content

Commit

Permalink
netfilter: nf_tables: add netlink set API
Browse files Browse the repository at this point in the history
This patch adds the new netlink API for maintaining nf_tables sets
independently of the ruleset. The API supports the following operations:

- creation of sets
- deletion of sets
- querying of specific sets
- dumping of all sets

- addition of set elements
- removal of set elements
- dumping of all set elements

Sets are identified by name, each table defines an individual namespace.
The name of a set may be allocated automatically, this is mostly useful
in combination with the NFT_SET_ANONYMOUS flag, which destroys a set
automatically once the last reference has been released.

Sets can be marked constant, meaning they're not allowed to change while
linked to a rule. This allows to perform lockless operation for set
types that would otherwise require locking.

Additionally, if the implementation supports it, sets can (as before) be
used as maps, associating a data value with each key (or range), by
specifying the NFT_SET_MAP flag and can be used for interval queries by
specifying the NFT_SET_INTERVAL flag.

Set elements are added and removed incrementally. All element operations
support batching, reducing netlink message and set lookup overhead.

The old "set" and "hash" expressions are replaced by a generic "lookup"
expression, which binds to the specified set. Userspace is not aware
of the actual set implementation used by the kernel anymore, all
configuration options are generic.

Currently the implementation selection logic is largely missing and the
kernel will simply use the first registered implementation supporting the
requested operation. Eventually, the plan is to have userspace supply a
description of the data characteristics and select the implementation
based on expected performance and memory use.

This patch includes the new 'lookup' expression to look up for element
matching in the set.

This patch includes kernel-doc descriptions for this set API and it
also includes the following fixes.

From Patrick McHardy:
* netfilter: nf_tables: fix set element data type in dumps
* netfilter: nf_tables: fix indentation of struct nft_set_elem comments
* netfilter: nf_tables: fix oops in nft_validate_data_load()
* netfilter: nf_tables: fix oops while listing sets of built-in tables
* netfilter: nf_tables: destroy anonymous sets immediately if binding fails
* netfilter: nf_tables: propagate context to set iter callback
* netfilter: nf_tables: add loop detection

From Pablo Neira Ayuso:
* netfilter: nf_tables: allow to dump all existing sets
* netfilter: nf_tables: fix wrong type for flags variable in newelem

Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
  • Loading branch information
kaber authored and ummakynes committed Oct 14, 2013
1 parent 9651851 commit 20a6934
Show file tree
Hide file tree
Showing 11 changed files with 1,854 additions and 677 deletions.
149 changes: 142 additions & 7 deletions include/net/netfilter/nf_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
#include <linux/netfilter/nf_tables.h>
#include <net/netlink.h>

#define NFT_JUMP_STACK_SIZE 16

struct nft_pktinfo {
struct sk_buff *skb;
const struct net_device *in;
Expand Down Expand Up @@ -48,23 +50,22 @@ static inline void nft_data_debug(const struct nft_data *data)
}

/**
* struct nft_ctx - nf_tables rule context
* struct nft_ctx - nf_tables rule/set context
*
* @skb: netlink skb
* @nlh: netlink message header
* @afi: address family info
* @table: the table the chain is contained in
* @chain: the chain the rule is contained in
*/
struct nft_ctx {
const struct sk_buff *skb;
const struct nlmsghdr *nlh;
const struct nft_af_info *afi;
const struct nft_table *table;
const struct nft_chain *chain;
};

enum nft_data_types {
NFT_DATA_VALUE,
NFT_DATA_VERDICT,
};

struct nft_data_desc {
enum nft_data_types type;
unsigned int len;
Expand All @@ -83,13 +84,144 @@ static inline enum nft_data_types nft_dreg_to_type(enum nft_registers reg)
return reg == NFT_REG_VERDICT ? NFT_DATA_VERDICT : NFT_DATA_VALUE;
}

static inline enum nft_registers nft_type_to_reg(enum nft_data_types type)
{
return type == NFT_DATA_VERDICT ? NFT_REG_VERDICT : NFT_REG_1;
}

extern int nft_validate_input_register(enum nft_registers reg);
extern int nft_validate_output_register(enum nft_registers reg);
extern int nft_validate_data_load(const struct nft_ctx *ctx,
enum nft_registers reg,
const struct nft_data *data,
enum nft_data_types type);

/**
* 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.
*/
struct nft_set_elem {
void *cookie;
struct nft_data key;
struct nft_data data;
u32 flags;
};

struct nft_set;
struct nft_set_iter {
unsigned int count;
unsigned int skip;
int err;
int (*fn)(const struct nft_ctx *ctx,
const struct nft_set *set,
const struct nft_set_iter *iter,
const struct nft_set_elem *elem);
};

/**
* struct nft_set_ops - nf_tables set operations
*
* @lookup: look up an element within the set
* @insert: insert new element into set
* @remove: remove element from set
* @walk: iterate over all set elemeennts
* @privsize: function to return size of set private data
* @init: initialize private data of new set instance
* @destroy: destroy private data of set instance
* @list: nf_tables_set_ops list node
* @owner: module reference
* @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);
int (*insert)(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,
const struct nft_set *set,
struct nft_set_iter *iter);

unsigned int (*privsize)(const struct nlattr * const nla[]);
int (*init)(const struct nft_set *set,
const struct nlattr * const nla[]);
void (*destroy)(const struct nft_set *set);

struct list_head list;
struct module *owner;
u32 features;
};

extern int nft_register_set(struct nft_set_ops *ops);
extern void nft_unregister_set(struct nft_set_ops *ops);

/**
* struct nft_set - nf_tables set instance
*
* @list: table set list node
* @bindings: list of set bindings
* @name: name of the set
* @ktype: key type (numeric type defined by userspace, not used in the kernel)
* @dtype: data type (verdict or numeric type defined by userspace)
* @ops: set ops
* @flags: set flags
* @klen: key length
* @dlen: data length
* @data: private set data
*/
struct nft_set {
struct list_head list;
struct list_head bindings;
char name[IFNAMSIZ];
u32 ktype;
u32 dtype;
/* runtime data below here */
const struct nft_set_ops *ops ____cacheline_aligned;
u16 flags;
u8 klen;
u8 dlen;
unsigned char data[]
__attribute__((aligned(__alignof__(u64))));
};

static inline void *nft_set_priv(const struct nft_set *set)
{
return (void *)set->data;
}

extern struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
const struct nlattr *nla);

/**
* struct nft_set_binding - nf_tables set binding
*
* @list: set bindings list node
* @chain: chain containing the rule bound to the set
*
* A set binding contains all information necessary for validation
* of new elements added to a bound set.
*/
struct nft_set_binding {
struct list_head list;
const struct nft_chain *chain;
};

extern int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
struct nft_set_binding *binding);
extern void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
struct nft_set_binding *binding);

/**
* struct nft_expr_ops - nf_tables expression operations
*
Expand All @@ -115,7 +247,7 @@ struct nft_expr_ops {
void (*destroy)(const struct nft_expr *expr);
int (*dump)(struct sk_buff *skb,
const struct nft_expr *expr);

const struct nft_data * (*get_verdict)(const struct nft_expr *expr);
struct list_head list;
const char *name;
struct module *owner;
Expand Down Expand Up @@ -298,4 +430,7 @@ extern void nft_unregister_expr(struct nft_expr_ops *);
#define MODULE_ALIAS_NFT_EXPR(name) \
MODULE_ALIAS("nft-expr-" name)

#define MODULE_ALIAS_NFT_SET() \
MODULE_ALIAS("nft-set")

#endif /* _NET_NF_TABLES_H */
Loading

0 comments on commit 20a6934

Please sign in to comment.