Signed-off-by: Felix Fietkau <nbd@nbd.name>master
parent
8cdc71fc92
commit
bc3e0f6052
@ -0,0 +1,515 @@ |
||||
From: Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
Date: Mon, 4 Dec 2017 13:28:25 +0100
|
||||
Subject: [PATCH] src: support for flowtable listing
|
||||
|
||||
This patch allows you to dump existing flowtable.
|
||||
|
||||
# nft list ruleset
|
||||
table ip x {
|
||||
flowtable x {
|
||||
hook ingress priority 10
|
||||
devices = { eth0, tap0 }
|
||||
}
|
||||
}
|
||||
|
||||
You can also list existing flowtables via:
|
||||
|
||||
# nft list flowtables
|
||||
table ip x {
|
||||
flowtable x {
|
||||
hook ingress priority 10
|
||||
devices = { eth0, tap0 }
|
||||
}
|
||||
}
|
||||
|
||||
You need a Linux kernel >= 4.16-rc to test this new feature.
|
||||
|
||||
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
---
|
||||
|
||||
--- a/include/linux/netfilter/nf_tables.h
|
||||
+++ b/include/linux/netfilter/nf_tables.h
|
||||
@@ -92,6 +92,9 @@ enum nft_verdicts {
|
||||
* @NFT_MSG_GETOBJ: get a stateful object (enum nft_obj_attributes)
|
||||
* @NFT_MSG_DELOBJ: delete a stateful object (enum nft_obj_attributes)
|
||||
* @NFT_MSG_GETOBJ_RESET: get and reset a stateful object (enum nft_obj_attributes)
|
||||
+ * @NFT_MSG_NEWFLOWTABLE: add new flow table (enum nft_flowtable_attributes)
|
||||
+ * @NFT_MSG_GETFLOWTABLE: get flow table (enum nft_flowtable_attributes)
|
||||
+ * @NFT_MSG_DELFLOWTABLE: delete flow table (enum nft_flowtable_attributes)
|
||||
*/
|
||||
enum nf_tables_msg_types {
|
||||
NFT_MSG_NEWTABLE,
|
||||
@@ -116,6 +119,9 @@ enum nf_tables_msg_types {
|
||||
NFT_MSG_GETOBJ,
|
||||
NFT_MSG_DELOBJ,
|
||||
NFT_MSG_GETOBJ_RESET,
|
||||
+ NFT_MSG_NEWFLOWTABLE,
|
||||
+ NFT_MSG_GETFLOWTABLE,
|
||||
+ NFT_MSG_DELFLOWTABLE,
|
||||
NFT_MSG_MAX,
|
||||
};
|
||||
|
||||
--- a/include/mnl.h
|
||||
+++ b/include/mnl.h
|
||||
@@ -89,6 +89,9 @@ int mnl_nft_obj_batch_add(struct nftnl_o
|
||||
int mnl_nft_obj_batch_del(struct nftnl_obj *nln, struct nftnl_batch *batch,
|
||||
unsigned int flags, uint32_t seqnum);
|
||||
|
||||
+struct nftnl_flowtable_list *
|
||||
+mnl_nft_flowtable_dump(struct netlink_ctx *ctx, int family, const char *table);
|
||||
+
|
||||
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
|
||||
@@ -179,6 +179,10 @@ extern int netlink_add_obj(struct netlin
|
||||
extern int netlink_delete_obj(struct netlink_ctx *ctx, const struct handle *h,
|
||||
struct location *loc, uint32_t type);
|
||||
|
||||
+extern int netlink_list_flowtables(struct netlink_ctx *ctx,
|
||||
+ const struct handle *h,
|
||||
+ const struct location *loc);
|
||||
+
|
||||
extern void netlink_dump_chain(const struct nftnl_chain *nlc,
|
||||
struct netlink_ctx *ctx);
|
||||
extern void netlink_dump_rule(const struct nftnl_rule *nlr,
|
||||
--- a/include/rule.h
|
||||
+++ b/include/rule.h
|
||||
@@ -35,6 +35,7 @@ struct position_spec {
|
||||
* @chain: chain name (chains and rules only)
|
||||
* @set: set name (sets only)
|
||||
* @obj: stateful object name (stateful object only)
|
||||
+ * @flowtable: flow table name (flow table only)
|
||||
* @handle: rule handle (rules only)
|
||||
* @position: rule position (rules only)
|
||||
* @set_id: set ID (sets only)
|
||||
@@ -45,6 +46,7 @@ struct handle {
|
||||
const char *chain;
|
||||
const char *set;
|
||||
const char *obj;
|
||||
+ const char *flowtable;
|
||||
struct handle_spec handle;
|
||||
struct position_spec position;
|
||||
uint32_t set_id;
|
||||
@@ -98,6 +100,7 @@ enum table_flags {
|
||||
* @chains: chains contained in the table
|
||||
* @sets: sets contained in the table
|
||||
* @objs: stateful objects contained in the table
|
||||
+ * @flowtables: flow tables contained in the table
|
||||
* @flags: table flags
|
||||
* @refcnt: table reference counter
|
||||
*/
|
||||
@@ -109,6 +112,7 @@ struct table {
|
||||
struct list_head chains;
|
||||
struct list_head sets;
|
||||
struct list_head objs;
|
||||
+ struct list_head flowtables;
|
||||
enum table_flags flags;
|
||||
unsigned int refcnt;
|
||||
};
|
||||
@@ -315,6 +319,24 @@ void obj_print_plain(const struct obj *o
|
||||
const char *obj_type_name(uint32_t type);
|
||||
uint32_t obj_type_to_cmd(uint32_t type);
|
||||
|
||||
+struct flowtable {
|
||||
+ struct list_head list;
|
||||
+ struct handle handle;
|
||||
+ struct location location;
|
||||
+ unsigned int hooknum;
|
||||
+ int priority;
|
||||
+ const char **dev_array;
|
||||
+ int dev_array_len;
|
||||
+ unsigned int refcnt;
|
||||
+};
|
||||
+
|
||||
+extern struct flowtable *flowtable_alloc(const struct location *loc);
|
||||
+extern struct flowtable *flowtable_get(struct flowtable *flowtable);
|
||||
+extern void flowtable_free(struct flowtable *flowtable);
|
||||
+extern void flowtable_add_hash(struct flowtable *flowtable, struct table *table);
|
||||
+
|
||||
+void flowtable_print(const struct flowtable *n, struct output_ctx *octx);
|
||||
+
|
||||
/**
|
||||
* enum cmd_ops - command operations
|
||||
*
|
||||
@@ -373,6 +395,7 @@ enum cmd_ops {
|
||||
* @CMD_OBJ_QUOTAS: multiple quotas
|
||||
* @CMD_OBJ_LIMIT: limit
|
||||
* @CMD_OBJ_LIMITS: multiple limits
|
||||
+ * @CMD_OBJ_FLOWTABLES: flow tables
|
||||
*/
|
||||
enum cmd_obj {
|
||||
CMD_OBJ_INVALID,
|
||||
@@ -399,6 +422,7 @@ enum cmd_obj {
|
||||
CMD_OBJ_CT_HELPERS,
|
||||
CMD_OBJ_LIMIT,
|
||||
CMD_OBJ_LIMITS,
|
||||
+ CMD_OBJ_FLOWTABLES,
|
||||
};
|
||||
|
||||
struct markup {
|
||||
--- a/src/evaluate.c
|
||||
+++ b/src/evaluate.c
|
||||
@@ -3196,6 +3196,7 @@ static int cmd_evaluate_list(struct eval
|
||||
case CMD_OBJ_CT_HELPERS:
|
||||
case CMD_OBJ_LIMITS:
|
||||
case CMD_OBJ_SETS:
|
||||
+ case CMD_OBJ_FLOWTABLES:
|
||||
if (cmd->handle.table == NULL)
|
||||
return 0;
|
||||
if (table_lookup(&cmd->handle, ctx->cache) == NULL)
|
||||
--- a/src/mnl.c
|
||||
+++ b/src/mnl.c
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <libnftnl/expr.h>
|
||||
#include <libnftnl/set.h>
|
||||
#include <libnftnl/object.h>
|
||||
+#include <libnftnl/flowtable.h>
|
||||
#include <libnftnl/batch.h>
|
||||
|
||||
#include <linux/netfilter/nfnetlink.h>
|
||||
@@ -953,6 +954,63 @@ int mnl_nft_setelem_get(struct netlink_c
|
||||
return nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, set_elem_cb, nls);
|
||||
}
|
||||
|
||||
+static int flowtable_cb(const struct nlmsghdr *nlh, void *data)
|
||||
+{
|
||||
+ struct nftnl_flowtable_list *nln_list = data;
|
||||
+ struct nftnl_flowtable *n;
|
||||
+
|
||||
+ if (check_genid(nlh) < 0)
|
||||
+ return MNL_CB_ERROR;
|
||||
+
|
||||
+ n = nftnl_flowtable_alloc();
|
||||
+ if (n == NULL)
|
||||
+ memory_allocation_error();
|
||||
+
|
||||
+ if (nftnl_flowtable_nlmsg_parse(nlh, n) < 0)
|
||||
+ goto err_free;
|
||||
+
|
||||
+ nftnl_flowtable_list_add_tail(n, nln_list);
|
||||
+ return MNL_CB_OK;
|
||||
+
|
||||
+err_free:
|
||||
+ nftnl_flowtable_free(n);
|
||||
+ return MNL_CB_OK;
|
||||
+}
|
||||
+
|
||||
+struct nftnl_flowtable_list *
|
||||
+mnl_nft_flowtable_dump(struct netlink_ctx *ctx, int family, const char *table)
|
||||
+{
|
||||
+ struct nftnl_flowtable_list *nln_list;
|
||||
+ char buf[MNL_SOCKET_BUFFER_SIZE];
|
||||
+ struct nftnl_flowtable *n;
|
||||
+ struct nlmsghdr *nlh;
|
||||
+ int ret;
|
||||
+
|
||||
+ n = nftnl_flowtable_alloc();
|
||||
+ if (n == NULL)
|
||||
+ memory_allocation_error();
|
||||
+
|
||||
+ nlh = nftnl_nlmsg_build_hdr(buf, NFT_MSG_GETFLOWTABLE, family,
|
||||
+ NLM_F_DUMP | NLM_F_ACK, ctx->seqnum);
|
||||
+ if (table != NULL)
|
||||
+ nftnl_flowtable_set_str(n, NFTNL_FLOWTABLE_TABLE, table);
|
||||
+ nftnl_flowtable_nlmsg_build_payload(nlh, n);
|
||||
+ nftnl_flowtable_free(n);
|
||||
+
|
||||
+ nln_list = nftnl_flowtable_list_alloc();
|
||||
+ if (nln_list == NULL)
|
||||
+ memory_allocation_error();
|
||||
+
|
||||
+ ret = nft_mnl_talk(ctx, nlh, nlh->nlmsg_len, flowtable_cb, nln_list);
|
||||
+ if (ret < 0)
|
||||
+ goto err;
|
||||
+
|
||||
+ return nln_list;
|
||||
+err:
|
||||
+ nftnl_flowtable_list_free(nln_list);
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* ruleset
|
||||
*/
|
||||
--- a/src/netlink.c
|
||||
+++ b/src/netlink.c
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <libnftnl/expr.h>
|
||||
#include <libnftnl/object.h>
|
||||
#include <libnftnl/set.h>
|
||||
+#include <libnftnl/flowtable.h>
|
||||
#include <libnftnl/udata.h>
|
||||
#include <libnftnl/ruleset.h>
|
||||
#include <libnftnl/common.h>
|
||||
@@ -1826,6 +1827,70 @@ int netlink_reset_objs(struct netlink_ct
|
||||
return err;
|
||||
}
|
||||
|
||||
+static struct flowtable *
|
||||
+netlink_delinearize_flowtable(struct netlink_ctx *ctx,
|
||||
+ struct nftnl_flowtable *nlo)
|
||||
+{
|
||||
+ struct flowtable *flowtable;
|
||||
+ const char **dev_array;
|
||||
+ int len = 0, i;
|
||||
+
|
||||
+ flowtable = flowtable_alloc(&netlink_location);
|
||||
+ flowtable->handle.family =
|
||||
+ nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_FAMILY);
|
||||
+ flowtable->handle.table =
|
||||
+ xstrdup(nftnl_flowtable_get_str(nlo, NFTNL_FLOWTABLE_TABLE));
|
||||
+ flowtable->handle.flowtable =
|
||||
+ xstrdup(nftnl_flowtable_get_str(nlo, NFTNL_FLOWTABLE_NAME));
|
||||
+ dev_array = nftnl_flowtable_get_array(nlo, NFTNL_FLOWTABLE_DEVICES);
|
||||
+ while (dev_array[len] != '\0')
|
||||
+ len++;
|
||||
+
|
||||
+ flowtable->dev_array = calloc(1, len * sizeof(char *));
|
||||
+ for (i = 0; i < len; i++)
|
||||
+ flowtable->dev_array[i] = xstrdup(dev_array[i]);
|
||||
+
|
||||
+ flowtable->dev_array_len = len;
|
||||
+
|
||||
+ flowtable->priority =
|
||||
+ nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_PRIO);
|
||||
+ flowtable->hooknum =
|
||||
+ nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_HOOKNUM);
|
||||
+
|
||||
+ return flowtable;
|
||||
+}
|
||||
+
|
||||
+static int list_flowtable_cb(struct nftnl_flowtable *nls, void *arg)
|
||||
+{
|
||||
+ struct netlink_ctx *ctx = arg;
|
||||
+ struct flowtable *flowtable;
|
||||
+
|
||||
+ flowtable = netlink_delinearize_flowtable(ctx, nls);
|
||||
+ if (flowtable == NULL)
|
||||
+ return -1;
|
||||
+ list_add_tail(&flowtable->list, &ctx->list);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+int netlink_list_flowtables(struct netlink_ctx *ctx, const struct handle *h,
|
||||
+ const struct location *loc)
|
||||
+{
|
||||
+ struct nftnl_flowtable_list *flowtable_cache;
|
||||
+ int err;
|
||||
+
|
||||
+ flowtable_cache = mnl_nft_flowtable_dump(ctx, h->family, h->table);
|
||||
+ if (flowtable_cache == NULL) {
|
||||
+ if (errno == EINTR)
|
||||
+ return -1;
|
||||
+
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ err = nftnl_flowtable_list_foreach(flowtable_cache, list_flowtable_cb, ctx);
|
||||
+ nftnl_flowtable_list_free(flowtable_cache);
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
int netlink_batch_send(struct netlink_ctx *ctx, struct list_head *err_list)
|
||||
{
|
||||
return mnl_batch_talk(ctx, err_list);
|
||||
--- a/src/parser_bison.y
|
||||
+++ b/src/parser_bison.y
|
||||
@@ -248,6 +248,8 @@ int nft_lex(void *, void *, void *);
|
||||
%token METER "meter"
|
||||
%token METERS "meters"
|
||||
|
||||
+%token FLOWTABLES "flowtables"
|
||||
+
|
||||
%token <val> NUM "number"
|
||||
%token <string> STRING "string"
|
||||
%token <string> QUOTED_STRING "quoted string"
|
||||
@@ -1104,6 +1106,10 @@ list_cmd : TABLE table_spec
|
||||
{
|
||||
$$ = cmd_alloc(CMD_LIST, CMD_OBJ_METER, &$2, &@$, NULL);
|
||||
}
|
||||
+ | FLOWTABLES ruleset_spec
|
||||
+ {
|
||||
+ $$ = cmd_alloc(CMD_LIST, CMD_OBJ_FLOWTABLES, &$2, &@$, NULL);
|
||||
+ }
|
||||
| MAPS ruleset_spec
|
||||
{
|
||||
$$ = cmd_alloc(CMD_LIST, CMD_OBJ_MAPS, &$2, &@$, NULL);
|
||||
--- a/src/rule.c
|
||||
+++ b/src/rule.c
|
||||
@@ -95,6 +95,11 @@ static int cache_init_objects(struct net
|
||||
return -1;
|
||||
list_splice_tail_init(&ctx->list, &table->chains);
|
||||
|
||||
+ ret = netlink_list_flowtables(ctx, &table->handle, &internal_location);
|
||||
+ if (ret < 0)
|
||||
+ return -1;
|
||||
+ list_splice_tail_init(&ctx->list, &table->flowtables);
|
||||
+
|
||||
if (cmd != CMD_RESET) {
|
||||
ret = netlink_list_objs(ctx, &table->handle, &internal_location);
|
||||
if (ret < 0)
|
||||
@@ -722,6 +727,7 @@ struct table *table_alloc(void)
|
||||
init_list_head(&table->chains);
|
||||
init_list_head(&table->sets);
|
||||
init_list_head(&table->objs);
|
||||
+ init_list_head(&table->flowtables);
|
||||
init_list_head(&table->scope.symbols);
|
||||
table->refcnt = 1;
|
||||
|
||||
@@ -797,6 +803,7 @@ static void table_print_options(const st
|
||||
|
||||
static void table_print(const struct table *table, struct output_ctx *octx)
|
||||
{
|
||||
+ struct flowtable *flowtable;
|
||||
struct chain *chain;
|
||||
struct obj *obj;
|
||||
struct set *set;
|
||||
@@ -818,6 +825,11 @@ static void table_print(const struct tab
|
||||
set_print(set, octx);
|
||||
delim = "\n";
|
||||
}
|
||||
+ list_for_each_entry(flowtable, &table->flowtables, list) {
|
||||
+ nft_print(octx, "%s", delim);
|
||||
+ flowtable_print(flowtable, octx);
|
||||
+ delim = "\n";
|
||||
+ }
|
||||
list_for_each_entry(chain, &table->chains, list) {
|
||||
nft_print(octx, "%s", delim);
|
||||
chain_print(chain, octx);
|
||||
@@ -1481,6 +1493,114 @@ static int do_list_obj(struct netlink_ct
|
||||
return 0;
|
||||
}
|
||||
|
||||
+struct flowtable *flowtable_alloc(const struct location *loc)
|
||||
+{
|
||||
+ struct flowtable *flowtable;
|
||||
+
|
||||
+ flowtable = xzalloc(sizeof(*flowtable));
|
||||
+ if (loc != NULL)
|
||||
+ flowtable->location = *loc;
|
||||
+
|
||||
+ flowtable->refcnt = 1;
|
||||
+ return flowtable;
|
||||
+}
|
||||
+
|
||||
+struct flowtable *flowtable_get(struct flowtable *flowtable)
|
||||
+{
|
||||
+ flowtable->refcnt++;
|
||||
+ return flowtable;
|
||||
+}
|
||||
+
|
||||
+void flowtable_free(struct flowtable *flowtable)
|
||||
+{
|
||||
+ if (--flowtable->refcnt > 0)
|
||||
+ return;
|
||||
+ handle_free(&flowtable->handle);
|
||||
+ xfree(flowtable);
|
||||
+}
|
||||
+
|
||||
+void flowtable_add_hash(struct flowtable *flowtable, struct table *table)
|
||||
+{
|
||||
+ list_add_tail(&flowtable->list, &table->flowtables);
|
||||
+}
|
||||
+
|
||||
+static void flowtable_print_declaration(const struct flowtable *flowtable,
|
||||
+ struct print_fmt_options *opts,
|
||||
+ struct output_ctx *octx)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ nft_print(octx, "%sflowtable", opts->tab);
|
||||
+
|
||||
+ if (opts->family != NULL)
|
||||
+ nft_print(octx, " %s", opts->family);
|
||||
+
|
||||
+ if (opts->table != NULL)
|
||||
+ nft_print(octx, " %s", opts->table);
|
||||
+
|
||||
+ nft_print(octx, " %s {%s", flowtable->handle.flowtable, opts->nl);
|
||||
+
|
||||
+ nft_print(octx, "%s%shook %s priority %d%s",
|
||||
+ opts->tab, opts->tab, "ingress",
|
||||
+ flowtable->priority, opts->stmt_separator);
|
||||
+
|
||||
+ nft_print(octx, "%s%sdevices = { ", opts->tab, opts->tab);
|
||||
+ for (i = 0; i < flowtable->dev_array_len; i++) {
|
||||
+ nft_print(octx, "%s", flowtable->dev_array[i]);
|
||||
+ if (i + 1 != flowtable->dev_array_len)
|
||||
+ nft_print(octx, ", ");
|
||||
+ }
|
||||
+ nft_print(octx, " }%s", opts->stmt_separator);
|
||||
+}
|
||||
+
|
||||
+static void do_flowtable_print(const struct flowtable *flowtable,
|
||||
+ struct print_fmt_options *opts,
|
||||
+ struct output_ctx *octx)
|
||||
+{
|
||||
+ flowtable_print_declaration(flowtable, opts, octx);
|
||||
+ nft_print(octx, "%s}%s", opts->tab, opts->nl);
|
||||
+}
|
||||
+
|
||||
+void flowtable_print(const struct flowtable *s, struct output_ctx *octx)
|
||||
+{
|
||||
+ struct print_fmt_options opts = {
|
||||
+ .tab = "\t",
|
||||
+ .nl = "\n",
|
||||
+ .stmt_separator = "\n",
|
||||
+ };
|
||||
+
|
||||
+ do_flowtable_print(s, &opts, octx);
|
||||
+}
|
||||
+
|
||||
+static int do_list_flowtables(struct netlink_ctx *ctx, struct cmd *cmd)
|
||||
+{
|
||||
+ struct print_fmt_options opts = {
|
||||
+ .tab = "\t",
|
||||
+ .nl = "\n",
|
||||
+ .stmt_separator = "\n",
|
||||
+ };
|
||||
+ struct flowtable *flowtable;
|
||||
+ struct table *table;
|
||||
+
|
||||
+ list_for_each_entry(table, &ctx->cache->list, list) {
|
||||
+ if (cmd->handle.family != NFPROTO_UNSPEC &&
|
||||
+ cmd->handle.family != table->handle.family)
|
||||
+ continue;
|
||||
+
|
||||
+ nft_print(ctx->octx, "table %s %s {\n",
|
||||
+ family2str(table->handle.family),
|
||||
+ table->handle.table);
|
||||
+
|
||||
+ list_for_each_entry(flowtable, &table->flowtables, list) {
|
||||
+ flowtable_print_declaration(flowtable, &opts, ctx->octx);
|
||||
+ nft_print(ctx->octx, "%s}%s", opts.tab, opts.nl);
|
||||
+ }
|
||||
+
|
||||
+ nft_print(ctx->octx, "}\n");
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int do_list_ruleset(struct netlink_ctx *ctx, struct cmd *cmd)
|
||||
{
|
||||
unsigned int family = cmd->handle.family;
|
||||
@@ -1628,6 +1748,8 @@ static int do_command_list(struct netlin
|
||||
case CMD_OBJ_LIMIT:
|
||||
case CMD_OBJ_LIMITS:
|
||||
return do_list_obj(ctx, cmd, NFT_OBJECT_LIMIT);
|
||||
+ case CMD_OBJ_FLOWTABLES:
|
||||
+ return do_list_flowtables(ctx, cmd);
|
||||
default:
|
||||
BUG("invalid command object type %u\n", cmd->obj);
|
||||
}
|
||||
--- a/src/scanner.l
|
||||
+++ b/src/scanner.l
|
||||
@@ -297,6 +297,8 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr
|
||||
"meter" { return METER; }
|
||||
"meters" { return METERS; }
|
||||
|
||||
+"flowtables" { return FLOWTABLES; }
|
||||
+
|
||||
"counter" { return COUNTER; }
|
||||
"name" { return NAME; }
|
||||
"packets" { return PACKETS; }
|
@ -0,0 +1,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; }
|
@ -0,0 +1,122 @@ |
||||
From: Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
Date: Fri, 19 Jan 2018 01:41:38 +0100
|
||||
Subject: [PATCH] src: delete flowtable
|
||||
|
||||
This patch allows you to delete an existing flowtable:
|
||||
|
||||
# nft delete flowtable x m
|
||||
|
||||
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
---
|
||||
|
||||
--- a/include/mnl.h
|
||||
+++ b/include/mnl.h
|
||||
@@ -95,6 +95,9 @@ mnl_nft_flowtable_dump(struct netlink_ct
|
||||
int mnl_nft_flowtable_batch_add(struct nftnl_flowtable *flo,
|
||||
struct nftnl_batch *batch, unsigned int flags,
|
||||
uint32_t seqnum);
|
||||
+int mnl_nft_flowtable_batch_del(struct nftnl_flowtable *flow,
|
||||
+ struct nftnl_batch *batch, unsigned int flags,
|
||||
+ uint32_t seqnum);
|
||||
|
||||
struct nftnl_ruleset *mnl_nft_ruleset_dump(struct netlink_ctx *ctx,
|
||||
uint32_t family);
|
||||
--- a/include/netlink.h
|
||||
+++ b/include/netlink.h
|
||||
@@ -186,6 +186,9 @@ extern int netlink_list_flowtables(struc
|
||||
extern int netlink_add_flowtable(struct netlink_ctx *ctx,
|
||||
const struct handle *h, struct flowtable *ft,
|
||||
uint32_t flags);
|
||||
+extern int netlink_delete_flowtable(struct netlink_ctx *ctx,
|
||||
+ const struct handle *h,
|
||||
+ struct location *loc);
|
||||
|
||||
extern void netlink_dump_chain(const struct nftnl_chain *nlc,
|
||||
struct netlink_ctx *ctx);
|
||||
--- a/src/evaluate.c
|
||||
+++ b/src/evaluate.c
|
||||
@@ -3121,6 +3121,7 @@ static int cmd_evaluate_delete(struct ev
|
||||
case CMD_OBJ_RULE:
|
||||
case CMD_OBJ_CHAIN:
|
||||
case CMD_OBJ_TABLE:
|
||||
+ case CMD_OBJ_FLOWTABLE:
|
||||
case CMD_OBJ_COUNTER:
|
||||
case CMD_OBJ_QUOTA:
|
||||
case CMD_OBJ_CT_HELPER:
|
||||
--- a/src/mnl.c
|
||||
+++ b/src/mnl.c
|
||||
@@ -1027,6 +1027,22 @@ int mnl_nft_flowtable_batch_add(struct n
|
||||
return 0;
|
||||
}
|
||||
|
||||
+int mnl_nft_flowtable_batch_del(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_DELFLOWTABLE,
|
||||
+ nftnl_flowtable_get_u32(flo, NFTNL_FLOWTABLE_FAMILY),
|
||||
+ 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
|
||||
@@ -1831,6 +1831,24 @@ int netlink_add_flowtable(struct netlink
|
||||
return err;
|
||||
}
|
||||
|
||||
+int netlink_delete_flowtable(struct netlink_ctx *ctx, const struct handle *h,
|
||||
+ struct location *loc)
|
||||
+{
|
||||
+ struct nftnl_flowtable *flo;
|
||||
+ int err;
|
||||
+
|
||||
+ flo = alloc_nftnl_flowtable(h, NULL);
|
||||
+ netlink_dump_flowtable(flo, ctx);
|
||||
+
|
||||
+ err = mnl_nft_flowtable_batch_del(flo, ctx->batch, 0, ctx->seqnum);
|
||||
+ if (err < 0)
|
||||
+ netlink_io_error(ctx, loc, "Could not delete 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
|
||||
@@ -1024,6 +1024,10 @@ delete_cmd : TABLE table_spec
|
||||
{
|
||||
$$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SETELEM, &$2, &@$, $3);
|
||||
}
|
||||
+ | FLOWTABLE flowtable_spec
|
||||
+ {
|
||||
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_FLOWTABLE, &$2, &@$, NULL);
|
||||
+ }
|
||||
| COUNTER obj_spec
|
||||
{
|
||||
$$ = cmd_alloc(CMD_DELETE, CMD_OBJ_COUNTER, &$2, &@$, NULL);
|
||||
--- a/src/rule.c
|
||||
+++ b/src/rule.c
|
||||
@@ -1177,6 +1177,9 @@ static int do_command_delete(struct netl
|
||||
case CMD_OBJ_LIMIT:
|
||||
return netlink_delete_obj(ctx, &cmd->handle, &cmd->location,
|
||||
NFT_OBJECT_LIMIT);
|
||||
+ case CMD_OBJ_FLOWTABLE:
|
||||
+ return netlink_delete_flowtable(ctx, &cmd->handle,
|
||||
+ &cmd->location);
|
||||
default:
|
||||
BUG("invalid command object type %u\n", cmd->obj);
|
||||
}
|
@ -0,0 +1,191 @@ |
||||
From: Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
Date: Sun, 3 Dec 2017 21:27:03 +0100
|
||||
Subject: [PATCH] src: flow offload support
|
||||
|
||||
This patch allows us to refer to existing flowtables:
|
||||
|
||||
# nft add rule x x flow offload @m
|
||||
|
||||
Packets matching this rule create an entry in the flow table 'm', hence,
|
||||
follow up packets that get to the flowtable at ingress bypass the
|
||||
classic forwarding path.
|
||||
|
||||
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
---
|
||||
|
||||
--- a/include/ct.h
|
||||
+++ b/include/ct.h
|
||||
@@ -29,6 +29,8 @@ extern struct expr *ct_expr_alloc(const
|
||||
extern void ct_expr_update_type(struct proto_ctx *ctx, struct expr *expr);
|
||||
|
||||
extern struct stmt *notrack_stmt_alloc(const struct location *loc);
|
||||
+extern struct stmt *flow_offload_stmt_alloc(const struct location *loc,
|
||||
+ const char *table_name);
|
||||
|
||||
extern const struct datatype ct_dir_type;
|
||||
extern const struct datatype ct_state_type;
|
||||
--- a/include/statement.h
|
||||
+++ b/include/statement.h
|
||||
@@ -10,6 +10,12 @@ extern struct stmt *expr_stmt_alloc(cons
|
||||
extern struct stmt *verdict_stmt_alloc(const struct location *loc,
|
||||
struct expr *expr);
|
||||
|
||||
+struct flow_stmt {
|
||||
+ const char *table_name;
|
||||
+};
|
||||
+
|
||||
+struct stmt *flow_stmt_alloc(const struct location *loc, const char *name);
|
||||
+
|
||||
struct objref_stmt {
|
||||
uint32_t type;
|
||||
struct expr *expr;
|
||||
@@ -231,6 +237,7 @@ extern struct stmt *xt_stmt_alloc(const
|
||||
* @STMT_NOTRACK: notrack statement
|
||||
* @STMT_OBJREF: stateful object reference statement
|
||||
* @STMT_EXTHDR: extension header statement
|
||||
+ * @STMT_FLOW_OFFLOAD: flow offload statement
|
||||
*/
|
||||
enum stmt_types {
|
||||
STMT_INVALID,
|
||||
@@ -256,6 +263,7 @@ enum stmt_types {
|
||||
STMT_NOTRACK,
|
||||
STMT_OBJREF,
|
||||
STMT_EXTHDR,
|
||||
+ STMT_FLOW_OFFLOAD,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -316,6 +324,7 @@ struct stmt {
|
||||
struct fwd_stmt fwd;
|
||||
struct xt_stmt xt;
|
||||
struct objref_stmt objref;
|
||||
+ struct flow_stmt flow;
|
||||
};
|
||||
};
|
||||
|
||||
--- a/src/ct.c
|
||||
+++ b/src/ct.c
|
||||
@@ -456,3 +456,26 @@ struct stmt *notrack_stmt_alloc(const st
|
||||
{
|
||||
return stmt_alloc(loc, ¬rack_stmt_ops);
|
||||
}
|
||||
+
|
||||
+static void flow_offload_stmt_print(const struct stmt *stmt,
|
||||
+ struct output_ctx *octx)
|
||||
+{
|
||||
+ printf("flow offload @%s", stmt->flow.table_name);
|
||||
+}
|
||||
+
|
||||
+static const struct stmt_ops flow_offload_stmt_ops = {
|
||||
+ .type = STMT_FLOW_OFFLOAD,
|
||||
+ .name = "flow_offload",
|
||||
+ .print = flow_offload_stmt_print,
|
||||
+};
|
||||
+
|
||||
+struct stmt *flow_offload_stmt_alloc(const struct location *loc,
|
||||
+ const char *table_name)
|
||||
+{
|
||||
+ struct stmt *stmt;
|
||||
+
|
||||
+ stmt = stmt_alloc(loc, &flow_offload_stmt_ops);
|
||||
+ stmt->flow.table_name = table_name;
|
||||
+
|
||||
+ return stmt;
|
||||
+}
|
||||
--- a/src/evaluate.c
|
||||
+++ b/src/evaluate.c
|
||||
@@ -2773,6 +2773,7 @@ int stmt_evaluate(struct eval_ctx *ctx,
|
||||
case STMT_LIMIT:
|
||||
case STMT_QUOTA:
|
||||
case STMT_NOTRACK:
|
||||
+ case STMT_FLOW_OFFLOAD:
|
||||
return 0;
|
||||
case STMT_EXPRESSION:
|
||||
return stmt_evaluate_expr(ctx, stmt);
|
||||
--- a/src/netlink_delinearize.c
|
||||
+++ b/src/netlink_delinearize.c
|
||||
@@ -680,6 +680,16 @@ static void netlink_parse_notrack(struct
|
||||
ctx->stmt = notrack_stmt_alloc(loc);
|
||||
}
|
||||
|
||||
+static void netlink_parse_flow_offload(struct netlink_parse_ctx *ctx,
|
||||
+ const struct location *loc,
|
||||
+ const struct nftnl_expr *nle)
|
||||
+{
|
||||
+ const char *table_name;
|
||||
+
|
||||
+ table_name = xstrdup(nftnl_expr_get_str(nle, NFTNL_EXPR_FLOW_TABLE_NAME));
|
||||
+ ctx->stmt = flow_offload_stmt_alloc(loc, table_name);
|
||||
+}
|
||||
+
|
||||
static void netlink_parse_ct_stmt(struct netlink_parse_ctx *ctx,
|
||||
const struct location *loc,
|
||||
const struct nftnl_expr *nle)
|
||||
@@ -1255,6 +1265,7 @@ static const struct {
|
||||
{ .name = "hash", .parse = netlink_parse_hash },
|
||||
{ .name = "fib", .parse = netlink_parse_fib },
|
||||
{ .name = "tcpopt", .parse = netlink_parse_exthdr },
|
||||
+ { .name = "flow_offload", .parse = netlink_parse_flow_offload },
|
||||
};
|
||||
|
||||
static int netlink_parse_expr(const struct nftnl_expr *nle,
|
||||
--- a/src/netlink_linearize.c
|
||||
+++ b/src/netlink_linearize.c
|
||||
@@ -1201,6 +1201,17 @@ static void netlink_gen_notrack_stmt(str
|
||||
nftnl_rule_add_expr(ctx->nlr, nle);
|
||||
}
|
||||
|
||||
+static void netlink_gen_flow_offload_stmt(struct netlink_linearize_ctx *ctx,
|
||||
+ const struct stmt *stmt)
|
||||
+{
|
||||
+ struct nftnl_expr *nle;
|
||||
+
|
||||
+ nle = alloc_nft_expr("flow_offload");
|
||||
+ nftnl_expr_set_str(nle, NFTNL_EXPR_FLOW_TABLE_NAME,
|
||||
+ stmt->flow.table_name);
|
||||
+ nftnl_rule_add_expr(ctx->nlr, nle);
|
||||
+}
|
||||
+
|
||||
static void netlink_gen_set_stmt(struct netlink_linearize_ctx *ctx,
|
||||
const struct stmt *stmt)
|
||||
{
|
||||
@@ -1300,6 +1311,8 @@ static void netlink_gen_stmt(struct netl
|
||||
break;
|
||||
case STMT_NOTRACK:
|
||||
return netlink_gen_notrack_stmt(ctx, stmt);
|
||||
+ case STMT_FLOW_OFFLOAD:
|
||||
+ return netlink_gen_flow_offload_stmt(ctx, stmt);
|
||||
case STMT_OBJREF:
|
||||
return netlink_gen_objref_stmt(ctx, stmt);
|
||||
default:
|
||||
--- a/src/parser_bison.y
|
||||
+++ b/src/parser_bison.y
|
||||
@@ -248,6 +248,7 @@ int nft_lex(void *, void *, void *);
|
||||
%token SIZE "size"
|
||||
|
||||
%token FLOW "flow"
|
||||
+%token OFFLOAD "offload"
|
||||
%token METER "meter"
|
||||
%token METERS "meters"
|
||||
|
||||
@@ -3384,6 +3385,10 @@ meta_stmt : META meta_key SET stmt_expr
|
||||
{
|
||||
$$ = notrack_stmt_alloc(&@$);
|
||||
}
|
||||
+ | FLOW OFFLOAD AT string
|
||||
+ {
|
||||
+ $$ = flow_offload_stmt_alloc(&@$, $4);
|
||||
+ }
|
||||
;
|
||||
|
||||
offset_opt : /* empty */ { $$ = 0; }
|
||||
--- a/src/scanner.l
|
||||
+++ b/src/scanner.l
|
||||
@@ -296,6 +296,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr
|
||||
"memory" { return MEMORY; }
|
||||
|
||||
"flow" { return FLOW; }
|
||||
+"offload" { return OFFLOAD; }
|
||||
"meter" { return METER; }
|
||||
"meters" { return METERS; }
|
||||
|
@ -0,0 +1,110 @@ |
||||
From: Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
Date: Mon, 22 Jan 2018 19:54:36 +0100
|
||||
Subject: [PATCH] tests: shell: add flowtable tests
|
||||
|
||||
Add basic flowtable tests.
|
||||
|
||||
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
---
|
||||
create mode 100755 tests/shell/testcases/flowtable/0001flowtable_0
|
||||
create mode 100755 tests/shell/testcases/flowtable/0002create_flowtable_0
|
||||
create mode 100755 tests/shell/testcases/flowtable/0003add_after_flush_0
|
||||
create mode 100755 tests/shell/testcases/flowtable/0004delete_after_add0
|
||||
create mode 100755 tests/shell/testcases/flowtable/0005delete_in_use_1
|
||||
|
||||
--- a/tests/shell/run-tests.sh
|
||||
+++ b/tests/shell/run-tests.sh
|
||||
@@ -68,7 +68,9 @@ kernel_cleanup() {
|
||||
nft_set_hash nft_set_rbtree nft_set_bitmap \
|
||||
nft_chain_nat_ipv4 nft_chain_nat_ipv6 \
|
||||
nf_tables_inet nf_tables_bridge nf_tables_arp \
|
||||
- nf_tables_ipv4 nf_tables_ipv6 nf_tables
|
||||
+ nf_tables_ipv4 nf_tables_ipv6 nf_tables \
|
||||
+ nf_flow_table nf_flow_table_ipv4 nf_flow_tables_ipv6 \
|
||||
+ nf_flow_table_inet nft_flow_offload
|
||||
}
|
||||
|
||||
find_tests() {
|
||||
--- /dev/null
|
||||
+++ b/tests/shell/testcases/flowtable/0001flowtable_0
|
||||
@@ -0,0 +1,33 @@
|
||||
+#!/bin/bash
|
||||
+
|
||||
+tmpfile=$(mktemp)
|
||||
+if [ ! -w $tmpfile ] ; then
|
||||
+ echo "Failed to create tmp file" >&2
|
||||
+ exit 0
|
||||
+fi
|
||||
+
|
||||
+trap "rm -rf $tmpfile" EXIT # cleanup if aborted
|
||||
+
|
||||
+
|
||||
+EXPECTED='table inet t {
|
||||
+ flowtable f {
|
||||
+ hook ingress priority 10
|
||||
+ devices = { eth0, wlan0 }
|
||||
+ }
|
||||
+
|
||||
+ chain c {
|
||||
+ flow offload @f
|
||||
+ }
|
||||
+}'
|
||||
+
|
||||
+echo "$EXPECTED" > $tmpfile
|
||||
+set -e
|
||||
+$NFT -f $tmpfile
|
||||
+
|
||||
+GET="$($NFT list ruleset)"
|
||||
+
|
||||
+if [ "$EXPECTED" != "$GET" ] ; then
|
||||
+ DIFF="$(which diff)"
|
||||
+ [ -x $DIFF ] && $DIFF -u <(echo "$EXPECTED") <(echo "$GET")
|
||||
+ exit 1
|
||||
+fi
|
||||
--- /dev/null
|
||||
+++ b/tests/shell/testcases/flowtable/0002create_flowtable_0
|
||||
@@ -0,0 +1,12 @@
|
||||
+#!/bin/bash
|
||||
+
|
||||
+set -e
|
||||
+$NFT add table t
|
||||
+$NFT add flowtable t f { hook ingress priority 10 \; devices = { eth0, wlan0 }\; }
|
||||
+if $NFT create flowtable t f { hook ingress priority 10 \; devices = { eth0, wlan0 }\; } 2>/dev/null ; then
|
||||
+ echo "E: flowtable creation not failing on existing set" >&2
|
||||
+ exit 1
|
||||
+fi
|
||||
+$NFT add flowtable t f { hook ingress priority 10 \; devices = { eth0, wlan0 }\; }
|
||||
+
|
||||
+exit 0
|
||||
--- /dev/null
|
||||
+++ b/tests/shell/testcases/flowtable/0003add_after_flush_0
|
||||
@@ -0,0 +1,8 @@
|
||||
+#!/bin/bash
|
||||
+
|
||||
+set -e
|
||||
+$NFT add table x
|
||||
+$NFT add flowtable x y { hook ingress priority 0\; devices = { eth0, wlan0 }\;}
|
||||
+$NFT flush ruleset
|
||||
+$NFT add table x
|
||||
+$NFT add flowtable x y { hook ingress priority 0\; devices = { eth0, wlan0 }\;}
|
||||
--- /dev/null
|
||||
+++ b/tests/shell/testcases/flowtable/0004delete_after_add0
|
||||
@@ -0,0 +1,6 @@
|
||||
+#!/bin/bash
|
||||
+
|
||||
+set -e
|
||||
+$NFT add table x
|
||||
+$NFT add flowtable x y { hook ingress priority 0\; devices = { eth0, wlan0 }\;}
|
||||
+$NFT delete flowtable x y
|
||||
--- /dev/null
|
||||
+++ b/tests/shell/testcases/flowtable/0005delete_in_use_1
|
||||
@@ -0,0 +1,9 @@
|
||||
+#!/bin/bash
|
||||
+
|
||||
+set -e
|
||||
+$NFT add table x
|
||||
+$NFT add chain x x
|
||||
+$NFT add flowtable x y { hook ingress priority 0\; devices = { eth0, wlan0 }\;}
|
||||
+$NFT add rule x x flow offload @y
|
||||
+$NFT delete flowtable x y
|
||||
+echo "E: delete flowtable in use"
|
@ -0,0 +1,128 @@ |
||||
From: Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
Date: Tue, 23 Jan 2018 12:58:30 +0100
|
||||
Subject: [PATCH] doc: nft: document flowtable
|
||||
|
||||
Document the new flowtable objects available since Linux kernel 4.16-rc.
|
||||
|
||||
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
---
|
||||
|
||||
--- a/doc/nft.xml
|
||||
+++ b/doc/nft.xml
|
||||
@@ -1166,6 +1166,91 @@ filter input iif $int_ifs accept
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
+ <title>Flowtables</title>
|
||||
+ <para>
|
||||
+ <cmdsynopsis>
|
||||
+ <group choice="req">
|
||||
+ <arg>add</arg>
|
||||
+ <arg>create</arg>
|
||||
+ </group>
|
||||
+ <command>flowtable</command>
|
||||
+ <arg choice="opt"><replaceable>family</replaceable></arg>
|
||||
+ <arg choice="plain"><replaceable>table</replaceable></arg>
|
||||
+ <arg choice="plain"><replaceable>flowtable</replaceable></arg>
|
||||
+ <arg choice="req">
|
||||
+ hook <replaceable>hook</replaceable>
|
||||
+ priority <replaceable>priority</replaceable> ;
|
||||
+ devices = { <replaceable>device</replaceable>[,...] } ;
|
||||
+ </arg>
|
||||
+ </cmdsynopsis>
|
||||
+ <cmdsynopsis>
|
||||
+ <group choice="req">
|
||||
+ <arg>delete</arg>
|
||||
+ <arg>list</arg>
|
||||
+ </group>
|
||||
+ <command>flowtable</command>
|
||||
+ <arg choice="opt"><replaceable>family</replaceable></arg>
|
||||
+ <replaceable>table</replaceable>
|
||||
+ <replaceable>flowtable</replaceable>
|
||||
+ </cmdsynopsis>
|
||||
+ </para>
|
||||
+
|
||||
+ <para>
|
||||
+ Flowtables allow you to accelerate packet forwarding in software.
|
||||
+ Flowtables entries are represented through a tuple that is composed of the
|
||||
+ input interface, source and destination address, source and destination
|
||||
+ port; and layer 3/4 protocols. Each entry also caches the destination
|
||||
+ interface and the gateway address - to update the destination link-layer
|
||||
+ address - to forward packets. The ttl and hoplimit fields are also
|
||||
+ decremented. Hence, flowtables provides an alternative path that allow
|
||||
+ packets to bypass the classic forwarding path. Flowtables reside in the
|
||||
+ ingress hook, that is located before the prerouting hook. You can select
|
||||
+ what flows you want to offload through the <literal>flow offload</literal>
|
||||
+ expression from the <literal>forward</literal> chain. Flowtables are
|
||||
+ identified by their address family and their name. The address family
|
||||
+ must be one of
|
||||
+
|
||||
+ <simplelist type="inline">
|
||||
+ <member><literal>ip</literal></member>
|
||||
+ <member><literal>ip6</literal></member>
|
||||
+ <member><literal>inet</literal></member>
|
||||
+ </simplelist>.
|
||||
+
|
||||
+ The <literal>inet</literal> address family is a dummy family which is used to create
|
||||
+ hybrid IPv4/IPv6 tables.
|
||||
+
|
||||
+ When no address family is specified, <literal>ip</literal> is used by default.
|
||||
+ </para>
|
||||
+
|
||||
+ <variablelist>
|
||||
+ <varlistentry>
|
||||
+ <term><option>add</option></term>
|
||||
+ <listitem>
|
||||
+ <para>
|
||||
+ Add a new flowtable for the given family with the given name.
|
||||
+ </para>
|
||||
+ </listitem>
|
||||
+ </varlistentry>
|
||||
+ <varlistentry>
|
||||
+ <term><option>delete</option></term>
|
||||
+ <listitem>
|
||||
+ <para>
|
||||
+ Delete the specified flowtable.
|
||||
+ </para>
|
||||
+ </listitem>
|
||||
+ </varlistentry>
|
||||
+ <varlistentry>
|
||||
+ <term><option>list</option></term>
|
||||
+ <listitem>
|
||||
+ <para>
|
||||
+ List all flowtables.
|
||||
+ </para>
|
||||
+ </listitem>
|
||||
+ </varlistentry>
|
||||
+ </variablelist>
|
||||
+ </refsect1>
|
||||
+
|
||||
+ <refsect1>
|
||||
<title>Stateful objects</title>
|
||||
<para>
|
||||
<cmdsynopsis>
|
||||
@@ -4923,6 +5008,24 @@ add rule nat prerouting tcp dport 22 red
|
||||
</example>
|
||||
</para>
|
||||
</refsect2>
|
||||
+
|
||||
+ <refsect2>
|
||||
+ <title>Flow offload statement</title>
|
||||
+ <para>
|
||||
+ A flow offload statement allows us to select what flows
|
||||
+ you want to accelerate forwarding through layer 3 network
|
||||
+ stack bypass. You have to specify the flowtable name where
|
||||
+ you want to offload this flow.
|
||||
+ </para>
|
||||
+ <para>
|
||||
+ <cmdsynopsis>
|
||||
+ <command>flow offload</command>
|
||||
+ <literal>@flowtable</literal>
|
||||
+ </cmdsynopsis>
|
||||
+ </para>
|
||||
+
|
||||
+ </refsect2>
|
||||
+
|
||||
<refsect2>
|
||||
<title>Queue statement</title>
|
||||
<para>
|
Loading…
Reference in new issue