|
|
@@ -0,0 +1,515 @@
|
|
|
+From: Pablo Neira Ayuso <[email protected]>
|
|
|
+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 <[email protected]>
|
|
|
+---
|
|
|
+
|
|
|
+--- 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; }
|