aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPatrick McHardy <kaber@trash.net>2013-10-11 06:06:22 -0400
committerPablo Neira Ayuso <pablo@netfilter.org>2013-10-14 11:16:07 -0400
commit20a69341f2d00cd042e81c82289fba8a13c05a25 (patch)
tree95340d318608a95c53d023962808edbcbc8e2291
parent96518518cc417bb0a8c80b9fb736202e28acdf96 (diff)
netfilter: nf_tables: add netlink set API
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>
-rw-r--r--include/net/netfilter/nf_tables.h149
-rw-r--r--include/uapi/linux/netfilter/nf_tables.h191
-rw-r--r--net/netfilter/Kconfig6
-rw-r--r--net/netfilter/Makefile2
-rw-r--r--net/netfilter/nf_tables_api.c1078
-rw-r--r--net/netfilter/nf_tables_core.c2
-rw-r--r--net/netfilter/nft_hash.c329
-rw-r--r--net/netfilter/nft_immediate.c11
-rw-r--r--net/netfilter/nft_lookup.c135
-rw-r--r--net/netfilter/nft_rbtree.c247
-rw-r--r--net/netfilter/nft_set.c381
11 files changed, 1854 insertions, 677 deletions
diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index d26dfa345f49..677dd79380ed 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -6,6 +6,8 @@
6#include <linux/netfilter/nf_tables.h> 6#include <linux/netfilter/nf_tables.h>
7#include <net/netlink.h> 7#include <net/netlink.h>
8 8
9#define NFT_JUMP_STACK_SIZE 16
10
9struct nft_pktinfo { 11struct nft_pktinfo {
10 struct sk_buff *skb; 12 struct sk_buff *skb;
11 const struct net_device *in; 13 const struct net_device *in;
@@ -48,23 +50,22 @@ static inline void nft_data_debug(const struct nft_data *data)
48} 50}
49 51
50/** 52/**
51 * struct nft_ctx - nf_tables rule context 53 * struct nft_ctx - nf_tables rule/set context
52 * 54 *
55 * @skb: netlink skb
56 * @nlh: netlink message header
53 * @afi: address family info 57 * @afi: address family info
54 * @table: the table the chain is contained in 58 * @table: the table the chain is contained in
55 * @chain: the chain the rule is contained in 59 * @chain: the chain the rule is contained in
56 */ 60 */
57struct nft_ctx { 61struct nft_ctx {
62 const struct sk_buff *skb;
63 const struct nlmsghdr *nlh;
58 const struct nft_af_info *afi; 64 const struct nft_af_info *afi;
59 const struct nft_table *table; 65 const struct nft_table *table;
60 const struct nft_chain *chain; 66 const struct nft_chain *chain;
61}; 67};
62 68
63enum nft_data_types {
64 NFT_DATA_VALUE,
65 NFT_DATA_VERDICT,
66};
67
68struct nft_data_desc { 69struct nft_data_desc {
69 enum nft_data_types type; 70 enum nft_data_types type;
70 unsigned int len; 71 unsigned int len;
@@ -83,6 +84,11 @@ static inline enum nft_data_types nft_dreg_to_type(enum nft_registers reg)
83 return reg == NFT_REG_VERDICT ? NFT_DATA_VERDICT : NFT_DATA_VALUE; 84 return reg == NFT_REG_VERDICT ? NFT_DATA_VERDICT : NFT_DATA_VALUE;
84} 85}
85 86
87static inline enum nft_registers nft_type_to_reg(enum nft_data_types type)
88{
89 return type == NFT_DATA_VERDICT ? NFT_REG_VERDICT : NFT_REG_1;
90}
91
86extern int nft_validate_input_register(enum nft_registers reg); 92extern int nft_validate_input_register(enum nft_registers reg);
87extern int nft_validate_output_register(enum nft_registers reg); 93extern int nft_validate_output_register(enum nft_registers reg);
88extern int nft_validate_data_load(const struct nft_ctx *ctx, 94extern int nft_validate_data_load(const struct nft_ctx *ctx,
@@ -91,6 +97,132 @@ extern int nft_validate_data_load(const struct nft_ctx *ctx,
91 enum nft_data_types type); 97 enum nft_data_types type);
92 98
93/** 99/**
100 * struct nft_set_elem - generic representation of set elements
101 *
102 * @cookie: implementation specific element cookie
103 * @key: element key
104 * @data: element data (maps only)
105 * @flags: element flags (end of interval)
106 *
107 * The cookie can be used to store a handle to the element for subsequent
108 * removal.
109 */
110struct nft_set_elem {
111 void *cookie;
112 struct nft_data key;
113 struct nft_data data;
114 u32 flags;
115};
116
117struct nft_set;
118struct nft_set_iter {
119 unsigned int count;
120 unsigned int skip;
121 int err;
122 int (*fn)(const struct nft_ctx *ctx,
123 const struct nft_set *set,
124 const struct nft_set_iter *iter,
125 const struct nft_set_elem *elem);
126};
127
128/**
129 * struct nft_set_ops - nf_tables set operations
130 *
131 * @lookup: look up an element within the set
132 * @insert: insert new element into set
133 * @remove: remove element from set
134 * @walk: iterate over all set elemeennts
135 * @privsize: function to return size of set private data
136 * @init: initialize private data of new set instance
137 * @destroy: destroy private data of set instance
138 * @list: nf_tables_set_ops list node
139 * @owner: module reference
140 * @features: features supported by the implementation
141 */
142struct nft_set_ops {
143 bool (*lookup)(const struct nft_set *set,
144 const struct nft_data *key,
145 struct nft_data *data);
146 int (*get)(const struct nft_set *set,
147 struct nft_set_elem *elem);
148 int (*insert)(const struct nft_set *set,
149 const struct nft_set_elem *elem);
150 void (*remove)(const struct nft_set *set,
151 const struct nft_set_elem *elem);
152 void (*walk)(const struct nft_ctx *ctx,
153 const struct nft_set *set,
154 struct nft_set_iter *iter);
155
156 unsigned int (*privsize)(const struct nlattr * const nla[]);
157 int (*init)(const struct nft_set *set,
158 const struct nlattr * const nla[]);
159 void (*destroy)(const struct nft_set *set);
160
161 struct list_head list;
162 struct module *owner;
163 u32 features;
164};
165
166extern int nft_register_set(struct nft_set_ops *ops);
167extern void nft_unregister_set(struct nft_set_ops *ops);
168
169/**
170 * struct nft_set - nf_tables set instance
171 *
172 * @list: table set list node
173 * @bindings: list of set bindings
174 * @name: name of the set
175 * @ktype: key type (numeric type defined by userspace, not used in the kernel)
176 * @dtype: data type (verdict or numeric type defined by userspace)
177 * @ops: set ops
178 * @flags: set flags
179 * @klen: key length
180 * @dlen: data length
181 * @data: private set data
182 */
183struct nft_set {
184 struct list_head list;
185 struct list_head bindings;
186 char name[IFNAMSIZ];
187 u32 ktype;
188 u32 dtype;
189 /* runtime data below here */
190 const struct nft_set_ops *ops ____cacheline_aligned;
191 u16 flags;
192 u8 klen;
193 u8 dlen;
194 unsigned char data[]
195 __attribute__((aligned(__alignof__(u64))));
196};
197
198static inline void *nft_set_priv(const struct nft_set *set)
199{
200 return (void *)set->data;
201}
202
203extern struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
204 const struct nlattr *nla);
205
206/**
207 * struct nft_set_binding - nf_tables set binding
208 *
209 * @list: set bindings list node
210 * @chain: chain containing the rule bound to the set
211 *
212 * A set binding contains all information necessary for validation
213 * of new elements added to a bound set.
214 */
215struct nft_set_binding {
216 struct list_head list;
217 const struct nft_chain *chain;
218};
219
220extern int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
221 struct nft_set_binding *binding);
222extern void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
223 struct nft_set_binding *binding);
224
225/**
94 * struct nft_expr_ops - nf_tables expression operations 226 * struct nft_expr_ops - nf_tables expression operations
95 * 227 *
96 * @eval: Expression evaluation function 228 * @eval: Expression evaluation function
@@ -115,7 +247,7 @@ struct nft_expr_ops {
115 void (*destroy)(const struct nft_expr *expr); 247 void (*destroy)(const struct nft_expr *expr);
116 int (*dump)(struct sk_buff *skb, 248 int (*dump)(struct sk_buff *skb,
117 const struct nft_expr *expr); 249 const struct nft_expr *expr);
118 250 const struct nft_data * (*get_verdict)(const struct nft_expr *expr);
119 struct list_head list; 251 struct list_head list;
120 const char *name; 252 const char *name;
121 struct module *owner; 253 struct module *owner;
@@ -298,4 +430,7 @@ extern void nft_unregister_expr(struct nft_expr_ops *);
298#define MODULE_ALIAS_NFT_EXPR(name) \ 430#define MODULE_ALIAS_NFT_EXPR(name) \
299 MODULE_ALIAS("nft-expr-" name) 431 MODULE_ALIAS("nft-expr-" name)
300 432
433#define MODULE_ALIAS_NFT_SET() \
434 MODULE_ALIAS("nft-set")
435
301#endif /* _NET_NF_TABLES_H */ 436#endif /* _NET_NF_TABLES_H */
diff --git a/include/uapi/linux/netfilter/nf_tables.h b/include/uapi/linux/netfilter/nf_tables.h
index ec6d84a8ed1e..9e924014efe3 100644
--- a/include/uapi/linux/netfilter/nf_tables.h
+++ b/include/uapi/linux/netfilter/nf_tables.h
@@ -44,6 +44,12 @@ enum nft_verdicts {
44 * @NFT_MSG_NEWRULE: create a new rule (enum nft_rule_attributes) 44 * @NFT_MSG_NEWRULE: create a new rule (enum nft_rule_attributes)
45 * @NFT_MSG_GETRULE: get a rule (enum nft_rule_attributes) 45 * @NFT_MSG_GETRULE: get a rule (enum nft_rule_attributes)
46 * @NFT_MSG_DELRULE: delete a rule (enum nft_rule_attributes) 46 * @NFT_MSG_DELRULE: delete a rule (enum nft_rule_attributes)
47 * @NFT_MSG_NEWSET: create a new set (enum nft_set_attributes)
48 * @NFT_MSG_GETSET: get a set (enum nft_set_attributes)
49 * @NFT_MSG_DELSET: delete a set (enum nft_set_attributes)
50 * @NFT_MSG_NEWSETELEM: create a new set element (enum nft_set_elem_attributes)
51 * @NFT_MSG_GETSETELEM: get a set element (enum nft_set_elem_attributes)
52 * @NFT_MSG_DELSETELEM: delete a set element (enum nft_set_elem_attributes)
47 */ 53 */
48enum nf_tables_msg_types { 54enum nf_tables_msg_types {
49 NFT_MSG_NEWTABLE, 55 NFT_MSG_NEWTABLE,
@@ -55,9 +61,20 @@ enum nf_tables_msg_types {
55 NFT_MSG_NEWRULE, 61 NFT_MSG_NEWRULE,
56 NFT_MSG_GETRULE, 62 NFT_MSG_GETRULE,
57 NFT_MSG_DELRULE, 63 NFT_MSG_DELRULE,
64 NFT_MSG_NEWSET,
65 NFT_MSG_GETSET,
66 NFT_MSG_DELSET,
67 NFT_MSG_NEWSETELEM,
68 NFT_MSG_GETSETELEM,
69 NFT_MSG_DELSETELEM,
58 NFT_MSG_MAX, 70 NFT_MSG_MAX,
59}; 71};
60 72
73/**
74 * enum nft_list_attributes - nf_tables generic list netlink attributes
75 *
76 * @NFTA_LIST_ELEM: list element (NLA_NESTED)
77 */
61enum nft_list_attributes { 78enum nft_list_attributes {
62 NFTA_LIST_UNPEC, 79 NFTA_LIST_UNPEC,
63 NFTA_LIST_ELEM, 80 NFTA_LIST_ELEM,
@@ -127,6 +144,113 @@ enum nft_rule_attributes {
127}; 144};
128#define NFTA_RULE_MAX (__NFTA_RULE_MAX - 1) 145#define NFTA_RULE_MAX (__NFTA_RULE_MAX - 1)
129 146
147/**
148 * enum nft_set_flags - nf_tables set flags
149 *
150 * @NFT_SET_ANONYMOUS: name allocation, automatic cleanup on unlink
151 * @NFT_SET_CONSTANT: set contents may not change while bound
152 * @NFT_SET_INTERVAL: set contains intervals
153 * @NFT_SET_MAP: set is used as a dictionary
154 */
155enum nft_set_flags {
156 NFT_SET_ANONYMOUS = 0x1,
157 NFT_SET_CONSTANT = 0x2,
158 NFT_SET_INTERVAL = 0x4,
159 NFT_SET_MAP = 0x8,
160};
161
162/**
163 * enum nft_set_attributes - nf_tables set netlink attributes
164 *
165 * @NFTA_SET_TABLE: table name (NLA_STRING)
166 * @NFTA_SET_NAME: set name (NLA_STRING)
167 * @NFTA_SET_FLAGS: bitmask of enum nft_set_flags (NLA_U32)
168 * @NFTA_SET_KEY_TYPE: key data type, informational purpose only (NLA_U32)
169 * @NFTA_SET_KEY_LEN: key data length (NLA_U32)
170 * @NFTA_SET_DATA_TYPE: mapping data type (NLA_U32)
171 * @NFTA_SET_DATA_LEN: mapping data length (NLA_U32)
172 */
173enum nft_set_attributes {
174 NFTA_SET_UNSPEC,
175 NFTA_SET_TABLE,
176 NFTA_SET_NAME,
177 NFTA_SET_FLAGS,
178 NFTA_SET_KEY_TYPE,
179 NFTA_SET_KEY_LEN,
180 NFTA_SET_DATA_TYPE,
181 NFTA_SET_DATA_LEN,
182 __NFTA_SET_MAX
183};
184#define NFTA_SET_MAX (__NFTA_SET_MAX - 1)
185
186/**
187 * enum nft_set_elem_flags - nf_tables set element flags
188 *
189 * @NFT_SET_ELEM_INTERVAL_END: element ends the previous interval
190 */
191enum nft_set_elem_flags {
192 NFT_SET_ELEM_INTERVAL_END = 0x1,
193};
194
195/**
196 * enum nft_set_elem_attributes - nf_tables set element netlink attributes
197 *
198 * @NFTA_SET_ELEM_KEY: key value (NLA_NESTED: nft_data)
199 * @NFTA_SET_ELEM_DATA: data value of mapping (NLA_NESTED: nft_data_attributes)
200 * @NFTA_SET_ELEM_FLAGS: bitmask of nft_set_elem_flags (NLA_U32)
201 */
202enum nft_set_elem_attributes {
203 NFTA_SET_ELEM_UNSPEC,
204 NFTA_SET_ELEM_KEY,
205 NFTA_SET_ELEM_DATA,
206 NFTA_SET_ELEM_FLAGS,
207 __NFTA_SET_ELEM_MAX
208};
209#define NFTA_SET_ELEM_MAX (__NFTA_SET_ELEM_MAX - 1)
210
211/**
212 * enum nft_set_elem_list_attributes - nf_tables set element list netlink attributes
213 *
214 * @NFTA_SET_ELEM_LIST_TABLE: table of the set to be changed (NLA_STRING)
215 * @NFTA_SET_ELEM_LIST_SET: name of the set to be changed (NLA_STRING)
216 * @NFTA_SET_ELEM_LIST_ELEMENTS: list of set elements (NLA_NESTED: nft_set_elem_attributes)
217 */
218enum nft_set_elem_list_attributes {
219 NFTA_SET_ELEM_LIST_UNSPEC,
220 NFTA_SET_ELEM_LIST_TABLE,
221 NFTA_SET_ELEM_LIST_SET,
222 NFTA_SET_ELEM_LIST_ELEMENTS,
223 __NFTA_SET_ELEM_LIST_MAX
224};
225#define NFTA_SET_ELEM_LIST_MAX (__NFTA_SET_ELEM_LIST_MAX - 1)
226
227/**
228 * enum nft_data_types - nf_tables data types
229 *
230 * @NFT_DATA_VALUE: generic data
231 * @NFT_DATA_VERDICT: netfilter verdict
232 *
233 * The type of data is usually determined by the kernel directly and is not
234 * explicitly specified by userspace. The only difference are sets, where
235 * userspace specifies the key and mapping data types.
236 *
237 * The values 0xffffff00-0xffffffff are reserved for internally used types.
238 * The remaining range can be freely used by userspace to encode types, all
239 * values are equivalent to NFT_DATA_VALUE.
240 */
241enum nft_data_types {
242 NFT_DATA_VALUE,
243 NFT_DATA_VERDICT = 0xffffff00U,
244};
245
246#define NFT_DATA_RESERVED_MASK 0xffffff00U
247
248/**
249 * enum nft_data_attributes - nf_tables data netlink attributes
250 *
251 * @NFTA_DATA_VALUE: generic data (NLA_BINARY)
252 * @NFTA_DATA_VERDICT: nf_tables verdict (NLA_NESTED: nft_verdict_attributes)
253 */
130enum nft_data_attributes { 254enum nft_data_attributes {
131 NFTA_DATA_UNSPEC, 255 NFTA_DATA_UNSPEC,
132 NFTA_DATA_VALUE, 256 NFTA_DATA_VALUE,
@@ -275,58 +399,21 @@ enum nft_cmp_attributes {
275}; 399};
276#define NFTA_CMP_MAX (__NFTA_CMP_MAX - 1) 400#define NFTA_CMP_MAX (__NFTA_CMP_MAX - 1)
277 401
278enum nft_set_elem_flags { 402/**
279 NFT_SE_INTERVAL_END = 0x1, 403 * enum nft_lookup_attributes - nf_tables set lookup expression netlink attributes
280}; 404 *
281 405 * @NFTA_LOOKUP_SET: name of the set where to look for (NLA_STRING)
282enum nft_set_elem_attributes { 406 * @NFTA_LOOKUP_SREG: source register of the data to look for (NLA_U32: nft_registers)
283 NFTA_SE_UNSPEC, 407 * @NFTA_LOOKUP_DREG: destination register (NLA_U32: nft_registers)
284 NFTA_SE_KEY, 408 */
285 NFTA_SE_DATA, 409enum nft_lookup_attributes {
286 NFTA_SE_FLAGS, 410 NFTA_LOOKUP_UNSPEC,
287 __NFTA_SE_MAX 411 NFTA_LOOKUP_SET,
288}; 412 NFTA_LOOKUP_SREG,
289#define NFTA_SE_MAX (__NFTA_SE_MAX - 1) 413 NFTA_LOOKUP_DREG,
290 414 __NFTA_LOOKUP_MAX
291enum nft_set_flags { 415};
292 NFT_SET_INTERVAL = 0x1, 416#define NFTA_LOOKUP_MAX (__NFTA_LOOKUP_MAX - 1)
293 NFT_SET_MAP = 0x2,
294};
295
296enum nft_set_attributes {
297 NFTA_SET_UNSPEC,
298 NFTA_SET_FLAGS,
299 NFTA_SET_SREG,
300 NFTA_SET_DREG,
301 NFTA_SET_KLEN,
302 NFTA_SET_DLEN,
303 NFTA_SET_ELEMENTS,
304 __NFTA_SET_MAX
305};
306#define NFTA_SET_MAX (__NFTA_SET_MAX - 1)
307
308enum nft_hash_flags {
309 NFT_HASH_MAP = 0x1,
310};
311
312enum nft_hash_elem_attributes {
313 NFTA_HE_UNSPEC,
314 NFTA_HE_KEY,
315 NFTA_HE_DATA,
316 __NFTA_HE_MAX
317};
318#define NFTA_HE_MAX (__NFTA_HE_MAX - 1)
319
320enum nft_hash_attributes {
321 NFTA_HASH_UNSPEC,
322 NFTA_HASH_FLAGS,
323 NFTA_HASH_SREG,
324 NFTA_HASH_DREG,
325 NFTA_HASH_KLEN,
326 NFTA_HASH_ELEMENTS,
327 __NFTA_HASH_MAX
328};
329#define NFTA_HASH_MAX (__NFTA_HASH_MAX - 1)
330 417
331/** 418/**
332 * enum nft_payload_bases - nf_tables payload expression offset bases 419 * enum nft_payload_bases - nf_tables payload expression offset bases
diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig
index c271e1af93b5..aa184a46bbf3 100644
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -430,13 +430,13 @@ config NFT_CT
430 depends on NF_CONNTRACK 430 depends on NF_CONNTRACK
431 tristate "Netfilter nf_tables conntrack module" 431 tristate "Netfilter nf_tables conntrack module"
432 432
433config NFT_SET 433config NFT_RBTREE
434 depends on NF_TABLES 434 depends on NF_TABLES
435 tristate "Netfilter nf_tables set module" 435 tristate "Netfilter nf_tables rbtree set module"
436 436
437config NFT_HASH 437config NFT_HASH
438 depends on NF_TABLES 438 depends on NF_TABLES
439 tristate "Netfilter nf_tables hash module" 439 tristate "Netfilter nf_tables hash set module"
440 440
441config NFT_COUNTER 441config NFT_COUNTER
442 depends on NF_TABLES 442 depends on NF_TABLES
diff --git a/net/netfilter/Makefile b/net/netfilter/Makefile
index 1ca3f3932826..b6b78754e4cc 100644
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -75,7 +75,7 @@ obj-$(CONFIG_NFT_META) += nft_meta.o
75obj-$(CONFIG_NFT_CT) += nft_ct.o 75obj-$(CONFIG_NFT_CT) += nft_ct.o
76obj-$(CONFIG_NFT_LIMIT) += nft_limit.o 76obj-$(CONFIG_NFT_LIMIT) += nft_limit.o
77#nf_tables-objs += nft_meta_target.o 77#nf_tables-objs += nft_meta_target.o
78obj-$(CONFIG_NFT_SET) += nft_set.o 78obj-$(CONFIG_NFT_RBTREE) += nft_rbtree.o
79obj-$(CONFIG_NFT_HASH) += nft_hash.o 79obj-$(CONFIG_NFT_HASH) += nft_hash.o
80obj-$(CONFIG_NFT_COUNTER) += nft_counter.o 80obj-$(CONFIG_NFT_COUNTER) += nft_counter.o
81obj-$(CONFIG_NFT_LOG) += nft_log.o 81obj-$(CONFIG_NFT_LOG) += nft_log.o
diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 7d59c89c6c75..5092c817c222 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2007, 2008 Patrick McHardy <kaber@trash.net> 2 * Copyright (c) 2007-2009 Patrick McHardy <kaber@trash.net>
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -315,6 +315,7 @@ static int nf_tables_newtable(struct sock *nlsk, struct sk_buff *skb,
315 315
316 nla_strlcpy(table->name, name, nla_len(name)); 316 nla_strlcpy(table->name, name, nla_len(name));
317 INIT_LIST_HEAD(&table->chains); 317 INIT_LIST_HEAD(&table->chains);
318 INIT_LIST_HEAD(&table->sets);
318 319
319 list_add_tail(&table->list, &afi->tables); 320 list_add_tail(&table->list, &afi->tables);
320 nf_tables_table_notify(skb, nlh, table, NFT_MSG_NEWTABLE, family); 321 nf_tables_table_notify(skb, nlh, table, NFT_MSG_NEWTABLE, family);
@@ -409,6 +410,7 @@ again:
409 } 410 }
410 411
411 table->flags |= NFT_TABLE_BUILTIN; 412 table->flags |= NFT_TABLE_BUILTIN;
413 INIT_LIST_HEAD(&table->sets);
412 list_add_tail(&table->list, &afi->tables); 414 list_add_tail(&table->list, &afi->tables);
413 nf_tables_table_notify(NULL, NULL, table, NFT_MSG_NEWTABLE, family); 415 nf_tables_table_notify(NULL, NULL, table, NFT_MSG_NEWTABLE, family);
414 list_for_each_entry(chain, &table->chains, list) 416 list_for_each_entry(chain, &table->chains, list)
@@ -820,10 +822,14 @@ static int nf_tables_delchain(struct sock *nlsk, struct sk_buff *skb,
820} 822}
821 823
822static void nft_ctx_init(struct nft_ctx *ctx, 824static void nft_ctx_init(struct nft_ctx *ctx,
825 const struct sk_buff *skb,
826 const struct nlmsghdr *nlh,
823 const struct nft_af_info *afi, 827 const struct nft_af_info *afi,
824 const struct nft_table *table, 828 const struct nft_table *table,
825 const struct nft_chain *chain) 829 const struct nft_chain *chain)
826{ 830{
831 ctx->skb = skb;
832 ctx->nlh = nlh;
827 ctx->afi = afi; 833 ctx->afi = afi;
828 ctx->table = table; 834 ctx->table = table;
829 ctx->chain = chain; 835 ctx->chain = chain;
@@ -1301,7 +1307,7 @@ static int nf_tables_newrule(struct sock *nlsk, struct sk_buff *skb,
1301 rule->handle = handle; 1307 rule->handle = handle;
1302 rule->dlen = size; 1308 rule->dlen = size;
1303 1309
1304 nft_ctx_init(&ctx, afi, table, chain); 1310 nft_ctx_init(&ctx, skb, nlh, afi, table, chain);
1305 expr = nft_expr_first(rule); 1311 expr = nft_expr_first(rule);
1306 for (i = 0; i < n; i++) { 1312 for (i = 0; i < n; i++) {
1307 err = nf_tables_newexpr(&ctx, &info[i], expr); 1313 err = nf_tables_newexpr(&ctx, &info[i], expr);
@@ -1392,6 +1398,939 @@ static int nf_tables_delrule(struct sock *nlsk, struct sk_buff *skb,
1392 return 0; 1398 return 0;
1393} 1399}
1394 1400
1401/*
1402 * Sets
1403 */
1404
1405static LIST_HEAD(nf_tables_set_ops);
1406
1407int nft_register_set(struct nft_set_ops *ops)
1408{
1409 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1410 list_add_tail(&ops->list, &nf_tables_set_ops);
1411 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1412 return 0;
1413}
1414EXPORT_SYMBOL_GPL(nft_register_set);
1415
1416void nft_unregister_set(struct nft_set_ops *ops)
1417{
1418 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1419 list_del(&ops->list);
1420 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1421}
1422EXPORT_SYMBOL_GPL(nft_unregister_set);
1423
1424static const struct nft_set_ops *nft_select_set_ops(const struct nlattr * const nla[])
1425{
1426 const struct nft_set_ops *ops;
1427 u32 features;
1428
1429#ifdef CONFIG_MODULES
1430 if (list_empty(&nf_tables_set_ops)) {
1431 nfnl_unlock(NFNL_SUBSYS_NFTABLES);
1432 request_module("nft-set");
1433 nfnl_lock(NFNL_SUBSYS_NFTABLES);
1434 if (!list_empty(&nf_tables_set_ops))
1435 return ERR_PTR(-EAGAIN);
1436 }
1437#endif
1438 features = 0;
1439 if (nla[NFTA_SET_FLAGS] != NULL) {
1440 features = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
1441 features &= NFT_SET_INTERVAL | NFT_SET_MAP;
1442 }
1443
1444 // FIXME: implement selection properly
1445 list_for_each_entry(ops, &nf_tables_set_ops, list) {
1446 if ((ops->features & features) != features)
1447 continue;
1448 if (!try_module_get(ops->owner))
1449 continue;
1450 return ops;
1451 }
1452
1453 return ERR_PTR(-EOPNOTSUPP);
1454}
1455
1456static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = {
1457 [NFTA_SET_TABLE] = { .type = NLA_STRING },
1458 [NFTA_SET_NAME] = { .type = NLA_STRING },
1459 [NFTA_SET_FLAGS] = { .type = NLA_U32 },
1460 [NFTA_SET_KEY_TYPE] = { .type = NLA_U32 },
1461 [NFTA_SET_KEY_LEN] = { .type = NLA_U32 },
1462 [NFTA_SET_DATA_TYPE] = { .type = NLA_U32 },
1463 [NFTA_SET_DATA_LEN] = { .type = NLA_U32 },
1464};
1465
1466static int nft_ctx_init_from_setattr(struct nft_ctx *ctx,
1467 const struct sk_buff *skb,
1468 const struct nlmsghdr *nlh,
1469 const struct nlattr * const nla[])
1470{
1471 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1472 const struct nft_af_info *afi;
1473 const struct nft_table *table = NULL;
1474
1475 afi = nf_tables_afinfo_lookup(nfmsg->nfgen_family, false);
1476 if (IS_ERR(afi))
1477 return PTR_ERR(afi);
1478
1479 if (nla[NFTA_SET_TABLE] != NULL) {
1480 table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE], false);
1481 if (IS_ERR(table))
1482 return PTR_ERR(table);
1483 }
1484
1485 nft_ctx_init(ctx, skb, nlh, afi, table, NULL);
1486 return 0;
1487}
1488
1489struct nft_set *nf_tables_set_lookup(const struct nft_table *table,
1490 const struct nlattr *nla)
1491{
1492 struct nft_set *set;
1493
1494 if (nla == NULL)
1495 return ERR_PTR(-EINVAL);
1496
1497 list_for_each_entry(set, &table->sets, list) {
1498 if (!nla_strcmp(nla, set->name))
1499 return set;
1500 }
1501 return ERR_PTR(-ENOENT);
1502}
1503
1504static int nf_tables_set_alloc_name(struct nft_ctx *ctx, struct nft_set *set,
1505 const char *name)
1506{
1507 const struct nft_set *i;
1508 const char *p;
1509 unsigned long *inuse;
1510 unsigned int n = 0;
1511
1512 p = strnchr(name, IFNAMSIZ, '%');
1513 if (p != NULL) {
1514 if (p[1] != 'd' || strchr(p + 2, '%'))
1515 return -EINVAL;
1516
1517 inuse = (unsigned long *)get_zeroed_page(GFP_KERNEL);
1518 if (inuse == NULL)
1519 return -ENOMEM;
1520
1521 list_for_each_entry(i, &ctx->table->sets, list) {
1522 if (!sscanf(i->name, name, &n))
1523 continue;
1524 if (n < 0 || n > BITS_PER_LONG * PAGE_SIZE)
1525 continue;
1526 set_bit(n, inuse);
1527 }
1528
1529 n = find_first_zero_bit(inuse, BITS_PER_LONG * PAGE_SIZE);
1530 free_page((unsigned long)inuse);
1531 }
1532
1533 snprintf(set->name, sizeof(set->name), name, n);
1534 list_for_each_entry(i, &ctx->table->sets, list) {
1535 if (!strcmp(set->name, i->name))
1536 return -ENFILE;
1537 }
1538 return 0;
1539}
1540
1541static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
1542 const struct nft_set *set, u16 event, u16 flags)
1543{
1544 struct nfgenmsg *nfmsg;
1545 struct nlmsghdr *nlh;
1546 u32 portid = NETLINK_CB(ctx->skb).portid;
1547 u32 seq = ctx->nlh->nlmsg_seq;
1548
1549 event |= NFNL_SUBSYS_NFTABLES << 8;
1550 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
1551 flags);
1552 if (nlh == NULL)
1553 goto nla_put_failure;
1554
1555 nfmsg = nlmsg_data(nlh);
1556 nfmsg->nfgen_family = ctx->afi->family;
1557 nfmsg->version = NFNETLINK_V0;
1558 nfmsg->res_id = 0;
1559
1560 if (nla_put_string(skb, NFTA_SET_TABLE, ctx->table->name))
1561 goto nla_put_failure;
1562 if (nla_put_string(skb, NFTA_SET_NAME, set->name))
1563 goto nla_put_failure;
1564 if (set->flags != 0)
1565 if (nla_put_be32(skb, NFTA_SET_FLAGS, htonl(set->flags)))
1566 goto nla_put_failure;
1567
1568 if (nla_put_be32(skb, NFTA_SET_KEY_TYPE, htonl(set->ktype)))
1569 goto nla_put_failure;
1570 if (nla_put_be32(skb, NFTA_SET_KEY_LEN, htonl(set->klen)))
1571 goto nla_put_failure;
1572 if (set->flags & NFT_SET_MAP) {
1573 if (nla_put_be32(skb, NFTA_SET_DATA_TYPE, htonl(set->dtype)))
1574 goto nla_put_failure;
1575 if (nla_put_be32(skb, NFTA_SET_DATA_LEN, htonl(set->dlen)))
1576 goto nla_put_failure;
1577 }
1578
1579 return nlmsg_end(skb, nlh);
1580
1581nla_put_failure:
1582 nlmsg_trim(skb, nlh);
1583 return -1;
1584}
1585
1586static int nf_tables_set_notify(const struct nft_ctx *ctx,
1587 const struct nft_set *set,
1588 int event)
1589{
1590 struct sk_buff *skb;
1591 u32 portid = NETLINK_CB(ctx->skb).portid;
1592 struct net *net = sock_net(ctx->skb->sk);
1593 bool report;
1594 int err;
1595
1596 report = nlmsg_report(ctx->nlh);
1597 if (!report && !nfnetlink_has_listeners(net, NFNLGRP_NFTABLES))
1598 return 0;
1599
1600 err = -ENOBUFS;
1601 skb = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
1602 if (skb == NULL)
1603 goto err;
1604
1605 err = nf_tables_fill_set(skb, ctx, set, event, 0);
1606 if (err < 0) {
1607 kfree_skb(skb);
1608 goto err;
1609 }
1610
1611 err = nfnetlink_send(skb, net, portid, NFNLGRP_NFTABLES, report,
1612 GFP_KERNEL);
1613err:
1614 if (err < 0)
1615 nfnetlink_set_err(net, portid, NFNLGRP_NFTABLES, err);
1616 return err;
1617}
1618
1619static int nf_tables_dump_sets_table(struct nft_ctx *ctx, struct sk_buff *skb,
1620 struct netlink_callback *cb)
1621{
1622 const struct nft_set *set;
1623 unsigned int idx = 0, s_idx = cb->args[0];
1624
1625 if (cb->args[1])
1626 return skb->len;
1627
1628 list_for_each_entry(set, &ctx->table->sets, list) {
1629 if (idx < s_idx)
1630 goto cont;
1631 if (nf_tables_fill_set(skb, ctx, set, NFT_MSG_NEWSET,
1632 NLM_F_MULTI) < 0) {
1633 cb->args[0] = idx;
1634 goto done;
1635 }
1636cont:
1637 idx++;
1638 }
1639 cb->args[1] = 1;
1640done:
1641 return skb->len;
1642}
1643
1644static int nf_tables_dump_sets_all(struct nft_ctx *ctx, struct sk_buff *skb,
1645 struct netlink_callback *cb)
1646{
1647 const struct nft_set *set;
1648 unsigned int idx = 0, s_idx = cb->args[0];
1649 struct nft_table *table, *cur_table = (struct nft_table *)cb->args[2];
1650
1651 if (cb->args[1])
1652 return skb->len;
1653
1654 list_for_each_entry(table, &ctx->afi->tables, list) {
1655 if (cur_table && cur_table != table)
1656 continue;
1657
1658 ctx->table = table;
1659 list_for_each_entry(set, &ctx->table->sets, list) {
1660 if (idx < s_idx)
1661 goto cont;
1662 if (nf_tables_fill_set(skb, ctx, set, NFT_MSG_NEWSET,
1663 NLM_F_MULTI) < 0) {
1664 cb->args[0] = idx;
1665 cb->args[2] = (unsigned long) table;
1666 goto done;
1667 }
1668cont:
1669 idx++;
1670 }
1671 }
1672 cb->args[1] = 1;
1673done:
1674 return skb->len;
1675}
1676
1677static int nf_tables_dump_sets(struct sk_buff *skb, struct netlink_callback *cb)
1678{
1679 const struct nfgenmsg *nfmsg = nlmsg_data(cb->nlh);
1680 struct nlattr *nla[NFTA_SET_MAX + 1];
1681 struct nft_ctx ctx;
1682 int err, ret;
1683
1684 err = nlmsg_parse(cb->nlh, sizeof(*nfmsg), nla, NFTA_SET_MAX,
1685 nft_set_policy);
1686 if (err < 0)
1687 return err;
1688
1689 err = nft_ctx_init_from_setattr(&ctx, cb->skb, cb->nlh, (void *)nla);
1690 if (err < 0)
1691 return err;
1692
1693 if (ctx.table == NULL)
1694 ret = nf_tables_dump_sets_all(&ctx, skb, cb);
1695 else
1696 ret = nf_tables_dump_sets_table(&ctx, skb, cb);
1697
1698 return ret;
1699}
1700
1701static int nf_tables_getset(struct sock *nlsk, struct sk_buff *skb,
1702 const struct nlmsghdr *nlh,
1703 const struct nlattr * const nla[])
1704{
1705 const struct nft_set *set;
1706 struct nft_ctx ctx;
1707 struct sk_buff *skb2;
1708 int err;
1709
1710 /* Verify existance before starting dump */
1711 err = nft_ctx_init_from_setattr(&ctx, skb, nlh, nla);
1712 if (err < 0)
1713 return err;
1714
1715 if (nlh->nlmsg_flags & NLM_F_DUMP) {
1716 struct netlink_dump_control c = {
1717 .dump = nf_tables_dump_sets,
1718 };
1719 return netlink_dump_start(nlsk, skb, nlh, &c);
1720 }
1721
1722 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
1723 if (IS_ERR(set))
1724 return PTR_ERR(set);
1725
1726 skb2 = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
1727 if (skb2 == NULL)
1728 return -ENOMEM;
1729
1730 err = nf_tables_fill_set(skb2, &ctx, set, NFT_MSG_NEWSET, 0);
1731 if (err < 0)
1732 goto err;
1733
1734 return nlmsg_unicast(nlsk, skb2, NETLINK_CB(skb).portid);
1735
1736err:
1737 kfree_skb(skb2);
1738 return err;
1739}
1740
1741static int nf_tables_newset(struct sock *nlsk, struct sk_buff *skb,
1742 const struct nlmsghdr *nlh,
1743 const struct nlattr * const nla[])
1744{
1745 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1746 const struct nft_set_ops *ops;
1747 const struct nft_af_info *afi;
1748 struct nft_table *table;
1749 struct nft_set *set;
1750 struct nft_ctx ctx;
1751 char name[IFNAMSIZ];
1752 unsigned int size;
1753 bool create;
1754 u32 ktype, klen, dlen, dtype, flags;
1755 int err;
1756
1757 if (nla[NFTA_SET_TABLE] == NULL ||
1758 nla[NFTA_SET_NAME] == NULL ||
1759 nla[NFTA_SET_KEY_LEN] == NULL)
1760 return -EINVAL;
1761
1762 ktype = NFT_DATA_VALUE;
1763 if (nla[NFTA_SET_KEY_TYPE] != NULL) {
1764 ktype = ntohl(nla_get_be32(nla[NFTA_SET_KEY_TYPE]));
1765 if ((ktype & NFT_DATA_RESERVED_MASK) == NFT_DATA_RESERVED_MASK)
1766 return -EINVAL;
1767 }
1768
1769 klen = ntohl(nla_get_be32(nla[NFTA_SET_KEY_LEN]));
1770 if (klen == 0 || klen > FIELD_SIZEOF(struct nft_data, data))
1771 return -EINVAL;
1772
1773 flags = 0;
1774 if (nla[NFTA_SET_FLAGS] != NULL) {
1775 flags = ntohl(nla_get_be32(nla[NFTA_SET_FLAGS]));
1776 if (flags & ~(NFT_SET_ANONYMOUS | NFT_SET_CONSTANT |
1777 NFT_SET_INTERVAL | NFT_SET_MAP))
1778 return -EINVAL;
1779 }
1780
1781 dtype = 0;
1782 dlen = 0;
1783 if (nla[NFTA_SET_DATA_TYPE] != NULL) {
1784 if (!(flags & NFT_SET_MAP))
1785 return -EINVAL;
1786
1787 dtype = ntohl(nla_get_be32(nla[NFTA_SET_DATA_TYPE]));
1788 if ((dtype & NFT_DATA_RESERVED_MASK) == NFT_DATA_RESERVED_MASK &&
1789 dtype != NFT_DATA_VERDICT)
1790 return -EINVAL;
1791
1792 if (dtype != NFT_DATA_VERDICT) {
1793 if (nla[NFTA_SET_DATA_LEN] == NULL)
1794 return -EINVAL;
1795 dlen = ntohl(nla_get_be32(nla[NFTA_SET_DATA_LEN]));
1796 if (dlen == 0 ||
1797 dlen > FIELD_SIZEOF(struct nft_data, data))
1798 return -EINVAL;
1799 } else
1800 dlen = sizeof(struct nft_data);
1801 } else if (flags & NFT_SET_MAP)
1802 return -EINVAL;
1803
1804 create = nlh->nlmsg_flags & NLM_F_CREATE ? true : false;
1805
1806 afi = nf_tables_afinfo_lookup(nfmsg->nfgen_family, create);
1807 if (IS_ERR(afi))
1808 return PTR_ERR(afi);
1809
1810 table = nf_tables_table_lookup(afi, nla[NFTA_SET_TABLE], create);
1811 if (IS_ERR(table))
1812 return PTR_ERR(table);
1813
1814 nft_ctx_init(&ctx, skb, nlh, afi, table, NULL);
1815
1816 set = nf_tables_set_lookup(table, nla[NFTA_SET_NAME]);
1817 if (IS_ERR(set)) {
1818 if (PTR_ERR(set) != -ENOENT)
1819 return PTR_ERR(set);
1820 set = NULL;
1821 }
1822
1823 if (set != NULL) {
1824 if (nlh->nlmsg_flags & NLM_F_EXCL)
1825 return -EEXIST;
1826 if (nlh->nlmsg_flags & NLM_F_REPLACE)
1827 return -EOPNOTSUPP;
1828 return 0;
1829 }
1830
1831 if (!(nlh->nlmsg_flags & NLM_F_CREATE))
1832 return -ENOENT;
1833
1834 ops = nft_select_set_ops(nla);
1835 if (IS_ERR(ops))
1836 return PTR_ERR(ops);
1837
1838 size = 0;
1839 if (ops->privsize != NULL)
1840 size = ops->privsize(nla);
1841
1842 err = -ENOMEM;
1843 set = kzalloc(sizeof(*set) + size, GFP_KERNEL);
1844 if (set == NULL)
1845 goto err1;
1846
1847 nla_strlcpy(name, nla[NFTA_SET_NAME], sizeof(set->name));
1848 err = nf_tables_set_alloc_name(&ctx, set, name);
1849 if (err < 0)
1850 goto err2;
1851
1852 INIT_LIST_HEAD(&set->bindings);
1853 set->ops = ops;
1854 set->ktype = ktype;
1855 set->klen = klen;
1856 set->dtype = dtype;
1857 set->dlen = dlen;
1858 set->flags = flags;
1859
1860 err = ops->init(set, nla);
1861 if (err < 0)
1862 goto err2;
1863
1864 list_add_tail(&set->list, &table->sets);
1865 nf_tables_set_notify(&ctx, set, NFT_MSG_NEWSET);
1866 return 0;
1867
1868err2:
1869 kfree(set);
1870err1:
1871 module_put(ops->owner);
1872 return err;
1873}
1874
1875static void nf_tables_set_destroy(const struct nft_ctx *ctx, struct nft_set *set)
1876{
1877 list_del(&set->list);
1878 if (!(set->flags & NFT_SET_ANONYMOUS))
1879 nf_tables_set_notify(ctx, set, NFT_MSG_DELSET);
1880
1881 set->ops->destroy(set);
1882 module_put(set->ops->owner);
1883 kfree(set);
1884}
1885
1886static int nf_tables_delset(struct sock *nlsk, struct sk_buff *skb,
1887 const struct nlmsghdr *nlh,
1888 const struct nlattr * const nla[])
1889{
1890 struct nft_set *set;
1891 struct nft_ctx ctx;
1892 int err;
1893
1894 if (nla[NFTA_SET_TABLE] == NULL)
1895 return -EINVAL;
1896
1897 err = nft_ctx_init_from_setattr(&ctx, skb, nlh, nla);
1898 if (err < 0)
1899 return err;
1900
1901 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_NAME]);
1902 if (IS_ERR(set))
1903 return PTR_ERR(set);
1904 if (!list_empty(&set->bindings))
1905 return -EBUSY;
1906
1907 nf_tables_set_destroy(&ctx, set);
1908 return 0;
1909}
1910
1911static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx,
1912 const struct nft_set *set,
1913 const struct nft_set_iter *iter,
1914 const struct nft_set_elem *elem)
1915{
1916 enum nft_registers dreg;
1917
1918 dreg = nft_type_to_reg(set->dtype);
1919 return nft_validate_data_load(ctx, dreg, &elem->data, set->dtype);
1920}
1921
1922int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
1923 struct nft_set_binding *binding)
1924{
1925 struct nft_set_binding *i;
1926 struct nft_set_iter iter;
1927
1928 if (!list_empty(&set->bindings) && set->flags & NFT_SET_ANONYMOUS)
1929 return -EBUSY;
1930
1931 if (set->flags & NFT_SET_MAP) {
1932 /* If the set is already bound to the same chain all
1933 * jumps are already validated for that chain.
1934 */
1935 list_for_each_entry(i, &set->bindings, list) {
1936 if (i->chain == binding->chain)
1937 goto bind;
1938 }
1939
1940 iter.skip = 0;
1941 iter.count = 0;
1942 iter.err = 0;
1943 iter.fn = nf_tables_bind_check_setelem;
1944
1945 set->ops->walk(ctx, set, &iter);
1946 if (iter.err < 0) {
1947 /* Destroy anonymous sets if binding fails */
1948 if (set->flags & NFT_SET_ANONYMOUS)
1949 nf_tables_set_destroy(ctx, set);
1950
1951 return iter.err;
1952 }
1953 }
1954bind:
1955 binding->chain = ctx->chain;
1956 list_add_tail(&binding->list, &set->bindings);
1957 return 0;
1958}
1959
1960void nf_tables_unbind_set(const struct nft_ctx *ctx, struct nft_set *set,
1961 struct nft_set_binding *binding)
1962{
1963 list_del(&binding->list);
1964
1965 if (list_empty(&set->bindings) && set->flags & NFT_SET_ANONYMOUS)
1966 nf_tables_set_destroy(ctx, set);
1967}
1968
1969/*
1970 * Set elements
1971 */
1972
1973static const struct nla_policy nft_set_elem_policy[NFTA_SET_ELEM_MAX + 1] = {
1974 [NFTA_SET_ELEM_KEY] = { .type = NLA_NESTED },
1975 [NFTA_SET_ELEM_DATA] = { .type = NLA_NESTED },
1976 [NFTA_SET_ELEM_FLAGS] = { .type = NLA_U32 },
1977};
1978
1979static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX + 1] = {
1980 [NFTA_SET_ELEM_LIST_TABLE] = { .type = NLA_STRING },
1981 [NFTA_SET_ELEM_LIST_SET] = { .type = NLA_STRING },
1982 [NFTA_SET_ELEM_LIST_ELEMENTS] = { .type = NLA_NESTED },
1983};
1984
1985static int nft_ctx_init_from_elemattr(struct nft_ctx *ctx,
1986 const struct sk_buff *skb,
1987 const struct nlmsghdr *nlh,
1988 const struct nlattr * const nla[])
1989{
1990 const struct nfgenmsg *nfmsg = nlmsg_data(nlh);
1991 const struct nft_af_info *afi;
1992 const struct nft_table *table;
1993
1994 afi = nf_tables_afinfo_lookup(nfmsg->nfgen_family, false);
1995 if (IS_ERR(afi))
1996 return PTR_ERR(afi);
1997
1998 table = nf_tables_table_lookup(afi, nla[NFTA_SET_ELEM_LIST_TABLE], false);
1999 if (IS_ERR(table))
2000 return PTR_ERR(table);
2001
2002 nft_ctx_init(ctx, skb, nlh, afi, table, NULL);
2003 return 0;
2004}
2005
2006static int nf_tables_fill_setelem(struct sk_buff *skb,
2007 const struct nft_set *set,
2008 const struct nft_set_elem *elem)
2009{
2010 unsigned char *b = skb_tail_pointer(skb);
2011 struct nlattr *nest;
2012
2013 nest = nla_nest_start(skb, NFTA_LIST_ELEM);
2014 if (nest == NULL)
2015 goto nla_put_failure;
2016
2017 if (nft_data_dump(skb, NFTA_SET_ELEM_KEY, &elem->key, NFT_DATA_VALUE,
2018 set->klen) < 0)
2019 goto nla_put_failure;
2020
2021 if (set->flags & NFT_SET_MAP &&
2022 !(elem->flags & NFT_SET_ELEM_INTERVAL_END) &&
2023 nft_data_dump(skb, NFTA_SET_ELEM_DATA, &elem->data,
2024 set->dtype == NFT_DATA_VERDICT ? NFT_DATA_VERDICT : NFT_DATA_VALUE,
2025 set->dlen) < 0)
2026 goto nla_put_failure;
2027
2028 if (elem->flags != 0)
2029 if (nla_put_be32(skb, NFTA_SET_ELEM_FLAGS, htonl(elem->flags)))
2030 goto nla_put_failure;
2031
2032 nla_nest_end(skb, nest);
2033 return 0;
2034
2035nla_put_failure:
2036 nlmsg_trim(skb, b);
2037 return -EMSGSIZE;
2038}
2039
2040struct nft_set_dump_args {
2041 const struct netlink_callback *cb;
2042 struct nft_set_iter iter;
2043 struct sk_buff *skb;
2044};
2045
2046static int nf_tables_dump_setelem(const struct nft_ctx *ctx,
2047 const struct nft_set *set,
2048 const struct nft_set_iter *iter,
2049 const struct nft_set_elem *elem)
2050{
2051 struct nft_set_dump_args *args;
2052
2053 args = container_of(iter, struct nft_set_dump_args, iter);
2054 return nf_tables_fill_setelem(args->skb, set, elem);
2055}
2056
2057static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
2058{
2059 const struct nft_set *set;
2060 struct nft_set_dump_args args;
2061 struct nft_ctx ctx;
2062 struct nlattr *nla[NFTA_SET_ELEM_LIST_MAX + 1];
2063 struct nfgenmsg *nfmsg;
2064 struct nlmsghdr *nlh;
2065 struct nlattr *nest;
2066 u32 portid, seq;
2067 int event, err;
2068
2069 nfmsg = nlmsg_data(cb->nlh);
2070 err = nlmsg_parse(cb->nlh, sizeof(*nfmsg), nla, NFTA_SET_ELEM_LIST_MAX,
2071 nft_set_elem_list_policy);
2072 if (err < 0)
2073 return err;
2074
2075 err = nft_ctx_init_from_elemattr(&ctx, cb->skb, cb->nlh, (void *)nla);
2076 if (err < 0)
2077 return err;
2078
2079 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2080 if (IS_ERR(set))
2081 return PTR_ERR(set);
2082
2083 event = NFT_MSG_NEWSETELEM;
2084 event |= NFNL_SUBSYS_NFTABLES << 8;
2085 portid = NETLINK_CB(cb->skb).portid;
2086 seq = cb->nlh->nlmsg_seq;
2087
2088 nlh = nlmsg_put(skb, portid, seq, event, sizeof(struct nfgenmsg),
2089 NLM_F_MULTI);
2090 if (nlh == NULL)
2091 goto nla_put_failure;
2092
2093 nfmsg = nlmsg_data(nlh);
2094 nfmsg->nfgen_family = NFPROTO_UNSPEC;
2095 nfmsg->version = NFNETLINK_V0;
2096 nfmsg->res_id = 0;
2097
2098 if (nla_put_string(skb, NFTA_SET_ELEM_LIST_TABLE, ctx.table->name))
2099 goto nla_put_failure;
2100 if (nla_put_string(skb, NFTA_SET_ELEM_LIST_SET, set->name))
2101 goto nla_put_failure;
2102
2103 nest = nla_nest_start(skb, NFTA_SET_ELEM_LIST_ELEMENTS);
2104 if (nest == NULL)
2105 goto nla_put_failure;
2106
2107 args.cb = cb;
2108 args.skb = skb;
2109 args.iter.skip = cb->args[0];
2110 args.iter.count = 0;
2111 args.iter.err = 0;
2112 args.iter.fn = nf_tables_dump_setelem;
2113 set->ops->walk(&ctx, set, &args.iter);
2114
2115 nla_nest_end(skb, nest);
2116 nlmsg_end(skb, nlh);
2117
2118 if (args.iter.err && args.iter.err != -EMSGSIZE)
2119 return args.iter.err;
2120 if (args.iter.count == cb->args[0])
2121 return 0;
2122
2123 cb->args[0] = args.iter.count;
2124 return skb->len;
2125
2126nla_put_failure:
2127 return -ENOSPC;
2128}
2129
2130static int nf_tables_getsetelem(struct sock *nlsk, struct sk_buff *skb,
2131 const struct nlmsghdr *nlh,
2132 const struct nlattr * const nla[])
2133{
2134 const struct nft_set *set;
2135 struct nft_ctx ctx;
2136 int err;
2137
2138 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
2139 if (err < 0)
2140 return err;
2141
2142 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2143 if (IS_ERR(set))
2144 return PTR_ERR(set);
2145
2146 if (nlh->nlmsg_flags & NLM_F_DUMP) {
2147 struct netlink_dump_control c = {
2148 .dump = nf_tables_dump_set,
2149 };
2150 return netlink_dump_start(nlsk, skb, nlh, &c);
2151 }
2152 return -EOPNOTSUPP;
2153}
2154
2155static int nft_add_set_elem(const struct nft_ctx *ctx, struct nft_set *set,
2156 const struct nlattr *attr)
2157{
2158 struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
2159 struct nft_data_desc d1, d2;
2160 struct nft_set_elem elem;
2161 struct nft_set_binding *binding;
2162 enum nft_registers dreg;
2163 int err;
2164
2165 err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
2166 nft_set_elem_policy);
2167 if (err < 0)
2168 return err;
2169
2170 if (nla[NFTA_SET_ELEM_KEY] == NULL)
2171 return -EINVAL;
2172
2173 elem.flags = 0;
2174 if (nla[NFTA_SET_ELEM_FLAGS] != NULL) {
2175 elem.flags = ntohl(nla_get_be32(nla[NFTA_SET_ELEM_FLAGS]));
2176 if (elem.flags & ~NFT_SET_ELEM_INTERVAL_END)
2177 return -EINVAL;
2178 }
2179
2180 if (set->flags & NFT_SET_MAP) {
2181 if (nla[NFTA_SET_ELEM_DATA] == NULL &&
2182 !(elem.flags & NFT_SET_ELEM_INTERVAL_END))
2183 return -EINVAL;
2184 } else {
2185 if (nla[NFTA_SET_ELEM_DATA] != NULL)
2186 return -EINVAL;
2187 }
2188
2189 err = nft_data_init(ctx, &elem.key, &d1, nla[NFTA_SET_ELEM_KEY]);
2190 if (err < 0)
2191 goto err1;
2192 err = -EINVAL;
2193 if (d1.type != NFT_DATA_VALUE || d1.len != set->klen)
2194 goto err2;
2195
2196 err = -EEXIST;
2197 if (set->ops->get(set, &elem) == 0)
2198 goto err2;
2199
2200 if (nla[NFTA_SET_ELEM_DATA] != NULL) {
2201 err = nft_data_init(ctx, &elem.data, &d2, nla[NFTA_SET_ELEM_DATA]);
2202 if (err < 0)
2203 goto err2;
2204
2205 err = -EINVAL;
2206 if (set->dtype != NFT_DATA_VERDICT && d2.len != set->dlen)
2207 goto err3;
2208
2209 dreg = nft_type_to_reg(set->dtype);
2210 list_for_each_entry(binding, &set->bindings, list) {
2211 struct nft_ctx bind_ctx = {
2212 .afi = ctx->afi,
2213 .table = ctx->table,
2214 .chain = binding->chain,
2215 };
2216
2217 err = nft_validate_data_load(&bind_ctx, dreg,
2218 &elem.data, d2.type);
2219 if (err < 0)
2220 goto err3;
2221 }
2222 }
2223
2224 err = set->ops->insert(set, &elem);
2225 if (err < 0)
2226 goto err3;
2227
2228 return 0;
2229
2230err3:
2231 if (nla[NFTA_SET_ELEM_DATA] != NULL)
2232 nft_data_uninit(&elem.data, d2.type);
2233err2:
2234 nft_data_uninit(&elem.key, d1.type);
2235err1:
2236 return err;
2237}
2238
2239static int nf_tables_newsetelem(struct sock *nlsk, struct sk_buff *skb,
2240 const struct nlmsghdr *nlh,
2241 const struct nlattr * const nla[])
2242{
2243 const struct nlattr *attr;
2244 struct nft_set *set;
2245 struct nft_ctx ctx;
2246 int rem, err;
2247
2248 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
2249 if (err < 0)
2250 return err;
2251
2252 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2253 if (IS_ERR(set))
2254 return PTR_ERR(set);
2255 if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
2256 return -EBUSY;
2257
2258 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
2259 err = nft_add_set_elem(&ctx, set, attr);
2260 if (err < 0)
2261 return err;
2262 }
2263 return 0;
2264}
2265
2266static int nft_del_setelem(const struct nft_ctx *ctx, struct nft_set *set,
2267 const struct nlattr *attr)
2268{
2269 struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
2270 struct nft_data_desc desc;
2271 struct nft_set_elem elem;
2272 int err;
2273
2274 err = nla_parse_nested(nla, NFTA_SET_ELEM_MAX, attr,
2275 nft_set_elem_policy);
2276 if (err < 0)
2277 goto err1;
2278
2279 err = -EINVAL;
2280 if (nla[NFTA_SET_ELEM_KEY] == NULL)
2281 goto err1;
2282
2283 err = nft_data_init(ctx, &elem.key, &desc, nla[NFTA_SET_ELEM_KEY]);
2284 if (err < 0)
2285 goto err1;
2286
2287 err = -EINVAL;
2288 if (desc.type != NFT_DATA_VALUE || desc.len != set->klen)
2289 goto err2;
2290
2291 err = set->ops->get(set, &elem);
2292 if (err < 0)
2293 goto err2;
2294
2295 set->ops->remove(set, &elem);
2296
2297 nft_data_uninit(&elem.key, NFT_DATA_VALUE);
2298 if (set->flags & NFT_SET_MAP)
2299 nft_data_uninit(&elem.data, set->dtype);
2300
2301err2:
2302 nft_data_uninit(&elem.key, desc.type);
2303err1:
2304 return err;
2305}
2306
2307static int nf_tables_delsetelem(struct sock *nlsk, struct sk_buff *skb,
2308 const struct nlmsghdr *nlh,
2309 const struct nlattr * const nla[])
2310{
2311 const struct nlattr *attr;
2312 struct nft_set *set;
2313 struct nft_ctx ctx;
2314 int rem, err;
2315
2316 err = nft_ctx_init_from_elemattr(&ctx, skb, nlh, nla);
2317 if (err < 0)
2318 return err;
2319
2320 set = nf_tables_set_lookup(ctx.table, nla[NFTA_SET_ELEM_LIST_SET]);
2321 if (IS_ERR(set))
2322 return PTR_ERR(set);
2323 if (!list_empty(&set->bindings) && set->flags & NFT_SET_CONSTANT)
2324 return -EBUSY;
2325
2326 nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
2327 err = nft_del_setelem(&ctx, set, attr);
2328 if (err < 0)
2329 return err;
2330 }
2331 return 0;
2332}
2333
1395static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = { 2334static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
1396 [NFT_MSG_NEWTABLE] = { 2335 [NFT_MSG_NEWTABLE] = {
1397 .call = nf_tables_newtable, 2336 .call = nf_tables_newtable,
@@ -1438,6 +2377,36 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
1438 .attr_count = NFTA_RULE_MAX, 2377 .attr_count = NFTA_RULE_MAX,
1439 .policy = nft_rule_policy, 2378 .policy = nft_rule_policy,
1440 }, 2379 },
2380 [NFT_MSG_NEWSET] = {
2381 .call = nf_tables_newset,
2382 .attr_count = NFTA_SET_MAX,
2383 .policy = nft_set_policy,
2384 },
2385 [NFT_MSG_GETSET] = {
2386 .call = nf_tables_getset,
2387 .attr_count = NFTA_SET_MAX,
2388 .policy = nft_set_policy,
2389 },
2390 [NFT_MSG_DELSET] = {
2391 .call = nf_tables_delset,
2392 .attr_count = NFTA_SET_MAX,
2393 .policy = nft_set_policy,
2394 },
2395 [NFT_MSG_NEWSETELEM] = {
2396 .call = nf_tables_newsetelem,
2397 .attr_count = NFTA_SET_ELEM_LIST_MAX,
2398 .policy = nft_set_elem_list_policy,
2399 },
2400 [NFT_MSG_GETSETELEM] = {
2401 .call = nf_tables_getsetelem,
2402 .attr_count = NFTA_SET_ELEM_LIST_MAX,
2403 .policy = nft_set_elem_list_policy,
2404 },
2405 [NFT_MSG_DELSETELEM] = {
2406 .call = nf_tables_delsetelem,
2407 .attr_count = NFTA_SET_ELEM_LIST_MAX,
2408 .policy = nft_set_elem_list_policy,
2409 },
1441}; 2410};
1442 2411
1443static const struct nfnetlink_subsystem nf_tables_subsys = { 2412static const struct nfnetlink_subsystem nf_tables_subsys = {
@@ -1447,6 +2416,90 @@ static const struct nfnetlink_subsystem nf_tables_subsys = {
1447 .cb = nf_tables_cb, 2416 .cb = nf_tables_cb,
1448}; 2417};
1449 2418
2419/*
2420 * Loop detection - walk through the ruleset beginning at the destination chain
2421 * of a new jump until either the source chain is reached (loop) or all
2422 * reachable chains have been traversed.
2423 *
2424 * The loop check is performed whenever a new jump verdict is added to an
2425 * expression or verdict map or a verdict map is bound to a new chain.
2426 */
2427
2428static int nf_tables_check_loops(const struct nft_ctx *ctx,
2429 const struct nft_chain *chain);
2430
2431static int nf_tables_loop_check_setelem(const struct nft_ctx *ctx,
2432 const struct nft_set *set,
2433 const struct nft_set_iter *iter,
2434 const struct nft_set_elem *elem)
2435{
2436 switch (elem->data.verdict) {
2437 case NFT_JUMP:
2438 case NFT_GOTO:
2439 return nf_tables_check_loops(ctx, elem->data.chain);
2440 default:
2441 return 0;
2442 }
2443}
2444
2445static int nf_tables_check_loops(const struct nft_ctx *ctx,
2446 const struct nft_chain *chain)
2447{
2448 const struct nft_rule *rule;
2449 const struct nft_expr *expr, *last;
2450 const struct nft_data *data;
2451 const struct nft_set *set;
2452 struct nft_set_binding *binding;
2453 struct nft_set_iter iter;
2454 int err;
2455
2456 if (ctx->chain == chain)
2457 return -ELOOP;
2458
2459 list_for_each_entry(rule, &chain->rules, list) {
2460 nft_rule_for_each_expr(expr, last, rule) {
2461 if (!expr->ops->get_verdict)
2462 continue;
2463
2464 data = expr->ops->get_verdict(expr);
2465 if (data == NULL)
2466 break;
2467
2468 switch (data->verdict) {
2469 case NFT_JUMP:
2470 case NFT_GOTO:
2471 err = nf_tables_check_loops(ctx, data->chain);
2472 if (err < 0)
2473 return err;
2474 default:
2475 break;
2476 }
2477 }
2478 }
2479
2480 list_for_each_entry(set, &ctx->table->sets, list) {
2481 if (!(set->flags & NFT_SET_MAP) ||
2482 set->dtype != NFT_DATA_VERDICT)
2483 continue;
2484
2485 list_for_each_entry(binding, &set->bindings, list) {
2486 if (binding->chain != chain)
2487 continue;
2488
2489 iter.skip = 0;
2490 iter.count = 0;
2491 iter.err = 0;
2492 iter.fn = nf_tables_loop_check_setelem;
2493
2494 set->ops->walk(ctx, set, &iter);
2495 if (iter.err < 0)
2496 return iter.err;
2497 }
2498 }
2499
2500 return 0;
2501}
2502
1450/** 2503/**
1451 * nft_validate_input_register - validate an expressions' input register 2504 * nft_validate_input_register - validate an expressions' input register
1452 * 2505 *
@@ -1500,11 +2553,25 @@ int nft_validate_data_load(const struct nft_ctx *ctx, enum nft_registers reg,
1500 const struct nft_data *data, 2553 const struct nft_data *data,
1501 enum nft_data_types type) 2554 enum nft_data_types type)
1502{ 2555{
2556 int err;
2557
1503 switch (reg) { 2558 switch (reg) {
1504 case NFT_REG_VERDICT: 2559 case NFT_REG_VERDICT:
1505 if (data == NULL || type != NFT_DATA_VERDICT) 2560 if (data == NULL || type != NFT_DATA_VERDICT)
1506 return -EINVAL; 2561 return -EINVAL;
1507 // FIXME: do loop detection 2562
2563 if (data->verdict == NFT_GOTO || data->verdict == NFT_JUMP) {
2564 err = nf_tables_check_loops(ctx, data->chain);
2565 if (err < 0)
2566 return err;
2567
2568 if (ctx->chain->level + 1 > data->chain->level) {
2569 if (ctx->chain->level + 1 == NFT_JUMP_STACK_SIZE)
2570 return -EMLINK;
2571 data->chain->level = ctx->chain->level + 1;
2572 }
2573 }
2574
1508 return 0; 2575 return 0;
1509 default: 2576 default:
1510 if (data != NULL && type != NFT_DATA_VALUE) 2577 if (data != NULL && type != NFT_DATA_VALUE)
@@ -1555,11 +2622,6 @@ static int nft_verdict_init(const struct nft_ctx *ctx, struct nft_data *data,
1555 if (chain->flags & NFT_BASE_CHAIN) 2622 if (chain->flags & NFT_BASE_CHAIN)
1556 return -EOPNOTSUPP; 2623 return -EOPNOTSUPP;
1557 2624
1558 if (ctx->chain->level + 1 > chain->level) {
1559 if (ctx->chain->level + 1 == 16)
1560 return -EMLINK;
1561 chain->level = ctx->chain->level + 1;
1562 }
1563 chain->use++; 2625 chain->use++;
1564 data->chain = chain; 2626 data->chain = chain;
1565 desc->len = sizeof(data); 2627 desc->len = sizeof(data);
diff --git a/net/netfilter/nf_tables_core.c b/net/netfilter/nf_tables_core.c
index bc7fb85d4002..fd0ecd3255c1 100644
--- a/net/netfilter/nf_tables_core.c
+++ b/net/netfilter/nf_tables_core.c
@@ -20,8 +20,6 @@
20#include <net/netfilter/nf_tables_core.h> 20#include <net/netfilter/nf_tables_core.h>
21#include <net/netfilter/nf_tables.h> 21#include <net/netfilter/nf_tables.h>
22 22
23#define NFT_JUMP_STACK_SIZE 16
24
25unsigned int nft_do_chain(const struct nf_hook_ops *ops, 23unsigned int nft_do_chain(const struct nf_hook_ops *ops,
26 struct sk_buff *skb, 24 struct sk_buff *skb,
27 const struct net_device *in, 25 const struct net_device *in,
diff --git a/net/netfilter/nft_hash.c b/net/netfilter/nft_hash.c
index 67cc502881f1..3d3f8fce10a5 100644
--- a/net/netfilter/nft_hash.c
+++ b/net/netfilter/nft_hash.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net> 2 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
3 * 3 *
4 * This program is free software; you can redistribute it and/or modify 4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as 5 * it under the terms of the GNU General Public License version 2 as
@@ -21,11 +21,6 @@
21struct nft_hash { 21struct nft_hash {
22 struct hlist_head *hash; 22 struct hlist_head *hash;
23 unsigned int hsize; 23 unsigned int hsize;
24 enum nft_registers sreg:8;
25 enum nft_registers dreg:8;
26 u8 klen;
27 u8 dlen;
28 u16 flags;
29}; 24};
30 25
31struct nft_hash_elem { 26struct nft_hash_elem {
@@ -42,213 +37,140 @@ static unsigned int nft_hash_data(const struct nft_data *data,
42{ 37{
43 unsigned int h; 38 unsigned int h;
44 39
45 // FIXME: can we reasonably guarantee the upper bits are fixed? 40 h = jhash(data->data, len, nft_hash_rnd);
46 h = jhash2(data->data, len >> 2, nft_hash_rnd);
47 return ((u64)h * hsize) >> 32; 41 return ((u64)h * hsize) >> 32;
48} 42}
49 43
50static void nft_hash_eval(const struct nft_expr *expr, 44static bool nft_hash_lookup(const struct nft_set *set,
51 struct nft_data data[NFT_REG_MAX + 1], 45 const struct nft_data *key,
52 const struct nft_pktinfo *pkt) 46 struct nft_data *data)
53{ 47{
54 const struct nft_hash *priv = nft_expr_priv(expr); 48 const struct nft_hash *priv = nft_set_priv(set);
55 const struct nft_hash_elem *elem; 49 const struct nft_hash_elem *he;
56 const struct nft_data *key = &data[priv->sreg];
57 unsigned int h; 50 unsigned int h;
58 51
59 h = nft_hash_data(key, priv->hsize, priv->klen); 52 h = nft_hash_data(key, priv->hsize, set->klen);
60 hlist_for_each_entry(elem, &priv->hash[h], hnode) { 53 hlist_for_each_entry(he, &priv->hash[h], hnode) {
61 if (nft_data_cmp(&elem->key, key, priv->klen)) 54 if (nft_data_cmp(&he->key, key, set->klen))
62 continue; 55 continue;
63 if (priv->flags & NFT_HASH_MAP) 56 if (set->flags & NFT_SET_MAP)
64 nft_data_copy(&data[priv->dreg], elem->data); 57 nft_data_copy(data, he->data);
65 return; 58 return true;
66 } 59 }
67 data[NFT_REG_VERDICT].verdict = NFT_BREAK; 60 return false;
68} 61}
69 62
70static void nft_hash_elem_destroy(const struct nft_expr *expr, 63static void nft_hash_elem_destroy(const struct nft_set *set,
71 struct nft_hash_elem *elem) 64 struct nft_hash_elem *he)
72{ 65{
73 const struct nft_hash *priv = nft_expr_priv(expr); 66 nft_data_uninit(&he->key, NFT_DATA_VALUE);
74 67 if (set->flags & NFT_SET_MAP)
75 nft_data_uninit(&elem->key, NFT_DATA_VALUE); 68 nft_data_uninit(he->data, set->dtype);
76 if (priv->flags & NFT_HASH_MAP) 69 kfree(he);
77 nft_data_uninit(elem->data, nft_dreg_to_type(priv->dreg));
78 kfree(elem);
79} 70}
80 71
81static const struct nla_policy nft_he_policy[NFTA_HE_MAX + 1] = { 72static int nft_hash_insert(const struct nft_set *set,
82 [NFTA_HE_KEY] = { .type = NLA_NESTED }, 73 const struct nft_set_elem *elem)
83 [NFTA_HE_DATA] = { .type = NLA_NESTED },
84};
85
86static int nft_hash_elem_init(const struct nft_ctx *ctx,
87 const struct nft_expr *expr,
88 const struct nlattr *nla,
89 struct nft_hash_elem **new)
90{ 74{
91 struct nft_hash *priv = nft_expr_priv(expr); 75 struct nft_hash *priv = nft_set_priv(set);
92 struct nlattr *tb[NFTA_HE_MAX + 1]; 76 struct nft_hash_elem *he;
93 struct nft_hash_elem *elem; 77 unsigned int size, h;
94 struct nft_data_desc d1, d2;
95 unsigned int size;
96 int err;
97 78
98 err = nla_parse_nested(tb, NFTA_HE_MAX, nla, nft_he_policy); 79 if (elem->flags != 0)
99 if (err < 0)
100 return err;
101
102 if (tb[NFTA_HE_KEY] == NULL)
103 return -EINVAL; 80 return -EINVAL;
104 size = sizeof(*elem);
105
106 if (priv->flags & NFT_HASH_MAP) {
107 if (tb[NFTA_HE_DATA] == NULL)
108 return -EINVAL;
109 size += sizeof(elem->data[0]);
110 } else {
111 if (tb[NFTA_HE_DATA] != NULL)
112 return -EINVAL;
113 }
114 81
115 elem = kzalloc(size, GFP_KERNEL); 82 size = sizeof(*he);
116 if (elem == NULL) 83 if (set->flags & NFT_SET_MAP)
84 size += sizeof(he->data[0]);
85
86 he = kzalloc(size, GFP_KERNEL);
87 if (he == NULL)
117 return -ENOMEM; 88 return -ENOMEM;
118 89
119 err = nft_data_init(ctx, &elem->key, &d1, tb[NFTA_HE_KEY]); 90 nft_data_copy(&he->key, &elem->key);
120 if (err < 0) 91 if (set->flags & NFT_SET_MAP)
121 goto err1; 92 nft_data_copy(he->data, &elem->data);
122 err = -EINVAL;
123 if (d1.type != NFT_DATA_VALUE || d1.len != priv->klen)
124 goto err2;
125
126 if (tb[NFTA_HE_DATA] != NULL) {
127 err = nft_data_init(ctx, elem->data, &d2, tb[NFTA_HE_DATA]);
128 if (err < 0)
129 goto err2;
130 err = nft_validate_data_load(ctx, priv->dreg, elem->data, d2.type);
131 if (err < 0)
132 goto err3;
133 }
134 93
135 *new = elem; 94 h = nft_hash_data(&he->key, priv->hsize, set->klen);
95 hlist_add_head_rcu(&he->hnode, &priv->hash[h]);
136 return 0; 96 return 0;
137
138err3:
139 nft_data_uninit(elem->data, d2.type);
140err2:
141 nft_data_uninit(&elem->key, d1.type);
142err1:
143 kfree(elem);
144 return err;
145} 97}
146 98
147static int nft_hash_elem_dump(struct sk_buff *skb, const struct nft_expr *expr, 99static void nft_hash_remove(const struct nft_set *set,
148 const struct nft_hash_elem *elem) 100 const struct nft_set_elem *elem)
149
150{ 101{
151 const struct nft_hash *priv = nft_expr_priv(expr); 102 struct nft_hash_elem *he = elem->cookie;
152 struct nlattr *nest;
153 103
154 nest = nla_nest_start(skb, NFTA_LIST_ELEM); 104 hlist_del_rcu(&he->hnode);
155 if (nest == NULL) 105 kfree(he);
156 goto nla_put_failure; 106}
157
158 if (nft_data_dump(skb, NFTA_HE_KEY, &elem->key,
159 NFT_DATA_VALUE, priv->klen) < 0)
160 goto nla_put_failure;
161 107
162 if (priv->flags & NFT_HASH_MAP) { 108static int nft_hash_get(const struct nft_set *set, struct nft_set_elem *elem)
163 if (nft_data_dump(skb, NFTA_HE_DATA, elem->data, 109{
164 NFT_DATA_VALUE, priv->dlen) < 0) 110 const struct nft_hash *priv = nft_set_priv(set);
165 goto nla_put_failure; 111 struct nft_hash_elem *he;
166 } 112 unsigned int h;
167 113
168 nla_nest_end(skb, nest); 114 h = nft_hash_data(&elem->key, priv->hsize, set->klen);
169 return 0; 115 hlist_for_each_entry(he, &priv->hash[h], hnode) {
116 if (nft_data_cmp(&he->key, &elem->key, set->klen))
117 continue;
170 118
171nla_put_failure: 119 elem->cookie = he;
172 return -1; 120 elem->flags = 0;
121 if (set->flags & NFT_SET_MAP)
122 nft_data_copy(&elem->data, he->data);
123 return 0;
124 }
125 return -ENOENT;
173} 126}
174 127
175static void nft_hash_destroy(const struct nft_ctx *ctx, 128static void nft_hash_walk(const struct nft_ctx *ctx, const struct nft_set *set,
176 const struct nft_expr *expr) 129 struct nft_set_iter *iter)
177{ 130{
178 const struct nft_hash *priv = nft_expr_priv(expr); 131 const struct nft_hash *priv = nft_set_priv(set);
179 const struct hlist_node *next; 132 const struct nft_hash_elem *he;
180 struct nft_hash_elem *elem; 133 struct nft_set_elem elem;
181 unsigned int i; 134 unsigned int i;
182 135
183 for (i = 0; i < priv->hsize; i++) { 136 for (i = 0; i < priv->hsize; i++) {
184 hlist_for_each_entry_safe(elem, next, &priv->hash[i], hnode) { 137 hlist_for_each_entry(he, &priv->hash[i], hnode) {
185 hlist_del(&elem->hnode); 138 if (iter->count < iter->skip)
186 nft_hash_elem_destroy(expr, elem); 139 goto cont;
140
141 memcpy(&elem.key, &he->key, sizeof(elem.key));
142 if (set->flags & NFT_SET_MAP)
143 memcpy(&elem.data, he->data, sizeof(elem.data));
144 elem.flags = 0;
145
146 iter->err = iter->fn(ctx, set, iter, &elem);
147 if (iter->err < 0)
148 return;
149cont:
150 iter->count++;
187 } 151 }
188 } 152 }
189 kfree(priv->hash);
190} 153}
191 154
192static const struct nla_policy nft_hash_policy[NFTA_HASH_MAX + 1] = { 155static unsigned int nft_hash_privsize(const struct nlattr * const nla[])
193 [NFTA_HASH_FLAGS] = { .type = NLA_U32 }, 156{
194 [NFTA_HASH_SREG] = { .type = NLA_U32 }, 157 return sizeof(struct nft_hash);
195 [NFTA_HASH_DREG] = { .type = NLA_U32 }, 158}
196 [NFTA_HASH_KLEN] = { .type = NLA_U32 },
197 [NFTA_HASH_ELEMENTS] = { .type = NLA_NESTED },
198};
199 159
200static int nft_hash_init(const struct nft_ctx *ctx, const struct nft_expr *expr, 160static int nft_hash_init(const struct nft_set *set,
201 const struct nlattr * const tb[]) 161 const struct nlattr * const tb[])
202{ 162{
203 struct nft_hash *priv = nft_expr_priv(expr); 163 struct nft_hash *priv = nft_set_priv(set);
204 struct nft_hash_elem *elem, *uninitialized_var(new);
205 const struct nlattr *nla;
206 unsigned int cnt, i; 164 unsigned int cnt, i;
207 unsigned int h;
208 int err, rem;
209 165
210 if (unlikely(!nft_hash_rnd_initted)) { 166 if (unlikely(!nft_hash_rnd_initted)) {
211 get_random_bytes(&nft_hash_rnd, 4); 167 get_random_bytes(&nft_hash_rnd, 4);
212 nft_hash_rnd_initted = true; 168 nft_hash_rnd_initted = true;
213 } 169 }
214 170
215 if (tb[NFTA_HASH_SREG] == NULL ||
216 tb[NFTA_HASH_KLEN] == NULL ||
217 tb[NFTA_HASH_ELEMENTS] == NULL)
218 return -EINVAL;
219
220 if (tb[NFTA_HASH_FLAGS] != NULL) {
221 priv->flags = ntohl(nla_get_be32(tb[NFTA_HASH_FLAGS]));
222 if (priv->flags & ~NFT_HASH_MAP)
223 return -EINVAL;
224 }
225
226 priv->sreg = ntohl(nla_get_be32(tb[NFTA_HASH_SREG]));
227 err = nft_validate_input_register(priv->sreg);
228 if (err < 0)
229 return err;
230
231 if (tb[NFTA_HASH_DREG] != NULL) {
232 if (!(priv->flags & NFT_HASH_MAP))
233 return -EINVAL;
234 priv->dreg = ntohl(nla_get_be32(tb[NFTA_HASH_DREG]));
235 err = nft_validate_output_register(priv->dreg);
236 if (err < 0)
237 return err;
238 }
239
240 priv->klen = ntohl(nla_get_be32(tb[NFTA_HASH_KLEN]));
241 if (priv->klen == 0)
242 return -EINVAL;
243
244 cnt = 0;
245 nla_for_each_nested(nla, tb[NFTA_HASH_ELEMENTS], rem) {
246 if (nla_type(nla) != NFTA_LIST_ELEM)
247 return -EINVAL;
248 cnt++;
249 }
250
251 /* Aim for a load factor of 0.75 */ 171 /* Aim for a load factor of 0.75 */
172 // FIXME: temporarily broken until we have set descriptions
173 cnt = 100;
252 cnt = cnt * 4 / 3; 174 cnt = cnt * 4 / 3;
253 175
254 priv->hash = kcalloc(cnt, sizeof(struct hlist_head), GFP_KERNEL); 176 priv->hash = kcalloc(cnt, sizeof(struct hlist_head), GFP_KERNEL);
@@ -259,85 +181,46 @@ static int nft_hash_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
259 for (i = 0; i < cnt; i++) 181 for (i = 0; i < cnt; i++)
260 INIT_HLIST_HEAD(&priv->hash[i]); 182 INIT_HLIST_HEAD(&priv->hash[i]);
261 183
262 err = -ENOMEM;
263 nla_for_each_nested(nla, tb[NFTA_HASH_ELEMENTS], rem) {
264 err = nft_hash_elem_init(ctx, expr, nla, &new);
265 if (err < 0)
266 goto err1;
267
268 h = nft_hash_data(&new->key, priv->hsize, priv->klen);
269 hlist_for_each_entry(elem, &priv->hash[h], hnode) {
270 if (nft_data_cmp(&elem->key, &new->key, priv->klen))
271 continue;
272 nft_hash_elem_destroy(expr, new);
273 err = -EEXIST;
274 goto err1;
275 }
276 hlist_add_head(&new->hnode, &priv->hash[h]);
277 }
278 return 0; 184 return 0;
279
280err1:
281 nft_hash_destroy(ctx, expr);
282 return err;
283} 185}
284 186
285static int nft_hash_dump(struct sk_buff *skb, const struct nft_expr *expr) 187static void nft_hash_destroy(const struct nft_set *set)
286{ 188{
287 const struct nft_hash *priv = nft_expr_priv(expr); 189 const struct nft_hash *priv = nft_set_priv(set);
288 const struct nft_hash_elem *elem; 190 const struct hlist_node *next;
289 struct nlattr *list; 191 struct nft_hash_elem *elem;
290 unsigned int i; 192 unsigned int i;
291 193
292 if (priv->flags)
293 if (nla_put_be32(skb, NFTA_HASH_FLAGS, htonl(priv->flags)))
294 goto nla_put_failure;
295 if (nla_put_be32(skb, NFTA_HASH_SREG, htonl(priv->sreg)))
296 goto nla_put_failure;
297 if (priv->flags & NFT_HASH_MAP)
298 if (nla_put_be32(skb, NFTA_HASH_DREG, htonl(priv->dreg)))
299 goto nla_put_failure;
300 if (nla_put_be32(skb, NFTA_HASH_KLEN, htonl(priv->klen)))
301 goto nla_put_failure;
302
303 list = nla_nest_start(skb, NFTA_HASH_ELEMENTS);
304 if (list == NULL)
305 goto nla_put_failure;
306
307 for (i = 0; i < priv->hsize; i++) { 194 for (i = 0; i < priv->hsize; i++) {
308 hlist_for_each_entry(elem, &priv->hash[i], hnode) { 195 hlist_for_each_entry_safe(elem, next, &priv->hash[i], hnode) {
309 if (nft_hash_elem_dump(skb, expr, elem) < 0) 196 hlist_del(&elem->hnode);
310 goto nla_put_failure; 197 nft_hash_elem_destroy(set, elem);
311 } 198 }
312 } 199 }
313 200 kfree(priv->hash);
314 nla_nest_end(skb, list);
315 return 0;
316
317nla_put_failure:
318 return -1;
319} 201}
320 202
321static struct nft_expr_ops nft_hash_ops __read_mostly = { 203static struct nft_set_ops nft_hash_ops __read_mostly = {
322 .name = "hash", 204 .privsize = nft_hash_privsize,
323 .size = NFT_EXPR_SIZE(sizeof(struct nft_hash)),
324 .owner = THIS_MODULE,
325 .eval = nft_hash_eval,
326 .init = nft_hash_init, 205 .init = nft_hash_init,
327 .destroy = nft_hash_destroy, 206 .destroy = nft_hash_destroy,
328 .dump = nft_hash_dump, 207 .get = nft_hash_get,
329 .policy = nft_hash_policy, 208 .insert = nft_hash_insert,
330 .maxattr = NFTA_HASH_MAX, 209 .remove = nft_hash_remove,
210 .lookup = nft_hash_lookup,
211 .walk = nft_hash_walk,
212 .features = NFT_SET_MAP,
213 .owner = THIS_MODULE,
331}; 214};
332 215
333static int __init nft_hash_module_init(void) 216static int __init nft_hash_module_init(void)
334{ 217{
335 return nft_register_expr(&nft_hash_ops); 218 return nft_register_set(&nft_hash_ops);
336} 219}
337 220
338static void __exit nft_hash_module_exit(void) 221static void __exit nft_hash_module_exit(void)
339{ 222{
340 nft_unregister_expr(&nft_hash_ops); 223 nft_unregister_set(&nft_hash_ops);
341} 224}
342 225
343module_init(nft_hash_module_init); 226module_init(nft_hash_module_init);
@@ -345,4 +228,4 @@ module_exit(nft_hash_module_exit);
345 228
346MODULE_LICENSE("GPL"); 229MODULE_LICENSE("GPL");
347MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); 230MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
348MODULE_ALIAS_NFT_EXPR("hash"); 231MODULE_ALIAS_NFT_SET();
diff --git a/net/netfilter/nft_immediate.c b/net/netfilter/nft_immediate.c
index 3bf42c3cc49a..78334bf37007 100644
--- a/net/netfilter/nft_immediate.c
+++ b/net/netfilter/nft_immediate.c
@@ -90,6 +90,16 @@ nla_put_failure:
90 return -1; 90 return -1;
91} 91}
92 92
93static const struct nft_data *nft_immediate_get_verdict(const struct nft_expr *expr)
94{
95 const struct nft_immediate_expr *priv = nft_expr_priv(expr);
96
97 if (priv->dreg == NFT_REG_VERDICT)
98 return &priv->data;
99 else
100 return NULL;
101}
102
93static struct nft_expr_ops nft_imm_ops __read_mostly = { 103static struct nft_expr_ops nft_imm_ops __read_mostly = {
94 .name = "immediate", 104 .name = "immediate",
95 .size = NFT_EXPR_SIZE(sizeof(struct nft_immediate_expr)), 105 .size = NFT_EXPR_SIZE(sizeof(struct nft_immediate_expr)),
@@ -98,6 +108,7 @@ static struct nft_expr_ops nft_imm_ops __read_mostly = {
98 .init = nft_immediate_init, 108 .init = nft_immediate_init,
99 .destroy = nft_immediate_destroy, 109 .destroy = nft_immediate_destroy,
100 .dump = nft_immediate_dump, 110 .dump = nft_immediate_dump,
111 .get_verdict = nft_immediate_get_verdict,
101 .policy = nft_immediate_policy, 112 .policy = nft_immediate_policy,
102 .maxattr = NFTA_IMMEDIATE_MAX, 113 .maxattr = NFTA_IMMEDIATE_MAX,
103}; 114};
diff --git a/net/netfilter/nft_lookup.c b/net/netfilter/nft_lookup.c
new file mode 100644
index 000000000000..4962d2173678
--- /dev/null
+++ b/net/netfilter/nft_lookup.c
@@ -0,0 +1,135 @@
1/*
2 * Copyright (c) 2009 Patrick McHardy <kaber@trash.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/list.h>
14#include <linux/rbtree.h>
15#include <linux/netlink.h>
16#include <linux/netfilter.h>
17#include <linux/netfilter/nf_tables.h>
18#include <net/netfilter/nf_tables.h>
19
20struct nft_lookup {
21 struct nft_set *set;
22 enum nft_registers sreg:8;
23 enum nft_registers dreg:8;
24 struct nft_set_binding binding;
25};
26
27static void nft_lookup_eval(const struct nft_expr *expr,
28 struct nft_data data[NFT_REG_MAX + 1],
29 const struct nft_pktinfo *pkt)
30{
31 const struct nft_lookup *priv = nft_expr_priv(expr);
32 const struct nft_set *set = priv->set;
33
34 if (set->ops->lookup(set, &data[priv->sreg], &data[priv->dreg]))
35 return;
36 data[NFT_REG_VERDICT].verdict = NFT_BREAK;
37}
38
39static const struct nla_policy nft_lookup_policy[NFTA_LOOKUP_MAX + 1] = {
40 [NFTA_LOOKUP_SET] = { .type = NLA_STRING },
41 [NFTA_LOOKUP_SREG] = { .type = NLA_U32 },
42 [NFTA_LOOKUP_DREG] = { .type = NLA_U32 },
43};
44
45static int nft_lookup_init(const struct nft_ctx *ctx,
46 const struct nft_expr *expr,
47 const struct nlattr * const tb[])
48{
49 struct nft_lookup *priv = nft_expr_priv(expr);
50 struct nft_set *set;
51 int err;
52
53 if (tb[NFTA_LOOKUP_SET] == NULL ||
54 tb[NFTA_LOOKUP_SREG] == NULL)
55 return -EINVAL;
56
57 set = nf_tables_set_lookup(ctx->table, tb[NFTA_LOOKUP_SET]);
58 if (IS_ERR(set))
59 return PTR_ERR(set);
60
61 priv->sreg = ntohl(nla_get_be32(tb[NFTA_LOOKUP_SREG]));
62 err = nft_validate_input_register(priv->sreg);
63 if (err < 0)
64 return err;
65
66 if (tb[NFTA_LOOKUP_DREG] != NULL) {
67 if (!(set->flags & NFT_SET_MAP))
68 return -EINVAL;
69
70 priv->dreg = ntohl(nla_get_be32(tb[NFTA_LOOKUP_DREG]));
71 err = nft_validate_output_register(priv->dreg);
72 if (err < 0)
73 return err;
74
75 if (priv->dreg == NFT_REG_VERDICT) {
76 if (set->dtype != NFT_DATA_VERDICT)
77 return -EINVAL;
78 } else if (set->dtype == NFT_DATA_VERDICT)
79 return -EINVAL;
80 } else if (set->flags & NFT_SET_MAP)
81 return -EINVAL;
82
83 err = nf_tables_bind_set(ctx, set, &priv->binding);
84 if (err < 0)
85 return err;
86
87 priv->set = set;
88 return 0;
89}
90
91static void nft_lookup_destroy(const struct nft_expr *expr)
92{
93 struct nft_lookup *priv = nft_expr_priv(expr);
94
95 nf_tables_unbind_set(NULL, priv->set, &priv->binding);
96}
97
98static int nft_lookup_dump(struct sk_buff *skb, const struct nft_expr *expr)
99{
100 const struct nft_lookup *priv = nft_expr_priv(expr);
101
102 if (nla_put_string(skb, NFTA_LOOKUP_SET, priv->set->name))
103 goto nla_put_failure;
104 if (nla_put_be32(skb, NFTA_LOOKUP_SREG, htonl(priv->sreg)))
105 goto nla_put_failure;
106 if (priv->set->flags & NFT_SET_MAP)
107 if (nla_put_be32(skb, NFTA_LOOKUP_DREG, htonl(priv->dreg)))
108 goto nla_put_failure;
109 return 0;
110
111nla_put_failure:
112 return -1;
113}
114
115static struct nft_expr_ops nft_lookup_ops __read_mostly = {
116 .name = "lookup",
117 .size = NFT_EXPR_SIZE(sizeof(struct nft_lookup)),
118 .owner = THIS_MODULE,
119 .eval = nft_lookup_eval,
120 .init = nft_lookup_init,
121 .destroy = nft_lookup_destroy,
122 .dump = nft_lookup_dump,
123 .policy = nft_lookup_policy,
124 .maxattr = NFTA_LOOKUP_MAX,
125};
126
127int __init nft_lookup_module_init(void)
128{
129 return nft_register_expr(&nft_lookup_ops);
130}
131
132void nft_lookup_module_exit(void)
133{
134 nft_unregister_expr(&nft_lookup_ops);
135}
diff --git a/net/netfilter/nft_rbtree.c b/net/netfilter/nft_rbtree.c
new file mode 100644
index 000000000000..ca0c1b231bfe
--- /dev/null
+++ b/net/netfilter/nft_rbtree.c
@@ -0,0 +1,247 @@
1/*
2 * Copyright (c) 2008-2009 Patrick McHardy <kaber@trash.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/kernel.h>
12#include <linux/init.h>
13#include <linux/module.h>
14#include <linux/list.h>
15#include <linux/rbtree.h>
16#include <linux/netlink.h>
17#include <linux/netfilter.h>
18#include <linux/netfilter/nf_tables.h>
19#include <net/netfilter/nf_tables.h>
20
21struct nft_rbtree {
22 struct rb_root root;
23};
24
25struct nft_rbtree_elem {
26 struct rb_node node;
27 u16 flags;
28 struct nft_data key;
29 struct nft_data data[];
30};
31
32static bool nft_rbtree_lookup(const struct nft_set *set,
33 const struct nft_data *key,
34 struct nft_data *data)
35{
36 const struct nft_rbtree *priv = nft_set_priv(set);
37 const struct nft_rbtree_elem *rbe, *interval = NULL;
38 const struct rb_node *parent = priv->root.rb_node;
39 int d;
40
41 while (parent != NULL) {
42 rbe = rb_entry(parent, struct nft_rbtree_elem, node);
43
44 d = nft_data_cmp(&rbe->key, key, set->klen);
45 if (d < 0) {
46 parent = parent->rb_left;
47 interval = rbe;
48 } else if (d > 0)
49 parent = parent->rb_right;
50 else {
51found:
52 if (rbe->flags & NFT_SET_ELEM_INTERVAL_END)
53 goto out;
54 if (set->flags & NFT_SET_MAP)
55 nft_data_copy(data, rbe->data);
56 return true;
57 }
58 }
59
60 if (set->flags & NFT_SET_INTERVAL && interval != NULL) {
61 rbe = interval;
62 goto found;
63 }
64out:
65 return false;
66}
67
68static void nft_rbtree_elem_destroy(const struct nft_set *set,
69 struct nft_rbtree_elem *rbe)
70{
71 nft_data_uninit(&rbe->key, NFT_DATA_VALUE);
72 if (set->flags & NFT_SET_MAP)
73 nft_data_uninit(rbe->data, set->dtype);
74 kfree(rbe);
75}
76
77static int __nft_rbtree_insert(const struct nft_set *set,
78 struct nft_rbtree_elem *new)
79{
80 struct nft_rbtree *priv = nft_set_priv(set);
81 struct nft_rbtree_elem *rbe;
82 struct rb_node *parent, **p;
83 int d;
84
85 parent = NULL;
86 p = &priv->root.rb_node;
87 while (*p != NULL) {
88 parent = *p;
89 rbe = rb_entry(parent, struct nft_rbtree_elem, node);
90 d = nft_data_cmp(&rbe->key, &new->key, set->klen);
91 if (d < 0)
92 p = &parent->rb_left;
93 else if (d > 0)
94 p = &parent->rb_right;
95 else
96 return -EEXIST;
97 }
98 rb_link_node(&new->node, parent, p);
99 rb_insert_color(&new->node, &priv->root);
100 return 0;
101}
102
103static int nft_rbtree_insert(const struct nft_set *set,
104 const struct nft_set_elem *elem)
105{
106 struct nft_rbtree_elem *rbe;
107 unsigned int size;
108 int err;
109
110 size = sizeof(*rbe);
111 if (set->flags & NFT_SET_MAP)
112 size += sizeof(rbe->data[0]);
113
114 rbe = kzalloc(size, GFP_KERNEL);
115 if (rbe == NULL)
116 return -ENOMEM;
117
118 rbe->flags = elem->flags;
119 nft_data_copy(&rbe->key, &elem->key);
120 if (set->flags & NFT_SET_MAP)
121 nft_data_copy(rbe->data, &elem->data);
122
123 err = __nft_rbtree_insert(set, rbe);
124 if (err < 0)
125 kfree(rbe);
126 return err;
127}
128
129static void nft_rbtree_remove(const struct nft_set *set,
130 const struct nft_set_elem *elem)
131{
132 struct nft_rbtree *priv = nft_set_priv(set);
133 struct nft_rbtree_elem *rbe = elem->cookie;
134
135 rb_erase(&rbe->node, &priv->root);
136 kfree(rbe);
137}
138
139static int nft_rbtree_get(const struct nft_set *set, struct nft_set_elem *elem)
140{
141 const struct nft_rbtree *priv = nft_set_priv(set);
142 const struct rb_node *parent = priv->root.rb_node;
143 struct nft_rbtree_elem *rbe;
144 int d;
145
146 while (parent != NULL) {
147 rbe = rb_entry(parent, struct nft_rbtree_elem, node);
148
149 d = nft_data_cmp(&rbe->key, &elem->key, set->klen);
150 if (d < 0)
151 parent = parent->rb_left;
152 else if (d > 0)
153 parent = parent->rb_right;
154 else {
155 elem->cookie = rbe;
156 if (set->flags & NFT_SET_MAP)
157 nft_data_copy(&elem->data, rbe->data);
158 elem->flags = rbe->flags;
159 return 0;
160 }
161 }
162 return -ENOENT;
163}
164
165static void nft_rbtree_walk(const struct nft_ctx *ctx,
166 const struct nft_set *set,
167 struct nft_set_iter *iter)
168{
169 const struct nft_rbtree *priv = nft_set_priv(set);
170 const struct nft_rbtree_elem *rbe;
171 struct nft_set_elem elem;
172 struct rb_node *node;
173
174 for (node = rb_first(&priv->root); node != NULL; node = rb_next(node)) {
175 if (iter->count < iter->skip)
176 goto cont;
177
178 rbe = rb_entry(node, struct nft_rbtree_elem, node);
179 nft_data_copy(&elem.key, &rbe->key);
180 if (set->flags & NFT_SET_MAP)
181 nft_data_copy(&elem.data, rbe->data);
182 elem.flags = rbe->flags;
183
184 iter->err = iter->fn(ctx, set, iter, &elem);
185 if (iter->err < 0)
186 return;
187cont:
188 iter->count++;
189 }
190}
191
192static unsigned int nft_rbtree_privsize(const struct nlattr * const nla[])
193{
194 return sizeof(struct nft_rbtree);
195}
196
197static int nft_rbtree_init(const struct nft_set *set,
198 const struct nlattr * const nla[])
199{
200 struct nft_rbtree *priv = nft_set_priv(set);
201
202 priv->root = RB_ROOT;
203 return 0;
204}
205
206static void nft_rbtree_destroy(const struct nft_set *set)
207{
208 struct nft_rbtree *priv = nft_set_priv(set);
209 struct nft_rbtree_elem *rbe;
210 struct rb_node *node;
211
212 while ((node = priv->root.rb_node) != NULL) {
213 rb_erase(node, &priv->root);
214 rbe = rb_entry(node, struct nft_rbtree_elem, node);
215 nft_rbtree_elem_destroy(set, rbe);
216 }
217}
218
219static struct nft_set_ops nft_rbtree_ops __read_mostly = {
220 .privsize = nft_rbtree_privsize,
221 .init = nft_rbtree_init,
222 .destroy = nft_rbtree_destroy,
223 .insert = nft_rbtree_insert,
224 .remove = nft_rbtree_remove,
225 .get = nft_rbtree_get,
226 .lookup = nft_rbtree_lookup,
227 .walk = nft_rbtree_walk,
228 .features = NFT_SET_INTERVAL | NFT_SET_MAP,
229 .owner = THIS_MODULE,
230};
231
232static int __init nft_rbtree_module_init(void)
233{
234 return nft_register_set(&nft_rbtree_ops);
235}
236
237static void __exit nft_rbtree_module_exit(void)
238{
239 nft_unregister_set(&nft_rbtree_ops);
240}
241
242module_init(nft_rbtree_module_init);
243module_exit(nft_rbtree_module_exit);
244
245MODULE_LICENSE("GPL");
246MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
247MODULE_ALIAS_NFT_SET();
diff --git a/net/netfilter/nft_set.c b/net/netfilter/nft_set.c
deleted file mode 100644
index 7b7c8354c327..000000000000
--- a/net/netfilter/nft_set.c
+++ /dev/null
@@ -1,381 +0,0 @@
1/*
2 * Copyright (c) 2008 Patrick McHardy <kaber@trash.net>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 *
8 * Development of this code funded by Astaro AG (http://www.astaro.com/)
9 */
10
11#include <linux/kernel.h>
12#include <linux/module.h>
13#include <linux/init.h>
14#include <linux/list.h>
15#include <linux/rbtree.h>
16#include <linux/netlink.h>
17#include <linux/netfilter.h>
18#include <linux/netfilter/nf_tables.h>
19#include <net/netfilter/nf_tables.h>
20
21struct nft_set {
22 struct rb_root root;
23 enum nft_registers sreg:8;
24 enum nft_registers dreg:8;
25 u8 klen;
26 u8 dlen;
27 u16 flags;
28};
29
30struct nft_set_elem {
31 struct rb_node node;
32 enum nft_set_elem_flags flags;
33 struct nft_data key;
34 struct nft_data data[];
35};
36
37static void nft_set_eval(const struct nft_expr *expr,
38 struct nft_data data[NFT_REG_MAX + 1],
39 const struct nft_pktinfo *pkt)
40{
41 const struct nft_set *priv = nft_expr_priv(expr);
42 const struct rb_node *parent = priv->root.rb_node;
43 const struct nft_set_elem *elem, *interval = NULL;
44 const struct nft_data *key = &data[priv->sreg];
45 int d;
46
47 while (parent != NULL) {
48 elem = rb_entry(parent, struct nft_set_elem, node);
49
50 d = nft_data_cmp(&elem->key, key, priv->klen);
51 if (d < 0) {
52 parent = parent->rb_left;
53 interval = elem;
54 } else if (d > 0)
55 parent = parent->rb_right;
56 else {
57found:
58 if (elem->flags & NFT_SE_INTERVAL_END)
59 goto out;
60 if (priv->flags & NFT_SET_MAP)
61 nft_data_copy(&data[priv->dreg], elem->data);
62 return;
63 }
64 }
65
66 if (priv->flags & NFT_SET_INTERVAL && interval != NULL) {
67 elem = interval;
68 goto found;
69 }
70out:
71 data[NFT_REG_VERDICT].verdict = NFT_BREAK;
72}
73
74static void nft_set_elem_destroy(const struct nft_expr *expr,
75 struct nft_set_elem *elem)
76{
77 const struct nft_set *priv = nft_expr_priv(expr);
78
79 nft_data_uninit(&elem->key, NFT_DATA_VALUE);
80 if (priv->flags & NFT_SET_MAP)
81 nft_data_uninit(elem->data, nft_dreg_to_type(priv->dreg));
82 kfree(elem);
83}
84
85static const struct nla_policy nft_se_policy[NFTA_SE_MAX + 1] = {
86 [NFTA_SE_KEY] = { .type = NLA_NESTED },
87 [NFTA_SE_DATA] = { .type = NLA_NESTED },
88 [NFTA_SE_FLAGS] = { .type = NLA_U32 },
89};
90
91static int nft_set_elem_init(const struct nft_ctx *ctx,
92 const struct nft_expr *expr,
93 const struct nlattr *nla,
94 struct nft_set_elem **new)
95{
96 struct nft_set *priv = nft_expr_priv(expr);
97 struct nlattr *tb[NFTA_SE_MAX + 1];
98 struct nft_set_elem *elem;
99 struct nft_data_desc d1, d2;
100 enum nft_set_elem_flags flags = 0;
101 unsigned int size;
102 int err;
103
104 err = nla_parse_nested(tb, NFTA_SE_MAX, nla, nft_se_policy);
105 if (err < 0)
106 return err;
107
108 if (tb[NFTA_SE_KEY] == NULL)
109 return -EINVAL;
110
111 if (tb[NFTA_SE_FLAGS] != NULL) {
112 flags = ntohl(nla_get_be32(tb[NFTA_SE_FLAGS]));
113 if (flags & ~NFT_SE_INTERVAL_END)
114 return -EINVAL;
115 }
116
117 size = sizeof(*elem);
118 if (priv->flags & NFT_SET_MAP) {
119 if (tb[NFTA_SE_DATA] == NULL && !(flags & NFT_SE_INTERVAL_END))
120 return -EINVAL;
121 size += sizeof(elem->data[0]);
122 } else {
123 if (tb[NFTA_SE_DATA] != NULL)
124 return -EINVAL;
125 }
126
127 elem = kzalloc(size, GFP_KERNEL);
128 if (elem == NULL)
129 return -ENOMEM;
130 elem->flags = flags;
131
132 err = nft_data_init(ctx, &elem->key, &d1, tb[NFTA_SE_KEY]);
133 if (err < 0)
134 goto err1;
135 err = -EINVAL;
136 if (d1.type != NFT_DATA_VALUE || d1.len != priv->klen)
137 goto err2;
138
139 if (tb[NFTA_SE_DATA] != NULL) {
140 err = nft_data_init(ctx, elem->data, &d2, tb[NFTA_SE_DATA]);
141 if (err < 0)
142 goto err2;
143 err = -EINVAL;
144 if (priv->dreg != NFT_REG_VERDICT && d2.len != priv->dlen)
145 goto err2;
146 err = nft_validate_data_load(ctx, priv->dreg, elem->data, d2.type);
147 if (err < 0)
148 goto err3;
149 }
150
151 *new = elem;
152 return 0;
153
154err3:
155 nft_data_uninit(elem->data, d2.type);
156err2:
157 nft_data_uninit(&elem->key, d1.type);
158err1:
159 kfree(elem);
160 return err;
161}
162
163static int nft_set_elem_dump(struct sk_buff *skb, const struct nft_expr *expr,
164 const struct nft_set_elem *elem)
165
166{
167 const struct nft_set *priv = nft_expr_priv(expr);
168 struct nlattr *nest;
169
170 nest = nla_nest_start(skb, NFTA_LIST_ELEM);
171 if (nest == NULL)
172 goto nla_put_failure;
173
174 if (nft_data_dump(skb, NFTA_SE_KEY, &elem->key,
175 NFT_DATA_VALUE, priv->klen) < 0)
176 goto nla_put_failure;
177
178 if (priv->flags & NFT_SET_MAP && !(elem->flags & NFT_SE_INTERVAL_END)) {
179 if (nft_data_dump(skb, NFTA_SE_DATA, elem->data,
180 nft_dreg_to_type(priv->dreg), priv->dlen) < 0)
181 goto nla_put_failure;
182 }
183
184 if (elem->flags){
185 if (nla_put_be32(skb, NFTA_SE_FLAGS, htonl(elem->flags)))
186 goto nla_put_failure;
187 }
188
189 nla_nest_end(skb, nest);
190 return 0;
191
192nla_put_failure:
193 return -1;
194}
195
196static void nft_set_destroy(const struct nft_expr *expr)
197{
198 struct nft_set *priv = nft_expr_priv(expr);
199 struct nft_set_elem *elem;
200 struct rb_node *node;
201
202 while ((node = priv->root.rb_node) != NULL) {
203 rb_erase(node, &priv->root);
204 elem = rb_entry(node, struct nft_set_elem, node);
205 nft_set_elem_destroy(expr, elem);
206 }
207}
208
209static const struct nla_policy nft_set_policy[NFTA_SET_MAX + 1] = {
210 [NFTA_SET_FLAGS] = { .type = NLA_U32 },
211 [NFTA_SET_SREG] = { .type = NLA_U32 },
212 [NFTA_SET_DREG] = { .type = NLA_U32 },
213 [NFTA_SET_KLEN] = { .type = NLA_U32 },
214 [NFTA_SET_DLEN] = { .type = NLA_U32 },
215 [NFTA_SET_ELEMENTS] = { .type = NLA_NESTED },
216};
217
218static int nft_set_init(const struct nft_ctx *ctx, const struct nft_expr *expr,
219 const struct nlattr * const tb[])
220{
221 struct nft_set *priv = nft_expr_priv(expr);
222 struct nft_set_elem *elem, *uninitialized_var(new);
223 struct rb_node *parent, **p;
224 const struct nlattr *nla;
225 int err, rem, d;
226
227 if (tb[NFTA_SET_SREG] == NULL ||
228 tb[NFTA_SET_KLEN] == NULL ||
229 tb[NFTA_SET_ELEMENTS] == NULL)
230 return -EINVAL;
231
232 priv->root = RB_ROOT;
233
234 if (tb[NFTA_SET_FLAGS] != NULL) {
235 priv->flags = ntohl(nla_get_be32(tb[NFTA_SET_FLAGS]));
236 if (priv->flags & ~(NFT_SET_INTERVAL | NFT_SET_MAP))
237 return -EINVAL;
238 }
239
240 priv->sreg = ntohl(nla_get_be32(tb[NFTA_SET_SREG]));
241 err = nft_validate_input_register(priv->sreg);
242 if (err < 0)
243 return err;
244
245 if (tb[NFTA_SET_DREG] != NULL) {
246 if (!(priv->flags & NFT_SET_MAP))
247 return -EINVAL;
248 if (tb[NFTA_SET_DLEN] == NULL)
249 return -EINVAL;
250
251 priv->dreg = ntohl(nla_get_be32(tb[NFTA_SET_DREG]));
252 err = nft_validate_output_register(priv->dreg);
253 if (err < 0)
254 return err;
255
256 if (priv->dreg == NFT_REG_VERDICT)
257 priv->dlen = FIELD_SIZEOF(struct nft_data, data);
258 else {
259 priv->dlen = ntohl(nla_get_be32(tb[NFTA_SET_DLEN]));
260 if (priv->dlen == 0 ||
261 priv->dlen > FIELD_SIZEOF(struct nft_data, data))
262 return -EINVAL;
263 }
264 } else {
265 if (priv->flags & NFT_SET_MAP)
266 return -EINVAL;
267 if (tb[NFTA_SET_DLEN] != NULL)
268 return -EINVAL;
269 }
270
271 priv->klen = ntohl(nla_get_be32(tb[NFTA_SET_KLEN]));
272 if (priv->klen == 0 ||
273 priv->klen > FIELD_SIZEOF(struct nft_data, data))
274 return -EINVAL;
275
276 nla_for_each_nested(nla, tb[NFTA_SET_ELEMENTS], rem) {
277 err = -EINVAL;
278 if (nla_type(nla) != NFTA_LIST_ELEM)
279 goto err1;
280
281 err = nft_set_elem_init(ctx, expr, nla, &new);
282 if (err < 0)
283 goto err1;
284
285 parent = NULL;
286 p = &priv->root.rb_node;
287 while (*p != NULL) {
288 parent = *p;
289 elem = rb_entry(parent, struct nft_set_elem, node);
290 d = nft_data_cmp(&elem->key, &new->key, priv->klen);
291 if (d < 0)
292 p = &parent->rb_left;
293 else if (d > 0)
294 p = &parent->rb_right;
295 else {
296 err = -EEXIST;
297 goto err2;
298 }
299 }
300 rb_link_node(&new->node, parent, p);
301 rb_insert_color(&new->node, &priv->root);
302 }
303
304 return 0;
305
306err2:
307 nft_set_elem_destroy(expr, new);
308err1:
309 nft_set_destroy(expr);
310 return err;
311}
312
313static int nft_set_dump(struct sk_buff *skb, const struct nft_expr *expr)
314{
315 struct nft_set *priv = nft_expr_priv(expr);
316 const struct nft_set_elem *elem;
317 struct rb_node *node;
318 struct nlattr *list;
319
320 if (priv->flags) {
321 if (nla_put_be32(skb, NFTA_SET_FLAGS, htonl(priv->flags)))
322 goto nla_put_failure;
323 }
324
325 if (nla_put_be32(skb, NFTA_SET_SREG, htonl(priv->sreg)))
326 goto nla_put_failure;
327 if (nla_put_be32(skb, NFTA_SET_KLEN, htonl(priv->klen)))
328 goto nla_put_failure;
329
330 if (priv->flags & NFT_SET_MAP) {
331 if (nla_put_be32(skb, NFTA_SET_DREG, htonl(priv->dreg)))
332 goto nla_put_failure;
333 if (nla_put_be32(skb, NFTA_SET_DLEN, htonl(priv->dlen)))
334 goto nla_put_failure;
335 }
336
337 list = nla_nest_start(skb, NFTA_SET_ELEMENTS);
338 if (list == NULL)
339 goto nla_put_failure;
340
341 for (node = rb_first(&priv->root); node; node = rb_next(node)) {
342 elem = rb_entry(node, struct nft_set_elem, node);
343 if (nft_set_elem_dump(skb, expr, elem) < 0)
344 goto nla_put_failure;
345 }
346
347 nla_nest_end(skb, list);
348 return 0;
349
350nla_put_failure:
351 return -1;
352}
353
354static struct nft_expr_ops nft_set_ops __read_mostly = {
355 .name = "set",
356 .size = NFT_EXPR_SIZE(sizeof(struct nft_set)),
357 .owner = THIS_MODULE,
358 .eval = nft_set_eval,
359 .init = nft_set_init,
360 .destroy = nft_set_destroy,
361 .dump = nft_set_dump,
362 .policy = nft_set_policy,
363 .maxattr = NFTA_SET_MAX,
364};
365
366static int __init nft_set_module_init(void)
367{
368 return nft_register_expr(&nft_set_ops);
369}
370
371static void __exit nft_set_module_exit(void)
372{
373 nft_unregister_expr(&nft_set_ops);
374}
375
376module_init(nft_set_module_init);
377module_exit(nft_set_module_exit);
378
379MODULE_LICENSE("GPL");
380MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
381MODULE_ALIAS_NFT_EXPR("set");