nftables: update to 0.8.2, backport flowtable support
[openwrt/openwrt.git] / package / network / utils / nftables / patches / 200-src-support-for-flowtable-listing.patch
1 From: Pablo Neira Ayuso <pablo@netfilter.org>
2 Date: Mon, 4 Dec 2017 13:28:25 +0100
3 Subject: [PATCH] src: support for flowtable listing
4
5 This patch allows you to dump existing flowtable.
6
7 # nft list ruleset
8 table ip x {
9 flowtable x {
10 hook ingress priority 10
11 devices = { eth0, tap0 }
12 }
13 }
14
15 You can also list existing flowtables via:
16
17 # nft list flowtables
18 table ip x {
19 flowtable x {
20 hook ingress priority 10
21 devices = { eth0, tap0 }
22 }
23 }
24
25 You need a Linux kernel >= 4.16-rc to test this new feature.
26
27 Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
28 ---
29
30 --- a/include/linux/netfilter/nf_tables.h
31 +++ b/include/linux/netfilter/nf_tables.h
32 @@ -92,6 +92,9 @@ enum nft_verdicts {
33 * @NFT_MSG_GETOBJ: get a stateful object (enum nft_obj_attributes)
34 * @NFT_MSG_DELOBJ: delete a stateful object (enum nft_obj_attributes)
35 * @NFT_MSG_GETOBJ_RESET: get and reset a stateful object (enum nft_obj_attributes)
36 + * @NFT_MSG_NEWFLOWTABLE: add new flow table (enum nft_flowtable_attributes)
37 + * @NFT_MSG_GETFLOWTABLE: get flow table (enum nft_flowtable_attributes)
38 + * @NFT_MSG_DELFLOWTABLE: delete flow table (enum nft_flowtable_attributes)
39 */
40 enum nf_tables_msg_types {
41 NFT_MSG_NEWTABLE,
42 @@ -116,6 +119,9 @@ enum nf_tables_msg_types {
43 NFT_MSG_GETOBJ,
44 NFT_MSG_DELOBJ,
45 NFT_MSG_GETOBJ_RESET,
46 + NFT_MSG_NEWFLOWTABLE,
47 + NFT_MSG_GETFLOWTABLE,
48 + NFT_MSG_DELFLOWTABLE,
49 NFT_MSG_MAX,
50 };
51
52 --- a/include/mnl.h
53 +++ b/include/mnl.h
54 @@ -89,6 +89,9 @@ int mnl_nft_obj_batch_add(struct nftnl_o
55 int mnl_nft_obj_batch_del(struct nftnl_obj *nln, struct nftnl_batch *batch,
56 unsigned int flags, uint32_t seqnum);
57
58 +struct nftnl_flowtable_list *
59 +mnl_nft_flowtable_dump(struct netlink_ctx *ctx, int family, const char *table);
60 +
61 struct nftnl_ruleset *mnl_nft_ruleset_dump(struct netlink_ctx *ctx,
62 uint32_t family);
63 int mnl_nft_event_listener(struct mnl_socket *nf_sock, unsigned int debug_mask,
64 --- a/include/netlink.h
65 +++ b/include/netlink.h
66 @@ -179,6 +179,10 @@ extern int netlink_add_obj(struct netlin
67 extern int netlink_delete_obj(struct netlink_ctx *ctx, const struct handle *h,
68 struct location *loc, uint32_t type);
69
70 +extern int netlink_list_flowtables(struct netlink_ctx *ctx,
71 + const struct handle *h,
72 + const struct location *loc);
73 +
74 extern void netlink_dump_chain(const struct nftnl_chain *nlc,
75 struct netlink_ctx *ctx);
76 extern void netlink_dump_rule(const struct nftnl_rule *nlr,
77 --- a/include/rule.h
78 +++ b/include/rule.h
79 @@ -35,6 +35,7 @@ struct position_spec {
80 * @chain: chain name (chains and rules only)
81 * @set: set name (sets only)
82 * @obj: stateful object name (stateful object only)
83 + * @flowtable: flow table name (flow table only)
84 * @handle: rule handle (rules only)
85 * @position: rule position (rules only)
86 * @set_id: set ID (sets only)
87 @@ -45,6 +46,7 @@ struct handle {
88 const char *chain;
89 const char *set;
90 const char *obj;
91 + const char *flowtable;
92 struct handle_spec handle;
93 struct position_spec position;
94 uint32_t set_id;
95 @@ -98,6 +100,7 @@ enum table_flags {
96 * @chains: chains contained in the table
97 * @sets: sets contained in the table
98 * @objs: stateful objects contained in the table
99 + * @flowtables: flow tables contained in the table
100 * @flags: table flags
101 * @refcnt: table reference counter
102 */
103 @@ -109,6 +112,7 @@ struct table {
104 struct list_head chains;
105 struct list_head sets;
106 struct list_head objs;
107 + struct list_head flowtables;
108 enum table_flags flags;
109 unsigned int refcnt;
110 };
111 @@ -315,6 +319,24 @@ void obj_print_plain(const struct obj *o
112 const char *obj_type_name(uint32_t type);
113 uint32_t obj_type_to_cmd(uint32_t type);
114
115 +struct flowtable {
116 + struct list_head list;
117 + struct handle handle;
118 + struct location location;
119 + unsigned int hooknum;
120 + int priority;
121 + const char **dev_array;
122 + int dev_array_len;
123 + unsigned int refcnt;
124 +};
125 +
126 +extern struct flowtable *flowtable_alloc(const struct location *loc);
127 +extern struct flowtable *flowtable_get(struct flowtable *flowtable);
128 +extern void flowtable_free(struct flowtable *flowtable);
129 +extern void flowtable_add_hash(struct flowtable *flowtable, struct table *table);
130 +
131 +void flowtable_print(const struct flowtable *n, struct output_ctx *octx);
132 +
133 /**
134 * enum cmd_ops - command operations
135 *
136 @@ -373,6 +395,7 @@ enum cmd_ops {
137 * @CMD_OBJ_QUOTAS: multiple quotas
138 * @CMD_OBJ_LIMIT: limit
139 * @CMD_OBJ_LIMITS: multiple limits
140 + * @CMD_OBJ_FLOWTABLES: flow tables
141 */
142 enum cmd_obj {
143 CMD_OBJ_INVALID,
144 @@ -399,6 +422,7 @@ enum cmd_obj {
145 CMD_OBJ_CT_HELPERS,
146 CMD_OBJ_LIMIT,
147 CMD_OBJ_LIMITS,
148 + CMD_OBJ_FLOWTABLES,
149 };
150
151 struct markup {
152 --- a/src/evaluate.c
153 +++ b/src/evaluate.c
154 @@ -3196,6 +3196,7 @@ static int cmd_evaluate_list(struct eval
155 case CMD_OBJ_CT_HELPERS:
156 case CMD_OBJ_LIMITS:
157 case CMD_OBJ_SETS:
158 + case CMD_OBJ_FLOWTABLES:
159 if (cmd->handle.table == NULL)
160 return 0;
161 if (table_lookup(&cmd->handle, ctx->cache) == NULL)
162 --- a/src/mnl.c
163 +++ b/src/mnl.c
164 @@ -17,6 +17,7 @@
165 #include <libnftnl/expr.h>
166 #include <libnftnl/set.h>
167 #include <libnftnl/object.h>
168 +#include <libnftnl/flowtable.h>
169 #include <libnftnl/batch.h>
170
171 #include <linux/netfilter/nfnetlink.h>
172 @@ -953,6 +954,63 @@ int mnl_nft_setelem_get(struct netlink_c
173 return nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, set_elem_cb, nls);
174 }
175
176 +static int flowtable_cb(const struct nlmsghdr *nlh, void *data)
177 +{
178 + struct nftnl_flowtable_list *nln_list = data;
179 + struct nftnl_flowtable *n;
180 +
181 + if (check_genid(nlh) < 0)
182 + return MNL_CB_ERROR;
183 +
184 + n = nftnl_flowtable_alloc();
185 + if (n == NULL)
186 + memory_allocation_error();
187 +
188 + if (nftnl_flowtable_nlmsg_parse(nlh, n) < 0)
189 + goto err_free;
190 +
191 + nftnl_flowtable_list_add_tail(n, nln_list);
192 + return MNL_CB_OK;
193 +
194 +err_free:
195 + nftnl_flowtable_free(n);
196 + return MNL_CB_OK;
197 +}
198 +
199 +struct nftnl_flowtable_list *
200 +mnl_nft_flowtable_dump(struct netlink_ctx *ctx, int family, const char *table)
201 +{
202 + struct nftnl_flowtable_list *nln_list;
203 + char buf[MNL_SOCKET_BUFFER_SIZE];
204 + struct nftnl_flowtable *n;
205 + struct nlmsghdr *nlh;
206 + int ret;
207 +
208 + n = nftnl_flowtable_alloc();
209 + if (n == NULL)
210 + memory_allocation_error();
211 +
212 + nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETFLOWTABLE, family,
213 + NLM_F_DUMP | NLM_F_ACK, ctx->seqnum);
214 + if (table != NULL)
215 + nftnl_flowtable_set_str(n, NFTNL_FLOWTABLE_TABLE, table);
216 + nftnl_flowtable_nlmsg_build_payload(nlh, n);
217 + nftnl_flowtable_free(n);
218 +
219 + nln_list = nftnl_flowtable_list_alloc();
220 + if (nln_list == NULL)
221 + memory_allocation_error();
222 +
223 + ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, flowtable_cb, nln_list);
224 + if (ret < 0)
225 + goto err;
226 +
227 + return nln_list;
228 +err:
229 + nftnl_flowtable_list_free(nln_list);
230 + return NULL;
231 +}
232 +
233 /*
234 * ruleset
235 */
236 --- a/src/netlink.c
237 +++ b/src/netlink.c
238 @@ -23,6 +23,7 @@
239 #include <libnftnl/expr.h>
240 #include <libnftnl/object.h>
241 #include <libnftnl/set.h>
242 +#include <libnftnl/flowtable.h>
243 #include <libnftnl/udata.h>
244 #include <libnftnl/ruleset.h>
245 #include <libnftnl/common.h>
246 @@ -1826,6 +1827,70 @@ int netlink_reset_objs(struct netlink_ct
247 return err;
248 }
249
250 +static struct flowtable *
251 +netlink_delinearize_flowtable(struct netlink_ctx *ctx,
252 + struct nftnl_flowtable *nlo)
253 +{
254 + struct flowtable *flowtable;
255 + const char **dev_array;
256 + int len = 0, i;
257 +
258 + flowtable = flowtable_alloc(&netlink_location);
259 + flowtable->handle.family =
260 + nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_FAMILY);
261 + flowtable->handle.table =
262 + xstrdup(nftnl_flowtable_get_str(nlo, NFTNL_FLOWTABLE_TABLE));
263 + flowtable->handle.flowtable =
264 + xstrdup(nftnl_flowtable_get_str(nlo, NFTNL_FLOWTABLE_NAME));
265 + dev_array = nftnl_flowtable_get_array(nlo, NFTNL_FLOWTABLE_DEVICES);
266 + while (dev_array[len] != '\0')
267 + len++;
268 +
269 + flowtable->dev_array = calloc(1, len * sizeof(char *));
270 + for (i = 0; i < len; i++)
271 + flowtable->dev_array[i] = xstrdup(dev_array[i]);
272 +
273 + flowtable->dev_array_len = len;
274 +
275 + flowtable->priority =
276 + nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_PRIO);
277 + flowtable->hooknum =
278 + nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_HOOKNUM);
279 +
280 + return flowtable;
281 +}
282 +
283 +static int list_flowtable_cb(struct nftnl_flowtable *nls, void *arg)
284 +{
285 + struct netlink_ctx *ctx = arg;
286 + struct flowtable *flowtable;
287 +
288 + flowtable = netlink_delinearize_flowtable(ctx, nls);
289 + if (flowtable == NULL)
290 + return -1;
291 + list_add_tail(&flowtable->list, &ctx->list);
292 + return 0;
293 +}
294 +
295 +int netlink_list_flowtables(struct netlink_ctx *ctx, const struct handle *h,
296 + const struct location *loc)
297 +{
298 + struct nftnl_flowtable_list *flowtable_cache;
299 + int err;
300 +
301 + flowtable_cache = mnl_nft_flowtable_dump(ctx, h->family, h->table);
302 + if (flowtable_cache == NULL) {
303 + if (errno == EINTR)
304 + return -1;
305 +
306 + return 0;
307 + }
308 +
309 + err = nftnl_flowtable_list_foreach(flowtable_cache, list_flowtable_cb, ctx);
310 + nftnl_flowtable_list_free(flowtable_cache);
311 + return err;
312 +}
313 +
314 int netlink_batch_send(struct netlink_ctx *ctx, struct list_head *err_list)
315 {
316 return mnl_batch_talk(ctx, err_list);
317 --- a/src/parser_bison.y
318 +++ b/src/parser_bison.y
319 @@ -248,6 +248,8 @@ int nft_lex(void *, void *, void *);
320 %token METER "meter"
321 %token METERS "meters"
322
323 +%token FLOWTABLES "flowtables"
324 +
325 %token <val> NUM "number"
326 %token <string> STRING "string"
327 %token <string> QUOTED_STRING "quoted string"
328 @@ -1104,6 +1106,10 @@ list_cmd : TABLE table_spec
329 {
330 $$ = cmd_alloc(CMD_LIST, CMD_OBJ_METER, &$2, &@$, NULL);
331 }
332 + | FLOWTABLES ruleset_spec
333 + {
334 + $$ = cmd_alloc(CMD_LIST, CMD_OBJ_FLOWTABLES, &$2, &@$, NULL);
335 + }
336 | MAPS ruleset_spec
337 {
338 $$ = cmd_alloc(CMD_LIST, CMD_OBJ_MAPS, &$2, &@$, NULL);
339 --- a/src/rule.c
340 +++ b/src/rule.c
341 @@ -95,6 +95,11 @@ static int cache_init_objects(struct net
342 return -1;
343 list_splice_tail_init(&ctx->list, &table->chains);
344
345 + ret = netlink_list_flowtables(ctx, &table->handle, &internal_location);
346 + if (ret < 0)
347 + return -1;
348 + list_splice_tail_init(&ctx->list, &table->flowtables);
349 +
350 if (cmd != CMD_RESET) {
351 ret = netlink_list_objs(ctx, &table->handle, &internal_location);
352 if (ret < 0)
353 @@ -722,6 +727,7 @@ struct table *table_alloc(void)
354 init_list_head(&table->chains);
355 init_list_head(&table->sets);
356 init_list_head(&table->objs);
357 + init_list_head(&table->flowtables);
358 init_list_head(&table->scope.symbols);
359 table->refcnt = 1;
360
361 @@ -797,6 +803,7 @@ static void table_print_options(const st
362
363 static void table_print(const struct table *table, struct output_ctx *octx)
364 {
365 + struct flowtable *flowtable;
366 struct chain *chain;
367 struct obj *obj;
368 struct set *set;
369 @@ -818,6 +825,11 @@ static void table_print(const struct tab
370 set_print(set, octx);
371 delim = "\n";
372 }
373 + list_for_each_entry(flowtable, &table->flowtables, list) {
374 + nft_print(octx, "%s", delim);
375 + flowtable_print(flowtable, octx);
376 + delim = "\n";
377 + }
378 list_for_each_entry(chain, &table->chains, list) {
379 nft_print(octx, "%s", delim);
380 chain_print(chain, octx);
381 @@ -1481,6 +1493,114 @@ static int do_list_obj(struct netlink_ct
382 return 0;
383 }
384
385 +struct flowtable *flowtable_alloc(const struct location *loc)
386 +{
387 + struct flowtable *flowtable;
388 +
389 + flowtable = xzalloc(sizeof(*flowtable));
390 + if (loc != NULL)
391 + flowtable->location = *loc;
392 +
393 + flowtable->refcnt = 1;
394 + return flowtable;
395 +}
396 +
397 +struct flowtable *flowtable_get(struct flowtable *flowtable)
398 +{
399 + flowtable->refcnt++;
400 + return flowtable;
401 +}
402 +
403 +void flowtable_free(struct flowtable *flowtable)
404 +{
405 + if (--flowtable->refcnt > 0)
406 + return;
407 + handle_free(&flowtable->handle);
408 + xfree(flowtable);
409 +}
410 +
411 +void flowtable_add_hash(struct flowtable *flowtable, struct table *table)
412 +{
413 + list_add_tail(&flowtable->list, &table->flowtables);
414 +}
415 +
416 +static void flowtable_print_declaration(const struct flowtable *flowtable,
417 + struct print_fmt_options *opts,
418 + struct output_ctx *octx)
419 +{
420 + int i;
421 +
422 + nft_print(octx, "%sflowtable", opts->tab);
423 +
424 + if (opts->family != NULL)
425 + nft_print(octx, " %s", opts->family);
426 +
427 + if (opts->table != NULL)
428 + nft_print(octx, " %s", opts->table);
429 +
430 + nft_print(octx, " %s {%s", flowtable->handle.flowtable, opts->nl);
431 +
432 + nft_print(octx, "%s%shook %s priority %d%s",
433 + opts->tab, opts->tab, "ingress",
434 + flowtable->priority, opts->stmt_separator);
435 +
436 + nft_print(octx, "%s%sdevices = { ", opts->tab, opts->tab);
437 + for (i = 0; i < flowtable->dev_array_len; i++) {
438 + nft_print(octx, "%s", flowtable->dev_array[i]);
439 + if (i + 1 != flowtable->dev_array_len)
440 + nft_print(octx, ", ");
441 + }
442 + nft_print(octx, " }%s", opts->stmt_separator);
443 +}
444 +
445 +static void do_flowtable_print(const struct flowtable *flowtable,
446 + struct print_fmt_options *opts,
447 + struct output_ctx *octx)
448 +{
449 + flowtable_print_declaration(flowtable, opts, octx);
450 + nft_print(octx, "%s}%s", opts->tab, opts->nl);
451 +}
452 +
453 +void flowtable_print(const struct flowtable *s, struct output_ctx *octx)
454 +{
455 + struct print_fmt_options opts = {
456 + .tab = "\t",
457 + .nl = "\n",
458 + .stmt_separator = "\n",
459 + };
460 +
461 + do_flowtable_print(s, &opts, octx);
462 +}
463 +
464 +static int do_list_flowtables(struct netlink_ctx *ctx, struct cmd *cmd)
465 +{
466 + struct print_fmt_options opts = {
467 + .tab = "\t",
468 + .nl = "\n",
469 + .stmt_separator = "\n",
470 + };
471 + struct flowtable *flowtable;
472 + struct table *table;
473 +
474 + list_for_each_entry(table, &ctx->cache->list, list) {
475 + if (cmd->handle.family != NFPROTO_UNSPEC &&
476 + cmd->handle.family != table->handle.family)
477 + continue;
478 +
479 + nft_print(ctx->octx, "table %s %s {\n",
480 + family2str(table->handle.family),
481 + table->handle.table);
482 +
483 + list_for_each_entry(flowtable, &table->flowtables, list) {
484 + flowtable_print_declaration(flowtable, &opts, ctx->octx);
485 + nft_print(ctx->octx, "%s}%s", opts.tab, opts.nl);
486 + }
487 +
488 + nft_print(ctx->octx, "}\n");
489 + }
490 + return 0;
491 +}
492 +
493 static int do_list_ruleset(struct netlink_ctx *ctx, struct cmd *cmd)
494 {
495 unsigned int family = cmd->handle.family;
496 @@ -1628,6 +1748,8 @@ static int do_command_list(struct netlin
497 case CMD_OBJ_LIMIT:
498 case CMD_OBJ_LIMITS:
499 return do_list_obj(ctx, cmd, NFT_OBJECT_LIMIT);
500 + case CMD_OBJ_FLOWTABLES:
501 + return do_list_flowtables(ctx, cmd);
502 default:
503 BUG("invalid command object type %u\n", cmd->obj);
504 }
505 --- a/src/scanner.l
506 +++ b/src/scanner.l
507 @@ -297,6 +297,8 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr
508 "meter" { return METER; }
509 "meters" { return METERS; }
510
511 +"flowtables" { return FLOWTABLES; }
512 +
513 "counter" { return COUNTER; }
514 "name" { return NAME; }
515 "packets" { return PACKETS; }