nftables: update to 0.8.2, backport flowtable support
[openwrt/openwrt.git] / package / network / utils / nftables / patches / 201-src-add-support-to-add-flowtables.patch
1 From: Pablo Neira Ayuso <pablo@netfilter.org>
2 Date: Thu, 18 Jan 2018 08:43:23 +0100
3 Subject: [PATCH] src: add support to add flowtables
4
5 This patch allows you to create flowtable:
6
7 # nft add table x
8 # nft add flowtable x m { hook ingress priority 10\; devices = { eth0, wlan0 }\; }
9
10 You have to specify hook and priority. So far, only the ingress hook is
11 supported. The priority represents where this flowtable is placed in the
12 ingress hook, which is registered to the devices that the user
13 specifies.
14
15 You can also use the 'create' command instead to bail out in case that
16 there is an existing flowtable with this name.
17
18 Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
19 ---
20
21 --- a/include/expression.h
22 +++ b/include/expression.h
23 @@ -407,6 +407,8 @@ extern struct expr *prefix_expr_alloc(co
24 extern struct expr *range_expr_alloc(const struct location *loc,
25 struct expr *low, struct expr *high);
26
27 +extern struct expr *compound_expr_alloc(const struct location *loc,
28 + const struct expr_ops *ops);
29 extern void compound_expr_add(struct expr *compound, struct expr *expr);
30 extern void compound_expr_remove(struct expr *compound, struct expr *expr);
31 extern void list_expr_sort(struct list_head *head);
32 --- a/include/mnl.h
33 +++ b/include/mnl.h
34 @@ -92,6 +92,10 @@ int mnl_nft_obj_batch_del(struct nftnl_o
35 struct nftnl_flowtable_list *
36 mnl_nft_flowtable_dump(struct netlink_ctx *ctx, int family, const char *table);
37
38 +int mnl_nft_flowtable_batch_add(struct nftnl_flowtable *flo,
39 + struct nftnl_batch *batch, unsigned int flags,
40 + uint32_t seqnum);
41 +
42 struct nftnl_ruleset *mnl_nft_ruleset_dump(struct netlink_ctx *ctx,
43 uint32_t family);
44 int mnl_nft_event_listener(struct mnl_socket *nf_sock, unsigned int debug_mask,
45 --- a/include/netlink.h
46 +++ b/include/netlink.h
47 @@ -7,6 +7,7 @@
48 #include <libnftnl/expr.h>
49 #include <libnftnl/set.h>
50 #include <libnftnl/object.h>
51 +#include <libnftnl/flowtable.h>
52
53 #include <linux/netlink.h>
54 #include <linux/netfilter/nf_tables.h>
55 @@ -182,6 +183,9 @@ extern int netlink_delete_obj(struct net
56 extern int netlink_list_flowtables(struct netlink_ctx *ctx,
57 const struct handle *h,
58 const struct location *loc);
59 +extern int netlink_add_flowtable(struct netlink_ctx *ctx,
60 + const struct handle *h, struct flowtable *ft,
61 + uint32_t flags);
62
63 extern void netlink_dump_chain(const struct nftnl_chain *nlc,
64 struct netlink_ctx *ctx);
65 --- a/include/rule.h
66 +++ b/include/rule.h
67 @@ -322,10 +322,13 @@ uint32_t obj_type_to_cmd(uint32_t type);
68 struct flowtable {
69 struct list_head list;
70 struct handle handle;
71 + struct scope scope;
72 struct location location;
73 + const char * hookstr;
74 unsigned int hooknum;
75 int priority;
76 const char **dev_array;
77 + struct expr *dev_expr;
78 int dev_array_len;
79 unsigned int refcnt;
80 };
81 @@ -383,6 +386,8 @@ enum cmd_ops {
82 * @CMD_OBJ_CHAIN: chain
83 * @CMD_OBJ_CHAINS: multiple chains
84 * @CMD_OBJ_TABLE: table
85 + * @CMD_OBJ_FLOWTABLE: flowtable
86 + * @CMD_OBJ_FLOWTABLES: flowtables
87 * @CMD_OBJ_RULESET: ruleset
88 * @CMD_OBJ_EXPR: expression
89 * @CMD_OBJ_MONITOR: monitor
90 @@ -422,6 +427,7 @@ enum cmd_obj {
91 CMD_OBJ_CT_HELPERS,
92 CMD_OBJ_LIMIT,
93 CMD_OBJ_LIMITS,
94 + CMD_OBJ_FLOWTABLE,
95 CMD_OBJ_FLOWTABLES,
96 };
97
98 @@ -481,6 +487,7 @@ struct cmd {
99 struct rule *rule;
100 struct chain *chain;
101 struct table *table;
102 + struct flowtable *flowtable;
103 struct monitor *monitor;
104 struct markup *markup;
105 struct obj *object;
106 --- a/src/evaluate.c
107 +++ b/src/evaluate.c
108 @@ -2897,6 +2897,24 @@ static int set_evaluate(struct eval_ctx
109 return 0;
110 }
111
112 +static uint32_t str2hooknum(uint32_t family, const char *hook);
113 +
114 +static int flowtable_evaluate(struct eval_ctx *ctx, struct flowtable *ft)
115 +{
116 + struct table *table;
117 +
118 + table = table_lookup_global(ctx);
119 + if (table == NULL)
120 + return cmd_error(ctx, "Could not process rule: Table '%s' does not exist",
121 + ctx->cmd->handle.table);
122 +
123 + ft->hooknum = str2hooknum(NFPROTO_NETDEV, ft->hookstr);
124 + if (ft->hooknum == NF_INET_NUMHOOKS)
125 + return chain_error(ctx, ft, "invalid hook %s", ft->hookstr);
126 +
127 + return 0;
128 +}
129 +
130 static int rule_evaluate(struct eval_ctx *ctx, struct rule *rule)
131 {
132 struct stmt *stmt, *tstmt = NULL;
133 @@ -3069,6 +3087,14 @@ static int cmd_evaluate_add(struct eval_
134 return chain_evaluate(ctx, cmd->chain);
135 case CMD_OBJ_TABLE:
136 return table_evaluate(ctx, cmd->table);
137 + case CMD_OBJ_FLOWTABLE:
138 + ret = cache_update(ctx->nf_sock, ctx->cache, cmd->op,
139 + ctx->msgs, ctx->debug_mask & NFT_DEBUG_NETLINK, ctx->octx);
140 + if (ret < 0)
141 + return ret;
142 +
143 + handle_merge(&cmd->flowtable->handle, &cmd->handle);
144 + return flowtable_evaluate(ctx, cmd->flowtable);
145 case CMD_OBJ_COUNTER:
146 case CMD_OBJ_QUOTA:
147 case CMD_OBJ_CT_HELPER:
148 --- a/src/expression.c
149 +++ b/src/expression.c
150 @@ -663,8 +663,8 @@ struct expr *range_expr_alloc(const stru
151 return expr;
152 }
153
154 -static struct expr *compound_expr_alloc(const struct location *loc,
155 - const struct expr_ops *ops)
156 +struct expr *compound_expr_alloc(const struct location *loc,
157 + const struct expr_ops *ops)
158 {
159 struct expr *expr;
160
161 --- a/src/mnl.c
162 +++ b/src/mnl.c
163 @@ -1011,6 +1011,22 @@ err:
164 return NULL;
165 }
166
167 +int mnl_nft_flowtable_batch_add(struct nftnl_flowtable *flo,
168 + struct nftnl_batch *batch, unsigned int flags,
169 + uint32_t seqnum)
170 +{
171 + struct nlmsghdr *nlh;
172 +
173 + nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(batch),
174 + NFT_MSG_NEWFLOWTABLE,
175 + nftnl_flowtable_get_u32(flo, NFTNL_FLOWTABLE_FAMILY),
176 + NLM_F_CREATE | flags, seqnum);
177 + nftnl_flowtable_nlmsg_build_payload(nlh, flo);
178 + mnl_nft_batch_continue(batch);
179 +
180 + return 0;
181 +}
182 +
183 /*
184 * ruleset
185 */
186 --- a/src/netlink.c
187 +++ b/src/netlink.c
188 @@ -1773,6 +1773,64 @@ static struct obj *netlink_delinearize_o
189 return obj;
190 }
191
192 +static struct nftnl_flowtable *alloc_nftnl_flowtable(const struct handle *h,
193 + const struct flowtable *ft)
194 +{
195 + struct nftnl_flowtable *flo;
196 +
197 + flo = nftnl_flowtable_alloc();
198 + if (flo == NULL)
199 + memory_allocation_error();
200 +
201 + nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_FAMILY, h->family);
202 + nftnl_flowtable_set_str(flo, NFTNL_FLOWTABLE_TABLE, h->table);
203 + if (h->flowtable != NULL)
204 + nftnl_flowtable_set_str(flo, NFTNL_FLOWTABLE_NAME, h->flowtable);
205 +
206 + return flo;
207 +}
208 +
209 +static void netlink_dump_flowtable(struct nftnl_flowtable *flo,
210 + struct netlink_ctx *ctx)
211 +{
212 + FILE *fp = ctx->octx->output_fp;
213 +
214 + if (!(ctx->debug_mask & NFT_DEBUG_NETLINK) || !fp)
215 + return;
216 +
217 + nftnl_flowtable_fprintf(fp, flo, 0, 0);
218 + fprintf(fp, "\n");
219 +}
220 +
221 +int netlink_add_flowtable(struct netlink_ctx *ctx, const struct handle *h,
222 + struct flowtable *ft, uint32_t flags)
223 +{
224 + struct nftnl_flowtable *flo;
225 + const char *dev_array[8];
226 + struct expr *expr;
227 + int i = 0, err;
228 +
229 + flo = alloc_nftnl_flowtable(h, ft);
230 + nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_HOOKNUM, ft->hooknum);
231 + nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_PRIO, ft->priority);
232 +
233 + list_for_each_entry(expr, &ft->dev_expr->expressions, list)
234 + dev_array[i++] = expr->identifier;
235 +
236 + dev_array[i] = NULL;
237 + nftnl_flowtable_set_array(flo, NFTNL_FLOWTABLE_DEVICES, dev_array);
238 +
239 + netlink_dump_flowtable(flo, ctx);
240 +
241 + err = mnl_nft_flowtable_batch_add(flo, ctx->batch, flags, ctx->seqnum);
242 + if (err < 0)
243 + netlink_io_error(ctx, &ft->location, "Could not add flowtable: %s",
244 + strerror(errno));
245 + nftnl_flowtable_free(flo);
246 +
247 + return err;
248 +}
249 +
250 static int list_obj_cb(struct nftnl_obj *nls, void *arg)
251 {
252 struct netlink_ctx *ctx = arg;
253 --- a/src/parser_bison.y
254 +++ b/src/parser_bison.y
255 @@ -145,6 +145,7 @@ int nft_lex(void *, void *, void *);
256 struct expr *expr;
257 struct set *set;
258 struct obj *obj;
259 + struct flowtable *flowtable;
260 struct counter *counter;
261 struct quota *quota;
262 struct ct *ct;
263 @@ -189,6 +190,7 @@ int nft_lex(void *, void *, void *);
264
265 %token HOOK "hook"
266 %token DEVICE "device"
267 +%token DEVICES "devices"
268 %token TABLE "table"
269 %token TABLES "tables"
270 %token CHAIN "chain"
271 @@ -200,6 +202,7 @@ int nft_lex(void *, void *, void *);
272 %token ELEMENT "element"
273 %token MAP "map"
274 %token MAPS "maps"
275 +%token FLOWTABLE "flowtable"
276 %token HANDLE "handle"
277 %token RULESET "ruleset"
278 %token TRACE "trace"
279 @@ -500,9 +503,9 @@ int nft_lex(void *, void *, void *);
280 %type <cmd> base_cmd add_cmd replace_cmd create_cmd insert_cmd delete_cmd list_cmd reset_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd import_cmd
281 %destructor { cmd_free($$); } base_cmd add_cmd replace_cmd create_cmd insert_cmd delete_cmd list_cmd reset_cmd flush_cmd rename_cmd export_cmd monitor_cmd describe_cmd import_cmd
282
283 -%type <handle> table_spec chain_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec
284 -%destructor { handle_free(&$$); } table_spec chain_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec
285 -%type <handle> set_spec set_identifier obj_spec obj_identifier
286 +%type <handle> table_spec chain_spec flowtable_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec
287 +%destructor { handle_free(&$$); } table_spec chain_spec flowtable_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec
288 +%type <handle> set_spec set_identifier flowtable_identifier obj_spec obj_identifier
289 %destructor { handle_free(&$$); } set_spec set_identifier obj_spec obj_identifier
290 %type <val> family_spec family_spec_explicit chain_policy prio_spec
291
292 @@ -526,6 +529,9 @@ int nft_lex(void *, void *, void *);
293 %type <set> map_block_alloc map_block
294 %destructor { set_free($$); } map_block_alloc
295
296 +%type <flowtable> flowtable_block_alloc flowtable_block
297 +%destructor { flowtable_free($$); } flowtable_block_alloc
298 +
299 %type <obj> obj_block_alloc counter_block quota_block ct_helper_block limit_block
300 %destructor { obj_free($$); } obj_block_alloc
301
302 @@ -606,8 +612,8 @@ int nft_lex(void *, void *, void *);
303 %type <expr> verdict_map_expr verdict_map_list_expr verdict_map_list_member_expr
304 %destructor { expr_free($$); } verdict_map_expr verdict_map_list_expr verdict_map_list_member_expr
305
306 -%type <expr> set_expr set_block_expr set_list_expr set_list_member_expr
307 -%destructor { expr_free($$); } set_expr set_block_expr set_list_expr set_list_member_expr
308 +%type <expr> set_expr set_block_expr set_list_expr set_list_member_expr flowtable_expr flowtable_list_expr flowtable_expr_member
309 +%destructor { expr_free($$); } set_expr set_block_expr set_list_expr set_list_member_expr flowtable_expr flowtable_list_expr flowtable_expr_member
310 %type <expr> set_elem_expr set_elem_expr_alloc set_lhs_expr set_rhs_expr
311 %destructor { expr_free($$); } set_elem_expr set_elem_expr_alloc set_lhs_expr set_rhs_expr
312 %type <expr> set_elem_expr_stmt set_elem_expr_stmt_alloc
313 @@ -872,6 +878,13 @@ add_cmd : TABLE table_spec
314 {
315 $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SETELEM, &$2, &@$, $3);
316 }
317 + | FLOWTABLE flowtable_spec flowtable_block_alloc
318 + '{' flowtable_block '}'
319 + {
320 + $5->location = @5;
321 + handle_merge(&$3->handle, &$2);
322 + $$ = cmd_alloc(CMD_ADD, CMD_OBJ_FLOWTABLE, &$2, &@$, $5);
323 + }
324 | COUNTER obj_spec
325 {
326 struct obj *obj;
327 @@ -947,6 +960,13 @@ create_cmd : TABLE table_spec
328 {
329 $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_SETELEM, &$2, &@$, $3);
330 }
331 + | FLOWTABLE flowtable_spec flowtable_block_alloc
332 + '{' flowtable_block '}'
333 + {
334 + $5->location = @5;
335 + handle_merge(&$3->handle, &$2);
336 + $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_FLOWTABLE, &$2, &@$, $5);
337 + }
338 | COUNTER obj_spec
339 {
340 struct obj *obj;
341 @@ -1317,6 +1337,17 @@ table_block : /* empty */ { $$ = $<tabl
342 list_add_tail(&$4->list, &$1->sets);
343 $$ = $1;
344 }
345 +
346 + | table_block FLOWTABLE flowtable_identifier
347 + flowtable_block_alloc '{' flowtable_block '}'
348 + stmt_separator
349 + {
350 + $4->location = @3;
351 + handle_merge(&$4->handle, &$3);
352 + handle_free(&$3);
353 + list_add_tail(&$4->list, &$1->flowtables);
354 + $$ = $1;
355 + }
356 | table_block COUNTER obj_identifier
357 obj_block_alloc '{' counter_block '}'
358 stmt_separator
359 @@ -1512,6 +1543,62 @@ set_policy_spec : PERFORMANCE { $$ = NF
360 | MEMORY { $$ = NFT_SET_POL_MEMORY; }
361 ;
362
363 +flowtable_block_alloc : /* empty */
364 + {
365 + $$ = flowtable_alloc(NULL);
366 + }
367 + ;
368 +
369 +flowtable_block : /* empty */ { $$ = $<flowtable>-1; }
370 + | flowtable_block common_block
371 + | flowtable_block stmt_separator
372 + | flowtable_block HOOK STRING PRIORITY prio_spec stmt_separator
373 + {
374 + $$->hookstr = chain_hookname_lookup($3);
375 + if ($$->hookstr == NULL) {
376 + erec_queue(error(&@3, "unknown chain hook %s", $3),
377 + state->msgs);
378 + xfree($3);
379 + YYERROR;
380 + }
381 + xfree($3);
382 +
383 + $$->priority = $5;
384 + }
385 + | flowtable_block DEVICES '=' flowtable_expr stmt_separator
386 + {
387 + $$->dev_expr = $4;
388 + }
389 + ;
390 +
391 +flowtable_expr : '{' flowtable_list_expr '}'
392 + {
393 + $2->location = @$;
394 + $$ = $2;
395 + }
396 + ;
397 +
398 +flowtable_list_expr : flowtable_expr_member
399 + {
400 + $$ = compound_expr_alloc(&@$, NULL);
401 + compound_expr_add($$, $1);
402 + }
403 + | flowtable_list_expr COMMA flowtable_expr_member
404 + {
405 + compound_expr_add($1, $3);
406 + $$ = $1;
407 + }
408 + | flowtable_list_expr COMMA opt_newline
409 + ;
410 +
411 +flowtable_expr_member : STRING
412 + {
413 + $$ = symbol_expr_alloc(&@$, SYMBOL_VALUE,
414 + current_scope(state),
415 + $1);
416 + }
417 + ;
418 +
419 data_type_atom_expr : type_identifier
420 {
421 const struct datatype *dtype = datatype_lookup_byname($1);
422 @@ -1720,6 +1807,21 @@ set_identifier : identifier
423 }
424 ;
425
426 +
427 +flowtable_spec : table_spec identifier
428 + {
429 + $$ = $1;
430 + $$.flowtable = $2;
431 + }
432 + ;
433 +
434 +flowtable_identifier : identifier
435 + {
436 + memset(&$$, 0, sizeof($$));
437 + $$.flowtable = $1;
438 + }
439 + ;
440 +
441 obj_spec : table_spec identifier
442 {
443 $$ = $1;
444 --- a/src/rule.c
445 +++ b/src/rule.c
446 @@ -45,6 +45,8 @@ void handle_merge(struct handle *dst, co
447 dst->chain = xstrdup(src->chain);
448 if (dst->set == NULL && src->set != NULL)
449 dst->set = xstrdup(src->set);
450 + if (dst->flowtable == NULL && src->flowtable != NULL)
451 + dst->flowtable = xstrdup(src->flowtable);
452 if (dst->obj == NULL && src->obj != NULL)
453 dst->obj = xstrdup(src->obj);
454 if (dst->handle.id == 0)
455 @@ -857,6 +859,7 @@ struct cmd *cmd_alloc(enum cmd_ops op, e
456 void nft_cmd_expand(struct cmd *cmd)
457 {
458 struct list_head new_cmds;
459 + struct flowtable *ft;
460 struct table *table;
461 struct chain *chain;
462 struct rule *rule;
463 @@ -896,6 +899,14 @@ void nft_cmd_expand(struct cmd *cmd)
464 &set->location, set_get(set));
465 list_add_tail(&new->list, &new_cmds);
466 }
467 + list_for_each_entry(ft, &table->flowtables, list) {
468 + handle_merge(&ft->handle, &table->handle);
469 + memset(&h, 0, sizeof(h));
470 + handle_merge(&h, &ft->handle);
471 + new = cmd_alloc(CMD_ADD, CMD_OBJ_FLOWTABLE, &h,
472 + &ft->location, flowtable_get(ft));
473 + list_add_tail(&new->list, &new_cmds);
474 + }
475 list_for_each_entry(chain, &table->chains, list) {
476 list_for_each_entry(rule, &chain->rules, list) {
477 memset(&h, 0, sizeof(h));
478 @@ -982,6 +993,9 @@ void cmd_free(struct cmd *cmd)
479 case CMD_OBJ_LIMIT:
480 obj_free(cmd->object);
481 break;
482 + case CMD_OBJ_FLOWTABLE:
483 + flowtable_free(cmd->flowtable);
484 + break;
485 default:
486 BUG("invalid command object type %u\n", cmd->obj);
487 }
488 @@ -1071,6 +1085,9 @@ static int do_command_add(struct netlink
489 case CMD_OBJ_CT_HELPER:
490 case CMD_OBJ_LIMIT:
491 return netlink_add_obj(ctx, &cmd->handle, cmd->object, flags);
492 + case CMD_OBJ_FLOWTABLE:
493 + return netlink_add_flowtable(ctx, &cmd->handle, cmd->flowtable,
494 + flags);
495 default:
496 BUG("invalid command object type %u\n", cmd->obj);
497 }
498 --- a/src/scanner.l
499 +++ b/src/scanner.l
500 @@ -238,6 +238,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr
501
502 "hook" { return HOOK; }
503 "device" { return DEVICE; }
504 +"devices" { return DEVICES; }
505 "table" { return TABLE; }
506 "tables" { return TABLES; }
507 "chain" { return CHAIN; }
508 @@ -249,6 +250,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr
509 "element" { return ELEMENT; }
510 "map" { return MAP; }
511 "maps" { return MAPS; }
512 +"flowtable" { return FLOWTABLE; }
513 "handle" { return HANDLE; }
514 "ruleset" { return RULESET; }
515 "trace" { return TRACE; }