summaryrefslogtreecommitdiffstats
path: root/src/rule.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/rule.c')
-rw-r--r--src/rule.c1122
1 files changed, 535 insertions, 587 deletions
diff --git a/src/rule.c b/src/rule.c
index 883b0707..45289cc0 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -8,11 +8,10 @@
* Development of this code funded by Astaro AG (http://www.astaro.com/)
*/
+#include <nft.h>
+
#include <stddef.h>
-#include <stdlib.h>
#include <stdio.h>
-#include <stdint.h>
-#include <string.h>
#include <inttypes.h>
#include <errno.h>
@@ -25,6 +24,9 @@
#include <misspell.h>
#include <json.h>
#include <cache.h>
+#include <owner.h>
+#include <intervals.h>
+#include "nftutils.h"
#include <libnftnl/common.h>
#include <libnftnl/ruleset.h>
@@ -71,10 +73,10 @@ static uint32_t tcp_dflt_timeout[] = {
static uint32_t udp_dflt_timeout[] = {
[NFTNL_CTTIMEOUT_UDP_UNREPLIED] = 30,
- [NFTNL_CTTIMEOUT_UDP_REPLIED] = 180,
+ [NFTNL_CTTIMEOUT_UDP_REPLIED] = 120,
};
-struct timeout_protocol timeout_protocol[IPPROTO_MAX] = {
+struct timeout_protocol timeout_protocol[UINT8_MAX + 1] = {
[IPPROTO_TCP] = {
.array_size = NFTNL_CTTIMEOUT_TCP_MAX,
.state_to_name = tcp_state_to_name,
@@ -102,11 +104,11 @@ int timeout_str2num(uint16_t l4proto, struct timeout_state *ts)
void handle_free(struct handle *h)
{
- xfree(h->table.name);
- xfree(h->chain.name);
- xfree(h->set.name);
- xfree(h->flowtable.name);
- xfree(h->obj.name);
+ free_const(h->table.name);
+ free_const(h->chain.name);
+ free_const(h->set.name);
+ free_const(h->flowtable.name);
+ free_const(h->obj.name);
}
void handle_merge(struct handle *dst, const struct handle *src)
@@ -137,176 +139,6 @@ void handle_merge(struct handle *dst, const struct handle *src)
dst->index = src->index;
}
-static int cache_init_tables(struct netlink_ctx *ctx, struct handle *h,
- struct nft_cache *cache)
-{
- int ret;
-
- ret = netlink_list_tables(ctx, h);
- if (ret < 0)
- return -1;
-
- list_splice_tail_init(&ctx->list, &cache->list);
- return 0;
-}
-
-static int cache_init_objects(struct netlink_ctx *ctx, unsigned int flags)
-{
- struct rule *rule, *nrule;
- struct table *table;
- struct chain *chain;
- struct set *set;
- int ret;
-
- list_for_each_entry(table, &ctx->nft->cache.list, list) {
- if (flags & NFT_CACHE_SET_BIT) {
- ret = netlink_list_sets(ctx, &table->handle);
- list_splice_tail_init(&ctx->list, &table->sets);
- if (ret < 0)
- return -1;
- }
- if (flags & NFT_CACHE_SETELEM_BIT) {
- list_for_each_entry(set, &table->sets, list) {
- ret = netlink_list_setelems(ctx, &set->handle,
- set);
- if (ret < 0)
- return -1;
- }
- }
- if (flags & NFT_CACHE_CHAIN_BIT) {
- ret = netlink_list_chains(ctx, &table->handle);
- if (ret < 0)
- return -1;
- list_splice_tail_init(&ctx->list, &table->chains);
- }
- if (flags & NFT_CACHE_FLOWTABLE_BIT) {
- ret = netlink_list_flowtables(ctx, &table->handle);
- if (ret < 0)
- return -1;
- list_splice_tail_init(&ctx->list, &table->flowtables);
- }
- if (flags & NFT_CACHE_OBJECT_BIT) {
- ret = netlink_list_objs(ctx, &table->handle);
- if (ret < 0)
- return -1;
- list_splice_tail_init(&ctx->list, &table->objs);
- }
-
- if (flags & NFT_CACHE_RULE_BIT) {
- ret = netlink_list_rules(ctx, &table->handle);
- list_for_each_entry_safe(rule, nrule, &ctx->list, list) {
- chain = chain_lookup(table, &rule->handle);
- list_move_tail(&rule->list, &chain->rules);
- }
- if (ret < 0)
- return -1;
- }
- }
- return 0;
-}
-
-static int cache_init(struct netlink_ctx *ctx, unsigned int flags)
-{
- struct handle handle = {
- .family = NFPROTO_UNSPEC,
- };
- int ret;
-
- if (flags == NFT_CACHE_EMPTY)
- return 0;
-
- /* assume NFT_CACHE_TABLE is always set. */
- ret = cache_init_tables(ctx, &handle, &ctx->nft->cache);
- if (ret < 0)
- return ret;
- ret = cache_init_objects(ctx, flags);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
-static bool cache_is_complete(struct nft_cache *cache, unsigned int flags)
-{
- return (cache->flags & flags) == flags;
-}
-
-static bool cache_is_updated(struct nft_cache *cache, uint16_t genid)
-{
- return genid && genid == cache->genid;
-}
-
-bool cache_needs_update(struct nft_cache *cache)
-{
- return cache->flags & NFT_CACHE_UPDATE;
-}
-
-int cache_update(struct nft_ctx *nft, unsigned int flags, struct list_head *msgs)
-{
- struct netlink_ctx ctx = {
- .list = LIST_HEAD_INIT(ctx.list),
- .nft = nft,
- .msgs = msgs,
- };
- struct nft_cache *cache = &nft->cache;
- uint32_t genid, genid_stop, oldflags;
- int ret;
-replay:
- ctx.seqnum = cache->seqnum++;
- genid = mnl_genid_get(&ctx);
- if (cache_is_complete(cache, flags) &&
- cache_is_updated(cache, genid))
- return 0;
-
- if (cache->genid)
- cache_release(cache);
-
- if (flags & NFT_CACHE_FLUSHED) {
- oldflags = flags;
- flags = NFT_CACHE_EMPTY;
- if (oldflags & NFT_CACHE_UPDATE)
- flags |= NFT_CACHE_UPDATE;
- goto skip;
- }
-
- ret = cache_init(&ctx, flags);
- if (ret < 0) {
- cache_release(cache);
- if (errno == EINTR) {
- nft->nf_sock = nft_mnl_socket_reopen(nft->nf_sock);
- goto replay;
- }
- return -1;
- }
-
- genid_stop = mnl_genid_get(&ctx);
- if (genid != genid_stop) {
- cache_release(cache);
- goto replay;
- }
-skip:
- cache->genid = genid;
- cache->flags = flags;
- return 0;
-}
-
-static void __cache_flush(struct list_head *table_list)
-{
- struct table *table, *next;
-
- list_for_each_entry_safe(table, next, table_list, list) {
- list_del(&table->list);
- table_free(table);
- }
-}
-
-void cache_release(struct nft_cache *cache)
-{
- __cache_flush(&cache->list);
- cache->genid = 0;
- cache->flags = NFT_CACHE_EMPTY;
-}
-
/* internal ID to uniquely identify a set in the batch */
static uint32_t set_id;
@@ -314,11 +146,15 @@ struct set *set_alloc(const struct location *loc)
{
struct set *set;
+ assert(loc);
+
set = xzalloc(sizeof(*set));
set->refcnt = 1;
set->handle.set_id = ++set_id;
- if (loc != NULL)
- set->location = *loc;
+ set->location = *loc;
+
+ init_list_head(&set->stmt_list);
+
return set;
}
@@ -326,7 +162,7 @@ struct set *set_clone(const struct set *set)
{
struct set *new_set;
- new_set = set_alloc(NULL);
+ new_set = set_alloc(&internal_location);
handle_merge(&new_set->handle, &set->handle);
new_set->flags = set->flags;
new_set->gc_int = set->gc_int;
@@ -337,7 +173,8 @@ struct set *set_clone(const struct set *set)
new_set->objtype = set->objtype;
new_set->policy = set->policy;
new_set->automerge = set->automerge;
- new_set->desc.size = set->desc.size;
+ new_set->desc = set->desc;
+ init_list_head(&new_set->stmt_list);
return new_set;
}
@@ -350,30 +187,20 @@ struct set *set_get(struct set *set)
void set_free(struct set *set)
{
+ struct stmt *stmt, *next;
+
if (--set->refcnt > 0)
return;
- if (set->init != NULL)
- expr_free(set->init);
+
+ expr_free(set->init);
+ if (set->comment)
+ free_const(set->comment);
handle_free(&set->handle);
+ list_for_each_entry_safe(stmt, next, &set->stmt_list, list)
+ stmt_free(stmt);
expr_free(set->key);
expr_free(set->data);
- xfree(set);
-}
-
-void set_add_hash(struct set *set, struct table *table)
-{
- list_add_tail(&set->list, &table->sets);
-}
-
-struct set *set_lookup(const struct table *table, const char *name)
-{
- struct set *set;
-
- list_for_each_entry(set, &table->sets, list) {
- if (!strcmp(set->handle.set.name, name))
- return set;
- }
- return NULL;
+ free(set);
}
struct set *set_lookup_fuzzy(const char *set_name,
@@ -386,14 +213,10 @@ struct set *set_lookup_fuzzy(const char *set_name,
string_misspell_init(&st);
- list_for_each_entry(table, &cache->list, list) {
- list_for_each_entry(set, &table->sets, list) {
+ list_for_each_entry(table, &cache->table_cache.list, cache.list) {
+ list_for_each_entry(set, &table->set_cache.list, cache.list) {
if (set_is_anonymous(set->flags))
continue;
- if (!strcmp(set->handle.set.name, set_name)) {
- *t = table;
- return set;
- }
if (string_misspell_update(set->handle.set.name,
set_name, set, &st))
*t = table;
@@ -405,17 +228,13 @@ struct set *set_lookup_fuzzy(const char *set_name,
struct set *set_lookup_global(uint32_t family, const char *table,
const char *name, struct nft_cache *cache)
{
- struct handle h;
struct table *t;
- h.family = family;
- h.table.name = table;
-
- t = table_lookup(&h, cache);
+ t = table_cache_find(&cache->table_cache, table, family);
if (t == NULL)
return NULL;
- return set_lookup(t, name);
+ return set_cache_find(t, name);
}
struct print_fmt_options {
@@ -461,6 +280,9 @@ static void set_print_key_and_data(const struct set *set, struct output_ctx *oct
if (set_is_datamap(set->flags)) {
nft_print(octx, " : ");
+ if (set->data->flags & EXPR_F_INTERVAL)
+ nft_print(octx, "interval ");
+
if (use_typeof)
expr_print(set->data, octx);
else
@@ -475,6 +297,7 @@ static void set_print_declaration(const struct set *set,
struct output_ctx *octx)
{
const char *delim = "";
+ struct stmt *stmt;
const char *type;
uint32_t flags;
@@ -544,6 +367,23 @@ static void set_print_declaration(const struct set *set,
}
nft_print(octx, "%s", opts->stmt_separator);
}
+
+ if (!list_empty(&set->stmt_list)) {
+ unsigned int flags = octx->flags;
+
+ nft_print(octx, "%s%s", opts->tab, opts->tab);
+
+ octx->flags |= NFT_CTX_OUTPUT_STATELESS;
+ list_for_each_entry(stmt, &set->stmt_list, list) {
+ stmt_print(stmt, octx);
+ if (!list_is_last(&stmt->list, &set->stmt_list))
+ nft_print(octx, " ");
+ }
+ octx->flags = flags;
+
+ nft_print(octx, "%s", opts->stmt_separator);
+ }
+
if (set->automerge)
nft_print(octx, "%s%sauto-merge%s", opts->tab, opts->tab,
opts->stmt_separator);
@@ -558,6 +398,13 @@ static void set_print_declaration(const struct set *set,
time_print(set->gc_int, octx);
nft_print(octx, "%s", opts->stmt_separator);
}
+
+ if (set->comment) {
+ nft_print(octx, "%s%scomment \"%s\"%s",
+ opts->tab, opts->tab,
+ set->comment,
+ opts->stmt_separator);
+ }
}
static void do_set_print(const struct set *set, struct print_fmt_options *opts,
@@ -607,6 +454,8 @@ struct rule *rule_alloc(const struct location *loc, const struct handle *h)
{
struct rule *rule;
+ assert(loc);
+
rule = xzalloc(sizeof(*rule));
rule->location = *loc;
init_list_head(&rule->list);
@@ -630,8 +479,8 @@ void rule_free(struct rule *rule)
return;
stmt_list_free(&rule->stmts);
handle_free(&rule->handle);
- xfree(rule->comment);
- xfree(rule);
+ free_const(rule->comment);
+ free(rule);
}
void rule_print(const struct rule *rule, struct output_ctx *octx)
@@ -673,6 +522,19 @@ struct rule *rule_lookup_by_index(const struct chain *chain, uint64_t index)
return NULL;
}
+void rule_stmt_append(struct rule *rule, struct stmt *stmt)
+{
+ list_add_tail(&stmt->list, &rule->stmts);
+ rule->num_stmts++;
+}
+
+void rule_stmt_insert_at(struct rule *rule, struct stmt *nstmt,
+ struct stmt *stmt)
+{
+ list_add_tail(&nstmt->list, &stmt->list);
+ rule->num_stmts++;
+}
+
struct scope *scope_alloc(void)
{
struct scope *scope = xzalloc(sizeof(struct scope));
@@ -695,16 +557,16 @@ void scope_release(const struct scope *scope)
list_for_each_entry_safe(sym, next, &scope->symbols, list) {
assert(sym->refcnt == 1);
list_del(&sym->list);
- xfree(sym->identifier);
+ free_const(sym->identifier);
expr_free(sym->expr);
- xfree(sym);
+ free(sym);
}
}
void scope_free(struct scope *scope)
{
scope_release(scope);
- xfree(scope);
+ free(scope);
}
void symbol_bind(struct scope *scope, const char *identifier, struct expr *expr)
@@ -735,9 +597,9 @@ struct symbol *symbol_get(const struct scope *scope, const char *identifier)
static void symbol_put(struct symbol *sym)
{
if (--sym->refcnt == 0) {
- xfree(sym->identifier);
+ free_const(sym->identifier);
expr_free(sym->expr);
- xfree(sym);
+ free(sym);
}
}
@@ -817,6 +679,7 @@ static const char * const chain_hookname_str_array[] = {
"postrouting",
"output",
"ingress",
+ "egress",
NULL,
};
@@ -832,16 +695,19 @@ const char *chain_hookname_lookup(const char *name)
return NULL;
}
-struct chain *chain_alloc(const char *name)
+/* internal ID to uniquely identify a set in the batch */
+static uint32_t chain_id;
+
+struct chain *chain_alloc(void)
{
struct chain *chain;
chain = xzalloc(sizeof(*chain));
+ chain->location = internal_location;
chain->refcnt = 1;
+ chain->handle.chain_id = ++chain_id;
init_list_head(&chain->rules);
init_list_head(&chain->scope.symbols);
- if (name != NULL)
- chain->handle.chain.name = xstrdup(name);
chain->policy = NULL;
return chain;
@@ -863,28 +729,29 @@ void chain_free(struct chain *chain)
list_for_each_entry_safe(rule, next, &chain->rules, list)
rule_free(rule);
handle_free(&chain->handle);
- scope_release(&chain->scope);
- xfree(chain->type);
+ free_const(chain->type.str);
expr_free(chain->dev_expr);
for (i = 0; i < chain->dev_array_len; i++)
- xfree(chain->dev_array[i]);
- xfree(chain->dev_array);
+ free_const(chain->dev_array[i]);
+ free(chain->dev_array);
expr_free(chain->priority.expr);
expr_free(chain->policy);
- xfree(chain);
-}
+ free_const(chain->comment);
-void chain_add_hash(struct chain *chain, struct table *table)
-{
- list_add_tail(&chain->list, &table->chains);
+ /* MUST be released after all expressions, they could
+ * hold refcounts.
+ */
+ scope_release(&chain->scope);
+ free(chain);
}
-struct chain *chain_lookup(const struct table *table, const struct handle *h)
+struct chain *chain_binding_lookup(const struct table *table,
+ const char *chain_name)
{
struct chain *chain;
- list_for_each_entry(chain, &table->chains, list) {
- if (!strcmp(chain->handle.chain.name, h->chain.name))
+ list_for_each_entry(chain, &table->chain_bindings, cache.list) {
+ if (!strcmp(chain->handle.chain.name, chain_name))
return chain;
}
return NULL;
@@ -898,14 +765,13 @@ struct chain *chain_lookup_fuzzy(const struct handle *h,
struct table *table;
struct chain *chain;
+ if (!h->chain.name)
+ return NULL;
+
string_misspell_init(&st);
- list_for_each_entry(table, &cache->list, list) {
- list_for_each_entry(chain, &table->chains, list) {
- if (!strcmp(chain->handle.chain.name, h->chain.name)) {
- *t = table;
- return chain;
- }
+ list_for_each_entry(table, &cache->table_cache.list, cache.list) {
+ list_for_each_entry(chain, &table->chain_cache.list, cache.list) {
if (string_misspell_update(chain->handle.chain.name,
h->chain.name, chain, &st))
*t = table;
@@ -953,6 +819,8 @@ const char *hooknum2str(unsigned int family, unsigned int hooknum)
return "postrouting";
case NF_INET_LOCAL_OUT:
return "output";
+ case NF_INET_INGRESS:
+ return "ingress";
default:
break;
};
@@ -965,6 +833,8 @@ const char *hooknum2str(unsigned int family, unsigned int hooknum)
return "forward";
case NF_ARP_OUT:
return "output";
+ case __NF_ARP_INGRESS:
+ return "ingress";
default:
break;
}
@@ -973,6 +843,8 @@ const char *hooknum2str(unsigned int family, unsigned int hooknum)
switch (hooknum) {
case NF_NETDEV_INGRESS:
return "ingress";
+ case NF_NETDEV_EGRESS:
+ return "egress";
}
break;
default:
@@ -998,7 +870,7 @@ struct prio_tag {
const char *str;
};
-const static struct prio_tag std_prios[] = {
+static const struct prio_tag std_prios[] = {
{ NF_IP_PRI_RAW, "raw" },
{ NF_IP_PRI_MANGLE, "mangle" },
{ NF_IP_PRI_NAT_DST, "dstnat" },
@@ -1007,7 +879,7 @@ const static struct prio_tag std_prios[] = {
{ NF_IP_PRI_NAT_SRC, "srcnat" },
};
-const static struct prio_tag bridge_std_prios[] = {
+static const struct prio_tag bridge_std_prios[] = {
{ NF_BR_PRI_NAT_DST_BRIDGED, "dstnat" },
{ NF_BR_PRI_FILTER_BRIDGED, "filter" },
{ NF_BR_PRI_NAT_DST_OTHER, "out" },
@@ -1061,7 +933,8 @@ static bool std_prio_family_hook_compat(int prio, int family, int hook)
case NFPROTO_INET:
case NFPROTO_IPV4:
case NFPROTO_IPV6:
- if (hook == NF_INET_PRE_ROUTING)
+ if (hook == NF_INET_PRE_ROUTING ||
+ hook == NF_INET_LOCAL_OUT)
return true;
}
break;
@@ -1070,7 +943,8 @@ static bool std_prio_family_hook_compat(int prio, int family, int hook)
case NFPROTO_INET:
case NFPROTO_IPV4:
case NFPROTO_IPV6:
- if (hook == NF_INET_POST_ROUTING)
+ if (hook == NF_INET_LOCAL_IN ||
+ hook == NF_INET_POST_ROUTING)
return true;
}
}
@@ -1103,10 +977,11 @@ static const char *prio2str(const struct output_ctx *octx,
const struct expr *expr)
{
const struct prio_tag *prio_arr;
- int std_prio, offset, prio;
+ const uint32_t reach = 10;
const char *std_prio_str;
- const int reach = 10;
+ int std_prio, prio;
size_t i, arr_size;
+ int64_t offset;
mpz_export_data(&prio, expr->value, BYTEORDER_HOST_ENDIAN, sizeof(int));
if (family == NFPROTO_BRIDGE) {
@@ -1121,19 +996,21 @@ static const char *prio2str(const struct output_ctx *octx,
for (i = 0; i < arr_size; ++i) {
std_prio = prio_arr[i].val;
std_prio_str = prio_arr[i].str;
- if (abs(prio - std_prio) <= reach) {
+
+ offset = (int64_t)prio - std_prio;
+ if (llabs(offset) <= reach) {
if (!std_prio_family_hook_compat(std_prio,
family, hook))
break;
- offset = prio - std_prio;
+
strncpy(buf, std_prio_str, bufsize);
if (offset > 0)
snprintf(buf + strlen(buf),
- bufsize - strlen(buf), " + %d",
+ bufsize - strlen(buf), " + %" PRIu64,
offset);
else if (offset < 0)
snprintf(buf + strlen(buf),
- bufsize - strlen(buf), " - %d",
+ bufsize - strlen(buf), " - %" PRIu64,
-offset);
return buf;
}
@@ -1149,13 +1026,18 @@ static void chain_print_declaration(const struct chain *chain,
char priobuf[STD_PRIO_BUFSIZE];
int policy, i;
+ if (chain->flags & CHAIN_F_BINDING)
+ return;
+
nft_print(octx, "\tchain %s {", chain->handle.chain.name);
if (nft_output_handle(octx))
nft_print(octx, " # handle %" PRIu64, chain->handle.handle.id);
+ if (chain->comment)
+ nft_print(octx, "\n\t\tcomment \"%s\"", chain->comment);
nft_print(octx, "\n");
if (chain->flags & CHAIN_F_BASECHAIN) {
- nft_print(octx, "\t\ttype %s hook %s", chain->type,
- hooknum2str(chain->handle.family, chain->hooknum));
+ nft_print(octx, "\t\ttype %s hook %s", chain->type.str,
+ hooknum2str(chain->handle.family, chain->hook.num));
if (chain->dev_array_len == 1) {
nft_print(octx, " device \"%s\"", chain->dev_array[0]);
} else if (chain->dev_array_len > 1) {
@@ -1169,7 +1051,7 @@ static void chain_print_declaration(const struct chain *chain,
}
nft_print(octx, " priority %s;",
prio2str(octx, priobuf, sizeof(priobuf),
- chain->handle.family, chain->hooknum,
+ chain->handle.family, chain->hook.num,
chain->priority.expr));
if (chain->policy) {
mpz_export_data(&policy, chain->policy->value,
@@ -1177,21 +1059,35 @@ static void chain_print_declaration(const struct chain *chain,
nft_print(octx, " policy %s;",
chain_policy2str(policy));
}
+ if (chain->flags & CHAIN_F_HW_OFFLOAD)
+ nft_print(octx, " flags offload;");
+
nft_print(octx, "\n");
}
}
-static void chain_print(const struct chain *chain, struct output_ctx *octx)
+void chain_rules_print(const struct chain *chain, struct output_ctx *octx,
+ const char *indent)
{
+ unsigned int flags = octx->flags;
struct rule *rule;
- chain_print_declaration(chain, octx);
+ if (chain->flags & CHAIN_F_BINDING)
+ octx->flags &= ~NFT_CTX_OUTPUT_HANDLE;
list_for_each_entry(rule, &chain->rules, list) {
- nft_print(octx, "\t\t");
+ nft_print(octx, "\t\t%s", indent ? : "");
rule_print(rule, octx);
nft_print(octx, "\n");
}
+
+ octx->flags = flags;
+}
+
+static void chain_print(const struct chain *chain, struct output_ctx *octx)
+{
+ chain_print_declaration(chain, octx);
+ chain_rules_print(chain, octx, NULL);
nft_print(octx, "\t}\n");
}
@@ -1206,10 +1102,23 @@ void chain_print_plain(const struct chain *chain, struct output_ctx *octx)
if (chain->flags & CHAIN_F_BASECHAIN) {
mpz_export_data(&policy, chain->policy->value,
BYTEORDER_HOST_ENDIAN, sizeof(int));
- nft_print(octx, " { type %s hook %s priority %s; policy %s; }",
- chain->type, chain->hookstr,
+ nft_print(octx, " { type %s hook %s ",
+ chain->type.str, chain->hook.name);
+
+ if (chain->dev_array_len > 0) {
+ int i;
+
+ nft_print(octx, "devices = { ");
+ for (i = 0; i < chain->dev_array_len; i++) {
+ nft_print(octx, "%s", chain->dev_array[i]);
+ if (i + 1 != chain->dev_array_len)
+ nft_print(octx, ", ");
+ }
+ nft_print(octx, " } ");
+ }
+ nft_print(octx, "priority %s; policy %s; }",
prio2str(octx, priobuf, sizeof(priobuf),
- chain->handle.family, chain->hooknum,
+ chain->handle.family, chain->hook.num,
chain->priority.expr),
chain_policy2str(policy));
}
@@ -1222,13 +1131,20 @@ struct table *table_alloc(void)
struct table *table;
table = xzalloc(sizeof(*table));
+ table->location = internal_location;
init_list_head(&table->chains);
init_list_head(&table->sets);
init_list_head(&table->objs);
init_list_head(&table->flowtables);
+ init_list_head(&table->chain_bindings);
init_list_head(&table->scope.symbols);
table->refcnt = 1;
+ cache_init(&table->chain_cache);
+ cache_init(&table->set_cache);
+ cache_init(&table->obj_cache);
+ cache_init(&table->ft_cache);
+
return table;
}
@@ -1241,17 +1157,38 @@ void table_free(struct table *table)
if (--table->refcnt > 0)
return;
+ if (table->comment)
+ free_const(table->comment);
list_for_each_entry_safe(chain, next, &table->chains, list)
chain_free(chain);
+ list_for_each_entry_safe(chain, next, &table->chain_bindings, cache.list)
+ chain_free(chain);
+ /* this is implicitly releasing chains in the hashtable cache */
+ list_for_each_entry_safe(chain, next, &table->chain_cache.list, cache.list)
+ chain_free(chain);
list_for_each_entry_safe(set, nset, &table->sets, list)
set_free(set);
+ /* this is implicitly releasing sets in the hashtable cache */
+ list_for_each_entry_safe(set, nset, &table->set_cache.list, cache.list)
+ set_free(set);
list_for_each_entry_safe(ft, nft, &table->flowtables, list)
flowtable_free(ft);
+ /* this is implicitly releasing flowtables in the hashtable cache */
+ list_for_each_entry_safe(ft, nft, &table->ft_cache.list, cache.list)
+ flowtable_free(ft);
list_for_each_entry_safe(obj, nobj, &table->objs, list)
obj_free(obj);
+ /* this is implicitly releasing objs in the hashtable cache */
+ list_for_each_entry_safe(obj, nobj, &table->obj_cache.list, cache.list)
+ obj_free(obj);
+
handle_free(&table->handle);
scope_release(&table->scope);
- xfree(table);
+ cache_free(&table->chain_cache);
+ cache_free(&table->set_cache);
+ cache_free(&table->obj_cache);
+ cache_free(&table->ft_cache);
+ free(table);
}
struct table *table_get(struct table *table)
@@ -1260,24 +1197,6 @@ struct table *table_get(struct table *table)
return table;
}
-void table_add_hash(struct table *table, struct nft_cache *cache)
-{
- list_add_tail(&table->list, &cache->list);
-}
-
-struct table *table_lookup(const struct handle *h,
- const struct nft_cache *cache)
-{
- struct table *table;
-
- list_for_each_entry(table, &cache->list, list) {
- if (table->handle.family == h->family &&
- !strcmp(table->handle.table.name, h->table.name))
- return table;
- }
- return NULL;
-}
-
struct table *table_lookup_fuzzy(const struct handle *h,
const struct nft_cache *cache)
{
@@ -1286,39 +1205,48 @@ struct table *table_lookup_fuzzy(const struct handle *h,
string_misspell_init(&st);
- list_for_each_entry(table, &cache->list, list) {
- if (!strcmp(table->handle.table.name, h->table.name))
- return table;
-
+ list_for_each_entry(table, &cache->table_cache.list, cache.list) {
string_misspell_update(table->handle.table.name,
h->table.name, table, &st);
}
return st.obj;
}
-const char *table_flags_name[TABLE_FLAGS_MAX] = {
+static const char *table_flags_name[TABLE_FLAGS_MAX] = {
"dormant",
+ "owner",
};
-static void table_print_options(const struct table *table, const char **delim,
- struct output_ctx *octx)
+const char *table_flag_name(uint32_t flag)
+{
+ if (flag >= TABLE_FLAGS_MAX)
+ return "unknown";
+
+ return table_flags_name[flag];
+}
+
+static void table_print_flags(const struct table *table, const char **delim,
+ struct output_ctx *octx)
{
uint32_t flags = table->flags;
+ bool comma = false;
int i;
- if (flags) {
- nft_print(octx, "\tflags ");
+ if (!table->flags)
+ return;
- for (i = 0; i < TABLE_FLAGS_MAX; i++) {
- if (flags & 0x1)
- nft_print(octx, "%s", table_flags_name[i]);
- flags >>= 1;
- if (flags)
+ nft_print(octx, "\tflags ");
+ for (i = 0; i < TABLE_FLAGS_MAX; i++) {
+ if (flags & (1 << i)) {
+ if (comma)
nft_print(octx, ",");
+
+ nft_print(octx, "%s", table_flag_name(i));
+ comma = true;
}
- nft_print(octx, "\n");
- *delim = "\n";
}
+ nft_print(octx, "\n");
+ *delim = "\n";
}
static void table_print(const struct table *table, struct output_ctx *octx)
@@ -1330,30 +1258,43 @@ static void table_print(const struct table *table, struct output_ctx *octx)
const char *delim = "";
const char *family = family2str(table->handle.family);
+ if (table->has_xt_stmts)
+ fprintf(octx->error_fp,
+ "# Warning: table %s %s is managed by iptables-nft, do not touch!\n",
+ family, table->handle.table.name);
+
nft_print(octx, "table %s %s {", family, table->handle.table.name);
+ if (nft_output_handle(octx) || table->flags & TABLE_F_OWNER)
+ nft_print(octx, " #");
if (nft_output_handle(octx))
- nft_print(octx, " # handle %" PRIu64, table->handle.handle.id);
+ nft_print(octx, " handle %" PRIu64, table->handle.handle.id);
+ if (table->flags & TABLE_F_OWNER)
+ nft_print(octx, " progname %s", get_progname(table->owner));
+
nft_print(octx, "\n");
- table_print_options(table, &delim, octx);
+ table_print_flags(table, &delim, octx);
+
+ if (table->comment)
+ nft_print(octx, "\tcomment \"%s\"\n", table->comment);
- list_for_each_entry(obj, &table->objs, list) {
+ list_for_each_entry(obj, &table->obj_cache.list, cache.list) {
nft_print(octx, "%s", delim);
obj_print(obj, octx);
delim = "\n";
}
- list_for_each_entry(set, &table->sets, list) {
+ list_for_each_entry(set, &table->set_cache.list, cache.list) {
if (set_is_anonymous(set->flags))
continue;
nft_print(octx, "%s", delim);
set_print(set, octx);
delim = "\n";
}
- list_for_each_entry(flowtable, &table->flowtables, list) {
+ list_for_each_entry(flowtable, &table->ft_cache.list, cache.list) {
nft_print(octx, "%s", delim);
flowtable_print(flowtable, octx);
delim = "\n";
}
- list_for_each_entry(chain, &table->chains, list) {
+ list_for_each_entry(chain, &table->chain_cache.list, cache.list) {
nft_print(octx, "%s", delim);
chain_print(chain, octx);
delim = "\n";
@@ -1367,6 +1308,8 @@ struct cmd *cmd_alloc(enum cmd_ops op, enum cmd_obj obj,
{
struct cmd *cmd;
+ assert(loc);
+
cmd = xzalloc(sizeof(*cmd));
init_list_head(&cmd->list);
cmd->op = op;
@@ -1374,75 +1317,12 @@ struct cmd *cmd_alloc(enum cmd_ops op, enum cmd_obj obj,
cmd->handle = *h;
cmd->location = *loc;
cmd->data = data;
- return cmd;
-}
-
-void nft_cmd_expand(struct cmd *cmd)
-{
- struct list_head new_cmds;
- struct flowtable *ft;
- struct table *table;
- struct chain *chain;
- struct rule *rule;
- struct set *set;
- struct obj *obj;
- struct cmd *new;
- struct handle h;
-
- init_list_head(&new_cmds);
+ cmd->attr = xzalloc_array(NFT_NLATTR_LOC_MAX,
+ sizeof(struct nlerr_loc));
+ cmd->attr_array_len = NFT_NLATTR_LOC_MAX;
+ init_list_head(&cmd->collapse_list);
- switch (cmd->obj) {
- case CMD_OBJ_TABLE:
- table = cmd->table;
- if (!table)
- return;
-
- list_for_each_entry(chain, &table->chains, list) {
- memset(&h, 0, sizeof(h));
- handle_merge(&h, &chain->handle);
- new = cmd_alloc(CMD_ADD, CMD_OBJ_CHAIN, &h,
- &chain->location, chain_get(chain));
- list_add_tail(&new->list, &new_cmds);
- }
- list_for_each_entry(obj, &table->objs, list) {
- handle_merge(&obj->handle, &table->handle);
- memset(&h, 0, sizeof(h));
- handle_merge(&h, &obj->handle);
- new = cmd_alloc(CMD_ADD, obj_type_to_cmd(obj->type), &h,
- &obj->location, obj_get(obj));
- list_add_tail(&new->list, &new_cmds);
- }
- list_for_each_entry(set, &table->sets, list) {
- handle_merge(&set->handle, &table->handle);
- memset(&h, 0, sizeof(h));
- handle_merge(&h, &set->handle);
- new = cmd_alloc(CMD_ADD, CMD_OBJ_SET, &h,
- &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));
- handle_merge(&h, &rule->handle);
- new = cmd_alloc(CMD_ADD, CMD_OBJ_RULE, &h,
- &rule->location,
- rule_get(rule));
- list_add_tail(&new->list, &new_cmds);
- }
- }
- list_splice(&new_cmds, &cmd->list);
- break;
- default:
- break;
- }
+ return cmd;
}
struct markup *markup_alloc(uint32_t format)
@@ -1457,7 +1337,7 @@ struct markup *markup_alloc(uint32_t format)
void markup_free(struct markup *m)
{
- xfree(m);
+ free(m);
}
struct monitor *monitor_alloc(uint32_t format, uint32_t type, const char *event)
@@ -1475,8 +1355,8 @@ struct monitor *monitor_alloc(uint32_t format, uint32_t type, const char *event)
void monitor_free(struct monitor *m)
{
- xfree(m->event);
- xfree(m);
+ free_const(m->event);
+ free(m);
}
void cmd_free(struct cmd *cmd)
@@ -1484,10 +1364,15 @@ void cmd_free(struct cmd *cmd)
handle_free(&cmd->handle);
if (cmd->data != NULL) {
switch (cmd->obj) {
- case CMD_OBJ_SETELEM:
+ case CMD_OBJ_ELEMENTS:
expr_free(cmd->expr);
+ if (cmd->elem.set)
+ set_free(cmd->elem.set);
break;
case CMD_OBJ_SET:
+ case CMD_OBJ_MAP:
+ case CMD_OBJ_METER:
+ case CMD_OBJ_SETELEMS:
set_free(cmd->set);
break;
case CMD_OBJ_RULE:
@@ -1525,68 +1410,66 @@ void cmd_free(struct cmd *cmd)
BUG("invalid command object type %u\n", cmd->obj);
}
}
- xfree(cmd->arg);
- xfree(cmd);
+ free(cmd->attr);
+ free_const(cmd->arg);
+ free(cmd);
}
#include <netlink.h>
#include <mnl.h>
-static int __do_add_setelems(struct netlink_ctx *ctx, struct set *set,
- struct expr *expr, uint32_t flags)
+static int __do_add_elements(struct netlink_ctx *ctx, struct cmd *cmd,
+ struct set *set, struct expr *expr, uint32_t flags)
{
expr->set_flags |= set->flags;
- if (mnl_nft_setelem_add(ctx, set, expr, flags) < 0)
+ if (mnl_nft_setelem_add(ctx, cmd, set, expr, flags) < 0)
return -1;
- if (set->init != NULL &&
- set->flags & NFT_SET_INTERVAL) {
- interval_map_decompose(expr);
- list_splice_tail_init(&expr->expressions, &set->init->expressions);
- set->init->size += expr->size;
- expr->size = 0;
- }
-
return 0;
}
-static int do_add_setelems(struct netlink_ctx *ctx, struct cmd *cmd,
+static int do_add_elements(struct netlink_ctx *ctx, struct cmd *cmd,
uint32_t flags)
{
- struct handle *h = &cmd->handle;
struct expr *init = cmd->expr;
- struct table *table;
- struct set *set;
-
- table = table_lookup(h, &ctx->nft->cache);
- set = set_lookup(table, h->set.name);
+ struct set *set = cmd->elem.set;
- if (set->flags & NFT_SET_INTERVAL &&
- set_to_intervals(ctx->msgs, set, init, true,
- ctx->nft->debug_mask, set->automerge,
- &ctx->nft->output) < 0)
+ if (set_is_non_concat_range(set) &&
+ set_to_intervals(set, init, true) < 0)
return -1;
- return __do_add_setelems(ctx, set, init, flags);
+ return __do_add_elements(ctx, cmd, set, init, flags);
}
-static int do_add_set(struct netlink_ctx *ctx, const struct cmd *cmd,
+static int do_add_setelems(struct netlink_ctx *ctx, struct cmd *cmd,
+ uint32_t flags)
+{
+ struct set *set = cmd->set;
+
+ return __do_add_elements(ctx, cmd, set, set->init, flags);
+}
+
+static int do_add_set(struct netlink_ctx *ctx, struct cmd *cmd,
uint32_t flags)
{
struct set *set = cmd->set;
if (set->init != NULL) {
- if (set->flags & NFT_SET_INTERVAL &&
- set_to_intervals(ctx->msgs, set, set->init, true,
- ctx->nft->debug_mask, set->automerge,
- &ctx->nft->output) < 0)
+ /* Update set->init->size (NFTNL_SET_DESC_SIZE) before adding
+ * the set to the kernel. Calling this from do_add_setelems()
+ * comes too late which might result in spurious ENFILE errors.
+ */
+ if (set_is_non_concat_range(set) &&
+ set_to_intervals(set, set->init, true) < 0)
return -1;
}
+
if (mnl_nft_set_add(ctx, cmd, flags) < 0)
return -1;
- if (set->init != NULL) {
- return __do_add_setelems(ctx, set, set->init, flags);
- }
+
+ if (set_is_anonymous(set->flags))
+ return __do_add_elements(ctx, cmd, set, set->init, flags);
+
return 0;
}
@@ -1606,8 +1489,10 @@ static int do_command_add(struct netlink_ctx *ctx, struct cmd *cmd, bool excl)
return mnl_nft_rule_add(ctx, cmd, flags | NLM_F_APPEND);
case CMD_OBJ_SET:
return do_add_set(ctx, cmd, flags);
- case CMD_OBJ_SETELEM:
+ case CMD_OBJ_SETELEMS:
return do_add_setelems(ctx, cmd, flags);
+ case CMD_OBJ_ELEMENTS:
+ return do_add_elements(ctx, cmd, flags);
case CMD_OBJ_COUNTER:
case CMD_OBJ_QUOTA:
case CMD_OBJ_CT_HELPER:
@@ -1654,21 +1539,14 @@ static int do_command_insert(struct netlink_ctx *ctx, struct cmd *cmd)
static int do_delete_setelems(struct netlink_ctx *ctx, struct cmd *cmd)
{
- struct handle *h = &cmd->handle;
- struct expr *expr = cmd->expr;
- struct table *table;
- struct set *set;
-
- table = table_lookup(h, &ctx->nft->cache);
- set = set_lookup(table, h->set.name);
+ struct expr *expr = cmd->elem.expr;
+ struct set *set = cmd->elem.set;
- if (set->flags & NFT_SET_INTERVAL &&
- set_to_intervals(ctx->msgs, set, expr, false,
- ctx->nft->debug_mask, set->automerge,
- &ctx->nft->output) < 0)
+ if (set_is_non_concat_range(set) &&
+ set_to_intervals(set, expr, false) < 0)
return -1;
- if (mnl_nft_setelem_del(ctx, cmd) < 0)
+ if (mnl_nft_setelem_del(ctx, cmd, &cmd->handle, cmd->elem.expr) < 0)
return -1;
return 0;
@@ -1685,7 +1563,7 @@ static int do_command_delete(struct netlink_ctx *ctx, struct cmd *cmd)
return mnl_nft_rule_del(ctx, cmd);
case CMD_OBJ_SET:
return mnl_nft_set_del(ctx, cmd);
- case CMD_OBJ_SETELEM:
+ case CMD_OBJ_ELEMENTS:
return do_delete_setelems(ctx, cmd);
case CMD_OBJ_COUNTER:
return mnl_nft_obj_del(ctx, cmd, NFT_OBJECT_COUNTER);
@@ -1710,8 +1588,7 @@ static int do_command_delete(struct netlink_ctx *ctx, struct cmd *cmd)
}
}
-static int do_list_table(struct netlink_ctx *ctx, struct cmd *cmd,
- struct table *table)
+static int do_list_table(struct netlink_ctx *ctx, struct table *table)
{
table_print(table, &ctx->nft->output);
return 0;
@@ -1719,15 +1596,10 @@ static int do_list_table(struct netlink_ctx *ctx, struct cmd *cmd,
static int do_list_sets(struct netlink_ctx *ctx, struct cmd *cmd)
{
- struct print_fmt_options opts = {
- .tab = "\t",
- .nl = "\n",
- .stmt_separator = "\n",
- };
struct table *table;
struct set *set;
- list_for_each_entry(table, &ctx->nft->cache.list, list) {
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
if (cmd->handle.family != NFPROTO_UNSPEC &&
cmd->handle.family != table->handle.family)
continue;
@@ -1736,18 +1608,17 @@ static int do_list_sets(struct netlink_ctx *ctx, struct cmd *cmd)
family2str(table->handle.family),
table->handle.table.name);
- list_for_each_entry(set, &table->sets, list) {
+ list_for_each_entry(set, &table->set_cache.list, cache.list) {
if (cmd->obj == CMD_OBJ_SETS &&
!set_is_literal(set->flags))
continue;
if (cmd->obj == CMD_OBJ_METERS &&
- !set_is_meter(set->flags))
+ !set_is_meter_compat(set->flags))
continue;
if (cmd->obj == CMD_OBJ_MAPS &&
!map_is_literal(set->flags))
continue;
- set_print_declaration(set, &opts, &ctx->nft->output);
- nft_print(&ctx->nft->output, "%s}%s", opts.tab, opts.nl);
+ set_print(set, &ctx->nft->output);
}
nft_print(&ctx->nft->output, "}\n");
@@ -1759,9 +1630,10 @@ struct obj *obj_alloc(const struct location *loc)
{
struct obj *obj;
+ assert(loc);
+
obj = xzalloc(sizeof(*obj));
- if (loc != NULL)
- obj->location = *loc;
+ obj->location = *loc;
obj->refcnt = 1;
return obj;
@@ -1777,26 +1649,18 @@ void obj_free(struct obj *obj)
{
if (--obj->refcnt > 0)
return;
+ free_const(obj->comment);
handle_free(&obj->handle);
- xfree(obj);
-}
-
-void obj_add_hash(struct obj *obj, struct table *table)
-{
- list_add_tail(&obj->list, &table->objs);
-}
+ if (obj->type == NFT_OBJECT_CT_TIMEOUT) {
+ struct timeout_state *ts, *next;
-struct obj *obj_lookup(const struct table *table, const char *name,
- uint32_t type)
-{
- struct obj *obj;
-
- list_for_each_entry(obj, &table->objs, list) {
- if (!strcmp(obj->handle.obj.name, name) &&
- obj->type == type)
- return obj;
+ list_for_each_entry_safe(ts, next, &obj->ct_timeout.timeout_list, head) {
+ list_del(&ts->head);
+ free_const(ts->timeout_str);
+ free(ts);
+ }
}
- return NULL;
+ free(obj);
}
struct obj *obj_lookup_fuzzy(const char *obj_name,
@@ -1809,12 +1673,8 @@ struct obj *obj_lookup_fuzzy(const char *obj_name,
string_misspell_init(&st);
- list_for_each_entry(table, &cache->list, list) {
- list_for_each_entry(obj, &table->objs, list) {
- if (!strcmp(obj->handle.obj.name, obj_name)) {
- *t = table;
- return obj;
- }
+ list_for_each_entry(table, &cache->table_cache.list, cache.list) {
+ list_for_each_entry(obj, &table->obj_cache.list, cache.list) {
if (string_misspell_update(obj->handle.obj.name,
obj_name, obj, &st))
*t = table;
@@ -1825,10 +1685,10 @@ struct obj *obj_lookup_fuzzy(const char *obj_name,
static void print_proto_name_proto(uint8_t l4, struct output_ctx *octx)
{
- const struct protoent *p = getprotobynumber(l4);
+ char name[NFT_PROTONAME_MAXSIZE];
- if (p)
- nft_print(octx, "%s", p->p_name);
+ if (nft_getprotobynumber(l4, name, sizeof(name)))
+ nft_print(octx, "%s", name);
else
nft_print(octx, "%d", l4);
}
@@ -1843,11 +1703,14 @@ static void print_proto_timeout_policy(uint8_t l4, const uint32_t *timeout,
nft_print(octx, "%s%spolicy = { ", opts->tab, opts->tab);
for (i = 0; i < timeout_protocol[l4].array_size; i++) {
if (timeout[i] != timeout_protocol[l4].dflt_timeout[i]) {
+ uint64_t timeout_ms;
+
if (comma)
nft_print(octx, ", ");
- nft_print(octx, "%s : %u",
- timeout_protocol[l4].state_to_name[i],
- timeout[i]);
+ timeout_ms = timeout[i] * 1000u;
+ nft_print(octx, "%s : ",
+ timeout_protocol[l4].state_to_name[i]);
+ time_print(timeout_ms, octx);
comma = true;
}
}
@@ -1870,6 +1733,16 @@ static const char *synproxy_timestamp_to_str(const uint32_t flags)
return "";
}
+static void obj_print_comment(const struct obj *obj,
+ struct print_fmt_options *opts,
+ struct output_ctx *octx)
+{
+ if (obj->comment)
+ nft_print(octx, "%s%s%scomment \"%s\"",
+ opts->nl, opts->tab, opts->tab,
+ obj->comment);
+}
+
static void obj_print_data(const struct obj *obj,
struct print_fmt_options *opts,
struct output_ctx *octx)
@@ -1879,13 +1752,14 @@ static void obj_print_data(const struct obj *obj,
nft_print(octx, " %s {", obj->handle.obj.name);
if (nft_output_handle(octx))
nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
- nft_print(octx, "%s%s%s", opts->nl, opts->tab, opts->tab);
- if (nft_output_stateless(octx)) {
- nft_print(octx, "packets 0 bytes 0");
- break;
- }
- nft_print(octx, "packets %" PRIu64 " bytes %" PRIu64 "%s",
- obj->counter.packets, obj->counter.bytes, opts->nl);
+
+ obj_print_comment(obj, opts, octx);
+ if (nft_output_stateless(octx))
+ nft_print(octx, "%s", opts->nl);
+ else
+ nft_print(octx, "%s%s%spackets %" PRIu64 " bytes %" PRIu64 "%s",
+ opts->nl, opts->tab, opts->tab,
+ obj->counter.packets, obj->counter.bytes, opts->nl);
break;
case NFT_OBJECT_QUOTA: {
const char *data_unit;
@@ -1894,6 +1768,8 @@ static void obj_print_data(const struct obj *obj,
nft_print(octx, " %s {", obj->handle.obj.name);
if (nft_output_handle(octx))
nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
+
+ obj_print_comment(obj, opts, octx);
nft_print(octx, "%s%s%s", opts->nl, opts->tab, opts->tab);
data_unit = get_rate(obj->quota.bytes, &bytes);
nft_print(octx, "%s%" PRIu64 " %s",
@@ -1911,6 +1787,8 @@ static void obj_print_data(const struct obj *obj,
nft_print(octx, " %s {", obj->handle.obj.name);
if (nft_output_handle(octx))
nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
+
+ obj_print_comment(obj, opts, octx);
nft_print(octx, "%s%s%s", opts->nl, opts->tab, opts->tab);
nft_print(octx, "\"%s\"%s", obj->secmark.ctx, opts->nl);
break;
@@ -1918,6 +1796,8 @@ static void obj_print_data(const struct obj *obj,
nft_print(octx, " %s {", obj->handle.obj.name);
if (nft_output_handle(octx))
nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
+
+ obj_print_comment(obj, opts, octx);
nft_print(octx, "%s", opts->nl);
nft_print(octx, "%s%stype \"%s\" protocol ",
opts->tab, opts->tab, obj->ct_helper.name);
@@ -1932,6 +1812,8 @@ static void obj_print_data(const struct obj *obj,
nft_print(octx, " %s {", obj->handle.obj.name);
if (nft_output_handle(octx))
nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
+
+ obj_print_comment(obj, opts, octx);
nft_print(octx, "%s", opts->nl);
nft_print(octx, "%s%sprotocol ", opts->tab, opts->tab);
print_proto_name_proto(obj->ct_timeout.l4proto, octx);
@@ -1947,6 +1829,8 @@ static void obj_print_data(const struct obj *obj,
nft_print(octx, " %s {", obj->handle.obj.name);
if (nft_output_handle(octx))
nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
+
+ obj_print_comment(obj, opts, octx);
nft_print(octx, "%s", opts->nl);
nft_print(octx, "%s%sprotocol ", opts->tab, opts->tab);
print_proto_name_proto(obj->ct_expect.l4proto, octx);
@@ -1975,6 +1859,8 @@ static void obj_print_data(const struct obj *obj,
nft_print(octx, " %s {", obj->handle.obj.name);
if (nft_output_handle(octx))
nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
+
+ obj_print_comment(obj, opts, octx);
nft_print(octx, "%s%s%s", opts->nl, opts->tab, opts->tab);
switch (obj->limit.type) {
case NFT_LIMIT_PKTS:
@@ -2012,6 +1898,8 @@ static void obj_print_data(const struct obj *obj,
if (nft_output_handle(octx))
nft_print(octx, " # handle %" PRIu64, obj->handle.handle.id);
+ obj_print_comment(obj, opts, octx);
+
if (flags & NF_SYNPROXY_OPT_MSS) {
nft_print(octx, "%s%s%s", opts->nl, opts->tab, opts->tab);
nft_print(octx, "mss %u", obj->synproxy.mss);
@@ -2044,7 +1932,7 @@ static const char * const obj_type_name_array[] = {
[NFT_OBJECT_CT_EXPECT] = "ct expectation",
};
-const char *obj_type_name(enum stmt_types type)
+const char *obj_type_name(unsigned int type)
{
assert(type <= NFT_OBJECT_MAX && obj_type_name_array[type]);
@@ -2062,7 +1950,7 @@ static uint32_t obj_type_cmd_array[NFT_OBJECT_MAX + 1] = {
[NFT_OBJECT_CT_EXPECT] = CMD_OBJ_CT_EXPECT,
};
-uint32_t obj_type_to_cmd(uint32_t type)
+enum cmd_obj obj_type_to_cmd(uint32_t type)
{
assert(type <= NFT_OBJECT_MAX && obj_type_cmd_array[type]);
@@ -2120,7 +2008,7 @@ static int do_list_obj(struct netlink_ctx *ctx, struct cmd *cmd, uint32_t type)
struct table *table;
struct obj *obj;
- list_for_each_entry(table, &ctx->nft->cache.list, list) {
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
if (cmd->handle.family != NFPROTO_UNSPEC &&
cmd->handle.family != table->handle.family)
continue;
@@ -2129,14 +2017,14 @@ static int do_list_obj(struct netlink_ctx *ctx, struct cmd *cmd, uint32_t type)
strcmp(cmd->handle.table.name, table->handle.table.name))
continue;
- if (list_empty(&table->objs))
+ if (list_empty(&table->obj_cache.list))
continue;
nft_print(&ctx->nft->output, "table %s %s {\n",
family2str(table->handle.family),
table->handle.table.name);
- list_for_each_entry(obj, &table->objs, list) {
+ list_for_each_entry(obj, &table->obj_cache.list, cache.list) {
if (obj->type != type ||
(cmd->handle.obj.name != NULL &&
strcmp(cmd->handle.obj.name, obj->handle.obj.name)))
@@ -2154,9 +2042,10 @@ struct flowtable *flowtable_alloc(const struct location *loc)
{
struct flowtable *flowtable;
+ assert(loc);
+
flowtable = xzalloc(sizeof(*flowtable));
- if (loc != NULL)
- flowtable->location = *loc;
+ flowtable->location = *loc;
flowtable->refcnt = 1;
return flowtable;
@@ -2180,15 +2069,10 @@ void flowtable_free(struct flowtable *flowtable)
if (flowtable->dev_array != NULL) {
for (i = 0; i < flowtable->dev_array_len; i++)
- xfree(flowtable->dev_array[i]);
- xfree(flowtable->dev_array);
+ free_const(flowtable->dev_array[i]);
+ free(flowtable->dev_array);
}
- xfree(flowtable);
-}
-
-void flowtable_add_hash(struct flowtable *flowtable, struct table *table)
-{
- list_add_tail(&flowtable->list, &table->flowtables);
+ free(flowtable);
}
static void flowtable_print_declaration(const struct flowtable *flowtable,
@@ -2213,18 +2097,28 @@ static void flowtable_print_declaration(const struct flowtable *flowtable,
nft_print(octx, "%s", opts->nl);
nft_print(octx, "%s%shook %s priority %s%s",
opts->tab, opts->tab,
- hooknum2str(NFPROTO_NETDEV, flowtable->hooknum),
+ hooknum2str(NFPROTO_NETDEV, flowtable->hook.num),
prio2str(octx, priobuf, sizeof(priobuf), NFPROTO_NETDEV,
- flowtable->hooknum, flowtable->priority.expr),
+ flowtable->hook.num, flowtable->priority.expr),
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, ", ");
+ if (flowtable->dev_array_len > 0) {
+ 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);
}
- nft_print(octx, " }%s", opts->stmt_separator);
+
+ if (flowtable->flags & NFT_FLOWTABLE_HW_OFFLOAD)
+ nft_print(octx, "%s%sflags offload%s", opts->tab, opts->tab,
+ opts->stmt_separator);
+
+ if (flowtable->flags & NFT_FLOWTABLE_COUNTER)
+ nft_print(octx, "%s%scounter%s", opts->tab, opts->tab,
+ opts->stmt_separator);
}
static void do_flowtable_print(const struct flowtable *flowtable,
@@ -2246,17 +2140,6 @@ void flowtable_print(const struct flowtable *s, struct output_ctx *octx)
do_flowtable_print(s, &opts, octx);
}
-struct flowtable *flowtable_lookup(const struct table *table, const char *name)
-{
- struct flowtable *ft;
-
- list_for_each_entry(ft, &table->flowtables, list) {
- if (!strcmp(ft->handle.flowtable.name, name))
- return ft;
- }
- return NULL;
-}
-
struct flowtable *flowtable_lookup_fuzzy(const char *ft_name,
const struct nft_cache *cache,
const struct table **t)
@@ -2267,12 +2150,8 @@ struct flowtable *flowtable_lookup_fuzzy(const char *ft_name,
string_misspell_init(&st);
- list_for_each_entry(table, &cache->list, list) {
- list_for_each_entry(ft, &table->flowtables, list) {
- if (!strcmp(ft->handle.flowtable.name, ft_name)) {
- *t = table;
- return ft;
- }
+ list_for_each_entry(table, &cache->table_cache.list, cache.list) {
+ list_for_each_entry(ft, &table->ft_cache.list, cache.list) {
if (string_misspell_update(ft->handle.flowtable.name,
ft_name, ft, &st))
*t = table;
@@ -2286,8 +2165,8 @@ static int do_list_flowtable(struct netlink_ctx *ctx, struct cmd *cmd,
{
struct flowtable *ft;
- ft = flowtable_lookup(table, cmd->handle.flowtable.name);
- if (ft == NULL)
+ ft = ft_cache_find(table, cmd->handle.flowtable.name);
+ if (!ft)
return -1;
nft_print(&ctx->nft->output, "table %s %s {\n",
@@ -2310,7 +2189,7 @@ static int do_list_flowtables(struct netlink_ctx *ctx, struct cmd *cmd)
struct flowtable *flowtable;
struct table *table;
- list_for_each_entry(table, &ctx->nft->cache.list, list) {
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
if (cmd->handle.family != NFPROTO_UNSPEC &&
cmd->handle.family != table->handle.family)
continue;
@@ -2319,7 +2198,7 @@ static int do_list_flowtables(struct netlink_ctx *ctx, struct cmd *cmd)
family2str(table->handle.family),
table->handle.table.name);
- list_for_each_entry(flowtable, &table->flowtables, list) {
+ list_for_each_entry(flowtable, &table->ft_cache.list, cache.list) {
flowtable_print_declaration(flowtable, &opts, &ctx->nft->output);
nft_print(&ctx->nft->output, "%s}%s", opts.tab, opts.nl);
}
@@ -2334,20 +2213,15 @@ static int do_list_ruleset(struct netlink_ctx *ctx, struct cmd *cmd)
unsigned int family = cmd->handle.family;
struct table *table;
- list_for_each_entry(table, &ctx->nft->cache.list, list) {
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
if (family != NFPROTO_UNSPEC &&
table->handle.family != family)
continue;
- cmd->handle.family = table->handle.family;
- cmd->handle.table.name = table->handle.table.name;
-
- if (do_list_table(ctx, cmd, table) < 0)
+ if (do_list_table(ctx, table) < 0)
return -1;
}
- cmd->handle.table.name = NULL;
-
return 0;
}
@@ -2355,7 +2229,7 @@ static int do_list_tables(struct netlink_ctx *ctx, struct cmd *cmd)
{
struct table *table;
- list_for_each_entry(table, &ctx->nft->cache.list, list) {
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
if (cmd->handle.family != NFPROTO_UNSPEC &&
cmd->handle.family != table->handle.family)
continue;
@@ -2371,9 +2245,14 @@ static int do_list_tables(struct netlink_ctx *ctx, struct cmd *cmd)
static void table_print_declaration(struct table *table,
struct output_ctx *octx)
{
- nft_print(octx, "table %s %s {\n",
- family2str(table->handle.family),
- table->handle.table.name);
+ const char *family = family2str(table->handle.family);
+
+ if (table->has_xt_stmts)
+ fprintf(octx->error_fp,
+ "# Warning: table %s %s is managed by iptables-nft, do not touch!\n",
+ family, table->handle.table.name);
+
+ nft_print(octx, "table %s %s {\n", family, table->handle.table.name);
}
static int do_list_chain(struct netlink_ctx *ctx, struct cmd *cmd,
@@ -2383,13 +2262,9 @@ static int do_list_chain(struct netlink_ctx *ctx, struct cmd *cmd,
table_print_declaration(table, &ctx->nft->output);
- list_for_each_entry(chain, &table->chains, list) {
- if (chain->handle.family != cmd->handle.family ||
- strcmp(cmd->handle.chain.name, chain->handle.chain.name) != 0)
- continue;
-
+ chain = chain_cache_find(table, cmd->handle.chain.name);
+ if (chain)
chain_print(chain, &ctx->nft->output);
- }
nft_print(&ctx->nft->output, "}\n");
@@ -2401,14 +2276,14 @@ static int do_list_chains(struct netlink_ctx *ctx, struct cmd *cmd)
struct table *table;
struct chain *chain;
- list_for_each_entry(table, &ctx->nft->cache.list, list) {
+ list_for_each_entry(table, &ctx->nft->cache.table_cache.list, cache.list) {
if (cmd->handle.family != NFPROTO_UNSPEC &&
cmd->handle.family != table->handle.family)
continue;
table_print_declaration(table, &ctx->nft->output);
- list_for_each_entry(chain, &table->chains, list) {
+ list_for_each_entry(chain, &table->chain_cache.list, cache.list) {
chain_print_declaration(chain, &ctx->nft->output);
nft_print(&ctx->nft->output, "\t}\n");
}
@@ -2419,9 +2294,15 @@ static int do_list_chains(struct netlink_ctx *ctx, struct cmd *cmd)
}
static void __do_list_set(struct netlink_ctx *ctx, struct cmd *cmd,
- struct table *table, struct set *set)
+ struct set *set)
{
+ struct table *table = table_alloc();
+
+ table->handle.table.name = xstrdup(cmd->handle.table.name);
+ table->handle.family = cmd->handle.family;
table_print_declaration(table, &ctx->nft->output);
+ table_free(table);
+
set_print(set, &ctx->nft->output);
nft_print(&ctx->nft->output, "}\n");
}
@@ -2429,17 +2310,30 @@ static void __do_list_set(struct netlink_ctx *ctx, struct cmd *cmd,
static int do_list_set(struct netlink_ctx *ctx, struct cmd *cmd,
struct table *table)
{
- struct set *set;
+ struct set *set = cmd->set;
- set = set_lookup(table, cmd->handle.set.name);
- if (set == NULL)
- return -1;
+ if (!set) {
+ set = set_cache_find(table, cmd->handle.set.name);
+ if (set == NULL)
+ return -1;
+ }
- __do_list_set(ctx, cmd, table, set);
+ __do_list_set(ctx, cmd, set);
return 0;
}
+static int do_list_hooks(struct netlink_ctx *ctx, struct cmd *cmd)
+{
+ const char *devname = cmd->handle.obj.name;
+ int hooknum = -1;
+
+ if (cmd->handle.chain.name)
+ hooknum = cmd->handle.chain_id;
+
+ return mnl_nft_dump_nf_hooks(ctx, cmd->handle.family, hooknum, devname);
+}
+
static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
{
struct table *table = NULL;
@@ -2448,13 +2342,14 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
return do_command_list_json(ctx, cmd);
if (cmd->handle.table.name != NULL)
- table = table_lookup(&cmd->handle, &ctx->nft->cache);
-
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
switch (cmd->obj) {
case CMD_OBJ_TABLE:
if (!cmd->handle.table.name)
return do_list_tables(ctx, cmd);
- return do_list_table(ctx, cmd, table);
+ return do_list_table(ctx, table);
case CMD_OBJ_CHAIN:
return do_list_chain(ctx, cmd, table);
case CMD_OBJ_CHAINS:
@@ -2464,6 +2359,8 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_SET:
return do_list_set(ctx, cmd, table);
case CMD_OBJ_RULESET:
+ case CMD_OBJ_RULES:
+ case CMD_OBJ_RULE:
return do_list_ruleset(ctx, cmd);
case CMD_OBJ_METERS:
return do_list_sets(ctx, cmd);
@@ -2483,8 +2380,10 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_CT_HELPERS:
return do_list_obj(ctx, cmd, NFT_OBJECT_CT_HELPER);
case CMD_OBJ_CT_TIMEOUT:
+ case CMD_OBJ_CT_TIMEOUTS:
return do_list_obj(ctx, cmd, NFT_OBJECT_CT_TIMEOUT);
case CMD_OBJ_CT_EXPECT:
+ case CMD_OBJ_CT_EXPECTATIONS:
return do_list_obj(ctx, cmd, NFT_OBJECT_CT_EXPECT);
case CMD_OBJ_LIMIT:
case CMD_OBJ_LIMITS:
@@ -2499,6 +2398,8 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
return do_list_flowtable(ctx, cmd, table);
case CMD_OBJ_FLOWTABLES:
return do_list_flowtables(ctx, cmd);
+ case CMD_OBJ_HOOKS:
+ return do_list_hooks(ctx, cmd);
default:
BUG("invalid command object type %u\n", cmd->obj);
}
@@ -2506,17 +2407,16 @@ static int do_command_list(struct netlink_ctx *ctx, struct cmd *cmd)
return 0;
}
-static int do_get_setelems(struct netlink_ctx *ctx, struct cmd *cmd,
- struct table *table)
+static int do_get_setelems(struct netlink_ctx *ctx, struct cmd *cmd, bool reset)
{
struct set *set, *new_set;
struct expr *init;
int err;
- set = set_lookup(table, cmd->handle.set.name);
+ set = cmd->elem.set;
/* Create a list of elements based of what we got from command line. */
- if (set->flags & NFT_SET_INTERVAL)
+ if (set_is_non_concat_range(set))
init = get_set_intervals(set, cmd->expr);
else
init = cmd->expr;
@@ -2525,11 +2425,11 @@ static int do_get_setelems(struct netlink_ctx *ctx, struct cmd *cmd,
/* Fetch from kernel the elements that have been requested .*/
err = netlink_get_setelem(ctx, &cmd->handle, &cmd->location,
- table, new_set, init);
+ cmd->elem.set, new_set, init, reset);
if (err >= 0)
- __do_list_set(ctx, cmd, table, new_set);
+ __do_list_set(ctx, cmd, new_set);
- if (set->flags & NFT_SET_INTERVAL)
+ if (set_is_non_concat_range(set))
expr_free(init);
set_free(new_set);
@@ -2539,14 +2439,9 @@ static int do_get_setelems(struct netlink_ctx *ctx, struct cmd *cmd,
static int do_command_get(struct netlink_ctx *ctx, struct cmd *cmd)
{
- struct table *table = NULL;
-
- if (cmd->handle.table.name != NULL)
- table = table_lookup(&cmd->handle, &ctx->nft->cache);
-
switch (cmd->obj) {
- case CMD_OBJ_SETELEM:
- return do_get_setelems(ctx, cmd, table);
+ case CMD_OBJ_ELEMENTS:
+ return do_get_setelems(ctx, cmd, false);
default:
BUG("invalid command object type %u\n", cmd->obj);
}
@@ -2575,20 +2470,41 @@ static int do_command_reset(struct netlink_ctx *ctx, struct cmd *cmd)
case CMD_OBJ_QUOTA:
type = NFT_OBJECT_QUOTA;
break;
+ case CMD_OBJ_RULES:
+ ret = netlink_reset_rules(ctx, cmd, true);
+ if (ret < 0)
+ return ret;
+
+ return do_command_list(ctx, cmd);
+ case CMD_OBJ_RULE:
+ return netlink_reset_rules(ctx, cmd, false);
+ case CMD_OBJ_ELEMENTS:
+ return do_get_setelems(ctx, cmd, true);
+ case CMD_OBJ_SET:
+ case CMD_OBJ_MAP:
+ ret = netlink_list_setelems(ctx, &cmd->handle, cmd->set, true);
+ if (ret < 0)
+ return ret;
+
+ return do_command_list(ctx, cmd);
default:
BUG("invalid command object type %u\n", cmd->obj);
}
ret = netlink_reset_objs(ctx, cmd, type, dump);
list_for_each_entry_safe(obj, next, &ctx->list, list) {
- table = table_lookup(&obj->handle, &ctx->nft->cache);
- if (!obj_lookup(table, obj->handle.obj.name, obj->type))
- list_move(&obj->list, &table->objs);
+ table = table_cache_find(&ctx->nft->cache.table_cache,
+ obj->handle.table.name,
+ obj->handle.family);
+ if (!obj_cache_find(table, obj->handle.obj.name, obj->type)) {
+ list_del(&obj->list);
+ obj_cache_add(obj, table);
+ }
}
if (ret < 0)
return ret;
- return do_list_obj(ctx, cmd, type);
+ return do_command_list(ctx, cmd);
}
static int do_command_flush(struct netlink_ctx *ctx, struct cmd *cmd)
@@ -2611,12 +2527,14 @@ static int do_command_flush(struct netlink_ctx *ctx, struct cmd *cmd)
static int do_command_rename(struct netlink_ctx *ctx, struct cmd *cmd)
{
- struct table *table = table_lookup(&cmd->handle, &ctx->nft->cache);
+ struct table *table = table_cache_find(&ctx->nft->cache.table_cache,
+ cmd->handle.table.name,
+ cmd->handle.family);
const struct chain *chain;
switch (cmd->obj) {
case CMD_OBJ_CHAIN:
- chain = chain_lookup(table, &cmd->handle);
+ chain = chain_cache_find(table, cmd->handle.chain.name);
return mnl_nft_chain_rename(ctx, cmd, chain);
default:
@@ -2686,6 +2604,7 @@ int do_command(struct netlink_ctx *ctx, struct cmd *cmd)
case CMD_REPLACE:
return do_command_replace(ctx, cmd);
case CMD_DELETE:
+ case CMD_DESTROY:
return do_command_delete(ctx, cmd);
case CMD_GET:
return do_command_get(ctx, cmd);
@@ -2801,49 +2720,78 @@ static void payload_do_merge(struct stmt *sa[], unsigned int n)
}
/**
- * payload_try_merge - try to merge consecutive payload match statements
+ * stmt_reduce - reduce statements in rule
*
* @rule: nftables rule
*
+ * This function aims to:
+ *
+ * - remove redundant statement, e.g. remove 'meta protocol ip' if family is ip
+ * - merge consecutive payload match statements
+ *
* Locate sequences of payload match statements referring to adjacent
* header locations and merge those using only equality relations.
*
* As a side-effect, payload match statements are ordered in ascending
* order according to the location of the payload.
*/
-static void payload_try_merge(const struct rule *rule)
+static void stmt_reduce(const struct rule *rule)
{
+ struct stmt *stmt, *dstmt = NULL, *next;
struct stmt *sa[rule->num_stmts];
- struct stmt *stmt, *next;
unsigned int idx = 0;
list_for_each_entry_safe(stmt, next, &rule->stmts, list) {
+ /* delete this redundant statement */
+ if (dstmt) {
+ list_del(&dstmt->list);
+ stmt_free(dstmt);
+ dstmt = NULL;
+ }
+
/* Must not merge across other statements */
- if (stmt->ops->type != STMT_EXPRESSION)
- goto do_merge;
+ if (stmt->ops->type != STMT_EXPRESSION) {
+ if (idx >= 2)
+ payload_do_merge(sa, idx);
+ idx = 0;
+ continue;
+ }
if (stmt->expr->etype != EXPR_RELATIONAL)
continue;
- if (stmt->expr->left->etype != EXPR_PAYLOAD)
- continue;
if (stmt->expr->right->etype != EXPR_VALUE)
continue;
- switch (stmt->expr->op) {
- case OP_EQ:
- case OP_IMPLICIT:
- case OP_NEQ:
- break;
- default:
- continue;
- }
- sa[idx++] = stmt;
- continue;
-do_merge:
- if (idx < 2)
- continue;
- payload_do_merge(sa, idx);
- idx = 0;
+ if (stmt->expr->left->etype == EXPR_PAYLOAD) {
+ switch (stmt->expr->op) {
+ case OP_EQ:
+ case OP_IMPLICIT:
+ break;
+ default:
+ continue;
+ }
+
+ sa[idx++] = stmt;
+ } else if (stmt->expr->left->etype == EXPR_META) {
+ switch (stmt->expr->op) {
+ case OP_EQ:
+ case OP_IMPLICIT:
+ if (stmt->expr->left->meta.key == NFT_META_PROTOCOL &&
+ !stmt->expr->left->meta.inner_desc) {
+ uint16_t protocol;
+
+ protocol = mpz_get_uint16(stmt->expr->right->value);
+ if ((rule->handle.family == NFPROTO_IPV4 &&
+ protocol == ETH_P_IP) ||
+ (rule->handle.family == NFPROTO_IPV6 &&
+ protocol == ETH_P_IPV6))
+ dstmt = stmt;
+ }
+ break;
+ default:
+ break;
+ }
+ }
}
if (idx > 1)
@@ -2852,6 +2800,6 @@ do_merge:
struct error_record *rule_postprocess(struct rule *rule)
{
- payload_try_merge(rule);
+ stmt_reduce(rule);
return NULL;
}