aboutsummaryrefslogtreecommitdiffstats
path: root/package/network/utils/nftables/patches/201-src-add-support-to-add-flowtables.patch
blob: 888a767160f7ed2744dac617f7003a9d5b419682 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
From: Pablo Neira Ayuso <pablo@netfilter.org>
Date: Thu, 18 Jan 2018 08:43:23 +0100
Subject: [PATCH] src: add support to add flowtables

This patch allows you to create flowtable:

 # nft add table x
 # nft add flowtable x m { hook ingress priority 10\; devices = { eth0, wlan0 }\; }

You have to specify hook and priority. So far, only the ingress hook is
supported. The priority represents where this flowtable is placed in the
ingress hook, which is registered to the devices that the user
specifies.

You can also use the 'create' command instead to bail out in case that
there is an existing flowtable with this name.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---

--- a/include/expression.h
+++ b/include/expression.h
@@ -407,6 +407,8 @@ extern struct expr *prefix_expr_alloc(co
 extern struct expr *range_expr_alloc(const struct location *loc,
 				     struct expr *low, struct expr *high);
 
+extern struct expr *compound_expr_alloc(const struct location *loc,
+					const struct expr_ops *ops);
 extern void compound_expr_add(struct expr *compound, struct expr *expr);
 extern void compound_expr_remove(struct expr *compound, struct expr *expr);
 extern void list_expr_sort(struct list_head *head);
--- a/include/mnl.h
+++ b/include/mnl.h
@@ -92,6 +92,10 @@ int mnl_nft_obj_batch_del(struct nftnl_o
 struct nftnl_flowtable_list *
 mnl_nft_flowtable_dump(struct netlink_ctx *ctx, int family, const char *table);
 
+int mnl_nft_flowtable_batch_add(struct nftnl_flowtable *flo,
+				struct nftnl_batch *batch, unsigned int flags,
+				uint32_t seqnum);
+
 struct nftnl_ruleset *mnl_nft_ruleset_dump(struct netlink_ctx *ctx,
 					   uint32_t family);
 int mnl_nft_event_listener(struct mnl_socket *nf_sock, unsigned int debug_mask,
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -7,6 +7,7 @@
 #include <libnftnl/expr.h>
 #include <libnftnl/set.h>
 #include <libnftnl/object.h>
+#include <libnftnl/flowtable.h>
 
 #include <linux/netlink.h>
 #include <linux/netfilter/nf_tables.h>
@@ -182,6 +183,9 @@ extern int netlink_delete_obj(struct net
 extern int netlink_list_flowtables(struct netlink_ctx *ctx,
 				   const struct handle *h,
 				   const struct location *loc);
+extern int netlink_add_flowtable(struct netlink_ctx *ctx,
+				 const struct handle *h, struct flowtable *ft,
+				 uint32_t flags);
 
 extern void netlink_dump_chain(const struct nftnl_chain *nlc,
 			       struct netlink_ctx *ctx);
--- a/include/rule.h
+++ b/include/rule.h
@@ -322,10 +322,13 @@ uint32_t obj_type_to_cmd(uint32_t type);
 struct flowtable {
 	struct list_head	list;
 	struct handle		handle;
+	struct scope		scope;
 	struct location		location;
+	const char *		hookstr;
 	unsigned int		hooknum;
 	int			priority;
 	const char		**dev_array;
+	struct expr		*dev_expr;
 	int			dev_array_len;
 	unsigned int		refcnt;
 };
@@ -383,6 +386,8 @@ enum cmd_ops {
  * @CMD_OBJ_CHAIN:	chain
  * @CMD_OBJ_CHAINS:	multiple chains
  * @CMD_OBJ_TABLE:	table
+ * @CMD_OBJ_FLOWTABLE:	flowtable
+ * @CMD_OBJ_FLOWTABLES:	flowtables
  * @CMD_OBJ_RULESET:	ruleset
  * @CMD_OBJ_EXPR:	expression
  * @CMD_OBJ_MONITOR:	monitor
@@ -422,6 +427,7 @@ enum cmd_obj {
 	CMD_OBJ_CT_HELPERS,
 	CMD_OBJ_LIMIT,
 	CMD_OBJ_LIMITS,
+	CMD_OBJ_FLOWTABLE,
 	CMD_OBJ_FLOWTABLES,
 };
 
@@ -481,6 +487,7 @@ struct cmd {
 		struct rule	*rule;
 		struct chain	*chain;
 		struct table	*table;
+		struct flowtable *flowtable;
 		struct monitor	*monitor;
 		struct markup	*markup;
 		struct obj	*object;
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -2897,6 +2897,24 @@ static int set_evaluate(struct eval_ctx
 	return 0;
 }
 
+static uint32_t str2hooknum(uint32_t family, const char *hook);
+
+static int flowtable_evaluate(struct eval_ctx *ctx, struct flowtable *ft)
+{
+	struct table *table;
+
+	table = table_lookup_global(ctx);
+	if (table == NULL)
+		return cmd_error(ctx, "Could not process rule: Table '%s' does not exist",
+				 ctx->cmd->handle.table);
+
+	ft->hooknum = str2hooknum(NFPROTO_NETDEV, ft->hookstr);
+	if (ft->hooknum == NF_INET_NUMHOOKS)
+		return chain_error(ctx, ft, "invalid hook %s", ft->hookstr);
+
+	return 0;
+}
+
 static int rule_evaluate(struct eval_ctx *ctx, struct rule *rule)
 {
 	struct stmt *stmt, *tstmt = NULL;
@@ -3069,6 +3087,14 @@ static int cmd_evaluate_add(struct eval_
 		return chain_evaluate(ctx, cmd->chain);
 	case CMD_OBJ_TABLE:
 		return table_evaluate(ctx, cmd->table);
+	case CMD_OBJ_FLOWTABLE:
+		ret = cache_update(ctx->nf_sock, ctx->cache, cmd->op,
+				   ctx->msgs, ctx->debug_mask & NFT_DEBUG_NETLINK, ctx->octx);
+		if (ret < 0)
+			return ret;
+
+		handle_merge(&cmd->flowtable->handle, &cmd->handle);
+		return flowtable_evaluate(ctx, cmd->flowtable);
 	case CMD_OBJ_COUNTER:
 	case CMD_OBJ_QUOTA:
 	case CMD_OBJ_CT_HELPER:
--- a/src/expression.c
+++ b/src/expression.c
@@ -663,8 +663,8 @@ struct expr *range_expr_alloc(const stru
 	return expr;
 }
 
-static struct expr *compound_expr_alloc(const struct location *loc,
-					const struct expr_ops *ops)
+struct expr *compound_expr_alloc(const struct location *loc,
+				 const struct expr_ops *ops)
 {
 	struct expr *expr;
 
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -1011,6 +1011,22 @@ err:
 	return NULL;
 }
 
+int mnl_nft_flowtable_batch_add(struct nftnl_flowtable *flo,
+				struct nftnl_batch *batch, unsigned int flags,
+				uint32_t seqnum)
+{
+	struct nlmsghdr *nlh;
+
+	nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(batch),
+				    NFT_MSG_NEWFLOWTABLE,
+				    nftnl_flowtable_get_u32(flo, NFTNL_FLOWTABLE_FAMILY),
+				    NLM_F_CREATE | flags, seqnum);
+	nftnl_flowtable_nlmsg_build_payload(nlh, flo);
+	mnl_nft_batch_continue(batch);
+
+	return 0;
+}
+
 /*
  * ruleset
  */
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -1773,6 +1773,64 @@ static struct obj *netlink_delinearize_o
 	return obj;
 }
 
+static struct nftnl_flowtable *alloc_nftnl_flowtable(const struct handle *h,
+						     const struct flowtable *ft)
+{
+	struct nftnl_flowtable *flo;
+
+	flo = nftnl_flowtable_alloc();
+	if (flo == NULL)
+		memory_allocation_error();
+
+	nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_FAMILY, h->family);
+	nftnl_flowtable_set_str(flo, NFTNL_FLOWTABLE_TABLE, h->table);
+	if (h->flowtable != NULL)
+		nftnl_flowtable_set_str(flo, NFTNL_FLOWTABLE_NAME, h->flowtable);
+
+	return flo;
+}
+
+static void netlink_dump_flowtable(struct nftnl_flowtable *flo,
+				   struct netlink_ctx *ctx)
+{
+	FILE *fp = ctx->octx->output_fp;
+
+	if (!(ctx->debug_mask & NFT_DEBUG_NETLINK) || !fp)
+		return;
+
+	nftnl_flowtable_fprintf(fp, flo, 0, 0);
+	fprintf(fp, "\n");
+}
+
+int netlink_add_flowtable(struct netlink_ctx *ctx, const struct handle *h,
+			  struct flowtable *ft, uint32_t flags)
+{
+	struct nftnl_flowtable *flo;
+	const char *dev_array[8];
+	struct expr *expr;
+	int i = 0, err;
+
+	flo = alloc_nftnl_flowtable(h, ft);
+	nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_HOOKNUM, ft->hooknum);
+	nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_PRIO, ft->priority);
+
+	list_for_each_entry(expr, &ft->dev_expr->expressions, list)
+		dev_array[i++] = expr->identifier;
+
+	dev_array[i] = NULL;
+	nftnl_flowtable_set_array(flo, NFTNL_FLOWTABLE_DEVICES, dev_array);
+
+	netlink_dump_flowtable(flo, ctx);
+
+	err = mnl_nft_flowtable_batch_add(flo, ctx->batch, flags, ctx->seqnum);
+	if (err < 0)
+		netlink_io_error(ctx, &ft->location, "Could not add flowtable: %s",
+				 strerror(errno));
+	nftnl_flowtable_free(flo);
+
+	return err;
+}
+
 static int list_obj_cb(struct nftnl_obj *nls, void *arg)
 {
 	struct netlink_ctx *ctx = arg;
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -145,6 +145,7 @@ int nft_lex(void *, void *, void *);
 	struct expr		*expr;
 	struct set		*set;
 	struct obj		*obj;
+	struct flowtable	*flowtable;
 	struct counter		*counter;
 	struct quota		*quota;
 	struct ct		*ct;
@@ -189,6 +190,7 @@ int nft_lex(void *, void *, void *);
 
 %token HOOK			"hook"
 %token DEVICE			"device"
+%token DEVICES			"devices"
 %token TABLE			"table"
 %token TABLES			"tables"
 %token CHAIN			"chain"
@@ -200,6 +202,7 @@ int nft_lex(void *, void *, void *);
 %token ELEMENT			"element"
 %token MAP			"map"
 %token MAPS			"maps"
+%token FLOWTABLE		"flowtable"
 %token HANDLE			"handle"
 %token RULESET			"ruleset"
 %token TRACE			"trace"
@@ -500,9 +503,9 @@ int nft_lex(void *, void *, void *);
 %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
 %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
 
-%type <handle>			table_spec chain_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec
-%destructor { handle_free(&$$); } table_spec chain_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec
-%type <handle>			set_spec set_identifier obj_spec obj_identifier
+%type <handle>			table_spec chain_spec flowtable_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec
+%destructor { handle_free(&$$); } table_spec chain_spec flowtable_spec chain_identifier ruleid_spec handle_spec position_spec rule_position ruleset_spec
+%type <handle>			set_spec set_identifier flowtable_identifier obj_spec obj_identifier
 %destructor { handle_free(&$$); } set_spec set_identifier obj_spec obj_identifier
 %type <val>			family_spec family_spec_explicit chain_policy prio_spec
 
@@ -526,6 +529,9 @@ int nft_lex(void *, void *, void *);
 %type <set>			map_block_alloc map_block
 %destructor { set_free($$); }	map_block_alloc
 
+%type <flowtable>		flowtable_block_alloc flowtable_block
+%destructor { flowtable_free($$); }	flowtable_block_alloc
+
 %type <obj>			obj_block_alloc counter_block quota_block ct_helper_block limit_block
 %destructor { obj_free($$); }	obj_block_alloc
 
@@ -606,8 +612,8 @@ int nft_lex(void *, void *, void *);
 %type <expr>			verdict_map_expr verdict_map_list_expr verdict_map_list_member_expr
 %destructor { expr_free($$); }	verdict_map_expr verdict_map_list_expr verdict_map_list_member_expr
 
-%type <expr>			set_expr set_block_expr set_list_expr set_list_member_expr
-%destructor { expr_free($$); }	set_expr set_block_expr set_list_expr set_list_member_expr
+%type <expr>			set_expr set_block_expr set_list_expr set_list_member_expr flowtable_expr flowtable_list_expr flowtable_expr_member
+%destructor { expr_free($$); }	set_expr set_block_expr set_list_expr set_list_member_expr flowtable_expr flowtable_list_expr flowtable_expr_member
 %type <expr>			set_elem_expr set_elem_expr_alloc set_lhs_expr set_rhs_expr
 %destructor { expr_free($$); }	set_elem_expr set_elem_expr_alloc set_lhs_expr set_rhs_expr
 %type <expr>			set_elem_expr_stmt set_elem_expr_stmt_alloc
@@ -872,6 +878,13 @@ add_cmd			:	TABLE		table_spec
 			{
 				$$ = cmd_alloc(CMD_ADD, CMD_OBJ_SETELEM, &$2, &@$, $3);
 			}
+			|	FLOWTABLE	flowtable_spec	flowtable_block_alloc
+						'{'	flowtable_block	'}'
+			{
+				$5->location = @5;
+				handle_merge(&$3->handle, &$2);
+				$$ = cmd_alloc(CMD_ADD, CMD_OBJ_FLOWTABLE, &$2, &@$, $5);
+			}
 			|	COUNTER		obj_spec
 			{
 				struct obj *obj;
@@ -947,6 +960,13 @@ create_cmd		:	TABLE		table_spec
 			{
 				$$ = cmd_alloc(CMD_CREATE, CMD_OBJ_SETELEM, &$2, &@$, $3);
 			}
+			|	FLOWTABLE	flowtable_spec	flowtable_block_alloc
+						'{'	flowtable_block	'}'
+			{
+				$5->location = @5;
+				handle_merge(&$3->handle, &$2);
+				$$ = cmd_alloc(CMD_CREATE, CMD_OBJ_FLOWTABLE, &$2, &@$, $5);
+			}
 			|	COUNTER		obj_spec
 			{
 				struct obj *obj;
@@ -1317,6 +1337,17 @@ table_block		:	/* empty */	{ $$ = $<tabl
 				list_add_tail(&$4->list, &$1->sets);
 				$$ = $1;
 			}
+
+			|	table_block	FLOWTABLE	flowtable_identifier
+					flowtable_block_alloc	'{'	flowtable_block	'}'
+					stmt_separator
+			{
+				$4->location = @3;
+				handle_merge(&$4->handle, &$3);
+				handle_free(&$3);
+				list_add_tail(&$4->list, &$1->flowtables);
+				$$ = $1;
+			}
 			|	table_block	COUNTER		obj_identifier
 					obj_block_alloc	'{'	counter_block	'}'
 					stmt_separator
@@ -1512,6 +1543,62 @@ set_policy_spec		:	PERFORMANCE	{ $$ = NF
 			|	MEMORY		{ $$ = NFT_SET_POL_MEMORY; }
 			;
 
+flowtable_block_alloc	:	/* empty */
+			{
+				$$ = flowtable_alloc(NULL);
+			}
+			;
+
+flowtable_block		:	/* empty */	{ $$ = $<flowtable>-1; }
+			|	flowtable_block	common_block
+			|	flowtable_block	stmt_separator
+			|	flowtable_block	HOOK		STRING	PRIORITY        prio_spec	stmt_separator
+			{
+				$$->hookstr	= chain_hookname_lookup($3);
+				if ($$->hookstr == NULL) {
+					erec_queue(error(&@3, "unknown chain hook %s", $3),
+						   state->msgs);
+					xfree($3);
+					YYERROR;
+				}
+				xfree($3);
+
+				$$->priority = $5;
+			}
+			|	flowtable_block	DEVICES		'='	flowtable_expr	stmt_separator
+			{
+				$$->dev_expr = $4;
+			}
+			;
+
+flowtable_expr		:	'{'	flowtable_list_expr	'}'
+			{
+				$2->location = @$;
+				$$ = $2;
+			}
+			;
+
+flowtable_list_expr	:	flowtable_expr_member
+			{
+				$$ = compound_expr_alloc(&@$, NULL);
+				compound_expr_add($$, $1);
+			}
+			|	flowtable_list_expr	COMMA	flowtable_expr_member
+			{
+				compound_expr_add($1, $3);
+				$$ = $1;
+			}
+			|	flowtable_list_expr	COMMA	opt_newline
+			;
+
+flowtable_expr_member	:	STRING
+			{
+				$$ = symbol_expr_alloc(&@$, SYMBOL_VALUE,
+						       current_scope(state),
+						       $1);
+			}
+			;
+
 data_type_atom_expr	:	type_identifier
 			{
 				const struct datatype *dtype = datatype_lookup_byname($1);
@@ -1720,6 +1807,21 @@ set_identifier		:	identifier
 			}
 			;
 
+
+flowtable_spec		:	table_spec	identifier
+			{
+				$$		= $1;
+				$$.flowtable	= $2;
+			}
+			;
+
+flowtable_identifier	:	identifier
+			{
+				memset(&$$, 0, sizeof($$));
+				$$.flowtable	= $1;
+			}
+			;
+
 obj_spec		:	table_spec	identifier
 			{
 				$$		= $1;
--- a/src/rule.c
+++ b/src/rule.c
@@ -45,6 +45,8 @@ void handle_merge(struct handle *dst, co
 		dst->chain = xstrdup(src->chain);
 	if (dst->set == NULL && src->set != NULL)
 		dst->set = xstrdup(src->set);
+	if (dst->flowtable == NULL && src->flowtable != NULL)
+		dst->flowtable = xstrdup(src->flowtable);
 	if (dst->obj == NULL && src->obj != NULL)
 		dst->obj = xstrdup(src->obj);
 	if (dst->handle.id == 0)
@@ -857,6 +859,7 @@ struct cmd *cmd_alloc(enum cmd_ops op, e
 void nft_cmd_expand(struct cmd *cmd)
 {
 	struct list_head new_cmds;
+	struct flowtable *ft;
 	struct table *table;
 	struct chain *chain;
 	struct rule *rule;
@@ -896,6 +899,14 @@ void nft_cmd_expand(struct cmd *cmd)
 					&set->location, set_get(set));
 			list_add_tail(&new->list, &new_cmds);
 		}
+		list_for_each_entry(ft, &table->flowtables, list) {
+			handle_merge(&ft->handle, &table->handle);
+			memset(&h, 0, sizeof(h));
+			handle_merge(&h, &ft->handle);
+			new = cmd_alloc(CMD_ADD, CMD_OBJ_FLOWTABLE, &h,
+					&ft->location, flowtable_get(ft));
+			list_add_tail(&new->list, &new_cmds);
+		}
 		list_for_each_entry(chain, &table->chains, list) {
 			list_for_each_entry(rule, &chain->rules, list) {
 				memset(&h, 0, sizeof(h));
@@ -982,6 +993,9 @@ void cmd_free(struct cmd *cmd)
 		case CMD_OBJ_LIMIT:
 			obj_free(cmd->object);
 			break;
+		case CMD_OBJ_FLOWTABLE:
+			flowtable_free(cmd->flowtable);
+			break;
 		default:
 			BUG("invalid command object type %u\n", cmd->obj);
 		}
@@ -1071,6 +1085,9 @@ static int do_command_add(struct netlink
 	case CMD_OBJ_CT_HELPER:
 	case CMD_OBJ_LIMIT:
 		return netlink_add_obj(ctx, &cmd->handle, cmd->object, flags);
+	case CMD_OBJ_FLOWTABLE:
+		return netlink_add_flowtable(ctx, &cmd->handle, cmd->flowtable,
+					     flags);
 	default:
 		BUG("invalid command object type %u\n", cmd->obj);
 	}
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -238,6 +238,7 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr
 
 "hook"			{ return HOOK; }
 "device"		{ return DEVICE; }
+"devices"		{ return DEVICES; }
 "table"			{ return TABLE; }
 "tables"		{ return TABLES; }
 "chain"			{ return CHAIN; }
@@ -249,6 +250,7 @@ addrstring	({macaddr}|{ip4addr}|{ip6addr
 "element"		{ return ELEMENT; }
 "map"			{ return MAP; }
 "maps"			{ return MAPS; }
+"flowtable"		{ return FLOWTABLE; }
 "handle"		{ return HANDLE; }
 "ruleset"		{ return RULESET; }
 "trace"			{ return TRACE; }