diff options
-rw-r--r-- | include/expression.h | 2 | ||||
-rw-r--r-- | include/mnl.h | 4 | ||||
-rw-r--r-- | include/netlink.h | 4 | ||||
-rw-r--r-- | include/rule.h | 7 | ||||
-rw-r--r-- | src/evaluate.c | 26 | ||||
-rw-r--r-- | src/expression.c | 4 | ||||
-rw-r--r-- | src/mnl.c | 16 | ||||
-rw-r--r-- | src/netlink.c | 58 | ||||
-rw-r--r-- | src/parser_bison.y | 112 | ||||
-rw-r--r-- | src/rule.c | 17 | ||||
-rw-r--r-- | src/scanner.l | 2 |
11 files changed, 245 insertions, 7 deletions
diff --git a/include/expression.h b/include/expression.h index 7b9b6229..6f4edbf5 100644 --- a/include/expression.h +++ b/include/expression.h @@ -416,6 +416,8 @@ extern struct expr *prefix_expr_alloc(const struct location *loc, 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); diff --git a/include/mnl.h b/include/mnl.h index 4475e7f8..470b2978 100644 --- a/include/mnl.h +++ b/include/mnl.h @@ -92,6 +92,10 @@ int mnl_nft_obj_batch_del(struct nftnl_obj *nln, struct nftnl_batch *batch, 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, diff --git a/include/netlink.h b/include/netlink.h index 387eb9d8..41fd55f9 100644 --- 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 netlink_ctx *ctx, const struct handle *h, 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); diff --git a/include/rule.h b/include/rule.h index 33bb24fa..262814ea 100644 --- a/include/rule.h +++ b/include/rule.h @@ -326,10 +326,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; }; @@ -387,6 +390,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 @@ -426,6 +431,7 @@ enum cmd_obj { CMD_OBJ_CT_HELPERS, CMD_OBJ_LIMIT, CMD_OBJ_LIMITS, + CMD_OBJ_FLOWTABLE, CMD_OBJ_FLOWTABLES, }; @@ -485,6 +491,7 @@ struct cmd { struct rule *rule; struct chain *chain; struct table *table; + struct flowtable *flowtable; struct monitor *monitor; struct markup *markup; struct obj *object; diff --git a/src/evaluate.c b/src/evaluate.c index 6094d0c5..9da185c9 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -2910,6 +2910,24 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set) 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; @@ -3082,6 +3100,14 @@ static int cmd_evaluate_add(struct eval_ctx *ctx, struct cmd *cmd) 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: diff --git a/src/expression.c b/src/expression.c index ee75284e..d7f54ad7 100644 --- a/src/expression.c +++ b/src/expression.c @@ -702,8 +702,8 @@ struct expr *range_expr_alloc(const struct location *loc, 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; @@ -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 */ diff --git a/src/netlink.c b/src/netlink.c index 9fadccd0..5b2d5e16 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -1489,6 +1489,64 @@ static struct obj *netlink_delinearize_obj(struct netlink_ctx *ctx, 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; diff --git a/src/parser_bison.y b/src/parser_bison.y index faa613c2..c73eddde 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -146,6 +146,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; @@ -192,6 +193,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" @@ -203,6 +205,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" @@ -503,9 +506,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 @@ -529,6 +532,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 @@ -609,8 +615,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 @@ -895,6 +901,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; @@ -970,6 +983,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; @@ -1338,6 +1358,17 @@ table_block : /* empty */ { $$ = $<table>-1; } 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 @@ -1538,6 +1569,62 @@ set_policy_spec : PERFORMANCE { $$ = NFT_SET_POL_PERFORMANCE; } | 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); @@ -1746,6 +1833,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; @@ -45,6 +45,8 @@ void handle_merge(struct handle *dst, const struct handle *src) 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) @@ -899,6 +901,7 @@ struct cmd *cmd_alloc(enum cmd_ops op, enum cmd_obj obj, void nft_cmd_expand(struct cmd *cmd) { struct list_head new_cmds; + struct flowtable *ft; struct table *table; struct chain *chain; struct rule *rule; @@ -938,6 +941,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)); @@ -1024,6 +1035,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); } @@ -1115,6 +1129,9 @@ static int do_command_add(struct netlink_ctx *ctx, struct cmd *cmd, bool excl) 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); } diff --git a/src/scanner.l b/src/scanner.l index 3ea33b09..79dccda2 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -240,6 +240,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) "hook" { return HOOK; } "device" { return DEVICE; } +"devices" { return DEVICES; } "table" { return TABLE; } "tables" { return TABLES; } "chain" { return CHAIN; } @@ -251,6 +252,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; } |