summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/expression.h2
-rw-r--r--include/mnl.h4
-rw-r--r--include/netlink.h4
-rw-r--r--include/rule.h7
-rw-r--r--src/evaluate.c26
-rw-r--r--src/expression.c4
-rw-r--r--src/mnl.c16
-rw-r--r--src/netlink.c58
-rw-r--r--src/parser_bison.y112
-rw-r--r--src/rule.c17
-rw-r--r--src/scanner.l2
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;
diff --git a/src/mnl.c b/src/mnl.c
index e70b0cde..be6e05da 100644
--- 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
*/
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;
diff --git a/src/rule.c b/src/rule.c
index 9c8d7f7d..5f1c35d5 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -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; }