summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--configure.ac12
-rw-r--r--doc/Makefile.am15
-rw-r--r--doc/data-types.txt2
-rw-r--r--doc/payload-expression.txt5
-rw-r--r--doc/primary-expression.txt29
-rw-r--r--include/Makefile.am1
-rw-r--r--include/cmd.h7
-rw-r--r--include/expression.h5
-rw-r--r--include/linux/netfilter/nf_nat.h15
-rw-r--r--include/linux/netfilter/nf_tables.h27
-rw-r--r--include/list.h11
-rw-r--r--include/mnl.h27
-rw-r--r--include/netlink.h21
-rw-r--r--include/rule.h49
-rw-r--r--include/statement.h7
-rw-r--r--include/utils.h2
-rw-r--r--src/Makefile.am10
-rw-r--r--src/cache.c6
-rw-r--r--src/cmd.c159
-rw-r--r--src/ct.c2
-rw-r--r--src/datatype.c3
-rw-r--r--src/evaluate.c353
-rw-r--r--src/expression.c173
-rw-r--r--src/json.c4
-rw-r--r--src/libnftables.c12
-rw-r--r--src/main.c295
-rw-r--r--src/mnl.c398
-rw-r--r--src/monitor.c3
-rw-r--r--src/netlink.c184
-rw-r--r--src/netlink_delinearize.c96
-rw-r--r--src/netlink_linearize.c75
-rw-r--r--src/parser_bison.y177
-rw-r--r--src/parser_json.c74
-rw-r--r--src/rule.c103
-rw-r--r--src/scanner.l3
-rw-r--r--src/segtree.c97
-rw-r--r--src/statement.c7
-rw-r--r--src/xt.c4
-rw-r--r--tests/py/any/ct.t2
-rw-r--r--tests/py/any/ct.t.payload5
-rw-r--r--tests/py/any/meta.t.json.output2
-rw-r--r--tests/py/any/meta.t.payload4
-rw-r--r--tests/py/any/tcpopt.t (renamed from tests/py/inet/tcpopt.t)3
-rw-r--r--tests/py/any/tcpopt.t.json (renamed from tests/py/inet/tcpopt.t.json)70
-rw-r--r--tests/py/any/tcpopt.t.json.output (renamed from tests/py/inet/tcpopt.t.json.output)0
-rw-r--r--tests/py/any/tcpopt.t.payload603
-rw-r--r--tests/py/bridge/chains.t4
-rw-r--r--tests/py/bridge/reject.t8
-rw-r--r--tests/py/bridge/reject.t.payload20
-rw-r--r--tests/py/inet/dccp.t1
-rw-r--r--tests/py/inet/dnat.t.payload4
-rw-r--r--tests/py/inet/ip.t2
-rw-r--r--tests/py/inet/sets.t6
-rw-r--r--tests/py/inet/sets.t.json35
-rw-r--r--tests/py/inet/sets.t.payload.bridge27
-rw-r--r--tests/py/inet/sets.t.payload.inet24
-rw-r--r--tests/py/inet/sets.t.payload.netdev25
-rw-r--r--tests/py/inet/tcpopt.t.payload200
-rw-r--r--tests/py/ip/dnat.t.payload.ip2
-rw-r--r--tests/py/ip/icmp.t4
-rw-r--r--tests/py/ip/icmp.t.payload.ip2
-rw-r--r--tests/py/ip/masquerade.t.payload4
-rw-r--r--tests/py/ip/redirect.t.payload20
-rw-r--r--tests/py/ip/snat.t4
-rw-r--r--tests/py/ip/snat.t.payload27
-rw-r--r--tests/py/ip/tcpopt.t38
-rw-r--r--tests/py/ip/tcpopt.t.json416
-rw-r--r--tests/py/ip/tcpopt.t.json.output16
-rw-r--r--tests/py/ip/tcpopt.t.payload181
-rw-r--r--tests/py/ip6/dnat.t4
-rw-r--r--tests/py/ip6/dnat.t.payload.ip66
-rw-r--r--tests/py/ip6/masquerade.t.payload.ip64
-rw-r--r--tests/py/ip6/redirect.t.payload.ip614
-rw-r--r--tests/py/ip6/snat.t.payload.ip64
-rw-r--r--tests/py/ip6/tcpopt.t37
-rw-r--r--tests/py/ip6/tcpopt.t.json416
-rw-r--r--tests/py/ip6/tcpopt.t.json.output16
-rw-r--r--tests/py/ip6/tcpopt.t.payload181
-rwxr-xr-xtests/shell/run-tests.sh2
-rwxr-xr-xtests/shell/testcases/flowtable/0006segfault_03
-rw-r--r--tests/shell/testcases/maps/dumps/nat_addr_port.nft129
-rw-r--r--tests/shell/testcases/maps/dumps/typeof_maps_0.nft7
-rw-r--r--tests/shell/testcases/maps/dumps/typeof_maps_update_0.nft21
-rwxr-xr-xtests/shell/testcases/maps/nat_addr_port207
-rwxr-xr-xtests/shell/testcases/maps/typeof_maps_07
-rwxr-xr-xtests/shell/testcases/maps/typeof_maps_update_028
-rwxr-xr-xtests/shell/testcases/sets/0025anonymous_set_02
-rwxr-xr-xtests/shell/testcases/sets/0034get_element_062
-rwxr-xr-xtests/shell/testcases/sets/0043concatenated_ranges_0180
-rwxr-xr-xtests/shell/testcases/sets/0044interval_overlap_066
-rwxr-xr-xtests/shell/testcases/sets/0046netmap_014
-rwxr-xr-xtests/shell/testcases/sets/0047nat_020
-rw-r--r--tests/shell/testcases/sets/dumps/0025anonymous_set_0.nft2
-rw-r--r--tests/shell/testcases/sets/dumps/0046netmap_0.nft6
-rw-r--r--tests/shell/testcases/sets/dumps/0047nat_0.nft13
-rw-r--r--tests/shell/testcases/sets/dumps/typeof_sets_0.nft5
-rwxr-xr-xtests/shell/testcases/sets/typeof_sets_05
97 files changed, 3534 insertions, 2159 deletions
diff --git a/configure.ac b/configure.ac
index c487029a..5a1f89a0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,5 +1,5 @@
-AC_INIT([nftables], [0.9.3], [netfilter-devel@vger.kernel.org])
-AC_DEFINE([RELEASE_NAME], ["Topsy"], [Release name])
+AC_INIT([nftables], [0.9.4], [netfilter-devel@vger.kernel.org])
+AC_DEFINE([RELEASE_NAME], ["Jive at Five"], [Release name])
AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_MACRO_DIR([m4])
@@ -29,13 +29,13 @@ AC_PROG_SED
AM_PROG_LEX
AC_PROG_YACC
-if test -z "$ac_cv_prog_YACC"
+if test -z "$ac_cv_prog_YACC" -a ! -f "${srcdir}/src/parser_bison.c"
then
echo "*** Error: No suitable bison/yacc found. ***"
echo " Please install the 'bison' package."
exit 1
fi
-if test -z "$ac_cv_prog_LEX"
+if test -z "$ac_cv_prog_LEX" -a ! -f "${srcdir}/src/scanner.c"
then
echo "*** Error: No suitable flex/lex found. ***"
echo " Please install the 'flex' package."
@@ -52,12 +52,12 @@ CHECK_GCC_FVISIBILITY
AS_IF([test "x$enable_man_doc" = "xyes"], [
AC_CHECK_PROG(A2X, [a2x], [a2x], [no])
- AS_IF([test "$A2X" = "no"],
+ AS_IF([test "$A2X" = "no" -a ! -f "${srcdir}/doc/nft.8"],
[AC_MSG_ERROR([a2x not found, please install asciidoc])])
])
PKG_CHECK_MODULES([LIBMNL], [libmnl >= 1.0.3])
-PKG_CHECK_MODULES([LIBNFTNL], [libnftnl >= 1.1.5])
+PKG_CHECK_MODULES([LIBNFTNL], [libnftnl >= 1.1.6])
AC_ARG_WITH([mini-gmp], [AS_HELP_STRING([--with-mini-gmp],
[Use builtin mini-gmp (for embedded builds)])],
diff --git a/doc/Makefile.am b/doc/Makefile.am
index f0958b33..21482320 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -1,6 +1,5 @@
if BUILD_MAN
man_MANS = nft.8 libnftables-json.5 libnftables.3
-endif
A2X_OPTS_MANPAGE = -L --doctype manpage --format manpage -D ${builddir}
@@ -13,6 +12,11 @@ ASCIIDOC_INCLUDES = \
statements.txt
ASCIIDOCS = ${ASCIIDOC_MAIN} ${ASCIIDOC_INCLUDES}
+EXTRA_DIST = ${ASCIIDOCS} ${man_MANS} libnftables-json.adoc libnftables.adoc
+
+CLEANFILES = \
+ *~
+
nft.8: ${ASCIIDOCS}
${AM_V_GEN}${A2X} ${A2X_OPTS_MANPAGE} $<
@@ -22,10 +26,5 @@ nft.8: ${ASCIIDOCS}
.adoc.5:
${AM_V_GEN}${A2X} ${A2X_OPTS_MANPAGE} $<
-EXTRA_DIST = ${ASCIIDOCS} libnftables-json.adoc libnftables.adoc
-
-CLEANFILES = \
- nft.8 \
- libnftables-json.5 \
- libnftables.3 \
- *~
+CLEANFILES += ${man_MANS}
+endif
diff --git a/doc/data-types.txt b/doc/data-types.txt
index 90e19a8b..a42a55fa 100644
--- a/doc/data-types.txt
+++ b/doc/data-types.txt
@@ -254,6 +254,8 @@ The ICMP Code type is used to conveniently specify the ICMP header's code field.
2
|port-unreachable|
3
+|frag-needed|
+4
|net-prohibited|
9
|host-prohibited|
diff --git a/doc/payload-expression.txt b/doc/payload-expression.txt
index 4bbf8d05..e6f108b1 100644
--- a/doc/payload-expression.txt
+++ b/doc/payload-expression.txt
@@ -638,7 +638,7 @@ zone id is tied to the given direction. +
[verse]
*ct* {*state* | *direction* | *status* | *mark* | *expiration* | *helper* | *label*}
-*ct* [*original* | *reply*] {*l3proto* | *protocol* | *bytes* | *packets* | *avgpkt* | *zone*}
+*ct* [*original* | *reply*] {*l3proto* | *protocol* | *bytes* | *packets* | *avgpkt* | *zone* | *id*}
*ct* {*original* | *reply*} {*proto-src* | *proto-dst*}
*ct* {*original* | *reply*} {*ip* | *ip6*} {*saddr* | *daddr*}
@@ -700,6 +700,9 @@ integer (16 bit)
|count|
count number of connections
integer (32 bit)
+|id|
+Connection id
+ct_id
|==========================================
A description of conntrack-specific types listed above can be found sub-section CONNTRACK TYPES above.
diff --git a/doc/primary-expression.txt b/doc/primary-expression.txt
index b5488790..48a7609d 100644
--- a/doc/primary-expression.txt
+++ b/doc/primary-expression.txt
@@ -430,3 +430,32 @@ add rule nat prerouting dnat to numgen inc mod 2 map \
add rule nat prerouting dnat to numgen random mod 10 map \
{ 0-2 : 192.168.10.100, 3-9 : 192.168.20.200 }
------------------------
+
+HASH EXPRESSIONS
+~~~~~~~~~~~~~~~~
+
+[verse]
+*jhash* {*ip saddr* | *ip6 daddr* | *tcp dport* | *udp sport* | *ether saddr*} [*.* ...] *mod* 'NUM' [ *seed* 'NUM' ] [ *offset* 'NUM' ]
+*symhash* *mod* 'NUM' [ *offset* 'NUM' ]
+
+Use a hashing function to generate a number. The functions available are
+*jhash*, known as Jenkins Hash, and *symhash*, for Symmetric Hash. The
+*jhash* requires an expression to determine the parameters of the packet
+header to apply the hashing, concatenations are possible as well. The value
+after *mod* keyword specifies an upper boundary (read: modulus) which is
+not reached by returned numbers. The optional *seed* is used to specify an
+init value used as seed in the hashing function. The optional *offset*
+allows to increment the returned value by a fixed offset.
+
+A typical use-case for *jhash* and *symhash* is load-balancing:
+
+.Using hash expressions
+------------------------
+# load balance based on source ip between 2 ip addresses:
+add rule nat prerouting dnat to jhash ip saddr mod 2 map \
+ { 0 : 192.168.10.100, 1 : 192.168.20.200 }
+
+# symmetric load balancing between 2 ip addresses:
+add rule nat prerouting dnat to symhash mod 2 map \
+ { 0 : 192.168.10.100, 1 : 192.168.20.200 }
+------------------------
diff --git a/include/Makefile.am b/include/Makefile.am
index 04a4a619..42f24f35 100644
--- a/include/Makefile.am
+++ b/include/Makefile.am
@@ -3,6 +3,7 @@ SUBDIRS = linux \
noinst_HEADERS = cli.h \
cache.h \
+ cmd.h \
datatype.h \
expression.h \
fib.h \
diff --git a/include/cmd.h b/include/cmd.h
new file mode 100644
index 00000000..27fa6087
--- /dev/null
+++ b/include/cmd.h
@@ -0,0 +1,7 @@
+#ifndef _NFT_CMD_H_
+#define _NFT_CMD_H_
+
+void nft_cmd_error(struct netlink_ctx *ctx, struct cmd *cmd,
+ struct mnl_err *err);
+
+#endif
diff --git a/include/expression.h b/include/expression.h
index cbf09b59..8135a516 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -72,6 +72,7 @@ enum expr_types {
EXPR_FIB,
EXPR_XFRM,
};
+#define EXPR_MAX EXPR_XFRM
enum ops {
OP_INVALID,
@@ -183,6 +184,7 @@ const struct expr_ops *expr_ops_by_type(enum expr_types etype);
* @EXPR_F_PROTOCOL: expressions describes upper layer protocol
* @EXPR_F_INTERVAL_END: set member ends an open interval
* @EXPR_F_BOOLEAN: expression is boolean (set by relational expr on LHS)
+ * @EXPR_F_INTERVAL: expression describes a interval
*/
enum expr_flags {
EXPR_F_CONSTANT = 0x1,
@@ -190,6 +192,7 @@ enum expr_flags {
EXPR_F_PROTOCOL = 0x4,
EXPR_F_INTERVAL_END = 0x8,
EXPR_F_BOOLEAN = 0x10,
+ EXPR_F_INTERVAL = 0x20,
};
#include <payload.h>
@@ -299,6 +302,7 @@ struct expr {
enum proto_bases base;
unsigned int offset;
bool is_raw;
+ bool evaluated;
} payload;
struct {
/* EXPR_EXTHDR */
@@ -448,6 +452,7 @@ extern struct expr *prefix_expr_alloc(const struct location *loc,
extern struct expr *range_expr_alloc(const struct location *loc,
struct expr *low, struct expr *high);
+struct expr *range_expr_to_prefix(struct expr *range);
extern struct expr *compound_expr_alloc(const struct location *loc,
enum expr_types etypes);
diff --git a/include/linux/netfilter/nf_nat.h b/include/linux/netfilter/nf_nat.h
index 0880781a..a64586e7 100644
--- a/include/linux/netfilter/nf_nat.h
+++ b/include/linux/netfilter/nf_nat.h
@@ -1,3 +1,4 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _NETFILTER_NF_NAT_H
#define _NETFILTER_NF_NAT_H
@@ -9,6 +10,8 @@
#define NF_NAT_RANGE_PROTO_RANDOM (1 << 2)
#define NF_NAT_RANGE_PERSISTENT (1 << 3)
#define NF_NAT_RANGE_PROTO_RANDOM_FULLY (1 << 4)
+#define NF_NAT_RANGE_PROTO_OFFSET (1 << 5)
+#define NF_NAT_RANGE_NETMAP (1 << 6)
#define NF_NAT_RANGE_PROTO_RANDOM_ALL \
(NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PROTO_RANDOM_FULLY)
@@ -16,7 +19,8 @@
#define NF_NAT_RANGE_MASK \
(NF_NAT_RANGE_MAP_IPS | NF_NAT_RANGE_PROTO_SPECIFIED | \
NF_NAT_RANGE_PROTO_RANDOM | NF_NAT_RANGE_PERSISTENT | \
- NF_NAT_RANGE_PROTO_RANDOM_FULLY)
+ NF_NAT_RANGE_PROTO_RANDOM_FULLY | NF_NAT_RANGE_PROTO_OFFSET | \
+ NF_NAT_RANGE_NETMAP)
struct nf_nat_ipv4_range {
unsigned int flags;
@@ -39,4 +43,13 @@ struct nf_nat_range {
union nf_conntrack_man_proto max_proto;
};
+struct nf_nat_range2 {
+ unsigned int flags;
+ union nf_inet_addr min_addr;
+ union nf_inet_addr max_addr;
+ union nf_conntrack_man_proto min_proto;
+ union nf_conntrack_man_proto max_proto;
+ union nf_conntrack_man_proto base_proto;
+};
+
#endif /* _NETFILTER_NF_NAT_H */
diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index 065218a2..4565456c 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -276,6 +276,7 @@ enum nft_rule_compat_attributes {
* @NFT_SET_TIMEOUT: set uses timeouts
* @NFT_SET_EVAL: set can be updated from the evaluation path
* @NFT_SET_OBJECT: set contains stateful objects
+ * @NFT_SET_CONCAT: set contains a concatenation
*/
enum nft_set_flags {
NFT_SET_ANONYMOUS = 0x1,
@@ -285,6 +286,7 @@ enum nft_set_flags {
NFT_SET_TIMEOUT = 0x10,
NFT_SET_EVAL = 0x20,
NFT_SET_OBJECT = 0x40,
+ NFT_SET_CONCAT = 0x80,
};
/**
@@ -342,6 +344,7 @@ enum nft_set_field_attributes {
* @NFTA_SET_USERDATA: user data (NLA_BINARY)
* @NFTA_SET_OBJ_TYPE: stateful object type (NLA_U32: NFT_OBJECT_*)
* @NFTA_SET_HANDLE: set handle (NLA_U64)
+ * @NFTA_SET_EXPR: set expression (NLA_NESTED: nft_expr_attributes)
*/
enum nft_set_attributes {
NFTA_SET_UNSPEC,
@@ -361,6 +364,7 @@ enum nft_set_attributes {
NFTA_SET_PAD,
NFTA_SET_OBJ_TYPE,
NFTA_SET_HANDLE,
+ NFTA_SET_EXPR,
__NFTA_SET_MAX
};
#define NFTA_SET_MAX (__NFTA_SET_MAX - 1)
@@ -1552,6 +1556,19 @@ enum nft_object_attributes {
#define NFTA_OBJ_MAX (__NFTA_OBJ_MAX - 1)
/**
+ * enum nft_flowtable_flags - nf_tables flowtable flags
+ *
+ * @NFT_FLOWTABLE_HW_OFFLOAD: flowtable hardware offload is enabled
+ * @NFT_FLOWTABLE_COUNTER: enable flow counters
+ */
+enum nft_flowtable_flags {
+ NFT_FLOWTABLE_HW_OFFLOAD = 0x1,
+ NFT_FLOWTABLE_COUNTER = 0x2,
+ NFT_FLOWTABLE_MASK = (NFT_FLOWTABLE_HW_OFFLOAD |
+ NFT_FLOWTABLE_COUNTER)
+};
+
+/**
* enum nft_flowtable_attributes - nf_tables flow table netlink attributes
*
* @NFTA_FLOWTABLE_TABLE: name of the table containing the expression (NLA_STRING)
@@ -1770,6 +1787,7 @@ enum nft_tunnel_opts_attributes {
NFTA_TUNNEL_KEY_OPTS_UNSPEC,
NFTA_TUNNEL_KEY_OPTS_VXLAN,
NFTA_TUNNEL_KEY_OPTS_ERSPAN,
+ NFTA_TUNNEL_KEY_OPTS_GENEVE,
__NFTA_TUNNEL_KEY_OPTS_MAX
};
#define NFTA_TUNNEL_KEY_OPTS_MAX (__NFTA_TUNNEL_KEY_OPTS_MAX - 1)
@@ -1791,6 +1809,15 @@ enum nft_tunnel_opts_erspan_attributes {
};
#define NFTA_TUNNEL_KEY_ERSPAN_MAX (__NFTA_TUNNEL_KEY_ERSPAN_MAX - 1)
+enum nft_tunnel_opts_geneve_attributes {
+ NFTA_TUNNEL_KEY_GENEVE_UNSPEC,
+ NFTA_TUNNEL_KEY_GENEVE_CLASS,
+ NFTA_TUNNEL_KEY_GENEVE_TYPE,
+ NFTA_TUNNEL_KEY_GENEVE_DATA,
+ __NFTA_TUNNEL_KEY_GENEVE_MAX
+};
+#define NFTA_TUNNEL_KEY_GENEVE_MAX (__NFTA_TUNNEL_KEY_GENEVE_MAX - 1)
+
enum nft_tunnel_flags {
NFT_TUNNEL_F_ZERO_CSUM_TX = (1 << 0),
NFT_TUNNEL_F_DONT_FRAGMENT = (1 << 1),
diff --git a/include/list.h b/include/list.h
index 75d29212..9c4da817 100644
--- a/include/list.h
+++ b/include/list.h
@@ -33,6 +33,17 @@ static inline void init_list_head(struct list_head *list)
list->prev = list;
}
+/**
+ * list_is_first -- tests whether @list is the first entry in list @head
+ * @list: the entry to test
+ * @head: the head of the list
+ */
+static inline int list_is_first(const struct list_head *list,
+ const struct list_head *head)
+{
+ return list->prev == head;
+}
+
/*
* Insert a new entry between two known consecutive entries.
*
diff --git a/include/mnl.h b/include/mnl.h
index eeba7379..74b1b56f 100644
--- a/include/mnl.h
+++ b/include/mnl.h
@@ -16,6 +16,7 @@ struct mnl_err {
struct list_head head;
int err;
uint32_t seqnum;
+ uint32_t offset;
};
void mnl_err_list_free(struct mnl_err *err);
@@ -28,33 +29,33 @@ void mnl_batch_end(struct nftnl_batch *batch, uint32_t seqnum);
int mnl_batch_talk(struct netlink_ctx *ctx, struct list_head *err_list,
uint32_t num_cmds);
-int mnl_nft_rule_add(struct netlink_ctx *ctx, const struct cmd *cmd,
+int mnl_nft_rule_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags);
-int mnl_nft_rule_del(struct netlink_ctx *ctx, const struct cmd *cmd);
-int mnl_nft_rule_replace(struct netlink_ctx *ctx, const struct cmd *cmd);
+int mnl_nft_rule_del(struct netlink_ctx *ctx, struct cmd *cmd);
+int mnl_nft_rule_replace(struct netlink_ctx *ctx, struct cmd *cmd);
struct nftnl_rule_list *mnl_nft_rule_dump(struct netlink_ctx *ctx,
int family);
-int mnl_nft_chain_add(struct netlink_ctx *ctx, const struct cmd *cmd,
+int mnl_nft_chain_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags);
-int mnl_nft_chain_del(struct netlink_ctx *ctx, const struct cmd *cmd);
+int mnl_nft_chain_del(struct netlink_ctx *ctx, struct cmd *cmd);
int mnl_nft_chain_rename(struct netlink_ctx *ctx, const struct cmd *cmd,
const struct chain *chain);
struct nftnl_chain_list *mnl_nft_chain_dump(struct netlink_ctx *ctx,
int family);
-int mnl_nft_table_add(struct netlink_ctx *ctx, const struct cmd *cmd,
+int mnl_nft_table_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags);
-int mnl_nft_table_del(struct netlink_ctx *ctx, const struct cmd *cmd);
+int mnl_nft_table_del(struct netlink_ctx *ctx, struct cmd *cmd);
struct nftnl_table_list *mnl_nft_table_dump(struct netlink_ctx *ctx,
int family);
-int mnl_nft_set_add(struct netlink_ctx *ctx, const struct cmd *cmd,
+int mnl_nft_set_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags);
-int mnl_nft_set_del(struct netlink_ctx *ctx, const struct cmd *cmd);
+int mnl_nft_set_del(struct netlink_ctx *ctx, struct cmd *cmd);
struct nftnl_set_list *mnl_nft_set_dump(struct netlink_ctx *ctx, int family,
const char *table);
@@ -71,16 +72,16 @@ struct nftnl_obj_list *mnl_nft_obj_dump(struct netlink_ctx *ctx, int family,
const char *table,
const char *name, uint32_t type,
bool dump, bool reset);
-int mnl_nft_obj_add(struct netlink_ctx *ctx, const struct cmd *cmd,
+int mnl_nft_obj_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags);
-int mnl_nft_obj_del(struct netlink_ctx *ctx, const struct cmd *cmd, int type);
+int mnl_nft_obj_del(struct netlink_ctx *ctx, struct cmd *cmd, int type);
struct nftnl_flowtable_list *
mnl_nft_flowtable_dump(struct netlink_ctx *ctx, int family, const char *table);
-int mnl_nft_flowtable_add(struct netlink_ctx *ctx, const struct cmd *cmd,
+int mnl_nft_flowtable_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags);
-int mnl_nft_flowtable_del(struct netlink_ctx *ctx, const struct cmd *cmd);
+int mnl_nft_flowtable_del(struct netlink_ctx *ctx, struct cmd *cmd);
int mnl_nft_event_listener(struct mnl_socket *nf_sock, unsigned int debug_mask,
struct output_ctx *octx,
diff --git a/include/netlink.h b/include/netlink.h
index d02533ec..0a5fde3c 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -16,6 +16,22 @@
#define MAX_REGS (1 + NFT_REG32_15 - NFT_REG32_00)
+#ifndef NETLINK_EXT_ACK
+#define NETLINK_EXT_ACK 11
+
+enum nlmsgerr_attrs {
+ NLMSGERR_ATTR_UNUSED,
+ NLMSGERR_ATTR_MSG,
+ NLMSGERR_ATTR_OFFS,
+ NLMSGERR_ATTR_COOKIE,
+
+ __NLMSGERR_ATTR_MAX,
+ NLMSGERR_ATTR_MAX = __NLMSGERR_ATTR_MAX - 1
+};
+#define NLM_F_CAPPED 0x100 /* request was capped */
+#define NLM_F_ACK_TLVS 0x200 /* extended ACK TVLs were included */
+#endif
+
struct netlink_parse_ctx {
struct list_head *msgs;
struct table *table;
@@ -97,6 +113,7 @@ extern void netlink_gen_data(const struct expr *expr,
extern void netlink_gen_raw_data(const mpz_t value, enum byteorder byteorder,
unsigned int len,
struct nft_data_linearize *data);
+extern struct nftnl_expr *netlink_gen_stmt_stateful(const struct stmt *stmt);
extern struct expr *netlink_alloc_value(const struct location *loc,
const struct nft_data_delinearize *nld);
@@ -176,6 +193,10 @@ struct netlink_mon_handler {
extern int netlink_monitor(struct netlink_mon_handler *monhandler,
struct mnl_socket *nf_sock);
+struct netlink_cb_data {
+ struct netlink_ctx *nl_ctx;
+ struct list_head *err_list;
+};
int netlink_echo_callback(const struct nlmsghdr *nlh, void *data);
struct ruleset_parse {
diff --git a/include/rule.h b/include/rule.h
index c232221e..cfb76b8a 100644
--- a/include/rule.h
+++ b/include/rule.h
@@ -175,6 +175,7 @@ extern struct table *table_lookup_fuzzy(const struct handle *h,
*/
enum chain_flags {
CHAIN_F_BASECHAIN = 0x1,
+ CHAIN_F_HW_OFFLOAD = 0x2,
};
/**
@@ -188,6 +189,12 @@ struct prio_spec {
struct expr *expr;
};
+struct hook_spec {
+ struct location loc;
+ const char *name;
+ unsigned int num;
+};
+
/**
* struct chain - nftables chain
*
@@ -210,14 +217,16 @@ struct chain {
struct location location;
unsigned int refcnt;
uint32_t flags;
- const char *hookstr;
- unsigned int hooknum;
- struct prio_spec priority;
- struct expr *policy;
- const char *type;
- const char **dev_array;
- struct expr *dev_expr;
- int dev_array_len;
+ struct {
+ struct location loc;
+ struct prio_spec priority;
+ struct hook_spec hook;
+ struct expr *policy;
+ const char *type;
+ const char **dev_array;
+ struct expr *dev_expr;
+ int dev_array_len;
+ };
struct scope scope;
struct list_head rules;
};
@@ -271,6 +280,10 @@ extern void rule_print(const struct rule *rule, struct output_ctx *octx);
extern struct rule *rule_lookup(const struct chain *chain, uint64_t handle);
extern struct rule *rule_lookup_by_index(const struct chain *chain,
uint64_t index);
+void rule_stmt_append(struct rule *rule, struct stmt *stmt);
+void rule_stmt_insert_at(struct rule *rule, struct stmt *nstmt,
+ struct stmt *stmt);
+
/**
* struct set - nftables set
@@ -307,6 +320,7 @@ struct set {
struct expr *init;
struct expr *rg_cache;
uint32_t policy;
+ struct stmt *stmt;
bool root;
bool automerge;
bool key_typeof_valid;
@@ -483,12 +497,12 @@ struct flowtable {
struct handle handle;
struct scope scope;
struct location location;
- const char * hookstr;
- unsigned int hooknum;
+ struct hook_spec hook;
struct prio_spec priority;
const char **dev_array;
struct expr *dev_expr;
int dev_array_len;
+ uint32_t flags;
unsigned int refcnt;
};
@@ -544,9 +558,10 @@ enum cmd_ops {
* enum cmd_obj - command objects
*
* @CMD_OBJ_INVALID: invalid
- * @CMD_OBJ_SETELEM: set element(s)
+ * @CMD_OBJ_ELEMENTS: set element(s)
* @CMD_OBJ_SET: set
* @CMD_OBJ_SETS: multiple sets
+ * @CMD_OBJ_SETELEMS: set elements
* @CMD_OBJ_RULE: rule
* @CMD_OBJ_CHAIN: chain
* @CMD_OBJ_CHAINS: multiple chains
@@ -572,8 +587,9 @@ enum cmd_ops {
*/
enum cmd_obj {
CMD_OBJ_INVALID,
- CMD_OBJ_SETELEM,
+ CMD_OBJ_ELEMENTS,
CMD_OBJ_SET,
+ CMD_OBJ_SETELEMS,
CMD_OBJ_SETS,
CMD_OBJ_RULE,
CMD_OBJ_CHAIN,
@@ -635,6 +651,8 @@ struct monitor {
struct monitor *monitor_alloc(uint32_t format, uint32_t type, const char *event);
void monitor_free(struct monitor *m);
+#define NFT_NLATTR_LOC_MAX 8
+
/**
* struct cmd - command statement
*
@@ -666,6 +684,11 @@ struct cmd {
struct markup *markup;
struct obj *object;
};
+ struct {
+ uint16_t offset;
+ struct location *location;
+ } attr[NFT_NLATTR_LOC_MAX];
+ int num_attrs;
const void *arg;
};
@@ -678,6 +701,8 @@ extern struct cmd *cmd_alloc_obj_ct(enum cmd_ops op, int type,
const struct location *loc, struct obj *obj);
extern void cmd_free(struct cmd *cmd);
+void cmd_add_loc(struct cmd *cmd, uint16_t offset, struct location *loc);
+
#include <payload.h>
#include <expression.h>
diff --git a/include/statement.h b/include/statement.h
index 585908de..7d96b394 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -119,12 +119,19 @@ enum nft_nat_etypes {
extern const char *nat_etype2str(enum nft_nat_etypes type);
+enum {
+ STMT_NAT_F_INTERVAL = (1 << 0),
+ STMT_NAT_F_PREFIX = (1 << 1),
+ STMT_NAT_F_CONCAT = (1 << 2),
+};
+
struct nat_stmt {
enum nft_nat_etypes type;
struct expr *addr;
struct expr *proto;
uint32_t flags;
uint8_t family;
+ uint32_t type_flags;
};
extern struct stmt *nat_stmt_alloc(const struct location *loc,
diff --git a/include/utils.h b/include/utils.h
index 647e8bbe..f45f2513 100644
--- a/include/utils.h
+++ b/include/utils.h
@@ -94,7 +94,7 @@
* This is defined the same way as ffs.
* Note fls(0) = 0, fls(1) = 1, fls(0x80000000) = 32.
*/
-static inline int fls(int x)
+static inline int fls(uint32_t x)
{
int r = 32;
diff --git a/src/Makefile.am b/src/Makefile.am
index 740c21f2..3041a933 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -13,6 +13,15 @@ endif
if BUILD_XTABLES
AM_CPPFLAGS += ${XTABLES_CFLAGS}
endif
+if BUILD_MINIGMP
+AM_CPPFLAGS += -DHAVE_MINIGMP
+endif
+if BUILD_JSON
+AM_CPPFLAGS += -DHAVE_JSON
+endif
+if BUILD_XTABLES
+AM_CPPFLAGS += -DHAVE_XTABLES
+endif
AM_CFLAGS = -Wall \
-Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations \
@@ -32,6 +41,7 @@ libnftables_la_SOURCES = \
rule.c \
statement.c \
cache.c \
+ cmd.c \
datatype.c \
expression.c \
evaluate.c \
diff --git a/src/cache.c b/src/cache.c
index 05f0d68e..a45111a7 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -25,7 +25,7 @@ static unsigned int evaluate_cache_add(struct cmd *cmd, unsigned int flags)
case CMD_OBJ_FLOWTABLE:
flags |= NFT_CACHE_TABLE;
break;
- case CMD_OBJ_SETELEM:
+ case CMD_OBJ_ELEMENTS:
flags |= NFT_CACHE_TABLE |
NFT_CACHE_CHAIN |
NFT_CACHE_SET |
@@ -53,7 +53,7 @@ static unsigned int evaluate_cache_add(struct cmd *cmd, unsigned int flags)
static unsigned int evaluate_cache_del(struct cmd *cmd, unsigned int flags)
{
switch (cmd->obj) {
- case CMD_OBJ_SETELEM:
+ case CMD_OBJ_ELEMENTS:
flags |= NFT_CACHE_SETELEM;
break;
default:
@@ -66,7 +66,7 @@ static unsigned int evaluate_cache_del(struct cmd *cmd, unsigned int flags)
static unsigned int evaluate_cache_get(struct cmd *cmd, unsigned int flags)
{
switch (cmd->obj) {
- case CMD_OBJ_SETELEM:
+ case CMD_OBJ_ELEMENTS:
flags |= NFT_CACHE_TABLE |
NFT_CACHE_SET |
NFT_CACHE_SETELEM;
diff --git a/src/cmd.c b/src/cmd.c
new file mode 100644
index 00000000..c8ea4492
--- /dev/null
+++ b/src/cmd.c
@@ -0,0 +1,159 @@
+#include <erec.h>
+#include <mnl.h>
+#include <cmd.h>
+#include <parser.h>
+#include <utils.h>
+#include <iface.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+static int nft_cmd_enoent_table(struct netlink_ctx *ctx, const struct cmd *cmd,
+ struct location *loc)
+{
+ struct table *table;
+
+ table = table_lookup_fuzzy(&cmd->handle, &ctx->nft->cache);
+ if (!table)
+ return 0;
+
+ netlink_io_error(ctx, loc, "%s; did you mean table ‘%s’ in family %s?",
+ strerror(ENOENT), table->handle.table.name,
+ family2str(table->handle.family));
+ return 1;
+}
+
+static int nft_cmd_enoent_chain(struct netlink_ctx *ctx, const struct cmd *cmd,
+ struct location *loc)
+{
+ const struct table *table;
+ struct chain *chain;
+
+ chain = chain_lookup_fuzzy(&cmd->handle, &ctx->nft->cache, &table);
+ if (!chain)
+ return 0;
+
+ netlink_io_error(ctx, loc, "%s; did you mean table ‘%s’ in family %s?",
+ strerror(ENOENT), chain->handle.chain.name,
+ family2str(table->handle.family),
+ table->handle.table.name);
+ return 1;
+}
+
+static int nft_cmd_enoent_set(struct netlink_ctx *ctx, const struct cmd *cmd,
+ struct location *loc)
+{
+ const struct table *table;
+ struct set *set;
+
+ set = set_lookup_fuzzy(cmd->handle.set.name, &ctx->nft->cache, &table);
+ if (!set)
+ return 0;
+
+ netlink_io_error(ctx, loc, "%s; did you mean %s ‘%s’ in table %s ‘%s’?",
+ strerror(ENOENT),
+ set_is_map(set->flags) ? "map" : "set",
+ set->handle.set.name,
+ family2str(set->handle.family),
+ table->handle.table.name);
+ return 1;
+}
+
+static int nft_cmd_enoent_obj(struct netlink_ctx *ctx, const struct cmd *cmd,
+ struct location *loc)
+{
+ const struct table *table;
+ struct obj *obj;
+
+ obj = obj_lookup_fuzzy(cmd->handle.obj.name, &ctx->nft->cache, &table);
+ if (!obj)
+ return 0;
+
+ netlink_io_error(ctx, loc, "%s; did you mean obj ‘%s’ in table %s ‘%s’?",
+ strerror(ENOENT), obj->handle.obj.name,
+ family2str(obj->handle.family),
+ table->handle.table.name);
+ return 1;
+}
+
+static int nft_cmd_enoent_flowtable(struct netlink_ctx *ctx,
+ const struct cmd *cmd, struct location *loc)
+{
+ const struct table *table;
+ struct flowtable *ft;
+
+ ft = flowtable_lookup_fuzzy(cmd->handle.flowtable.name,
+ &ctx->nft->cache, &table);
+ if (!ft)
+ return 0;
+
+ netlink_io_error(ctx, loc, "%s; did you mean flowtable ‘%s’ in table %s ‘%s’?",
+ strerror(ENOENT), ft->handle.flowtable.name,
+ family2str(ft->handle.family),
+ table->handle.table.name);
+ return 1;
+}
+
+static void nft_cmd_enoent(struct netlink_ctx *ctx, const struct cmd *cmd,
+ struct location *loc, int err)
+{
+ int ret = 0;
+
+ switch (cmd->obj) {
+ case CMD_OBJ_TABLE:
+ ret = nft_cmd_enoent_table(ctx, cmd, loc);
+ break;
+ case CMD_OBJ_CHAIN:
+ ret = nft_cmd_enoent_chain(ctx, cmd, loc);
+ break;
+ case CMD_OBJ_SET:
+ ret = nft_cmd_enoent_set(ctx, cmd, loc);
+ break;
+ case CMD_OBJ_COUNTER:
+ case CMD_OBJ_QUOTA:
+ case CMD_OBJ_CT_HELPER:
+ case CMD_OBJ_CT_TIMEOUT:
+ case CMD_OBJ_LIMIT:
+ case CMD_OBJ_SECMARK:
+ case CMD_OBJ_CT_EXPECT:
+ case CMD_OBJ_SYNPROXY:
+ ret = nft_cmd_enoent_obj(ctx, cmd, loc);
+ break;
+ case CMD_OBJ_FLOWTABLE:
+ ret = nft_cmd_enoent_flowtable(ctx, cmd, loc);
+ break;
+ default:
+ break;
+ }
+
+ if (ret)
+ return;
+
+ netlink_io_error(ctx, loc, "Could not process rule: %s", strerror(err));
+}
+
+void nft_cmd_error(struct netlink_ctx *ctx, struct cmd *cmd,
+ struct mnl_err *err)
+{
+ struct location *loc = NULL;
+ int i;
+
+ for (i = 0; i < cmd->num_attrs; i++) {
+ if (!cmd->attr[i].offset)
+ break;
+ if (cmd->attr[i].offset == err->offset)
+ loc = cmd->attr[i].location;
+ }
+
+ if (loc) {
+ if (err->err == ENOENT) {
+ nft_cmd_enoent(ctx, cmd, loc, err->err);
+ return;
+ }
+ } else {
+ loc = &cmd->location;
+ }
+
+ netlink_io_error(ctx, loc, "Could not process rule: %s",
+ strerror(err->err));
+}
diff --git a/src/ct.c b/src/ct.c
index db1dabd3..0842c838 100644
--- a/src/ct.c
+++ b/src/ct.c
@@ -301,6 +301,8 @@ const struct ct_template ct_templates[__NFT_CT_MAX] = {
BYTEORDER_BIG_ENDIAN, 128),
[NFT_CT_SECMARK] = CT_TEMPLATE("secmark", &integer_type,
BYTEORDER_HOST_ENDIAN, 32),
+ [NFT_CT_ID] = CT_TEMPLATE("id", &integer_type,
+ BYTEORDER_BIG_ENDIAN, 32),
};
static void ct_print(enum nft_ct_keys key, int8_t dir, uint8_t nfproto,
diff --git a/src/datatype.c b/src/datatype.c
index 095598d9..90905258 100644
--- a/src/datatype.c
+++ b/src/datatype.c
@@ -825,6 +825,7 @@ static const struct symbol_table icmp_code_tbl = {
SYMBOL("net-prohibited", ICMP_NET_ANO),
SYMBOL("host-prohibited", ICMP_HOST_ANO),
SYMBOL("admin-prohibited", ICMP_PKT_FILTERED),
+ SYMBOL("frag-needed", ICMP_FRAG_NEEDED),
SYMBOL_LIST_END
},
};
@@ -1083,6 +1084,8 @@ struct datatype *datatype_get(const struct datatype *ptr)
void datatype_set(struct expr *expr, const struct datatype *dtype)
{
+ if (dtype == expr->dtype)
+ return;
datatype_free(expr->dtype);
expr->dtype = datatype_get(dtype);
}
diff --git a/src/evaluate.c b/src/evaluate.c
index a3cbf939..fbc8f1fb 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -18,6 +18,7 @@
#include <linux/netfilter_arp.h>
#include <linux/netfilter/nf_tables.h>
#include <linux/netfilter/nf_synproxy.h>
+#include <linux/netfilter/nf_nat.h>
#include <linux/netfilter_ipv4.h>
#include <netinet/ip_icmp.h>
#include <netinet/icmp6.h>
@@ -75,6 +76,7 @@ static void key_fix_dtype_byteorder(struct expr *key)
datatype_set(key, set_datatype_alloc(dtype, key->byteorder));
}
+static int set_evaluate(struct eval_ctx *ctx, struct set *set);
static struct expr *implicit_set_declaration(struct eval_ctx *ctx,
const char *name,
struct expr *key,
@@ -100,11 +102,14 @@ static struct expr *implicit_set_declaration(struct eval_ctx *ctx,
handle_merge(&set->handle, &ctx->cmd->handle);
memset(&h, 0, sizeof(h));
handle_merge(&h, &set->handle);
+ h.set.location = expr->location;
cmd = cmd_alloc(CMD_ADD, CMD_OBJ_SET, &h, &expr->location, set);
cmd->location = set->location;
list_add_tail(&cmd->list, &ctx->cmd->list);
}
+ set_evaluate(ctx, set);
+
return set_ref_expr_alloc(&expr->location, set);
}
@@ -147,7 +152,7 @@ static int byteorder_conversion(struct eval_ctx *ctx, struct expr **expr,
byteorder_names[byteorder],
byteorder_names[(*expr)->byteorder]);
- if (expr_is_constant(*expr))
+ if (expr_is_constant(*expr) || (*expr)->len / BITS_PER_BYTE < 2)
(*expr)->byteorder = byteorder;
else {
op = byteorder_conversion_op(*expr, byteorder);
@@ -483,6 +488,7 @@ static void expr_evaluate_bits(struct eval_ctx *ctx, struct expr **exprp)
mask = constant_expr_alloc(&expr->location, expr_basetype(expr),
BYTEORDER_HOST_ENDIAN, masklen, NULL);
mpz_set(mask->value, bitmask);
+ mpz_clear(bitmask);
and = binop_expr_alloc(&expr->location, OP_AND, expr, mask);
and->dtype = expr->dtype;
@@ -657,7 +663,7 @@ static int resolve_protocol_conflict(struct eval_ctx *ctx,
if (err < 0)
return err;
- list_add_tail(&nstmt->list, &ctx->stmt->list);
+ rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt);
}
assert(base <= PROTO_BASE_MAX);
@@ -671,7 +677,7 @@ static int resolve_protocol_conflict(struct eval_ctx *ctx,
return 1;
payload->payload.offset += ctx->pctx.protocol[base].offset;
- list_add_tail(&nstmt->list, &ctx->stmt->list);
+ rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt);
return 0;
}
@@ -696,7 +702,8 @@ static int __expr_evaluate_payload(struct eval_ctx *ctx, struct expr *expr)
if (desc == NULL) {
if (payload_gen_dependency(ctx, payload, &nstmt) < 0)
return -1;
- list_add_tail(&nstmt->list, &ctx->stmt->list);
+
+ rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt);
} else {
/* No conflict: Same payload protocol as context, adjust offset
* if needed.
@@ -736,6 +743,9 @@ static int expr_evaluate_payload(struct eval_ctx *ctx, struct expr **exprp)
{
struct expr *expr = *exprp;
+ if (expr->payload.evaluated)
+ return 0;
+
if (__expr_evaluate_payload(ctx, expr) < 0)
return -1;
@@ -745,6 +755,8 @@ static int expr_evaluate_payload(struct eval_ctx *ctx, struct expr **exprp)
if (payload_needs_adjustment(expr))
expr_evaluate_bits(ctx, exprp);
+ expr->payload.evaluated = true;
+
return 0;
}
@@ -833,8 +845,8 @@ static int ct_gen_nh_dependency(struct eval_ctx *ctx, struct expr *ct)
relational_expr_pctx_update(&ctx->pctx, dep);
nstmt = expr_stmt_alloc(&dep->location, dep);
+ rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt);
- list_add_tail(&nstmt->list, &ctx->stmt->list);
return 0;
}
@@ -1300,8 +1312,25 @@ static int expr_evaluate_list(struct eval_ctx *ctx, struct expr **expr)
static int expr_evaluate_set_elem(struct eval_ctx *ctx, struct expr **expr)
{
+ struct set *set = ctx->set;
struct expr *elem = *expr;
+ if (elem->stmt) {
+ if (set->stmt && set->stmt->ops != elem->stmt->ops) {
+ return stmt_error(ctx, elem->stmt,
+ "statement mismatch, element expects %s, "
+ "but %s has type %s",
+ elem->stmt->ops->name,
+ set_is_map(set->flags) ? "map" : "set",
+ set->stmt->ops->name);
+ } else if (!set->stmt && !(set->flags & NFT_SET_EVAL)) {
+ return stmt_error(ctx, elem->stmt,
+ "missing %s statement in %s definition",
+ elem->stmt->ops->name,
+ set_is_map(set->flags) ? "map" : "set");
+ }
+ }
+
if (expr_evaluate(ctx, &elem->key) < 0)
return -1;
@@ -1358,10 +1387,16 @@ static int expr_evaluate_set(struct eval_ctx *ctx, struct expr **expr)
set->size += i->size - 1;
set->set_flags |= i->set_flags;
expr_free(i);
- } else if (!expr_is_singleton(i))
+ } else if (!expr_is_singleton(i)) {
set->set_flags |= NFT_SET_INTERVAL;
+ if (i->key->etype == EXPR_CONCAT)
+ set->set_flags |= NFT_SET_CONCAT;
+ }
}
+ if (ctx->set && (ctx->set->flags & NFT_SET_CONCAT))
+ set->set_flags |= NFT_SET_CONCAT;
+
set->set_flags |= NFT_SET_CONSTANT;
datatype_set(set, ctx->ectx.dtype);
@@ -1416,6 +1451,9 @@ static int expr_evaluate_map(struct eval_ctx *ctx, struct expr **expr)
if (binop_transfer(ctx, expr) < 0)
return -1;
+ if (ctx->set->data->flags & EXPR_F_INTERVAL)
+ ctx->set->data->len *= 2;
+
ctx->set->key->len = ctx->ectx.len;
ctx->set = NULL;
map = *expr;
@@ -1456,6 +1494,7 @@ static int expr_evaluate_mapping(struct eval_ctx *ctx, struct expr **expr)
{
struct expr *mapping = *expr;
struct set *set = ctx->set;
+ uint32_t datalen;
if (set == NULL)
return expr_error(ctx->msgs, mapping,
@@ -1472,7 +1511,13 @@ static int expr_evaluate_mapping(struct eval_ctx *ctx, struct expr **expr)
mapping->flags |= mapping->left->flags & EXPR_F_SINGLETON;
if (set->data) {
- expr_set_context(&ctx->ectx, set->data->dtype, set->data->len);
+ if (!set_is_anonymous(set->flags) &&
+ set->data->flags & EXPR_F_INTERVAL)
+ datalen = set->data->len / 2;
+ else
+ datalen = set->data->len;
+
+ expr_set_context(&ctx->ectx, set->data->dtype, datalen);
} else {
assert((set->flags & NFT_SET_MAP) == 0);
}
@@ -1482,7 +1527,14 @@ static int expr_evaluate_mapping(struct eval_ctx *ctx, struct expr **expr)
if (!expr_is_constant(mapping->right))
return expr_error(ctx->msgs, mapping->right,
"Value must be a constant");
- if (!expr_is_singleton(mapping->right))
+
+ if (set_is_anonymous(set->flags) &&
+ (mapping->right->etype == EXPR_RANGE ||
+ mapping->right->etype == EXPR_PREFIX))
+ set->data->flags |= EXPR_F_INTERVAL;
+
+ if (!(set->data->flags & EXPR_F_INTERVAL) &&
+ !expr_is_singleton(mapping->right))
return expr_error(ctx->msgs, mapping->right,
"Value must be a singleton");
@@ -2102,14 +2154,10 @@ static int stmt_prefix_conversion(struct eval_ctx *ctx, struct expr **expr,
return 0;
}
-static int stmt_evaluate_arg(struct eval_ctx *ctx, struct stmt *stmt,
- const struct datatype *dtype, unsigned int len,
- enum byteorder byteorder, struct expr **expr)
+static int __stmt_evaluate_arg(struct eval_ctx *ctx, struct stmt *stmt,
+ const struct datatype *dtype, unsigned int len,
+ enum byteorder byteorder, struct expr **expr)
{
- __expr_set_context(&ctx->ectx, dtype, byteorder, len, 0);
- if (expr_evaluate(ctx, expr) < 0)
- return -1;
-
if ((*expr)->etype == EXPR_PAYLOAD &&
(*expr)->dtype->type == TYPE_INTEGER &&
((*expr)->dtype->type != datatype_basetype(dtype)->type ||
@@ -2147,6 +2195,17 @@ static int stmt_evaluate_arg(struct eval_ctx *ctx, struct stmt *stmt,
return 0;
}
+static int stmt_evaluate_arg(struct eval_ctx *ctx, struct stmt *stmt,
+ const struct datatype *dtype, unsigned int len,
+ enum byteorder byteorder, struct expr **expr)
+{
+ __expr_set_context(&ctx->ectx, dtype, byteorder, len, 0);
+ if (expr_evaluate(ctx, expr) < 0)
+ return -1;
+
+ return __stmt_evaluate_arg(ctx, stmt, dtype, len, byteorder, expr);
+}
+
static int stmt_evaluate_verdict(struct eval_ctx *ctx, struct stmt *stmt)
{
if (stmt_evaluate_arg(ctx, stmt, &verdict_type, 0, 0, &stmt->expr) < 0)
@@ -2197,7 +2256,7 @@ static int stmt_evaluate_exthdr(struct eval_ctx *ctx, struct stmt *stmt)
static int stmt_evaluate_payload(struct eval_ctx *ctx, struct stmt *stmt)
{
- struct expr *binop, *mask, *and, *payload_bytes;
+ struct expr *mask, *and, *xor, *payload_bytes;
unsigned int masklen, extra_len = 0;
unsigned int payload_byte_size, payload_byte_offset;
uint8_t shift_imm, data[NFT_REG_SIZE];
@@ -2213,6 +2272,11 @@ static int stmt_evaluate_payload(struct eval_ctx *ctx, struct stmt *stmt)
payload->byteorder, &stmt->payload.val) < 0)
return -1;
+ if (!expr_is_constant(stmt->payload.val) &&
+ byteorder_conversion(ctx, &stmt->payload.val,
+ payload->byteorder) < 0)
+ return -1;
+
need_csum = stmt_evaluate_payload_need_csum(payload);
if (!payload_needs_adjustment(payload)) {
@@ -2229,8 +2293,8 @@ static int stmt_evaluate_payload(struct eval_ctx *ctx, struct stmt *stmt)
shift_imm = expr_offset_shift(payload, payload->payload.offset,
&extra_len);
- payload_byte_size = round_up(payload->len, BITS_PER_BYTE) / BITS_PER_BYTE;
- payload_byte_size += (extra_len / BITS_PER_BYTE);
+ payload_byte_size = div_round_up(payload->len + extra_len,
+ BITS_PER_BYTE);
if (need_csum && payload_byte_size & 1) {
payload_byte_size++;
@@ -2244,22 +2308,21 @@ static int stmt_evaluate_payload(struct eval_ctx *ctx, struct stmt *stmt)
}
if (shift_imm) {
- struct expr *off;
+ struct expr *off, *lshift;
off = constant_expr_alloc(&payload->location,
expr_basetype(payload),
BYTEORDER_HOST_ENDIAN,
sizeof(shift_imm), &shift_imm);
- binop = binop_expr_alloc(&payload->location, OP_LSHIFT,
- stmt->payload.val, off);
- binop->dtype = payload->dtype;
- binop->byteorder = payload->byteorder;
+ lshift = binop_expr_alloc(&payload->location, OP_LSHIFT,
+ stmt->payload.val, off);
+ lshift->dtype = payload->dtype;
+ lshift->byteorder = payload->byteorder;
- stmt->payload.val = binop;
+ stmt->payload.val = lshift;
}
-
masklen = payload_byte_size * BITS_PER_BYTE;
mpz_init_bitmask(ff, masklen);
@@ -2274,6 +2337,7 @@ static int stmt_evaluate_payload(struct eval_ctx *ctx, struct stmt *stmt)
mpz_export_data(data, bitmask, BYTEORDER_HOST_ENDIAN, sizeof(data));
mask = constant_expr_alloc(&payload->location, expr_basetype(payload),
BYTEORDER_HOST_ENDIAN, masklen, data);
+ mpz_clear(bitmask);
payload_bytes = payload_expr_alloc(&payload->location, NULL, 0);
payload_init_raw(payload_bytes, payload->payload.base,
@@ -2288,16 +2352,17 @@ static int stmt_evaluate_payload(struct eval_ctx *ctx, struct stmt *stmt)
and = binop_expr_alloc(&payload->location, OP_AND, payload_bytes, mask);
- and->dtype = payload_bytes->dtype;
- and->byteorder = payload_bytes->byteorder;
- and->len = payload_bytes->len;
+ and->dtype = payload_bytes->dtype;
+ and->byteorder = payload_bytes->byteorder;
+ and->len = payload_bytes->len;
+
+ xor = binop_expr_alloc(&payload->location, OP_XOR, and,
+ stmt->payload.val);
+ xor->dtype = payload->dtype;
+ xor->byteorder = payload->byteorder;
+ xor->len = mask->len;
- binop = binop_expr_alloc(&payload->location, OP_XOR, and,
- stmt->payload.val);
- binop->dtype = payload->dtype;
- binop->byteorder = payload->byteorder;
- binop->len = mask->len;
- stmt->payload.val = binop;
+ stmt->payload.val = xor;
return expr_evaluate(ctx, &stmt->payload.val);
}
@@ -2554,7 +2619,7 @@ static int stmt_evaluate_reject_bridge(struct eval_ctx *ctx, struct stmt *stmt,
const struct proto_desc *desc;
desc = ctx->pctx.protocol[PROTO_BASE_LL_HDR].desc;
- if (desc != &proto_eth)
+ if (desc != &proto_eth && desc != &proto_vlan)
return stmt_binary_error(ctx,
&ctx->pctx.protocol[PROTO_BASE_LL_HDR],
stmt, "unsupported link layer protocol");
@@ -2681,6 +2746,8 @@ static int stmt_evaluate_reject_icmp(struct eval_ctx *ctx, struct stmt *stmt)
return -1;
}
stmt->reject.icmp_code = mpz_get_uint8(code->value);
+ expr_free(code);
+
return 0;
}
@@ -2762,22 +2829,28 @@ static int nat_evaluate_family(struct eval_ctx *ctx, struct stmt *stmt)
}
}
+static const struct datatype *get_addr_dtype(uint8_t family)
+{
+ switch (family) {
+ case NFPROTO_IPV4:
+ return &ipaddr_type;
+ case NFPROTO_IPV6:
+ return &ip6addr_type;
+ }
+
+ return &invalid_type;
+}
+
static int evaluate_addr(struct eval_ctx *ctx, struct stmt *stmt,
struct expr **expr)
{
struct proto_ctx *pctx = &ctx->pctx;
const struct datatype *dtype;
- unsigned int len;
- if (pctx->family == NFPROTO_IPV4) {
- dtype = &ipaddr_type;
- len = 4 * BITS_PER_BYTE;
- } else {
- dtype = &ip6addr_type;
- len = 16 * BITS_PER_BYTE;
- }
+ dtype = get_addr_dtype(pctx->family);
- return stmt_evaluate_arg(ctx, stmt, dtype, len, BYTEORDER_BIG_ENDIAN,
+ return stmt_evaluate_arg(ctx, stmt, dtype, dtype->size,
+ BYTEORDER_BIG_ENDIAN,
expr);
}
@@ -2807,9 +2880,10 @@ static int stmt_evaluate_l3proto(struct eval_ctx *ctx,
(nproto == &proto_ip6 && family != NFPROTO_IPV6))
return stmt_binary_error(ctx, stmt,
&ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR],
- "conflicting protocols specified: %s vs. %s. You must specify ip or ip6 family in tproxy statement",
+ "conflicting protocols specified: %s vs. %s. You must specify ip or ip6 family in %s statement",
ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc->name,
- family2str(stmt->tproxy.family));
+ family2str(family),
+ stmt->ops->name);
return 0;
}
@@ -2818,25 +2892,15 @@ static int stmt_evaluate_addr(struct eval_ctx *ctx, struct stmt *stmt,
struct expr **addr)
{
const struct datatype *dtype;
- unsigned int len;
int err;
if (ctx->pctx.family == NFPROTO_INET) {
- switch (family) {
- case NFPROTO_IPV4:
- dtype = &ipaddr_type;
- len = 4 * BITS_PER_BYTE;
- break;
- case NFPROTO_IPV6:
- dtype = &ip6addr_type;
- len = 16 * BITS_PER_BYTE;
- break;
- default:
+ dtype = get_addr_dtype(family);
+ if (dtype->size == 0)
return stmt_error(ctx, stmt,
"ip or ip6 must be specified with address for inet tables.");
- }
- err = stmt_evaluate_arg(ctx, stmt, dtype, len,
+ err = stmt_evaluate_arg(ctx, stmt, dtype, dtype->size,
BYTEORDER_BIG_ENDIAN, addr);
} else {
err = evaluate_addr(ctx, stmt, addr);
@@ -2845,6 +2909,67 @@ static int stmt_evaluate_addr(struct eval_ctx *ctx, struct stmt *stmt,
return err;
}
+static int stmt_evaluate_nat_map(struct eval_ctx *ctx, struct stmt *stmt)
+{
+ struct expr *one, *two, *data, *tmp;
+ const struct datatype *dtype;
+ int addr_type, err;
+
+ switch (stmt->nat.family) {
+ case NFPROTO_IPV4:
+ addr_type = TYPE_IPADDR;
+ break;
+ case NFPROTO_IPV6:
+ addr_type = TYPE_IP6ADDR;
+ break;
+ default:
+ return -1;
+ }
+ dtype = concat_type_alloc((addr_type << TYPE_BITS) | TYPE_INET_SERVICE);
+
+ expr_set_context(&ctx->ectx, dtype, dtype->size);
+ if (expr_evaluate(ctx, &stmt->nat.addr))
+ return -1;
+
+ if (stmt->nat.addr->etype != EXPR_MAP)
+ return 0;
+
+ data = stmt->nat.addr->mappings->set->data;
+ datatype_set(data, dtype);
+
+ if (expr_ops(data)->type != EXPR_CONCAT)
+ return __stmt_evaluate_arg(ctx, stmt, dtype, dtype->size,
+ BYTEORDER_BIG_ENDIAN,
+ &stmt->nat.addr);
+
+ one = list_first_entry(&data->expressions, struct expr, list);
+ two = list_entry(one->list.next, struct expr, list);
+
+ if (one == two || !list_is_last(&two->list, &data->expressions))
+ return __stmt_evaluate_arg(ctx, stmt, dtype, dtype->size,
+ BYTEORDER_BIG_ENDIAN,
+ &stmt->nat.addr);
+
+ dtype = get_addr_dtype(stmt->nat.family);
+ tmp = one;
+ err = __stmt_evaluate_arg(ctx, stmt, dtype, dtype->size,
+ BYTEORDER_BIG_ENDIAN,
+ &tmp);
+ if (err < 0)
+ return err;
+ if (tmp != one)
+ BUG("Internal error: Unexpected alteration of l3 expression");
+
+ tmp = two;
+ err = nat_evaluate_transport(ctx, stmt, &tmp);
+ if (err < 0)
+ return err;
+ if (tmp != two)
+ BUG("Internal error: Unexpected alteration of l4 expression");
+
+ return err;
+}
+
static int stmt_evaluate_nat(struct eval_ctx *ctx, struct stmt *stmt)
{
int err;
@@ -2858,15 +2983,47 @@ static int stmt_evaluate_nat(struct eval_ctx *ctx, struct stmt *stmt)
if (err < 0)
return err;
+ if (stmt->nat.type_flags & STMT_NAT_F_CONCAT) {
+ err = stmt_evaluate_nat_map(ctx, stmt);
+ if (err < 0)
+ return err;
+
+ stmt->flags |= STMT_F_TERMINAL;
+ return 0;
+ }
+
err = stmt_evaluate_addr(ctx, stmt, stmt->nat.family,
&stmt->nat.addr);
if (err < 0)
return err;
}
+
+ if (stmt->nat.type_flags & STMT_NAT_F_INTERVAL) {
+ switch (stmt->nat.addr->etype) {
+ case EXPR_MAP:
+ if (!(stmt->nat.addr->mappings->set->data->flags & EXPR_F_INTERVAL))
+ return expr_error(ctx->msgs, stmt->nat.addr,
+ "map is not defined as interval");
+ break;
+ case EXPR_RANGE:
+ case EXPR_PREFIX:
+ break;
+ default:
+ return expr_error(ctx->msgs, stmt->nat.addr,
+ "neither prefix, range nor map expression");
+ }
+
+ stmt->flags |= STMT_F_TERMINAL;
+
+ return 0;
+ }
+
if (stmt->nat.proto != NULL) {
err = nat_evaluate_transport(ctx, stmt, &stmt->nat.proto);
if (err < 0)
return err;
+
+ stmt->nat.flags |= NF_NAT_RANGE_PROTO_SPECIFIED;
}
stmt->flags |= STMT_F_TERMINAL;
@@ -3162,12 +3319,6 @@ static int stmt_evaluate_objref_map(struct eval_ctx *ctx, struct stmt *stmt)
mappings = implicit_set_declaration(ctx, "__objmap%d",
key, mappings);
-
- mappings->set->data = constant_expr_alloc(&netlink_location,
- &string_type,
- BYTEORDER_HOST_ENDIAN,
- NFT_OBJ_MAXNAMELEN * BITS_PER_BYTE,
- NULL);
mappings->set->objtype = stmt->objref.type;
map->mappings = mappings;
@@ -3360,6 +3511,7 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
memcpy(&set->desc.field_len, &set->key->field_len,
sizeof(set->desc.field_len));
set->desc.field_count = set->key->field_count;
+ set->flags |= NFT_SET_CONCAT;
}
if (set_is_datamap(set->flags)) {
@@ -3367,6 +3519,13 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
return set_error(ctx, set, "map definition does not "
"specify mapping data type");
+ if (set->data->flags & EXPR_F_INTERVAL)
+ set->data->len *= 2;
+
+ if (set->data->etype == EXPR_CONCAT &&
+ expr_evaluate_concat(ctx, &set->data, false) < 0)
+ return -1;
+
if (set->data->len == 0 && set->data->dtype->type != TYPE_VERDICT)
return set_key_data_error(ctx, set,
set->data->dtype, type);
@@ -3384,9 +3543,17 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
}
+ /* Default timeout value implies timeout support */
+ if (set->timeout)
+ set->flags |= NFT_SET_TIMEOUT;
+
+ if (set_is_anonymous(set->flags))
+ return 0;
+
ctx->set = set;
if (set->init != NULL) {
- expr_set_context(&ctx->ectx, set->key->dtype, set->key->len);
+ __expr_set_context(&ctx->ectx, set->key->dtype,
+ set->key->byteorder, set->key->len, 0);
if (expr_evaluate(ctx, &set->init) < 0)
return -1;
}
@@ -3395,10 +3562,6 @@ static int set_evaluate(struct eval_ctx *ctx, struct set *set)
if (set_lookup(table, set->handle.set.name) == NULL)
set_add_hash(set_get(set), table);
- /* Default timeout value implies timeout support */
- if (set->timeout)
- set->flags |= NFT_SET_TIMEOUT;
-
return 0;
}
@@ -3461,17 +3624,16 @@ static int flowtable_evaluate(struct eval_ctx *ctx, struct flowtable *ft)
if (table == NULL)
return table_not_found(ctx);
- ft->hooknum = str2hooknum(NFPROTO_NETDEV, ft->hookstr);
- if (ft->hooknum == NF_INET_NUMHOOKS)
- return chain_error(ctx, ft, "invalid hook %s", ft->hookstr);
-
- if (!evaluate_priority(ctx, &ft->priority, NFPROTO_NETDEV, ft->hooknum))
- return __stmt_binary_error(ctx, &ft->priority.loc, NULL,
- "invalid priority expression %s.",
- expr_name(ft->priority.expr));
-
- if (!ft->dev_expr)
- return chain_error(ctx, ft, "Unbound flowtable not allowed (must specify devices)");
+ if (ft->hook.name) {
+ ft->hook.num = str2hooknum(NFPROTO_NETDEV, ft->hook.name);
+ if (ft->hook.num == NF_INET_NUMHOOKS)
+ return chain_error(ctx, ft, "invalid hook %s",
+ ft->hook.name);
+ if (!evaluate_priority(ctx, &ft->priority, NFPROTO_NETDEV, ft->hook.num))
+ return __stmt_binary_error(ctx, &ft->priority.loc, NULL,
+ "invalid priority expression %s.",
+ expr_name(ft->priority.expr));
+ }
return 0;
}
@@ -3676,14 +3838,15 @@ static int chain_evaluate(struct eval_ctx *ctx, struct chain *chain)
}
if (chain->flags & CHAIN_F_BASECHAIN) {
- chain->hooknum = str2hooknum(chain->handle.family,
- chain->hookstr);
- if (chain->hooknum == NF_INET_NUMHOOKS)
- return chain_error(ctx, chain, "invalid hook %s",
- chain->hookstr);
+ chain->hook.num = str2hooknum(chain->handle.family,
+ chain->hook.name);
+ if (chain->hook.num == NF_INET_NUMHOOKS)
+ return __stmt_binary_error(ctx, &chain->hook.loc, NULL,
+ "The %s family does not support this hook",
+ family2str(chain->handle.family));
if (!evaluate_priority(ctx, &chain->priority,
- chain->handle.family, chain->hooknum))
+ chain->handle.family, chain->hook.num))
return __stmt_binary_error(ctx, &chain->priority.loc, NULL,
"invalid priority expression %s in this context.",
expr_name(chain->priority.expr));
@@ -3692,6 +3855,15 @@ static int chain_evaluate(struct eval_ctx *ctx, struct chain *chain)
return chain_error(ctx, chain, "invalid policy expression %s",
expr_name(chain->policy));
}
+
+ if (chain->handle.family == NFPROTO_NETDEV) {
+ if (!chain->dev_expr)
+ return __stmt_binary_error(ctx, &chain->loc, NULL,
+ "Missing `device' in this chain definition");
+ } else if (chain->dev_expr) {
+ return __stmt_binary_error(ctx, &chain->dev_expr->location, NULL,
+ "This chain type cannot be bound to device");
+ }
}
list_for_each_entry(rule, &chain->rules, list) {
@@ -3732,6 +3904,7 @@ static int ct_timeout_evaluate(struct eval_ctx *ctx, struct obj *obj)
ct->timeout[ts->timeout_index] = ts->timeout_value;
list_del(&ts->head);
+ xfree(ts->timeout_str);
xfree(ts);
}
@@ -3803,7 +3976,7 @@ static int table_evaluate(struct eval_ctx *ctx, struct table *table)
static int cmd_evaluate_add(struct eval_ctx *ctx, struct cmd *cmd)
{
switch (cmd->obj) {
- case CMD_OBJ_SETELEM:
+ case CMD_OBJ_ELEMENTS:
return setelem_evaluate(ctx, &cmd->expr);
case CMD_OBJ_SET:
handle_merge(&cmd->set->handle, &cmd->handle);
@@ -3835,7 +4008,7 @@ static int cmd_evaluate_add(struct eval_ctx *ctx, struct cmd *cmd)
static int cmd_evaluate_delete(struct eval_ctx *ctx, struct cmd *cmd)
{
switch (cmd->obj) {
- case CMD_OBJ_SETELEM:
+ case CMD_OBJ_ELEMENTS:
return setelem_evaluate(ctx, &cmd->expr);
case CMD_OBJ_SET:
case CMD_OBJ_RULE:
@@ -3862,7 +4035,7 @@ static int cmd_evaluate_get(struct eval_ctx *ctx, struct cmd *cmd)
struct set *set;
switch (cmd->obj) {
- case CMD_OBJ_SETELEM:
+ case CMD_OBJ_ELEMENTS:
table = table_lookup(&cmd->handle, &ctx->nft->cache);
if (table == NULL)
return table_not_found(ctx);
diff --git a/src/expression.c b/src/expression.c
index cb11cda4..a6bde70f 100644
--- a/src/expression.c
+++ b/src/expression.c
@@ -829,6 +829,142 @@ static void concat_expr_print(const struct expr *expr, struct output_ctx *octx)
compound_expr_print(expr, " . ", octx);
}
+#define NFTNL_UDATA_SET_KEY_CONCAT_NEST 0
+#define NFTNL_UDATA_SET_KEY_CONCAT_NEST_MAX NFT_REG32_SIZE
+
+#define NFTNL_UDATA_SET_KEY_CONCAT_SUB_TYPE 0
+#define NFTNL_UDATA_SET_KEY_CONCAT_SUB_DATA 1
+#define NFTNL_UDATA_SET_KEY_CONCAT_SUB_MAX 2
+
+static int concat_expr_build_udata(struct nftnl_udata_buf *udbuf,
+ const struct expr *concat_expr)
+{
+ struct nftnl_udata *nest;
+ unsigned int i = 0;
+ struct expr *expr;
+
+ list_for_each_entry(expr, &concat_expr->expressions, list) {
+ struct nftnl_udata *nest_expr;
+ int err;
+
+ if (!expr_ops(expr)->build_udata || i >= NFT_REG32_SIZE)
+ return -1;
+
+ nest = nftnl_udata_nest_start(udbuf, NFTNL_UDATA_SET_KEY_CONCAT_NEST + i);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_KEY_CONCAT_SUB_TYPE, expr->etype);
+ nest_expr = nftnl_udata_nest_start(udbuf, NFTNL_UDATA_SET_KEY_CONCAT_SUB_DATA);
+ err = expr_ops(expr)->build_udata(udbuf, expr);
+ if (err < 0)
+ return err;
+ nftnl_udata_nest_end(udbuf, nest_expr);
+ nftnl_udata_nest_end(udbuf, nest);
+ i++;
+ }
+
+ return 0;
+}
+
+static int concat_parse_udata_nest(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ if (type >= NFTNL_UDATA_SET_KEY_CONCAT_NEST_MAX)
+ return -1;
+
+ if (len <= sizeof(uint32_t))
+ return -1;
+
+ ud[type] = attr;
+ return 0;
+}
+
+static int concat_parse_udata_nested(const struct nftnl_udata *attr, void *data)
+{
+ const struct nftnl_udata **ud = data;
+ uint8_t type = nftnl_udata_type(attr);
+ uint8_t len = nftnl_udata_len(attr);
+
+ switch (type) {
+ case NFTNL_UDATA_SET_KEY_CONCAT_SUB_TYPE:
+ if (len != sizeof(uint32_t))
+ return -1;
+ break;
+ case NFTNL_UDATA_SET_KEY_CONCAT_SUB_DATA:
+ if (len <= sizeof(uint32_t))
+ return -1;
+ break;
+ default:
+ return 0;
+ }
+
+ ud[type] = attr;
+ return 0;
+}
+
+static struct expr *concat_expr_parse_udata(const struct nftnl_udata *attr)
+{
+ const struct nftnl_udata *ud[NFTNL_UDATA_SET_KEY_CONCAT_NEST_MAX] = {};
+ const struct datatype *dtype;
+ struct expr *concat_expr;
+ uint32_t dt = 0;
+ unsigned int i;
+ int err;
+
+ err = nftnl_udata_parse(nftnl_udata_get(attr), nftnl_udata_len(attr),
+ concat_parse_udata_nest, ud);
+ if (err < 0)
+ return NULL;
+
+ concat_expr = concat_expr_alloc(&internal_location);
+ if (!concat_expr)
+ return NULL;
+
+ for (i = 0; i < array_size(ud); i++) {
+ const struct nftnl_udata *nest_ud[NFTNL_UDATA_SET_KEY_CONCAT_SUB_MAX];
+ const struct nftnl_udata *nested, *subdata;
+ const struct expr_ops *ops;
+ struct expr *expr;
+ uint32_t etype;
+
+ if (ud[NFTNL_UDATA_SET_KEY_CONCAT_NEST + i] == NULL)
+ break;
+
+ nested = ud[NFTNL_UDATA_SET_KEY_CONCAT_NEST + i];
+ err = nftnl_udata_parse(nftnl_udata_get(nested), nftnl_udata_len(nested),
+ concat_parse_udata_nested, nest_ud);
+ if (err < 0)
+ goto err_free;
+
+ etype = nftnl_udata_get_u32(nest_ud[NFTNL_UDATA_SET_KEY_CONCAT_SUB_TYPE]);
+ ops = expr_ops_by_type(etype);
+ if (!ops || !ops->parse_udata)
+ goto err_free;
+
+ subdata = nest_ud[NFTNL_UDATA_SET_KEY_CONCAT_SUB_DATA];
+ expr = ops->parse_udata(subdata);
+ if (!expr)
+ goto err_free;
+
+ dt = concat_subtype_add(dt, expr->dtype->type);
+ compound_expr_add(concat_expr, expr);
+ }
+
+ dtype = concat_type_alloc(dt);
+ if (!dtype)
+ goto err_free;
+
+ concat_expr->dtype = datatype_get(dtype);
+ concat_expr->len = dtype->size;
+
+ return concat_expr;
+
+err_free:
+ expr_free(concat_expr);
+ return NULL;
+}
+
static const struct expr_ops concat_expr_ops = {
.type = EXPR_CONCAT,
.name = "concat",
@@ -836,6 +972,8 @@ static const struct expr_ops concat_expr_ops = {
.json = concat_expr_json,
.clone = compound_expr_clone,
.destroy = concat_expr_destroy,
+ .build_udata = concat_expr_build_udata,
+ .parse_udata = concat_expr_parse_udata,
};
struct expr *concat_expr_alloc(const struct location *loc)
@@ -1185,9 +1323,9 @@ void range_expr_value_high(mpz_t rop, const struct expr *expr)
}
}
-const struct expr_ops *expr_ops(const struct expr *e)
+static const struct expr_ops *__expr_ops_by_type(enum expr_types etype)
{
- switch (e->etype) {
+ switch (etype) {
case EXPR_INVALID:
BUG("Invalid expression ops requested");
break;
@@ -1220,26 +1358,21 @@ const struct expr_ops *expr_ops(const struct expr *e)
case EXPR_XFRM: return &xfrm_expr_ops;
}
- BUG("Unknown expression type %d\n", e->etype);
+ BUG("Unknown expression type %d\n", etype);
}
-const struct expr_ops *expr_ops_by_type(enum expr_types etype)
+const struct expr_ops *expr_ops(const struct expr *e)
{
- switch (etype) {
- case EXPR_PAYLOAD: return &payload_expr_ops;
- case EXPR_EXTHDR: return &exthdr_expr_ops;
- case EXPR_META: return &meta_expr_ops;
- case EXPR_SOCKET: return &socket_expr_ops;
- case EXPR_OSF: return &osf_expr_ops;
- case EXPR_CT: return &ct_expr_ops;
- case EXPR_NUMGEN: return &numgen_expr_ops;
- case EXPR_HASH: return &hash_expr_ops;
- case EXPR_RT: return &rt_expr_ops;
- case EXPR_FIB: return &fib_expr_ops;
- case EXPR_XFRM: return &xfrm_expr_ops;
- default:
- break;
- }
+ return __expr_ops_by_type(e->etype);
+}
- BUG("Unknown expression type %d\n", etype);
+const struct expr_ops *expr_ops_by_type(uint32_t value)
+{
+ /* value might come from unreliable source, such as "udata"
+ * annotation of set keys. Avoid BUG() assertion.
+ */
+ if (value == EXPR_INVALID || value > EXPR_MAX)
+ return NULL;
+
+ return __expr_ops_by_type(value);
}
diff --git a/src/json.c b/src/json.c
index 86028959..ed713181 100644
--- a/src/json.c
+++ b/src/json.c
@@ -240,7 +240,7 @@ static json_t *chain_print_json(const struct chain *chain)
tmp = json_pack("{s:s, s:s, s:i, s:s}",
"type", chain->type,
"hook", hooknum2str(chain->handle.family,
- chain->hooknum),
+ chain->hook.num),
"prio", priority,
"policy", chain_policy2str(policy));
if (chain->dev_expr) {
@@ -415,7 +415,7 @@ static json_t *flowtable_print_json(const struct flowtable *ftable)
"name", ftable->handle.flowtable.name,
"table", ftable->handle.table.name,
"handle", ftable->handle.handle.id,
- "hook", hooknum2str(NFPROTO_NETDEV, ftable->hooknum),
+ "hook", hooknum2str(NFPROTO_NETDEV, ftable->hook.num),
"prio", priority);
for (i = 0; i < ftable->dev_array_len; i++) {
diff --git a/src/libnftables.c b/src/libnftables.c
index cd2fcf2f..668e3fc4 100644
--- a/src/libnftables.c
+++ b/src/libnftables.c
@@ -12,7 +12,7 @@
#include <parser.h>
#include <utils.h>
#include <iface.h>
-
+#include <cmd.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
@@ -68,9 +68,7 @@ static int nft_netlink(struct nft_ctx *nft,
list_for_each_entry(cmd, cmds, list) {
if (err->seqnum == cmd->seqnum ||
err->seqnum == batch_seqnum) {
- netlink_io_error(&ctx, &cmd->location,
- "Could not process rule: %s",
- strerror(err->err));
+ nft_cmd_error(&ctx, cmd, err);
errno = err->err;
if (err->seqnum == cmd->seqnum) {
mnl_err_list_free(err);
@@ -421,8 +419,12 @@ static int nft_evaluate(struct nft_ctx *nft, struct list_head *msgs,
if (nft->state->nerrs)
return -1;
- list_for_each_entry(cmd, cmds, list)
+ list_for_each_entry(cmd, cmds, list) {
+ if (cmd->op != CMD_ADD)
+ continue;
+
nft_cmd_expand(cmd);
+ }
return 0;
}
diff --git a/src/main.c b/src/main.c
index 6ab1b89f..d830c7a2 100644
--- a/src/main.c
+++ b/src/main.c
@@ -24,9 +24,23 @@
static struct nft_ctx *nft;
+/*
+ * These options are grouped separately in the help, so we give them named
+ * indices for use there.
+ */
+enum opt_indices {
+ IDX_HELP,
+ IDX_VERSION,
+ IDX_VERSION_LONG,
+ IDX_CHECK,
+ IDX_FILE,
+ IDX_INTERACTIVE,
+};
+
enum opt_vals {
OPT_HELP = 'h',
OPT_VERSION = 'v',
+ OPT_VERSION_LONG = 'V',
OPT_CHECK = 'c',
OPT_FILE = 'f',
OPT_INTERACTIVE = 'i',
@@ -46,122 +60,174 @@ enum opt_vals {
OPT_TERSE = 't',
OPT_INVALID = '?',
};
-#define OPTSTRING "+hvd:cf:iI:jvnsNaeSupypTt"
-static const struct option options[] = {
- {
- .name = "help",
- .val = OPT_HELP,
- },
- {
- .name = "version",
- .val = OPT_VERSION,
- },
- {
- .name = "check",
- .val = OPT_CHECK,
- },
- {
- .name = "file",
- .val = OPT_FILE,
- .has_arg = 1,
- },
- {
- .name = "interactive",
- .val = OPT_INTERACTIVE,
- },
- {
- .name = "numeric",
- .val = OPT_NUMERIC,
- },
- {
- .name = "stateless",
- .val = OPT_STATELESS,
- },
- {
- .name = "reversedns",
- .val = OPT_IP2NAME,
- },
- {
- .name = "service",
- .val = OPT_SERVICE,
- },
- {
- .name = "includepath",
- .val = OPT_INCLUDEPATH,
- .has_arg = 1,
- },
- {
- .name = "debug",
- .val = OPT_DEBUG,
- .has_arg = 1,
- },
- {
- .name = "handle",
- .val = OPT_HANDLE_OUTPUT,
- },
- {
- .name = "echo",
- .val = OPT_ECHO,
- },
- {
- .name = "json",
- .val = OPT_JSON,
- },
- {
- .name = "guid",
- .val = OPT_GUID,
- },
- {
- .name = "numeric-priority",
- .val = OPT_NUMERIC_PRIO,
- },
- {
- .name = "numeric-protocol",
- .val = OPT_NUMERIC_PROTO,
- },
- {
- .name = "numeric-time",
- .val = OPT_NUMERIC_TIME,
- },
- {
- .name = "terse",
- .val = OPT_TERSE,
- },
- {
- .name = NULL
- }
+struct nft_opt {
+ const char *name;
+ enum opt_vals val;
+ const char *arg;
+ const char *help;
+};
+
+#define NFT_OPT(n, v, a, h) \
+ (struct nft_opt) { .name = n, .val = v, .arg = a, .help = h }
+
+static const struct nft_opt nft_options[] = {
+ NFT_OPT("help", OPT_HELP, NULL,
+ "Show this help"),
+ NFT_OPT("version", OPT_VERSION, NULL,
+ "Show version information"),
+ NFT_OPT(NULL, OPT_VERSION_LONG, NULL,
+ "Show extended version information"),
+ NFT_OPT("check", OPT_CHECK, NULL,
+ "Check commands validity without actually applying the changes."),
+ NFT_OPT("file", OPT_FILE, "<filename>",
+ "Read input from <filename>"),
+ NFT_OPT("interactive", OPT_INTERACTIVE, NULL,
+ "Read input from interactive CLI"),
+ NFT_OPT("numeric", OPT_NUMERIC, NULL,
+ "Print fully numerical output."),
+ NFT_OPT("stateless", OPT_STATELESS, NULL,
+ "Omit stateful information of ruleset."),
+ NFT_OPT("reversedns", OPT_IP2NAME, NULL,
+ "Translate IP addresses to names."),
+ NFT_OPT("service", OPT_SERVICE, NULL,
+ "Translate ports to service names as described in /etc/services."),
+ NFT_OPT("includepath", OPT_INCLUDEPATH, "<directory>",
+ "Add <directory> to the paths searched for include files. Default is: " DEFAULT_INCLUDE_PATH),
+ NFT_OPT("debug", OPT_DEBUG, "<level [,level...]>",
+ "Specify debugging level (scanner, parser, eval, netlink, mnl, proto-ctx, segtree, all)"),
+ NFT_OPT("handle", OPT_HANDLE_OUTPUT, NULL,
+ "Output rule handle."),
+ NFT_OPT("echo", OPT_ECHO, NULL,
+ "Echo what has been added, inserted or replaced."),
+ NFT_OPT("json", OPT_JSON, NULL,
+ "Format output in JSON"),
+ NFT_OPT("guid", OPT_GUID, NULL,
+ "Print UID/GID as defined in /etc/passwd and /etc/group."),
+ NFT_OPT("numeric-priority", OPT_NUMERIC_PRIO, NULL,
+ "Print chain priority numerically."),
+ NFT_OPT("numeric-protocol", OPT_NUMERIC_PROTO, NULL,
+ "Print layer 4 protocols numerically."),
+ NFT_OPT("numeric-time", OPT_NUMERIC_TIME, NULL,
+ "Print time values numerically."),
+ NFT_OPT("terse", OPT_TERSE, NULL,
+ "Omit contents of sets."),
};
+#define NR_NFT_OPTIONS (sizeof(nft_options) / sizeof(nft_options[0]))
+
+static const char *get_optstring(void)
+{
+ static char optstring[2 * NR_NFT_OPTIONS + 2];
+
+ if (!optstring[0]) {
+ size_t i, j;
+
+ optstring[0] = '+';
+ for (i = 0, j = 1; i < NR_NFT_OPTIONS && j < sizeof(optstring); i++)
+ j += snprintf(optstring + j, sizeof(optstring) - j, "%c%s",
+ nft_options[i].val,
+ nft_options[i].arg ? ":" : "");
+
+ assert(j < sizeof(optstring));
+ }
+ return optstring;
+}
+
+static const struct option *get_options(void)
+{
+ static struct option options[NR_NFT_OPTIONS + 1];
+
+ if (!options[0].name) {
+ size_t i, j;
+
+ for (i = 0, j = 0; i < NR_NFT_OPTIONS; ++i) {
+ if (nft_options[i].name) {
+ options[j].name = nft_options[i].name;
+ options[j].val = nft_options[i].val;
+ options[j].has_arg = nft_options[i].arg != NULL;
+ j++;
+ }
+ }
+ }
+ return options;
+}
+
+static void print_option(const struct nft_opt *opt)
+{
+ char optbuf[33] = "";
+ int i;
+
+ i = snprintf(optbuf, sizeof(optbuf), " -%c", opt->val);
+ if (opt->name)
+ i += snprintf(optbuf + i, sizeof(optbuf) - i, ", %s", opt->name);
+ if (opt->arg)
+ i += snprintf(optbuf + i, sizeof(optbuf) - i, " %s", opt->arg);
+
+ printf("%-32s%s\n", optbuf, opt->help);
+}
+
static void show_help(const char *name)
{
- printf(
-"Usage: %s [ options ] [ cmds... ]\n"
-"\n"
-"Options:\n"
-" -h, --help Show this help\n"
-" -v, --version Show version information\n"
-"\n"
-" -c, --check Check commands validity without actually applying the changes.\n"
-" -f, --file <filename> Read input from <filename>\n"
-" -i, --interactive Read input from interactive CLI\n"
-"\n"
-" -j, --json Format output in JSON\n"
-" -n, --numeric Print fully numerical output.\n"
-" -s, --stateless Omit stateful information of ruleset.\n"
-" -t, --terse Omit contents of sets.\n"
-" -u, --guid Print UID/GID as defined in /etc/passwd and /etc/group.\n"
-" -N Translate IP addresses to names.\n"
-" -S, --service Translate ports to service names as described in /etc/services.\n"
-" -p, --numeric-protocol Print layer 4 protocols numerically.\n"
-" -y, --numeric-priority Print chain priority numerically.\n"
-" -T, --numeric-time Print time values numerically.\n"
-" -a, --handle Output rule handle.\n"
-" -e, --echo Echo what has been added, inserted or replaced.\n"
-" -I, --includepath <directory> Add <directory> to the paths searched for include files. Default is: %s\n"
-" --debug <level [,level...]> Specify debugging level (scanner, parser, eval, netlink, mnl, proto-ctx, segtree, all)\n"
-"\n",
- name, DEFAULT_INCLUDE_PATH);
+ printf("Usage: %s [ options ] [ cmds... ]\n"
+ "\n"
+ "Options:\n", name);
+
+ print_option(&nft_options[IDX_HELP]);
+ print_option(&nft_options[IDX_VERSION]);
+ print_option(&nft_options[IDX_VERSION_LONG]);
+
+ fputs("\n", stdout);
+
+ print_option(&nft_options[IDX_CHECK]);
+ print_option(&nft_options[IDX_FILE]);
+ print_option(&nft_options[IDX_INTERACTIVE]);
+
+ fputs("\n", stdout);
+
+ for (size_t i = IDX_INTERACTIVE + 1; i < NR_NFT_OPTIONS; ++i)
+ print_option(&nft_options[i]);
+
+ fputs("\n", stdout);
+}
+
+static void show_version(void)
+{
+ const char *cli, *minigmp, *json, *xt;
+
+#if defined(HAVE_LIBREADLINE)
+ cli = "readline";
+#elif defined(HAVE_LIBLINENOISE)
+ cli = "linenoise";
+#else
+ cli = "no";
+#endif
+
+#if defined(HAVE_MINIGMP)
+ minigmp = "yes";
+#else
+ minigmp = "no";
+#endif
+
+#if defined(HAVE_JSON)
+ json = "yes";
+#else
+ json = "no";
+#endif
+
+#if defined(HAVE_XTABLES)
+ xt = "yes";
+#else
+ xt = "no";
+#endif
+
+ printf("%s v%s (%s)\n"
+ " cli: %s\n"
+ " json: %s\n"
+ " minigmp: %s\n"
+ " libxtables: %s\n",
+ PACKAGE_NAME, PACKAGE_VERSION, RELEASE_NAME,
+ cli, json, minigmp, xt);
}
static const struct {
@@ -247,6 +313,8 @@ static bool nft_options_check(int argc, char * const argv[])
int main(int argc, char * const *argv)
{
+ const struct option *options = get_options();
+ const char *optstring = get_optstring();
char *buf = NULL, *filename = NULL;
unsigned int output_flags = 0;
bool interactive = false;
@@ -260,7 +328,7 @@ int main(int argc, char * const *argv)
nft = nft_ctx_new(NFT_CTX_DEFAULT);
while (1) {
- val = getopt_long(argc, argv, OPTSTRING, options, NULL);
+ val = getopt_long(argc, argv, optstring, options, NULL);
if (val == -1)
break;
@@ -272,6 +340,9 @@ int main(int argc, char * const *argv)
printf("%s v%s (%s)\n",
PACKAGE_NAME, PACKAGE_VERSION, RELEASE_NAME);
exit(EXIT_SUCCESS);
+ case OPT_VERSION_LONG:
+ show_version();
+ exit(EXIT_SUCCESS);
case OPT_CHECK:
nft_ctx_set_dry_run(nft, true);
break;
diff --git a/src/mnl.c b/src/mnl.c
index 340380ba..19f66641 100644
--- a/src/mnl.c
+++ b/src/mnl.c
@@ -26,6 +26,7 @@
#include <mnl.h>
#include <string.h>
+#include <net/if.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <fcntl.h>
@@ -37,6 +38,7 @@
struct mnl_socket *nft_mnl_socket_open(void)
{
struct mnl_socket *nf_sock;
+ int one = 1;
nf_sock = mnl_socket_open(NETLINK_NETFILTER);
if (!nf_sock)
@@ -45,6 +47,8 @@ struct mnl_socket *nft_mnl_socket_open(void)
if (fcntl(mnl_socket_get_fd(nf_sock), F_SETFL, O_NONBLOCK))
netlink_init_error();
+ mnl_socket_setsockopt(nf_sock, NETLINK_EXT_ACK, &one, sizeof(one));
+
return nf_sock;
}
@@ -204,11 +208,13 @@ void mnl_batch_reset(struct nftnl_batch *batch)
}
static void mnl_err_list_node_add(struct list_head *err_list, int error,
- int seqnum)
+ int seqnum, uint32_t offset,
+ const char *errmsg)
{
struct mnl_err *err = xmalloc(sizeof(struct mnl_err));
err->seqnum = seqnum;
+ err->offset = offset;
err->err = error;
list_add_tail(&err->head, err_list);
}
@@ -305,6 +311,61 @@ static ssize_t mnl_nft_socket_sendmsg(struct netlink_ctx *ctx,
return sendmsg(mnl_socket_get_fd(ctx->nft->nf_sock), msg, 0);
}
+static int err_attr_cb(const struct nlattr *attr, void *data)
+{
+ const struct nlattr **tb = data;
+ uint16_t type;
+
+ if (mnl_attr_type_valid(attr, NLMSGERR_ATTR_MAX) < 0)
+ return MNL_CB_ERROR;
+
+ type = mnl_attr_get_type(attr);
+ switch (type) {
+ case NLMSGERR_ATTR_OFFS:
+ if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
+ return MNL_CB_ERROR;
+ break;
+ }
+
+ tb[type] = attr;
+ return MNL_CB_OK;
+}
+
+static int mnl_batch_extack_cb(const struct nlmsghdr *nlh, void *data)
+{
+ struct netlink_cb_data *cb_data = data;
+ struct nlattr *tb[NLMSGERR_ATTR_MAX + 1] = {};
+ const struct nlmsgerr *err = mnl_nlmsg_get_payload(nlh);
+ unsigned int hlen = sizeof(*err);
+ const char *msg = NULL;
+ uint32_t off = 0;
+ int errval;
+
+ if (nlh->nlmsg_len < mnl_nlmsg_size(sizeof(struct nlmsgerr)))
+ return MNL_CB_ERROR;
+
+ if (err->error < 0)
+ errval = -err->error;
+ else
+ errval = err->error;
+
+ if (errval == 0)
+ return MNL_CB_STOP;
+
+ if (!(nlh->nlmsg_flags & NLM_F_CAPPED))
+ hlen += mnl_nlmsg_get_payload_len(&err->msg);
+
+ if (mnl_attr_parse(nlh, hlen, err_attr_cb, tb) != MNL_CB_OK)
+ return MNL_CB_ERROR;
+
+ if (tb[NLMSGERR_ATTR_OFFS])
+ off = mnl_attr_get_u32(tb[NLMSGERR_ATTR_OFFS]);
+
+ mnl_err_list_node_add(cb_data->err_list, errval,
+ nlh->nlmsg_seq, off, msg);
+ return MNL_CB_ERROR;
+}
+
#define NFT_MNL_ECHO_RCVBUFF_DEFAULT (MNL_SOCKET_BUFFER_SIZE * 1024)
int mnl_batch_talk(struct netlink_ctx *ctx, struct list_head *err_list,
@@ -326,6 +387,13 @@ int mnl_batch_talk(struct netlink_ctx *ctx, struct list_head *err_list,
unsigned int rcvbufsiz;
size_t batch_size;
fd_set readfds;
+ static mnl_cb_t cb_ctl_array[NLMSG_MIN_TYPE] = {
+ [NLMSG_ERROR] = mnl_batch_extack_cb,
+ };
+ struct netlink_cb_data cb_data = {
+ .err_list = err_list,
+ .nl_ctx = ctx,
+ };
mnl_set_sndbuffer(ctx->nft->nf_sock, ctx->batch);
@@ -361,18 +429,15 @@ int mnl_batch_talk(struct netlink_ctx *ctx, struct list_head *err_list,
if (ret == -1)
return -1;
- ret = mnl_cb_run(rcv_buf, ret, 0, portid, &netlink_echo_callback, ctx);
/* Continue on error, make sure we get all acknowledgments */
- if (ret == -1) {
- struct nlmsghdr *nlh = (struct nlmsghdr *)rcv_buf;
-
- mnl_err_list_node_add(err_list, errno, nlh->nlmsg_seq);
- }
+ ret = mnl_cb_run2(rcv_buf, ret, 0, portid,
+ netlink_echo_callback, &cb_data,
+ cb_ctl_array, MNL_ARRAY_SIZE(cb_ctl_array));
}
return 0;
}
-int mnl_nft_rule_add(struct netlink_ctx *ctx, const struct cmd *cmd,
+int mnl_nft_rule_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags)
{
struct rule *rule = cmd->rule;
@@ -385,8 +450,6 @@ int mnl_nft_rule_add(struct netlink_ctx *ctx, const struct cmd *cmd,
memory_allocation_error();
nftnl_rule_set_u32(nlr, NFTNL_RULE_FAMILY, h->family);
- nftnl_rule_set_str(nlr, NFTNL_RULE_TABLE, h->table.name);
- nftnl_rule_set_str(nlr, NFTNL_RULE_CHAIN, h->chain.name);
if (h->position.id)
nftnl_rule_set_u64(nlr, NFTNL_RULE_POSITION, h->position.id);
if (h->rule_id)
@@ -399,6 +462,12 @@ int mnl_nft_rule_add(struct netlink_ctx *ctx, const struct cmd *cmd,
NFT_MSG_NEWRULE,
cmd->handle.family,
NLM_F_CREATE | flags, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->table.location);
+ mnl_attr_put_strz(nlh, NFTA_RULE_TABLE, h->table.name);
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->chain.location);
+ mnl_attr_put_strz(nlh, NFTA_RULE_CHAIN, h->chain.name);
+
nftnl_rule_nlmsg_build_payload(nlh, nlr);
nftnl_rule_free(nlr);
@@ -407,7 +476,7 @@ int mnl_nft_rule_add(struct netlink_ctx *ctx, const struct cmd *cmd,
return 0;
}
-int mnl_nft_rule_replace(struct netlink_ctx *ctx, const struct cmd *cmd)
+int mnl_nft_rule_replace(struct netlink_ctx *ctx, struct cmd *cmd)
{
struct rule *rule = cmd->rule;
struct handle *h = &rule->handle;
@@ -423,15 +492,20 @@ int mnl_nft_rule_replace(struct netlink_ctx *ctx, const struct cmd *cmd)
memory_allocation_error();
nftnl_rule_set_u32(nlr, NFTNL_RULE_FAMILY, h->family);
- nftnl_rule_set_str(nlr, NFTNL_RULE_TABLE, h->table.name);
- nftnl_rule_set_str(nlr, NFTNL_RULE_CHAIN, h->chain.name);
- nftnl_rule_set_u64(nlr, NFTNL_RULE_HANDLE, h->handle.id);
netlink_linearize_rule(ctx, nlr, rule);
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
NFT_MSG_NEWRULE,
cmd->handle.family,
NLM_F_REPLACE | flags, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->table.location);
+ mnl_attr_put_strz(nlh, NFTA_RULE_TABLE, h->table.name);
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->chain.location);
+ mnl_attr_put_strz(nlh, NFTA_RULE_CHAIN, h->chain.name);
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->handle.location);
+ mnl_attr_put_u64(nlh, NFTA_RULE_HANDLE, htobe64(h->handle.id));
+
nftnl_rule_nlmsg_build_payload(nlh, nlr);
nftnl_rule_free(nlr);
@@ -440,9 +514,9 @@ int mnl_nft_rule_replace(struct netlink_ctx *ctx, const struct cmd *cmd)
return 0;
}
-int mnl_nft_rule_del(struct netlink_ctx *ctx, const struct cmd *cmd)
+int mnl_nft_rule_del(struct netlink_ctx *ctx, struct cmd *cmd)
{
- const struct handle *h = &cmd->handle;
+ struct handle *h = &cmd->handle;
struct nftnl_rule *nlr;
struct nlmsghdr *nlh;
@@ -451,16 +525,23 @@ int mnl_nft_rule_del(struct netlink_ctx *ctx, const struct cmd *cmd)
memory_allocation_error();
nftnl_rule_set_u32(nlr, NFTNL_RULE_FAMILY, h->family);
- nftnl_rule_set_str(nlr, NFTNL_RULE_TABLE, h->table.name);
- if (h->chain.name)
- nftnl_rule_set_str(nlr, NFTNL_RULE_CHAIN, h->chain.name);
- if (h->handle.id)
- nftnl_rule_set_u64(nlr, NFTNL_RULE_HANDLE, h->handle.id);
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
NFT_MSG_DELRULE,
nftnl_rule_get_u32(nlr, NFTNL_RULE_FAMILY),
0, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->table.location);
+ mnl_attr_put_strz(nlh, NFTA_RULE_TABLE, h->table.name);
+ if (h->chain.name) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->chain.location);
+ mnl_attr_put_strz(nlh, NFTA_RULE_CHAIN, h->chain.name);
+ }
+ if (h->handle.id) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->handle.location);
+ mnl_attr_put_u64(nlh, NFTA_RULE_HANDLE, htobe64(h->handle.id));
+ }
+
nftnl_rule_nlmsg_build_payload(nlh, nlr);
nftnl_rule_free(nlr);
@@ -524,12 +605,14 @@ err:
/*
* Chain
*/
-int mnl_nft_chain_add(struct netlink_ctx *ctx, const struct cmd *cmd,
+int mnl_nft_chain_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags)
{
int priority, policy, i = 0;
struct nftnl_chain *nlc;
+ unsigned int ifname_len;
const char **dev_array;
+ char ifname[IFNAMSIZ];
struct nlmsghdr *nlh;
struct expr *expr;
int dev_array_len;
@@ -539,13 +622,15 @@ int mnl_nft_chain_add(struct netlink_ctx *ctx, const struct cmd *cmd,
memory_allocation_error();
nftnl_chain_set_u32(nlc, NFTNL_CHAIN_FAMILY, cmd->handle.family);
- nftnl_chain_set_str(nlc, NFTNL_CHAIN_TABLE, cmd->handle.table.name);
- nftnl_chain_set_str(nlc, NFTNL_CHAIN_NAME, cmd->handle.chain.name);
if (cmd->chain) {
+ if (cmd->chain->flags & CHAIN_F_HW_OFFLOAD) {
+ nftnl_chain_set_u32(nlc, NFTNL_CHAIN_FLAGS,
+ CHAIN_F_HW_OFFLOAD);
+ }
if (cmd->chain->flags & CHAIN_F_BASECHAIN) {
nftnl_chain_set_u32(nlc, NFTNL_CHAIN_HOOKNUM,
- cmd->chain->hooknum);
+ cmd->chain->hook.num);
mpz_export_data(&priority,
cmd->chain->priority.expr->value,
BYTEORDER_HOST_ENDIAN, sizeof(int));
@@ -553,16 +638,16 @@ int mnl_nft_chain_add(struct netlink_ctx *ctx, const struct cmd *cmd,
nftnl_chain_set_str(nlc, NFTNL_CHAIN_TYPE,
cmd->chain->type);
}
- if (cmd->chain->policy) {
- mpz_export_data(&policy, cmd->chain->policy->value,
- BYTEORDER_HOST_ENDIAN, sizeof(int));
- nftnl_chain_set_u32(nlc, NFTNL_CHAIN_POLICY, policy);
- }
if (cmd->chain->dev_expr) {
dev_array = xmalloc(sizeof(char *) * 8);
dev_array_len = 8;
list_for_each_entry(expr, &cmd->chain->dev_expr->expressions, list) {
- dev_array[i++] = expr->identifier;
+ ifname_len = div_round_up(expr->len, BITS_PER_BYTE);
+ memset(ifname, 0, sizeof(ifname));
+ mpz_export_data(ifname, expr->value,
+ BYTEORDER_HOST_ENDIAN,
+ ifname_len);
+ dev_array[i++] = xstrdup(ifname);
if (i == dev_array_len) {
dev_array_len *= 2;
dev_array = xrealloc(dev_array,
@@ -577,6 +662,10 @@ int mnl_nft_chain_add(struct netlink_ctx *ctx, const struct cmd *cmd,
nftnl_chain_set_data(nlc, NFTNL_CHAIN_DEVICES, dev_array,
sizeof(char *) * dev_array_len);
+ i = 0;
+ while (dev_array[i] != NULL)
+ xfree(dev_array[i++]);
+
xfree(dev_array);
}
}
@@ -586,6 +675,19 @@ int mnl_nft_chain_add(struct netlink_ctx *ctx, const struct cmd *cmd,
NFT_MSG_NEWCHAIN,
cmd->handle.family,
NLM_F_CREATE | flags, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_CHAIN_TABLE, cmd->handle.table.name);
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.chain.location);
+ mnl_attr_put_strz(nlh, NFTA_CHAIN_NAME, cmd->handle.chain.name);
+
+ if (cmd->chain && cmd->chain->policy) {
+ mpz_export_data(&policy, cmd->chain->policy->value,
+ BYTEORDER_HOST_ENDIAN, sizeof(int));
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->chain->policy->location);
+ mnl_attr_put_u32(nlh, NFTA_CHAIN_POLICY, htonl(policy));
+ }
+
nftnl_chain_nlmsg_build_payload(nlh, nlc);
nftnl_chain_free(nlc);
@@ -624,7 +726,7 @@ int mnl_nft_chain_rename(struct netlink_ctx *ctx, const struct cmd *cmd,
return 0;
}
-int mnl_nft_chain_del(struct netlink_ctx *ctx, const struct cmd *cmd)
+int mnl_nft_chain_del(struct netlink_ctx *ctx, struct cmd *cmd)
{
struct nftnl_chain *nlc;
struct nlmsghdr *nlh;
@@ -634,18 +736,23 @@ int mnl_nft_chain_del(struct netlink_ctx *ctx, const struct cmd *cmd)
memory_allocation_error();
nftnl_chain_set_u32(nlc, NFTNL_CHAIN_FAMILY, cmd->handle.family);
- nftnl_chain_set_str(nlc, NFTNL_CHAIN_TABLE, cmd->handle.table.name);
- if (cmd->handle.chain.name)
- nftnl_chain_set_str(nlc, NFTNL_CHAIN_NAME,
- cmd->handle.chain.name);
- else if (cmd->handle.handle.id)
- nftnl_chain_set_u64(nlc, NFTNL_CHAIN_HANDLE,
- cmd->handle.handle.id);
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
NFT_MSG_DELCHAIN,
cmd->handle.family,
0, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_CHAIN_TABLE, cmd->handle.table.name);
+ if (cmd->handle.chain.name) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.chain.location);
+ mnl_attr_put_strz(nlh, NFTA_CHAIN_NAME, cmd->handle.chain.name);
+ } else if (cmd->handle.handle.id) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.handle.location);
+ mnl_attr_put_u64(nlh, NFTA_CHAIN_HANDLE,
+ htobe64(cmd->handle.handle.id));
+ }
+
nftnl_chain_nlmsg_build_payload(nlh, nlc);
nftnl_chain_free(nlc);
@@ -705,7 +812,7 @@ err:
/*
* Table
*/
-int mnl_nft_table_add(struct netlink_ctx *ctx, const struct cmd *cmd,
+int mnl_nft_table_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags)
{
struct nftnl_table *nlt;
@@ -716,7 +823,6 @@ int mnl_nft_table_add(struct netlink_ctx *ctx, const struct cmd *cmd,
memory_allocation_error();
nftnl_table_set_u32(nlt, NFTNL_TABLE_FAMILY, cmd->handle.family);
- nftnl_table_set_str(nlt, NFTNL_TABLE_NAME, cmd->handle.table.name);
if (cmd->table)
nftnl_table_set_u32(nlt, NFTNL_TABLE_FLAGS, cmd->table->flags);
else
@@ -726,6 +832,9 @@ int mnl_nft_table_add(struct netlink_ctx *ctx, const struct cmd *cmd,
NFT_MSG_NEWTABLE,
cmd->handle.family,
flags, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_TABLE_NAME, cmd->handle.table.name);
nftnl_table_nlmsg_build_payload(nlh, nlt);
nftnl_table_free(nlt);
@@ -734,7 +843,7 @@ int mnl_nft_table_add(struct netlink_ctx *ctx, const struct cmd *cmd,
return 0;
}
-int mnl_nft_table_del(struct netlink_ctx *ctx, const struct cmd *cmd)
+int mnl_nft_table_del(struct netlink_ctx *ctx, struct cmd *cmd)
{
struct nftnl_table *nlt;
struct nlmsghdr *nlh;
@@ -744,17 +853,20 @@ int mnl_nft_table_del(struct netlink_ctx *ctx, const struct cmd *cmd)
memory_allocation_error();
nftnl_table_set_u32(nlt, NFTNL_TABLE_FAMILY, cmd->handle.family);
- if (cmd->handle.table.name)
- nftnl_table_set_str(nlt, NFTNL_TABLE_NAME,
- cmd->handle.table.name);
- else if (cmd->handle.handle.id)
- nftnl_table_set_u64(nlt, NFTNL_TABLE_HANDLE,
- cmd->handle.handle.id);
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
NFT_MSG_DELTABLE,
cmd->handle.family,
0, ctx->seqnum);
+
+ if (cmd->handle.table.name) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_TABLE_NAME, cmd->handle.table.name);
+ } else if (cmd->handle.handle.id) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.handle.location);
+ mnl_attr_put_u64(nlh, NFTA_TABLE_NAME,
+ htobe64(cmd->handle.handle.id));
+ }
nftnl_table_nlmsg_build_payload(nlh, nlt);
nftnl_table_free(nlt);
@@ -834,10 +946,10 @@ static void set_key_expression(struct netlink_ctx *ctx,
/*
* Set
*/
-int mnl_nft_set_add(struct netlink_ctx *ctx, const struct cmd *cmd,
+int mnl_nft_set_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags)
{
- const struct handle *h = &cmd->handle;
+ struct handle *h = &cmd->handle;
struct nftnl_udata_buf *udbuf;
struct set *set = cmd->set;
struct nftnl_set *nls;
@@ -902,8 +1014,11 @@ int mnl_nft_set_add(struct netlink_ctx *ctx, const struct cmd *cmd,
memory_allocation_error();
set_key_expression(ctx, set->key, set->flags, udbuf, NFTNL_UDATA_SET_KEY_TYPEOF);
- if (set->data)
+ if (set->data) {
set_key_expression(ctx, set->data, set->flags, udbuf, NFTNL_UDATA_SET_DATA_TYPEOF);
+ nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_DATA_INTERVAL,
+ !!(set->data->flags & EXPR_F_INTERVAL));
+ }
if (set->desc.field_len[0]) {
nftnl_set_set_data(nls, NFTNL_SET_DESC_CONCAT,
@@ -916,12 +1031,26 @@ int mnl_nft_set_add(struct netlink_ctx *ctx, const struct cmd *cmd,
nftnl_udata_buf_len(udbuf));
nftnl_udata_buf_free(udbuf);
+ if (set->stmt) {
+ nftnl_set_set_data(nls, NFTNL_SET_EXPR,
+ netlink_gen_stmt_stateful(set->stmt), 0);
+ }
+
netlink_dump_set(nls, ctx);
+ nftnl_set_unset(nls, NFTNL_SET_TABLE);
+ nftnl_set_unset(nls, NFTNL_SET_NAME);
+
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
NFT_MSG_NEWSET,
h->family,
NLM_F_CREATE | flags, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->table.location);
+ mnl_attr_put_strz(nlh, NFTA_SET_TABLE, h->table.name);
+ cmd_add_loc(cmd, nlh->nlmsg_len, &h->set.location);
+ mnl_attr_put_strz(nlh, NFTA_SET_NAME, h->set.name);
+
nftnl_set_nlmsg_build_payload(nlh, nls);
nftnl_set_free(nls);
@@ -930,7 +1059,7 @@ int mnl_nft_set_add(struct netlink_ctx *ctx, const struct cmd *cmd,
return 0;
}
-int mnl_nft_set_del(struct netlink_ctx *ctx, const struct cmd *cmd)
+int mnl_nft_set_del(struct netlink_ctx *ctx, struct cmd *cmd)
{
const struct handle *h = &cmd->handle;
struct nftnl_set *nls;
@@ -941,16 +1070,23 @@ int mnl_nft_set_del(struct netlink_ctx *ctx, const struct cmd *cmd)
memory_allocation_error();
nftnl_set_set_u32(nls, NFTNL_SET_FAMILY, h->family);
- nftnl_set_set_str(nls, NFTNL_SET_TABLE, h->table.name);
- if (h->set.name)
- nftnl_set_set_str(nls, NFTNL_SET_NAME, h->set.name);
- else if (h->handle.id)
- nftnl_set_set_u64(nls, NFTNL_SET_HANDLE, h->handle.id);
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
NFT_MSG_DELSET,
h->family,
0, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_SET_TABLE, cmd->handle.table.name);
+ if (h->set.name) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.set.location);
+ mnl_attr_put_strz(nlh, NFTA_SET_NAME, cmd->handle.set.name);
+ } else if (h->handle.id) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.handle.location);
+ mnl_attr_put_u64(nlh, NFTA_SET_HANDLE,
+ htobe64(cmd->handle.handle.id));
+ }
+
nftnl_set_nlmsg_build_payload(nlh, nls);
nftnl_set_free(nls);
@@ -1016,7 +1152,7 @@ err:
return NULL;
}
-int mnl_nft_obj_add(struct netlink_ctx *ctx, const struct cmd *cmd,
+int mnl_nft_obj_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags)
{
struct obj *obj = cmd->object;
@@ -1028,8 +1164,6 @@ int mnl_nft_obj_add(struct netlink_ctx *ctx, const struct cmd *cmd,
memory_allocation_error();
nftnl_obj_set_u32(nlo, NFTNL_OBJ_FAMILY, cmd->handle.family);
- nftnl_obj_set_str(nlo, NFTNL_OBJ_TABLE, cmd->handle.table.name);
- nftnl_obj_set_str(nlo, NFTNL_OBJ_NAME, cmd->handle.obj.name);
nftnl_obj_set_u32(nlo, NFTNL_OBJ_TYPE, obj->type);
switch (obj->type) {
@@ -1107,6 +1241,12 @@ int mnl_nft_obj_add(struct netlink_ctx *ctx, const struct cmd *cmd,
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
NFT_MSG_NEWOBJ, cmd->handle.family,
NLM_F_CREATE | flags, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_OBJ_TABLE, cmd->handle.table.name);
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.obj.location);
+ mnl_attr_put_strz(nlh, NFTA_OBJ_NAME, cmd->handle.obj.name);
+
nftnl_obj_nlmsg_build_payload(nlh, nlo);
nftnl_obj_free(nlo);
@@ -1115,7 +1255,7 @@ int mnl_nft_obj_add(struct netlink_ctx *ctx, const struct cmd *cmd,
return 0;
}
-int mnl_nft_obj_del(struct netlink_ctx *ctx, const struct cmd *cmd, int type)
+int mnl_nft_obj_del(struct netlink_ctx *ctx, struct cmd *cmd, int type)
{
struct nftnl_obj *nlo;
struct nlmsghdr *nlh;
@@ -1125,16 +1265,24 @@ int mnl_nft_obj_del(struct netlink_ctx *ctx, const struct cmd *cmd, int type)
memory_allocation_error();
nftnl_obj_set_u32(nlo, NFTNL_OBJ_FAMILY, cmd->handle.family);
- nftnl_obj_set_str(nlo, NFTNL_OBJ_TABLE, cmd->handle.table.name);
nftnl_obj_set_u32(nlo, NFTNL_OBJ_TYPE, type);
- if (cmd->handle.obj.name)
- nftnl_obj_set_str(nlo, NFTNL_OBJ_NAME, cmd->handle.obj.name);
- else if (cmd->handle.handle.id)
- nftnl_obj_set_u64(nlo, NFTNL_OBJ_HANDLE, cmd->handle.handle.id);
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
NFT_MSG_DELOBJ, cmd->handle.family,
0, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_OBJ_TABLE, cmd->handle.table.name);
+
+ if (cmd->handle.obj.name) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.obj.location);
+ mnl_attr_put_strz(nlh, NFTA_OBJ_NAME, cmd->handle.obj.name);
+ } else if (cmd->handle.handle.id) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.handle.location);
+ mnl_attr_put_u64(nlh, NFTA_OBJ_HANDLE,
+ htobe64(cmd->handle.handle.id));
+ }
+
nftnl_obj_nlmsg_build_payload(nlh, nlo);
nftnl_obj_free(nlo);
@@ -1442,14 +1590,48 @@ err:
return NULL;
}
-int mnl_nft_flowtable_add(struct netlink_ctx *ctx, const struct cmd *cmd,
+static const char **nft_flowtable_dev_array(struct cmd *cmd)
+{
+ unsigned int ifname_len;
+ const char **dev_array;
+ char ifname[IFNAMSIZ];
+ int i = 0, len = 1;
+ struct expr *expr;
+
+ list_for_each_entry(expr, &cmd->flowtable->dev_expr->expressions, list)
+ len++;
+
+ dev_array = xmalloc(sizeof(char *) * len);
+
+ list_for_each_entry(expr, &cmd->flowtable->dev_expr->expressions, list) {
+ ifname_len = div_round_up(expr->len, BITS_PER_BYTE);
+ memset(ifname, 0, sizeof(ifname));
+ mpz_export_data(ifname, expr->value, BYTEORDER_HOST_ENDIAN,
+ ifname_len);
+ dev_array[i++] = xstrdup(ifname);
+ }
+
+ dev_array[i] = NULL;
+
+ return dev_array;
+}
+
+static void nft_flowtable_dev_array_free(const char **dev_array)
+{
+ int i = 0;
+
+ while (dev_array[i] != NULL)
+ xfree(dev_array[i++]);
+
+ free(dev_array);
+}
+
+int mnl_nft_flowtable_add(struct netlink_ctx *ctx, struct cmd *cmd,
unsigned int flags)
{
struct nftnl_flowtable *flo;
const char **dev_array;
struct nlmsghdr *nlh;
- int i = 0, len = 1;
- struct expr *expr;
int priority;
flo = nftnl_flowtable_alloc();
@@ -1458,33 +1640,39 @@ int mnl_nft_flowtable_add(struct netlink_ctx *ctx, const struct cmd *cmd,
nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_FAMILY,
cmd->handle.family);
- nftnl_flowtable_set_str(flo, NFTNL_FLOWTABLE_TABLE,
- cmd->handle.table.name);
- nftnl_flowtable_set_str(flo, NFTNL_FLOWTABLE_NAME,
- cmd->handle.flowtable.name);
- nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_HOOKNUM,
- cmd->flowtable->hooknum);
- mpz_export_data(&priority, cmd->flowtable->priority.expr->value,
- BYTEORDER_HOST_ENDIAN, sizeof(int));
- nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_PRIO, priority);
- list_for_each_entry(expr, &cmd->flowtable->dev_expr->expressions, list)
- len++;
+ if (cmd->flowtable->hook.name) {
+ nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_HOOKNUM,
+ cmd->flowtable->hook.num);
+ mpz_export_data(&priority, cmd->flowtable->priority.expr->value,
+ BYTEORDER_HOST_ENDIAN, sizeof(int));
+ nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_PRIO, priority);
+ } else {
+ nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_HOOKNUM, 0);
+ nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_PRIO, 0);
+ }
- dev_array = calloc(len, sizeof(char *));
- list_for_each_entry(expr, &cmd->flowtable->dev_expr->expressions, list)
- dev_array[i++] = expr->identifier;
+ if (cmd->flowtable->dev_expr) {
+ dev_array = nft_flowtable_dev_array(cmd);
+ nftnl_flowtable_set_data(flo, NFTNL_FLOWTABLE_DEVICES,
+ dev_array, 0);
+ nft_flowtable_dev_array_free(dev_array);
+ }
- dev_array[i] = NULL;
- nftnl_flowtable_set_data(flo, NFTNL_FLOWTABLE_DEVICES,
- dev_array, sizeof(char *) * len);
- free(dev_array);
+ nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_FLAGS,
+ cmd->flowtable->flags);
netlink_dump_flowtable(flo, ctx);
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
NFT_MSG_NEWFLOWTABLE, cmd->handle.family,
NLM_F_CREATE | flags, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_TABLE, cmd->handle.table.name);
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.flowtable.location);
+ mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_NAME, cmd->handle.flowtable.name);
+
nftnl_flowtable_nlmsg_build_payload(nlh, flo);
nftnl_flowtable_free(flo);
@@ -1493,9 +1681,10 @@ int mnl_nft_flowtable_add(struct netlink_ctx *ctx, const struct cmd *cmd,
return 0;
}
-int mnl_nft_flowtable_del(struct netlink_ctx *ctx, const struct cmd *cmd)
+int mnl_nft_flowtable_del(struct netlink_ctx *ctx, struct cmd *cmd)
{
struct nftnl_flowtable *flo;
+ const char **dev_array;
struct nlmsghdr *nlh;
flo = nftnl_flowtable_alloc();
@@ -1504,18 +1693,35 @@ int mnl_nft_flowtable_del(struct netlink_ctx *ctx, const struct cmd *cmd)
nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_FAMILY,
cmd->handle.family);
- nftnl_flowtable_set_str(flo, NFTNL_FLOWTABLE_TABLE,
- cmd->handle.table.name);
- if (cmd->handle.flowtable.name)
- nftnl_flowtable_set_str(flo, NFTNL_FLOWTABLE_NAME,
- cmd->handle.flowtable.name);
- else if (cmd->handle.handle.id)
- nftnl_flowtable_set_u64(flo, NFTNL_FLOWTABLE_HANDLE,
- cmd->handle.handle.id);
+
+ if (cmd->flowtable && cmd->flowtable->dev_expr) {
+ nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_HOOKNUM, 0);
+ nftnl_flowtable_set_u32(flo, NFTNL_FLOWTABLE_PRIO, 0);
+
+ dev_array = nft_flowtable_dev_array(cmd);
+ nftnl_flowtable_set_data(flo, NFTNL_FLOWTABLE_DEVICES,
+ dev_array, 0);
+ nft_flowtable_dev_array_free(dev_array);
+ }
nlh = nftnl_nlmsg_build_hdr(nftnl_batch_buffer(ctx->batch),
NFT_MSG_DELFLOWTABLE, cmd->handle.family,
0, ctx->seqnum);
+
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.table.location);
+ mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_TABLE, cmd->handle.table.name);
+
+ if (cmd->handle.flowtable.name) {
+ cmd_add_loc(cmd, nlh->nlmsg_len,
+ &cmd->handle.flowtable.location);
+ mnl_attr_put_strz(nlh, NFTA_FLOWTABLE_NAME,
+ cmd->handle.flowtable.name);
+ } else if (cmd->handle.handle.id) {
+ cmd_add_loc(cmd, nlh->nlmsg_len, &cmd->handle.handle.location);
+ mnl_attr_put_u64(nlh, NFTA_FLOWTABLE_HANDLE,
+ htobe64(cmd->handle.handle.id));
+ }
+
nftnl_flowtable_nlmsg_build_payload(nlh, flo);
nftnl_flowtable_free(flo);
diff --git a/src/monitor.c b/src/monitor.c
index 142cc929..bb269c02 100644
--- a/src/monitor.c
+++ b/src/monitor.c
@@ -906,7 +906,8 @@ static int netlink_events_cb(const struct nlmsghdr *nlh, void *data)
int netlink_echo_callback(const struct nlmsghdr *nlh, void *data)
{
- struct netlink_ctx *ctx = data;
+ struct netlink_cb_data *nl_cb_data = data;
+ struct netlink_ctx *ctx = nl_cb_data->nl_ctx;
struct netlink_mon_handler echo_monh = {
.format = NFTNL_OUTPUT_DEFAULT,
.ctx = ctx,
diff --git a/src/netlink.c b/src/netlink.c
index e4128963..fb0a17ba 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -138,6 +138,9 @@ static struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
if (elem->expiration)
nftnl_set_elem_set_u64(nlse, NFTNL_SET_ELEM_EXPIRATION,
elem->expiration);
+ if (elem->stmt)
+ nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_EXPR,
+ netlink_gen_stmt_stateful(elem->stmt), 0);
if (elem->comment || expr->elem_flags) {
udbuf = nftnl_udata_buf_alloc(NFT_USERDATA_MAXLEN);
if (!udbuf)
@@ -169,7 +172,12 @@ static struct nftnl_set_elem *alloc_nftnl_setelem(const struct expr *set,
nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_CHAIN,
nld.chain, strlen(nld.chain));
break;
+ case EXPR_CONCAT:
+ assert(nld.len > 0);
+ /* fallthrough */
case EXPR_VALUE:
+ case EXPR_RANGE:
+ case EXPR_PREFIX:
nftnl_set_elem_set(nlse, NFTNL_SET_ELEM_DATA,
nld.value, nld.len);
break;
@@ -290,6 +298,38 @@ static void netlink_gen_verdict(const struct expr *expr,
}
}
+static void netlink_gen_range(const struct expr *expr,
+ struct nft_data_linearize *nld)
+{
+ unsigned int len = div_round_up(expr->left->len, BITS_PER_BYTE) * 2;
+ unsigned char data[len];
+ unsigned int offset = 0;
+
+ memset(data, 0, len);
+ offset = netlink_export_pad(data, expr->left->value, expr->left);
+ netlink_export_pad(data + offset, expr->right->value, expr->right);
+ memcpy(nld->value, data, len);
+ nld->len = len;
+}
+
+static void netlink_gen_prefix(const struct expr *expr,
+ struct nft_data_linearize *nld)
+{
+ unsigned int len = div_round_up(expr->len, BITS_PER_BYTE) * 2;
+ unsigned char data[len];
+ int offset;
+ mpz_t v;
+
+ offset = netlink_export_pad(data, expr->prefix->value, expr);
+ mpz_init_bitmask(v, expr->len - expr->prefix_len);
+ mpz_add(v, expr->prefix->value, v);
+ netlink_export_pad(data + offset, v, expr->prefix);
+ mpz_clear(v);
+
+ memcpy(nld->value, data, len);
+ nld->len = len;
+}
+
void netlink_gen_data(const struct expr *expr, struct nft_data_linearize *data)
{
switch (expr->etype) {
@@ -299,6 +339,10 @@ void netlink_gen_data(const struct expr *expr, struct nft_data_linearize *data)
return netlink_gen_concat_data(expr, data);
case EXPR_VERDICT:
return netlink_gen_verdict(expr, data);
+ case EXPR_RANGE:
+ return netlink_gen_range(expr, data);
+ case EXPR_PREFIX:
+ return netlink_gen_prefix(expr, data);
default:
BUG("invalid data expression type %s\n", expr_name(expr));
}
@@ -432,15 +476,17 @@ struct chain *netlink_delinearize_chain(struct netlink_ctx *ctx,
xstrdup(nftnl_chain_get_str(nlc, NFTNL_CHAIN_TABLE));
chain->handle.handle.id =
nftnl_chain_get_u64(nlc, NFTNL_CHAIN_HANDLE);
+ if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_FLAGS))
+ chain->flags = nftnl_chain_get_u32(nlc, NFTNL_CHAIN_FLAGS);
if (nftnl_chain_is_set(nlc, NFTNL_CHAIN_HOOKNUM) &&
nftnl_chain_is_set(nlc, NFTNL_CHAIN_PRIO) &&
nftnl_chain_is_set(nlc, NFTNL_CHAIN_TYPE) &&
nftnl_chain_is_set(nlc, NFTNL_CHAIN_POLICY)) {
- chain->hooknum =
+ chain->hook.num =
nftnl_chain_get_u32(nlc, NFTNL_CHAIN_HOOKNUM);
- chain->hookstr =
- hooknum2str(chain->handle.family, chain->hooknum);
+ chain->hook.name =
+ hooknum2str(chain->handle.family, chain->hook.num);
priority = nftnl_chain_get_s32(nlc, NFTNL_CHAIN_PRIO);
chain->priority.expr =
constant_expr_alloc(&netlink_location,
@@ -610,6 +656,7 @@ static int set_parse_udata_cb(const struct nftnl_udata *attr, void *data)
case NFTNL_UDATA_SET_KEYBYTEORDER:
case NFTNL_UDATA_SET_DATABYTEORDER:
case NFTNL_UDATA_SET_MERGE_ELEMENTS:
+ case NFTNL_UDATA_SET_DATA_INTERVAL:
if (len != sizeof(uint32_t))
return -1;
break;
@@ -693,6 +740,7 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
struct expr *typeof_expr_key, *typeof_expr_data;
uint32_t flags, key, objtype = 0;
const struct datatype *dtype;
+ uint32_t data_interval = 0;
bool automerge = false;
const char *udata;
struct set *set;
@@ -716,6 +764,7 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
GET_U32_UDATA(keybyteorder, NFTNL_UDATA_SET_KEYBYTEORDER);
GET_U32_UDATA(databyteorder, NFTNL_UDATA_SET_DATABYTEORDER);
GET_U32_UDATA(automerge, NFTNL_UDATA_SET_MERGE_ELEMENTS);
+ GET_U32_UDATA(data_interval, NFTNL_UDATA_SET_DATA_INTERVAL);
#undef GET_U32_UDATA
typeof_expr_key = set_make_key(ud[NFTNL_UDATA_SET_KEY_TYPEOF]);
@@ -758,6 +807,13 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
set->handle.set.name = xstrdup(nftnl_set_get_str(nls, NFTNL_SET_NAME));
set->automerge = automerge;
+ if (nftnl_set_is_set(nls, NFTNL_SET_EXPR)) {
+ const struct nftnl_expr *nle;
+
+ nle = nftnl_set_get(nls, NFTNL_SET_EXPR);
+ set->stmt = netlink_parse_set_expr(set, &ctx->nft->cache, nle);
+ }
+
if (datatype) {
dtype = set_datatype_alloc(datatype, databyteorder);
klen = nftnl_set_get_u32(nls, NFTNL_SET_DATA_LEN) * BITS_PER_BYTE;
@@ -777,6 +833,9 @@ struct set *netlink_delinearize_set(struct netlink_ctx *ctx,
typeof_expr_key = NULL;
}
+ if (data_interval)
+ set->data->flags |= EXPR_F_INTERVAL;
+
if (dtype != datatype)
datatype_free(datatype);
}
@@ -870,6 +929,69 @@ void alloc_setelem_cache(const struct expr *set, struct nftnl_set *nls)
}
}
+static bool mpz_bitmask_is_prefix(mpz_t bitmask, uint32_t len)
+{
+ unsigned long n1, n2;
+
+ n1 = mpz_scan0(bitmask, 0);
+ if (n1 == ULONG_MAX)
+ return false;
+
+ n2 = mpz_scan1(bitmask, n1 + 1);
+ if (n2 < len)
+ return false;
+
+ return true;
+}
+
+static uint32_t mpz_bitmask_to_prefix(mpz_t bitmask, uint32_t len)
+{
+ return len - mpz_scan0(bitmask, 0);
+}
+
+struct expr *range_expr_to_prefix(struct expr *range)
+{
+ struct expr *left = range->left, *right = range->right, *prefix;
+ uint32_t len = left->len, prefix_len;
+ mpz_t bitmask;
+
+ mpz_init2(bitmask, len);
+ mpz_xor(bitmask, left->value, right->value);
+
+ if (mpz_bitmask_is_prefix(bitmask, len)) {
+ prefix_len = mpz_bitmask_to_prefix(bitmask, len);
+ prefix = prefix_expr_alloc(&range->location, expr_get(left),
+ prefix_len);
+ mpz_clear(bitmask);
+ expr_free(range);
+
+ return prefix;
+ }
+ mpz_clear(bitmask);
+
+ return range;
+}
+
+static struct expr *netlink_parse_interval_elem(const struct datatype *dtype,
+ struct expr *expr)
+{
+ unsigned int len = div_round_up(expr->len, BITS_PER_BYTE);
+ struct expr *range, *left, *right;
+ char data[len];
+
+ mpz_export_data(data, expr->value, dtype->byteorder, len);
+ left = constant_expr_alloc(&internal_location, dtype,
+ dtype->byteorder,
+ (len / 2) * BITS_PER_BYTE, &data[0]);
+ right = constant_expr_alloc(&internal_location, dtype,
+ dtype->byteorder,
+ (len / 2) * BITS_PER_BYTE, &data[len / 2]);
+ range = range_expr_alloc(&expr->location, left, right);
+ expr_free(expr);
+
+ return range_expr_to_prefix(range);
+}
+
static struct expr *netlink_parse_concat_elem(const struct datatype *dtype,
struct expr *data)
{
@@ -1005,6 +1127,12 @@ key_end:
NFT_REG_VERDICT : NFT_REG_1);
datatype_set(data, set->data->dtype);
data->byteorder = set->data->byteorder;
+
+ if (set->data->flags & EXPR_F_INTERVAL)
+ data = netlink_parse_interval_elem(set->data->dtype, data);
+ else if (set->data->dtype->subtypes)
+ data = netlink_parse_concat_elem(set->data->dtype, data);
+
if (data->byteorder == BYTEORDER_HOST_ENDIAN)
mpz_switch_byteorder(data->value, data->len / BITS_PER_BYTE);
@@ -1108,8 +1236,10 @@ int netlink_get_setelem(struct netlink_ctx *ctx, const struct handle *h,
netlink_dump_set(nls, ctx);
nls_out = mnl_nft_setelem_get_one(ctx, nls);
- if (!nls_out)
+ if (!nls_out) {
+ nftnl_set_free(nls);
return -1;
+ }
ctx->set = set;
set->init = set_expr_alloc(loc, set);
@@ -1321,8 +1451,10 @@ netlink_delinearize_flowtable(struct netlink_ctx *ctx,
sizeof(int) *
BITS_PER_BYTE,
&priority);
- flowtable->hooknum =
+ flowtable->hook.num =
nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_HOOKNUM);
+ flowtable->flags =
+ nftnl_flowtable_get_u32(nlo, NFTNL_FLOWTABLE_FLAGS);
return flowtable;
}
@@ -1428,38 +1560,50 @@ static void trace_print_policy(const struct nftnl_trace *nlt,
expr_free(expr);
}
-static void trace_print_rule(const struct nftnl_trace *nlt,
- struct output_ctx *octx, struct nft_cache *cache)
+static struct rule *trace_lookup_rule(const struct nftnl_trace *nlt,
+ uint64_t rule_handle,
+ struct nft_cache *cache)
{
- const struct table *table;
- uint64_t rule_handle;
struct chain *chain;
- struct rule *rule;
+ struct table *table;
struct handle h;
h.family = nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY);
- h.table.name = nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE);
- h.chain.name = nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN);
+ h.table.name = nftnl_trace_get_str(nlt, NFTNL_TRACE_TABLE);
+ h.chain.name = nftnl_trace_get_str(nlt, NFTNL_TRACE_CHAIN);
if (!h.table.name)
- return;
+ return NULL;
table = table_lookup(&h, cache);
if (!table)
- return;
+ return NULL;
chain = chain_lookup(table, &h);
if (!chain)
- return;
+ return NULL;
+
+ return rule_lookup(chain, rule_handle);
+}
+
+static void trace_print_rule(const struct nftnl_trace *nlt,
+ struct output_ctx *octx, struct nft_cache *cache)
+{
+ uint64_t rule_handle;
+ struct rule *rule;
rule_handle = nftnl_trace_get_u64(nlt, NFTNL_TRACE_RULE_HANDLE);
- rule = rule_lookup(chain, rule_handle);
- if (!rule)
- return;
+ rule = trace_lookup_rule(nlt, rule_handle, cache);
trace_print_hdr(nlt, octx);
- nft_print(octx, "rule ");
- rule_print(rule, octx);
+
+ if (rule) {
+ nft_print(octx, "rule ");
+ rule_print(rule, octx);
+ } else {
+ nft_print(octx, "unknown rule handle %" PRIu64, rule_handle);
+ }
+
nft_print(octx, " (");
trace_print_verdict(nlt, octx);
nft_print(octx, ")\n");
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 7d9c7646..7f7ad262 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -15,6 +15,7 @@
#include <limits.h>
#include <linux/netfilter/nf_tables.h>
#include <arpa/inet.h>
+#include <linux/netfilter/nf_nat.h>
#include <linux/netfilter.h>
#include <net/ethernet.h>
#include <netlink.h>
@@ -440,6 +441,7 @@ static struct expr *netlink_parse_bitwise_shift(struct netlink_parse_ctx *ctx,
nld.value = nftnl_expr_get(nle, NFTNL_EXPR_BITWISE_DATA, &nld.len);
right = netlink_alloc_value(loc, &nld);
+ right->byteorder = BYTEORDER_HOST_ENDIAN;
expr = binop_expr_alloc(loc, op, left, right);
expr->len = left->len;
@@ -561,8 +563,7 @@ static void netlink_parse_payload_stmt(struct netlink_parse_ctx *ctx,
payload_init_raw(expr, base, offset, len);
stmt = payload_stmt_alloc(loc, expr, val);
-
- list_add_tail(&stmt->list, &ctx->rule->stmts);
+ rule_stmt_append(ctx->rule, stmt);
}
static void netlink_parse_payload(struct netlink_parse_ctx *ctx,
@@ -613,7 +614,7 @@ static void netlink_parse_exthdr(struct netlink_parse_ctx *ctx,
expr_set_type(val, expr->dtype, expr->byteorder);
stmt = exthdr_stmt_alloc(loc, expr, val);
- list_add_tail(&stmt->list, &ctx->rule->stmts);
+ rule_stmt_append(ctx->rule, stmt);
}
}
@@ -978,6 +979,67 @@ static void netlink_parse_reject(struct netlink_parse_ctx *ctx,
ctx->stmt = stmt;
}
+static bool is_nat_addr_map(const struct expr *addr, uint8_t family)
+{
+ const struct expr *mappings, *data;
+ const struct set *set;
+
+ if (!addr ||
+ expr_ops(addr)->type != EXPR_MAP)
+ return false;
+
+ mappings = addr->right;
+ if (expr_ops(mappings)->type != EXPR_SET_REF)
+ return false;
+
+ set = mappings->set;
+ data = set->data;
+
+ if (!(data->flags & EXPR_F_INTERVAL))
+ return false;
+
+ /* if we're dealing with an address:address map,
+ * the length will be bit_sizeof(addr) + 32 (one register).
+ */
+ switch (family) {
+ case NFPROTO_IPV4:
+ return data->len == 32 + 32;
+ case NFPROTO_IPV6:
+ return data->len == 128 + 128;
+ }
+
+ return false;
+}
+
+static bool is_nat_proto_map(const struct expr *addr, uint8_t family)
+{
+ const struct expr *mappings, *data;
+ const struct set *set;
+
+ if (!addr ||
+ expr_ops(addr)->type != EXPR_MAP)
+ return false;
+
+ mappings = addr->right;
+ if (expr_ops(mappings)->type != EXPR_SET_REF)
+ return false;
+
+ set = mappings->set;
+ data = set->data;
+
+ /* if we're dealing with an address:inet_service map,
+ * the length will be bit_sizeof(addr) + 32 (one register).
+ */
+ switch (family) {
+ case NFPROTO_IPV4:
+ return data->len == 32 + 32;
+ case NFPROTO_IPV6:
+ return data->len == 128 + 32;
+ }
+
+ return false;
+}
+
static void netlink_parse_nat(struct netlink_parse_ctx *ctx,
const struct location *loc,
const struct nftnl_expr *nle)
@@ -998,6 +1060,10 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx,
if (nftnl_expr_is_set(nle, NFTNL_EXPR_NAT_FLAGS))
stmt->nat.flags = nftnl_expr_get_u32(nle, NFTNL_EXPR_NAT_FLAGS);
+ if (stmt->nat.flags & NF_NAT_RANGE_NETMAP)
+ stmt->nat.type_flags |= STMT_NAT_F_PREFIX;
+
+ addr = NULL;
reg1 = netlink_parse_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MIN);
if (reg1) {
addr = netlink_get_register(ctx, loc, reg1);
@@ -1015,6 +1081,13 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx,
stmt->nat.addr = addr;
}
+ if (is_nat_addr_map(addr, family)) {
+ stmt->nat.family = family;
+ stmt->nat.type_flags |= STMT_NAT_F_INTERVAL;
+ ctx->stmt = stmt;
+ return;
+ }
+
reg2 = netlink_parse_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MAX);
if (reg2 && reg2 != reg1) {
addr = netlink_get_register(ctx, loc, reg2);
@@ -1029,11 +1102,20 @@ static void netlink_parse_nat(struct netlink_parse_ctx *ctx,
else
expr_set_type(addr, &ip6addr_type,
BYTEORDER_BIG_ENDIAN);
- if (stmt->nat.addr != NULL)
+ if (stmt->nat.addr != NULL) {
addr = range_expr_alloc(loc, stmt->nat.addr, addr);
+ addr = range_expr_to_prefix(addr);
+ }
stmt->nat.addr = addr;
}
+ if (is_nat_proto_map(addr, family)) {
+ stmt->nat.family = family;
+ stmt->nat.type_flags |= STMT_NAT_F_CONCAT;
+ ctx->stmt = stmt;
+ return;
+ }
+
reg1 = netlink_parse_register(nle, NFTNL_EXPR_NAT_REG_PROTO_MIN);
if (reg1) {
proto = netlink_get_register(ctx, loc, reg1);
@@ -1424,6 +1506,7 @@ static void netlink_parse_dynset(struct netlink_parse_ctx *ctx,
}
if (expr_data != NULL) {
+ expr_set_type(expr_data, set->data->dtype, set->data->byteorder);
stmt = map_stmt_alloc(loc);
stmt->map.set = set_ref_expr_alloc(loc, set);
stmt->map.key = expr;
@@ -1588,7 +1671,7 @@ static int netlink_parse_rule_expr(struct nftnl_expr *nle, void *arg)
if (err < 0)
return err;
if (ctx->stmt != NULL) {
- list_add_tail(&ctx->stmt->list, &ctx->rule->stmts);
+ rule_stmt_append(ctx->rule, ctx->stmt);
ctx->stmt = NULL;
}
return 0;
@@ -2214,6 +2297,8 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp)
case EXPR_RANGE:
expr_postprocess(ctx, &expr->left);
expr_postprocess(ctx, &expr->right);
+ case EXPR_PREFIX:
+ expr_postprocess(ctx, &expr->prefix);
break;
case EXPR_SET_ELEM:
expr_postprocess(ctx, &expr->key);
@@ -2519,6 +2604,7 @@ static void stmt_payload_binop_postprocess(struct rule_pp_ctx *ctx)
mpz_init_bitmask(bitmask, payload->len);
mpz_xor(bitmask, bitmask, value->value);
mpz_set(value->value, bitmask);
+ mpz_clear(bitmask);
break;
case OP_OR: /* IIb */
break;
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index b542aa3b..08f7f89f 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -822,9 +822,7 @@ static void netlink_gen_objref_stmt(struct netlink_linearize_ctx *ctx,
nftnl_rule_add_expr(ctx->nlr, nle);
}
-static struct nftnl_expr *
-netlink_gen_connlimit_stmt(struct netlink_linearize_ctx *ctx,
- const struct stmt *stmt)
+static struct nftnl_expr *netlink_gen_connlimit_stmt(const struct stmt *stmt)
{
struct nftnl_expr *nle;
@@ -837,9 +835,7 @@ netlink_gen_connlimit_stmt(struct netlink_linearize_ctx *ctx,
return nle;
}
-static struct nftnl_expr *
-netlink_gen_counter_stmt(struct netlink_linearize_ctx *ctx,
- const struct stmt *stmt)
+static struct nftnl_expr *netlink_gen_counter_stmt(const struct stmt *stmt)
{
struct nftnl_expr *nle;
@@ -856,9 +852,7 @@ netlink_gen_counter_stmt(struct netlink_linearize_ctx *ctx,
return nle;
}
-static struct nftnl_expr *
-netlink_gen_limit_stmt(struct netlink_linearize_ctx *ctx,
- const struct stmt *stmt)
+static struct nftnl_expr *netlink_gen_limit_stmt(const struct stmt *stmt)
{
struct nftnl_expr *nle;
@@ -874,9 +868,7 @@ netlink_gen_limit_stmt(struct netlink_linearize_ctx *ctx,
return nle;
}
-static struct nftnl_expr *
-netlink_gen_quota_stmt(struct netlink_linearize_ctx *ctx,
- const struct stmt *stmt)
+static struct nftnl_expr *netlink_gen_quota_stmt(const struct stmt *stmt)
{
struct nftnl_expr *nle;
@@ -888,19 +880,17 @@ netlink_gen_quota_stmt(struct netlink_linearize_ctx *ctx,
return nle;
}
-static struct nftnl_expr *
-netlink_gen_stmt_stateful(struct netlink_linearize_ctx *ctx,
- const struct stmt *stmt)
+struct nftnl_expr *netlink_gen_stmt_stateful(const struct stmt *stmt)
{
switch (stmt->ops->type) {
case STMT_CONNLIMIT:
- return netlink_gen_connlimit_stmt(ctx, stmt);
+ return netlink_gen_connlimit_stmt(stmt);
case STMT_COUNTER:
- return netlink_gen_counter_stmt(ctx, stmt);
+ return netlink_gen_counter_stmt(stmt);
case STMT_LIMIT:
- return netlink_gen_limit_stmt(ctx, stmt);
+ return netlink_gen_limit_stmt(stmt);
case STMT_QUOTA:
- return netlink_gen_quota_stmt(ctx, stmt);
+ return netlink_gen_quota_stmt(stmt);
default:
BUG("unknown stateful statement type %s\n", stmt->ops->name);
}
@@ -1052,14 +1042,25 @@ static void netlink_gen_reject_stmt(struct netlink_linearize_ctx *ctx,
nftnl_rule_add_expr(ctx->nlr, nle);
}
+static unsigned int nat_addrlen(uint8_t family)
+{
+ switch (family) {
+ case NFPROTO_IPV4: return 32;
+ case NFPROTO_IPV6: return 128;
+ }
+
+ BUG("invalid nat family %u\n", family);
+ return 0;
+}
+
static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx,
const struct stmt *stmt)
{
struct nftnl_expr *nle;
enum nft_registers amin_reg, amax_reg;
enum nft_registers pmin_reg, pmax_reg;
+ uint8_t family = 0;
int registers = 0;
- int family;
int nftnl_flag_attr;
int nftnl_reg_pmin, nftnl_reg_pmax;
@@ -1116,8 +1117,34 @@ static void netlink_gen_nat_stmt(struct netlink_linearize_ctx *ctx,
netlink_gen_expr(ctx, stmt->nat.addr, amin_reg);
netlink_put_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MIN,
amin_reg);
+ if (stmt->nat.addr->etype == EXPR_MAP &&
+ stmt->nat.addr->mappings->set->data->flags & EXPR_F_INTERVAL) {
+ amax_reg = get_register(ctx, NULL);
+ registers++;
+ amin_reg += netlink_register_space(nat_addrlen(family));
+ netlink_put_register(nle, NFTNL_EXPR_NAT_REG_ADDR_MAX,
+ amin_reg);
+ }
}
+ if (stmt->nat.type_flags & STMT_NAT_F_CONCAT) {
+ /* nat_stmt evaluation step doesn't allow
+ * STMT_NAT_F_CONCAT && stmt->nat.proto.
+ */
+ assert(stmt->nat.proto == NULL);
+
+ pmin_reg = amin_reg;
+
+ /* if STMT_NAT_F_CONCAT is set, the mapped type is a
+ * concatenation of 'addr . inet_service'.
+ * The map lookup will then return the
+ * concatenated value, so we need to skip
+ * the address and use the register that
+ * will hold the inet_service part.
+ */
+ pmin_reg += netlink_register_space(nat_addrlen(family));
+ netlink_put_register(nle, nftnl_reg_pmin, pmin_reg);
+ }
}
if (stmt->nat.proto) {
@@ -1349,7 +1376,7 @@ static void netlink_gen_set_stmt(struct netlink_linearize_ctx *ctx,
if (stmt->set.stmt)
nftnl_expr_set(nle, NFTNL_EXPR_DYNSET_EXPR,
- netlink_gen_stmt_stateful(ctx, stmt->set.stmt), 0);
+ netlink_gen_stmt_stateful(stmt->set.stmt), 0);
}
static void netlink_gen_map_stmt(struct netlink_linearize_ctx *ctx,
@@ -1379,7 +1406,7 @@ static void netlink_gen_map_stmt(struct netlink_linearize_ctx *ctx,
if (stmt->map.stmt)
nftnl_expr_set(nle, NFTNL_EXPR_DYNSET_EXPR,
- netlink_gen_stmt_stateful(ctx, stmt->map.stmt), 0);
+ netlink_gen_stmt_stateful(stmt->map.stmt), 0);
nftnl_rule_add_expr(ctx->nlr, nle);
}
@@ -1411,7 +1438,7 @@ static void netlink_gen_meter_stmt(struct netlink_linearize_ctx *ctx,
nftnl_expr_set_str(nle, NFTNL_EXPR_DYNSET_SET_NAME, set->handle.set.name);
nftnl_expr_set_u32(nle, NFTNL_EXPR_DYNSET_SET_ID, set->handle.set_id);
nftnl_expr_set(nle, NFTNL_EXPR_DYNSET_EXPR,
- netlink_gen_stmt_stateful(ctx, stmt->meter.stmt), 0);
+ netlink_gen_stmt_stateful(stmt->meter.stmt), 0);
nftnl_rule_add_expr(ctx->nlr, nle);
}
@@ -1457,7 +1484,7 @@ static void netlink_gen_stmt(struct netlink_linearize_ctx *ctx,
case STMT_COUNTER:
case STMT_LIMIT:
case STMT_QUOTA:
- nle = netlink_gen_stmt_stateful(ctx, stmt);
+ nle = netlink_gen_stmt_stateful(stmt);
nftnl_rule_add_expr(ctx->nlr, nle);
break;
case STMT_NOTRACK:
diff --git a/src/parser_bison.y b/src/parser_bison.y
index f5d7026a..461d9bf2 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -373,6 +373,7 @@ int nft_lex(void *, void *, void *);
%token FLAGS "flags"
%token CPI "cpi"
+%token PORT "port"
%token UDP "udp"
%token SPORT "sport"
%token DPORT "dport"
@@ -979,7 +980,7 @@ add_cmd : TABLE table_spec
}
| ELEMENT set_spec set_block_expr
{
- $$ = cmd_alloc(CMD_ADD, CMD_OBJ_SETELEM, &$2, &@$, $3);
+ $$ = cmd_alloc(CMD_ADD, CMD_OBJ_ELEMENTS, &$2, &@$, $3);
}
| FLOWTABLE flowtable_spec flowtable_block_alloc
'{' flowtable_block '}'
@@ -1076,7 +1077,7 @@ create_cmd : TABLE table_spec
}
| ELEMENT set_spec set_block_expr
{
- $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_SETELEM, &$2, &@$, $3);
+ $$ = cmd_alloc(CMD_CREATE, CMD_OBJ_ELEMENTS, &$2, &@$, $3);
}
| FLOWTABLE flowtable_spec flowtable_block_alloc
'{' flowtable_block '}'
@@ -1168,7 +1169,7 @@ delete_cmd : TABLE table_spec
}
| ELEMENT set_spec set_block_expr
{
- $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_SETELEM, &$2, &@$, $3);
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_ELEMENTS, &$2, &@$, $3);
}
| FLOWTABLE flowtable_spec
{
@@ -1178,6 +1179,13 @@ delete_cmd : TABLE table_spec
{
$$ = cmd_alloc(CMD_DELETE, CMD_OBJ_FLOWTABLE, &$2, &@$, NULL);
}
+ | FLOWTABLE flowtable_spec flowtable_block_alloc
+ '{' flowtable_block '}'
+ {
+ $5->location = @5;
+ handle_merge(&$3->handle, &$2);
+ $$ = cmd_alloc(CMD_DELETE, CMD_OBJ_FLOWTABLE, &$2, &@$, $5);
+ }
| COUNTER obj_spec
{
$$ = cmd_alloc(CMD_DELETE, CMD_OBJ_COUNTER, &$2, &@$, NULL);
@@ -1226,7 +1234,7 @@ delete_cmd : TABLE table_spec
get_cmd : ELEMENT set_spec set_block_expr
{
- $$ = cmd_alloc(CMD_GET, CMD_OBJ_SETELEM, &$2, &@$, $3);
+ $$ = cmd_alloc(CMD_GET, CMD_OBJ_ELEMENTS, &$2, &@$, $3);
}
;
@@ -1666,6 +1674,7 @@ chain_block : /* empty */ { $$ = $<chain>-1; }
| chain_block stmt_separator
| chain_block hook_spec stmt_separator
| chain_block policy_spec stmt_separator
+ | chain_block flags_spec stmt_separator
| chain_block rule stmt_separator
{
list_add_tail(&$2->list, &$1->rules);
@@ -1731,6 +1740,11 @@ set_block : /* empty */ { $$ = $<set>-1; }
$1->gc_int = $3;
$$ = $1;
}
+ | set_block COUNTER stmt_separator
+ {
+ $1->stmt = counter_stmt_alloc(&@$);
+ $$ = $1;
+ }
| set_block ELEMENTS '=' set_block_expr
{
$1->init = $4;
@@ -1785,6 +1799,17 @@ map_block : /* empty */ { $$ = $<set>-1; }
$1->flags |= NFT_SET_MAP;
$$ = $1;
}
+ | map_block TYPE
+ data_type_expr COLON INTERVAL data_type_expr
+ stmt_separator
+ {
+ $1->key = $3;
+ $1->data = $6;
+ $1->data->flags |= EXPR_F_INTERVAL;
+
+ $1->flags |= NFT_SET_MAP;
+ $$ = $1;
+ }
| map_block TYPEOF
typeof_expr COLON typeof_expr
stmt_separator
@@ -1796,6 +1821,18 @@ map_block : /* empty */ { $$ = $<set>-1; }
$1->flags |= NFT_SET_MAP;
$$ = $1;
}
+ | map_block TYPEOF
+ typeof_expr COLON INTERVAL typeof_expr
+ stmt_separator
+ {
+ $1->key = $3;
+ datatype_set($1->key, $3->dtype);
+ $1->data = $6;
+ $1->data->flags |= EXPR_F_INTERVAL;
+
+ $1->flags |= NFT_SET_MAP;
+ $$ = $1;
+ }
| map_block TYPE
data_type_expr COLON COUNTER
stmt_separator
@@ -1870,9 +1907,10 @@ flowtable_block : /* empty */ { $$ = $<flowtable>-1; }
| flowtable_block stmt_separator
| flowtable_block HOOK STRING prio_spec stmt_separator
{
- $$->hookstr = chain_hookname_lookup($3);
- if ($$->hookstr == NULL) {
- erec_queue(error(&@3, "unknown chain hook %s", $3),
+ $$->hook.loc = @3;
+ $$->hook.name = chain_hookname_lookup($3);
+ if ($$->hook.name == NULL) {
+ erec_queue(error(&@3, "unknown chain hook"),
state->msgs);
xfree($3);
YYERROR;
@@ -1885,6 +1923,10 @@ flowtable_block : /* empty */ { $$ = $<flowtable>-1; }
{
$$->dev_expr = $4;
}
+ | flowtable_block COUNTER
+ {
+ $$->flags |= NFT_FLOWTABLE_COUNTER;
+ }
;
flowtable_expr : '{' flowtable_list_expr '}'
@@ -1909,9 +1951,9 @@ flowtable_list_expr : flowtable_expr_member
flowtable_expr_member : STRING
{
- $$ = symbol_expr_alloc(&@$, SYMBOL_VALUE,
- current_scope(state),
- $1);
+ $$ = constant_expr_alloc(&@$, &string_type,
+ BYTEORDER_HOST_ENDIAN,
+ strlen($1) * BITS_PER_BYTE, $1);
xfree($1);
}
;
@@ -1980,7 +2022,11 @@ ct_helper_block : /* empty */ { $$ = $<obj>-1; }
}
;
-ct_timeout_block : /*empty */ { $$ = $<obj>-1; }
+ct_timeout_block : /*empty */
+ {
+ $$ = $<obj>-1;
+ init_list_head(&$$->ct_timeout.timeout_list);
+ }
| ct_timeout_block common_block
| ct_timeout_block stmt_separator
| ct_timeout_block ct_timeout_config
@@ -2037,7 +2083,7 @@ hook_spec : TYPE STRING HOOK STRING dev_spec prio_spec
const char *chain_type = chain_type_name_lookup($2);
if (chain_type == NULL) {
- erec_queue(error(&@2, "unknown chain type %s", $2),
+ erec_queue(error(&@2, "unknown chain type"),
state->msgs);
xfree($2);
YYERROR;
@@ -2045,9 +2091,11 @@ hook_spec : TYPE STRING HOOK STRING dev_spec prio_spec
$<chain>0->type = xstrdup(chain_type);
xfree($2);
- $<chain>0->hookstr = chain_hookname_lookup($4);
- if ($<chain>0->hookstr == NULL) {
- erec_queue(error(&@4, "unknown chain hook %s", $4),
+ $<chain>0->loc = @$;
+ $<chain>0->hook.loc = @4;
+ $<chain>0->hook.name = chain_hookname_lookup($4);
+ if ($<chain>0->hook.name == NULL) {
+ erec_queue(error(&@4, "unknown chain hook"),
state->msgs);
xfree($4);
YYERROR;
@@ -2126,6 +2174,7 @@ extended_prio_spec : int_num
BYTEORDER_HOST_ENDIAN,
strlen(str) * BITS_PER_BYTE,
str);
+ xfree($1);
$$ = spec;
}
;
@@ -2141,6 +2190,7 @@ dev_spec : DEVICE string
expr = constant_expr_alloc(&@$, &string_type,
BYTEORDER_HOST_ENDIAN,
strlen($2) * BITS_PER_BYTE, $2);
+ xfree($2);
$$ = compound_expr_alloc(&@$, EXPR_LIST);
compound_expr_add($$, expr);
@@ -2152,6 +2202,12 @@ dev_spec : DEVICE string
| /* empty */ { $$ = NULL; }
;
+flags_spec : FLAGS OFFLOAD
+ {
+ $<chain>0->flags |= CHAIN_F_HW_OFFLOAD;
+ }
+ ;
+
policy_spec : POLICY policy_expr
{
if ($<chain>0->policy) {
@@ -2160,7 +2216,8 @@ policy_spec : POLICY policy_expr
expr_free($2);
YYERROR;
}
- $<chain>0->policy = $2;
+ $<chain>0->policy = $2;
+ $<chain>0->policy->location = @$;
}
;
@@ -2231,7 +2288,7 @@ tableid_spec : family_spec HANDLE NUM
memset(&$$, 0, sizeof($$));
$$.family = $1;
$$.handle.id = $3;
- $$.handle.location = @$;
+ $$.handle.location = @3;
}
;
@@ -2246,7 +2303,7 @@ chain_spec : table_spec identifier
chainid_spec : table_spec HANDLE NUM
{
$$ = $1;
- $$.handle.location = @$;
+ $$.handle.location = @3;
$$.handle.id = $3;
}
;
@@ -2270,7 +2327,7 @@ set_spec : table_spec identifier
setid_spec : table_spec HANDLE NUM
{
$$ = $1;
- $$.handle.location = @$;
+ $$.handle.location = @3;
$$.handle.id = $3;
}
;
@@ -2294,7 +2351,7 @@ flowtable_spec : table_spec identifier
flowtableid_spec : table_spec HANDLE NUM
{
$$ = $1;
- $$.handle.location = @$;
+ $$.handle.location = @3;
$$.handle.id = $3;
}
;
@@ -2318,7 +2375,7 @@ obj_spec : table_spec identifier
objid_spec : table_spec HANDLE NUM
{
$$ = $1;
- $$.handle.location = @$;
+ $$.handle.location = @3;
$$.handle.id = $3;
}
;
@@ -2334,7 +2391,7 @@ obj_identifier : identifier
handle_spec : HANDLE NUM
{
memset(&$$, 0, sizeof($$));
- $$.handle.location = @$;
+ $$.handle.location = @2;
$$.handle.id = $2;
}
;
@@ -3012,7 +3069,7 @@ shift_stmt_expr : primary_stmt_expr
{
$$ = binop_expr_alloc(&@$, OP_LSHIFT, $1, $3);
}
- | shift_stmt_expr RSHIFT primary_rhs_expr
+ | shift_stmt_expr RSHIFT primary_stmt_expr
{
$$ = binop_expr_alloc(&@$, OP_RSHIFT, $1, $3);
}
@@ -3139,6 +3196,40 @@ nat_stmt_args : stmt_expr
{
$<stmt>0->nat.flags = $2;
}
+ | nf_key_proto ADDR DOT PORT TO stmt_expr
+ {
+ $<stmt>0->nat.family = $1;
+ $<stmt>0->nat.addr = $6;
+ $<stmt>0->nat.type_flags = STMT_NAT_F_CONCAT;
+ }
+ | nf_key_proto INTERVAL TO stmt_expr
+ {
+ $<stmt>0->nat.family = $1;
+ $<stmt>0->nat.addr = $4;
+ $<stmt>0->nat.type_flags = STMT_NAT_F_INTERVAL;
+ }
+ | INTERVAL TO stmt_expr
+ {
+ $<stmt>0->nat.addr = $3;
+ $<stmt>0->nat.type_flags = STMT_NAT_F_INTERVAL;
+ }
+ | nf_key_proto PREFIX TO stmt_expr
+ {
+ $<stmt>0->nat.family = $1;
+ $<stmt>0->nat.addr = $4;
+ $<stmt>0->nat.type_flags =
+ STMT_NAT_F_PREFIX |
+ STMT_NAT_F_INTERVAL;
+ $<stmt>0->nat.flags |= NF_NAT_RANGE_NETMAP;
+ }
+ | PREFIX TO stmt_expr
+ {
+ $<stmt>0->nat.addr = $3;
+ $<stmt>0->nat.type_flags =
+ STMT_NAT_F_PREFIX |
+ STMT_NAT_F_INTERVAL;
+ $<stmt>0->nat.flags |= NF_NAT_RANGE_NETMAP;
+ }
;
masq_stmt : masq_stmt_alloc masq_stmt_args
@@ -3655,7 +3746,7 @@ meter_key_expr_alloc : concat_expr
;
set_elem_expr : set_elem_expr_alloc
- | set_elem_expr_alloc set_elem_options
+ | set_elem_expr_alloc set_elem_expr_options
;
set_elem_expr_alloc : set_lhs_expr
@@ -3685,6 +3776,40 @@ set_elem_option : TIMEOUT time_spec
}
;
+set_elem_expr_options : set_elem_expr_option
+ {
+ $<expr>$ = $<expr>0;
+ }
+ | set_elem_expr_options set_elem_expr_option
+ ;
+
+set_elem_expr_option : TIMEOUT time_spec
+ {
+ $<expr>0->timeout = $2;
+ }
+ | EXPIRES time_spec
+ {
+ $<expr>0->expiration = $2;
+ }
+ | COUNTER
+ {
+ $<expr>0->stmt = counter_stmt_alloc(&@$);
+ }
+ | COUNTER PACKETS NUM BYTES NUM
+ {
+ struct stmt *stmt;
+
+ stmt = counter_stmt_alloc(&@$);
+ stmt->counter.packets = $3;
+ stmt->counter.bytes = $5;
+ $<expr>0->stmt = stmt;
+ }
+ | comment_spec
+ {
+ $<expr>0->comment = $1;
+ }
+ ;
+
set_lhs_expr : concat_rhs_expr
| wildcard_expr
;
@@ -3785,6 +3910,7 @@ ct_helper_config : TYPE QUOTED_STRING PROTOCOL ct_l4protoname stmt_separator
erec_queue(error(&@2, "invalid name '%s', max length is %u\n", $2, (int)sizeof(ct->name)), state->msgs);
YYERROR;
}
+ xfree($2);
ct->l4proto = $4;
}
@@ -3834,8 +3960,8 @@ ct_timeout_config : PROTOCOL ct_l4protoname stmt_separator
struct ct_timeout *ct;
ct = &$<obj>0->ct_timeout;
- init_list_head(&ct->timeout_list);
list_splice_tail($4, &ct->timeout_list);
+ xfree($4);
}
| L3PROTOCOL family_spec_explicit stmt_separator
{
@@ -4434,6 +4560,7 @@ ct_key : L3PROTOCOL { $$ = NFT_CT_L3PROTOCOL; }
| LABEL { $$ = NFT_CT_LABELS; }
| EVENT { $$ = NFT_CT_EVENTMASK; }
| SECMARK { $$ = NFT_CT_SECMARK; }
+ | ID { $$ = NFT_CT_ID; }
| ct_key_dir_optional
;
diff --git a/src/parser_json.c b/src/parser_json.c
index 85082cce..9fdef691 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -40,6 +40,7 @@
#define CTX_F_MANGLE (1 << 5)
#define CTX_F_SES (1 << 6) /* set_elem_expr_stmt */
#define CTX_F_MAP (1 << 7) /* LHS of map_expr */
+#define CTX_F_CONCAT (1 << 8) /* inside concat_expr */
struct json_ctx {
struct input_descriptor indesc;
@@ -99,6 +100,7 @@ static struct expr *json_parse_primary_expr(struct json_ctx *ctx, json_t *root);
static struct expr *json_parse_set_rhs_expr(struct json_ctx *ctx, json_t *root);
static struct expr *json_parse_set_elem_expr_stmt(struct json_ctx *ctx, json_t *root);
static struct expr *json_parse_map_lhs_expr(struct json_ctx *ctx, json_t *root);
+static struct expr *json_parse_concat_elem_expr(struct json_ctx *ctx, json_t *root);
static struct stmt *json_parse_stmt(struct json_ctx *ctx, json_t *root);
/* parsing helpers */
@@ -1058,7 +1060,7 @@ static struct expr *json_parse_concat_expr(struct json_ctx *ctx,
}
json_array_foreach(root, index, value) {
- tmp = json_parse_primary_expr(ctx, value);
+ tmp = json_parse_concat_elem_expr(ctx, value);
if (!tmp) {
json_error(ctx, "Parsing expr at index %zd failed.", index);
expr_free(expr);
@@ -1354,28 +1356,28 @@ static struct expr *json_parse_expr(struct json_ctx *ctx, json_t *root)
{ "set", json_parse_set_expr, CTX_F_RHS | CTX_F_STMT }, /* allow this as stmt expr because that allows set references */
{ "map", json_parse_map_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS },
/* below three are multiton_rhs_expr */
- { "prefix", json_parse_prefix_expr, CTX_F_RHS | CTX_F_STMT },
- { "range", json_parse_range_expr, CTX_F_RHS | CTX_F_STMT },
- { "payload", json_parse_payload_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP },
- { "exthdr", json_parse_exthdr_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { "tcp option", json_parse_tcp_option_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES },
- { "ip option", json_parse_ip_option_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES },
- { "meta", json_parse_meta_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP },
- { "osf", json_parse_osf_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_MAP },
- { "ipsec", json_parse_xfrm_expr, CTX_F_PRIMARY | CTX_F_MAP },
- { "socket", json_parse_socket_expr, CTX_F_PRIMARY },
- { "rt", json_parse_rt_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { "ct", json_parse_ct_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP },
- { "numgen", json_parse_numgen_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
+ { "prefix", json_parse_prefix_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_CONCAT },
+ { "range", json_parse_range_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_CONCAT },
+ { "payload", json_parse_payload_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "exthdr", json_parse_exthdr_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "tcp option", json_parse_tcp_option_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_CONCAT },
+ { "ip option", json_parse_ip_option_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_CONCAT },
+ { "meta", json_parse_meta_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "osf", json_parse_osf_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_MAP | CTX_F_CONCAT },
+ { "ipsec", json_parse_xfrm_expr, CTX_F_PRIMARY | CTX_F_MAP | CTX_F_CONCAT },
+ { "socket", json_parse_socket_expr, CTX_F_PRIMARY | CTX_F_CONCAT },
+ { "rt", json_parse_rt_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "ct", json_parse_ct_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_MANGLE | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "numgen", json_parse_numgen_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
/* below two are hash expr */
- { "jhash", json_parse_hash_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { "symhash", json_parse_hash_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { "fib", json_parse_fib_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { "|", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { "^", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { "&", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { ">>", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
- { "<<", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP },
+ { "jhash", json_parse_hash_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "symhash", json_parse_hash_expr, CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "fib", json_parse_fib_expr, CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "|", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "^", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "&", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { ">>", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
+ { "<<", json_parse_binop_expr, CTX_F_RHS | CTX_F_STMT | CTX_F_PRIMARY | CTX_F_SET_RHS | CTX_F_SES | CTX_F_MAP | CTX_F_CONCAT },
{ "accept", json_parse_verdict_expr, CTX_F_RHS | CTX_F_SET_RHS },
{ "drop", json_parse_verdict_expr, CTX_F_RHS | CTX_F_SET_RHS },
{ "continue", json_parse_verdict_expr, CTX_F_RHS | CTX_F_SET_RHS },
@@ -1500,6 +1502,11 @@ static struct expr *json_parse_map_lhs_expr(struct json_ctx *ctx, json_t *root)
return json_parse_flagged_expr(ctx, CTX_F_MAP, root);
}
+static struct expr *json_parse_concat_elem_expr(struct json_ctx *ctx, json_t *root)
+{
+ return json_parse_flagged_expr(ctx, CTX_F_CONCAT, root);
+}
+
static struct expr *json_parse_dtype_expr(struct json_ctx *ctx, json_t *root)
{
if (json_is_string(root)) {
@@ -2621,8 +2628,8 @@ static struct cmd *json_parse_cmd_add_chain(struct json_ctx *ctx, json_t *root,
BYTEORDER_HOST_ENDIAN,
sizeof(int) * BITS_PER_BYTE,
&prio);
- chain->hookstr = chain_hookname_lookup(hookstr);
- if (!chain->hookstr) {
+ chain->hook.name = chain_hookname_lookup(hookstr);
+ if (!chain->hook.name) {
json_error(ctx, "Invalid chain hook '%s'.", hookstr);
chain_free(chain);
return NULL;
@@ -2724,8 +2731,7 @@ static struct cmd *json_parse_cmd_add_rule(struct json_ctx *ctx, json_t *root,
return NULL;
}
- rule->num_stmts++;
- list_add_tail(&stmt->list, &rule->stmts);
+ rule_stmt_append(rule, stmt);
}
if (op == CMD_ADD)
@@ -3010,7 +3016,7 @@ static struct cmd *json_parse_cmd_add_flowtable(struct json_ctx *ctx,
}
flowtable = flowtable_alloc(int_loc);
- flowtable->hookstr = hookstr;
+ flowtable->hook.name = hookstr;
flowtable->priority.expr =
constant_expr_alloc(int_loc, &integer_type,
BYTEORDER_HOST_ENDIAN,
@@ -3287,7 +3293,7 @@ static struct cmd *json_parse_cmd_add(struct json_ctx *ctx,
{ "rule", CMD_OBJ_RULE, json_parse_cmd_add_rule },
{ "set", CMD_OBJ_SET, json_parse_cmd_add_set },
{ "map", CMD_OBJ_SET, json_parse_cmd_add_set },
- { "element", CMD_OBJ_SETELEM, json_parse_cmd_add_element },
+ { "element", CMD_OBJ_ELEMENTS, json_parse_cmd_add_element },
{ "flowtable", CMD_OBJ_FLOWTABLE, json_parse_cmd_add_flowtable },
{ "counter", CMD_OBJ_COUNTER, json_parse_cmd_add_object },
{ "quota", CMD_OBJ_QUOTA, json_parse_cmd_add_object },
@@ -3397,8 +3403,7 @@ static struct cmd *json_parse_cmd_replace(struct json_ctx *ctx,
return NULL;
}
- rule->num_stmts++;
- list_add_tail(&stmt->list, &rule->stmts);
+ rule_stmt_append(rule, stmt);
}
if (op == CMD_REPLACE)
@@ -3842,12 +3847,15 @@ static uint64_t handle_from_nlmsg(const struct nlmsghdr *nlh)
}
int json_events_cb(const struct nlmsghdr *nlh, struct netlink_mon_handler *monh)
{
- json_t *tmp, *json = seqnum_to_json(nlh->nlmsg_seq);
uint64_t handle = handle_from_nlmsg(nlh);
+ json_t *tmp, *json;
void *iter;
- /* might be anonymous set, ignore message */
- if (!json || !handle)
+ if (!handle)
+ return MNL_CB_OK;
+
+ json = seqnum_to_json(nlh->nlmsg_seq);
+ if (!json)
return MNL_CB_OK;
tmp = json_object_get(json, "add");
diff --git a/src/rule.c b/src/rule.c
index 337a66bb..21a52157 100644
--- a/src/rule.c
+++ b/src/rule.c
@@ -355,6 +355,7 @@ void set_free(struct set *set)
if (set->init != NULL)
expr_free(set->init);
handle_free(&set->handle);
+ stmt_free(set->stmt);
expr_free(set->key);
expr_free(set->data);
xfree(set);
@@ -461,6 +462,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
@@ -544,6 +548,15 @@ static void set_print_declaration(const struct set *set,
}
nft_print(octx, "%s", opts->stmt_separator);
}
+
+ if (set->stmt) {
+ nft_print(octx, "%s%s", opts->tab, opts->tab);
+ octx->flags |= NFT_CTX_OUTPUT_STATELESS;
+ stmt_print(set->stmt, octx);
+ octx->flags &= ~NFT_CTX_OUTPUT_STATELESS;
+ nft_print(octx, "%s", opts->stmt_separator);
+ }
+
if (set->automerge)
nft_print(octx, "%s%sauto-merge%s", opts->tab, opts->tab,
opts->stmt_separator);
@@ -673,6 +686,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));
@@ -1155,7 +1181,7 @@ static void chain_print_declaration(const struct chain *chain,
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));
+ 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 +1195,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,6 +1203,9 @@ 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");
}
}
@@ -1207,9 +1236,9 @@ void chain_print_plain(const struct chain *chain, struct output_ctx *octx)
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,
+ chain->type, chain->hook.name,
prio2str(octx, priobuf, sizeof(priobuf),
- chain->handle.family, chain->hooknum,
+ chain->handle.family, chain->hook.num,
chain->priority.expr),
chain_policy2str(policy));
}
@@ -1377,14 +1406,22 @@ struct cmd *cmd_alloc(enum cmd_ops op, enum cmd_obj obj,
return cmd;
}
+void cmd_add_loc(struct cmd *cmd, uint16_t offset, struct location *loc)
+{
+ assert(cmd->num_attrs < NFT_NLATTR_LOC_MAX);
+ cmd->attr[cmd->num_attrs].offset = offset;
+ cmd->attr[cmd->num_attrs].location = loc;
+ cmd->num_attrs++;
+}
+
void nft_cmd_expand(struct cmd *cmd)
{
struct list_head new_cmds;
+ struct set *set, *newset;
struct flowtable *ft;
struct table *table;
struct chain *chain;
struct rule *rule;
- struct set *set;
struct obj *obj;
struct cmd *new;
struct handle h;
@@ -1440,6 +1477,18 @@ void nft_cmd_expand(struct cmd *cmd)
}
list_splice(&new_cmds, &cmd->list);
break;
+ case CMD_OBJ_SET:
+ set = cmd->set;
+ memset(&h, 0, sizeof(h));
+ handle_merge(&h, &set->handle);
+ newset = set_clone(set);
+ newset->handle.set_id = set->handle.set_id;
+ newset->init = set->init;
+ set->init = NULL;
+ new = cmd_alloc(CMD_ADD, CMD_OBJ_SETELEMS, &h,
+ &set->location, newset);
+ list_add(&new->list, &cmd->list);
+ break;
default:
break;
}
@@ -1484,10 +1533,11 @@ 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);
break;
case CMD_OBJ_SET:
+ case CMD_OBJ_SETELEMS:
set_free(cmd->set);
break;
case CMD_OBJ_RULE:
@@ -1539,7 +1589,8 @@ static int __do_add_setelems(struct netlink_ctx *ctx, struct set *set,
if (mnl_nft_setelem_add(ctx, set, expr, flags) < 0)
return -1;
- if (set->init != NULL &&
+ if (!set_is_anonymous(set->flags) &&
+ set->init != NULL && set->init != expr &&
set->flags & NFT_SET_INTERVAL &&
set->desc.field_count <= 1) {
interval_map_decompose(expr);
@@ -1571,8 +1622,8 @@ static int do_add_setelems(struct netlink_ctx *ctx, struct cmd *cmd,
return __do_add_setelems(ctx, set, init, flags);
}
-static int do_add_set(struct netlink_ctx *ctx, const struct cmd *cmd,
- uint32_t flags)
+static int do_add_set(struct netlink_ctx *ctx, struct cmd *cmd,
+ uint32_t flags, bool add)
{
struct set *set = cmd->set;
@@ -1583,7 +1634,7 @@ static int do_add_set(struct netlink_ctx *ctx, const struct cmd *cmd,
&ctx->nft->output) < 0)
return -1;
}
- if (mnl_nft_set_add(ctx, cmd, flags) < 0)
+ if (add && mnl_nft_set_add(ctx, cmd, flags) < 0)
return -1;
if (set->init != NULL) {
return __do_add_setelems(ctx, set, set->init, flags);
@@ -1606,8 +1657,10 @@ static int do_command_add(struct netlink_ctx *ctx, struct cmd *cmd, bool excl)
case CMD_OBJ_RULE:
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:
+ return do_add_set(ctx, cmd, flags, true);
+ case CMD_OBJ_SETELEMS:
+ return do_add_set(ctx, cmd, flags, false);
+ case CMD_OBJ_ELEMENTS:
return do_add_setelems(ctx, cmd, flags);
case CMD_OBJ_COUNTER:
case CMD_OBJ_QUOTA:
@@ -1686,7 +1739,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);
@@ -2214,18 +2267,24 @@ 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_COUNTER)
+ nft_print(octx, "%s%scounter%s", opts->tab, opts->tab,
+ opts->stmt_separator);
}
static void do_flowtable_print(const struct flowtable *flowtable,
@@ -2546,7 +2605,7 @@ static int do_command_get(struct netlink_ctx *ctx, struct cmd *cmd)
table = table_lookup(&cmd->handle, &ctx->nft->cache);
switch (cmd->obj) {
- case CMD_OBJ_SETELEM:
+ case CMD_OBJ_ELEMENTS:
return do_get_setelems(ctx, cmd, table);
default:
BUG("invalid command object type %u\n", cmd->obj);
diff --git a/src/scanner.l b/src/scanner.l
index ed29833b..45699c85 100644
--- a/src/scanner.l
+++ b/src/scanner.l
@@ -471,6 +471,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr})
"udplite" { return UDPLITE; }
"sport" { return SPORT; }
"dport" { return DPORT; }
+"port" { return PORT; }
"tcp" { return TCP; }
"ackseq" { return ACKSEQ; }
@@ -678,7 +679,7 @@ static void scanner_push_indesc(struct parser_state *state,
static void scanner_pop_indesc(struct parser_state *state)
{
- if (!list_empty(&state->indesc_list)) {
+ if (!list_is_first(&state->indesc->list, &state->indesc_list)) {
state->indesc = list_entry(state->indesc->list.prev,
struct input_descriptor, list);
} else {
diff --git a/src/segtree.c b/src/segtree.c
index 8d79332d..266a2b4d 100644
--- a/src/segtree.c
+++ b/src/segtree.c
@@ -190,7 +190,8 @@ static bool segtree_debug(unsigned int debug_mask)
static int ei_insert(struct list_head *msgs, struct seg_tree *tree,
struct elementary_interval *new, bool merge)
{
- struct elementary_interval *lei, *rei;
+ struct elementary_interval *lei, *rei, *ei;
+ struct expr *new_expr, *expr;
mpz_t p;
mpz_init2(p, tree->keylen);
@@ -205,8 +206,10 @@ static int ei_insert(struct list_head *msgs, struct seg_tree *tree,
pr_gmp_debug("insert: [%Zx %Zx]\n", new->left, new->right);
if (lei != NULL && rei != NULL && lei == rei) {
- if (!merge)
+ if (!merge) {
+ ei = lei;
goto err;
+ }
/*
* The new interval is entirely contained in the same interval,
* split it into two parts:
@@ -228,8 +231,10 @@ static int ei_insert(struct list_head *msgs, struct seg_tree *tree,
ei_destroy(lei);
} else {
if (lei != NULL) {
- if (!merge)
+ if (!merge) {
+ ei = lei;
goto err;
+ }
/*
* Left endpoint is within lei, adjust it so we have:
*
@@ -248,8 +253,10 @@ static int ei_insert(struct list_head *msgs, struct seg_tree *tree,
}
}
if (rei != NULL) {
- if (!merge)
+ if (!merge) {
+ ei = rei;
goto err;
+ }
/*
* Right endpoint is within rei, adjust it so we have:
*
@@ -276,7 +283,15 @@ static int ei_insert(struct list_head *msgs, struct seg_tree *tree,
return 0;
err:
errno = EEXIST;
- return expr_binary_error(msgs, lei->expr, new->expr,
+ if (new->expr->etype == EXPR_MAPPING) {
+ new_expr = new->expr->left;
+ expr = ei->expr->left;
+ } else {
+ new_expr = new->expr;
+ expr = ei->expr;
+ }
+
+ return expr_binary_error(msgs, new_expr, expr,
"conflicting intervals specified");
}
@@ -679,67 +694,32 @@ static struct expr *get_set_interval_find(const struct table *table,
{
struct expr *range = NULL;
struct set *set;
- mpz_t low, high;
struct expr *i;
+ mpz_t val;
set = set_lookup(table, set_name);
- mpz_init2(low, set->key->len);
- mpz_init2(high, set->key->len);
+ mpz_init2(val, set->key->len);
list_for_each_entry(i, &set->init->expressions, list) {
switch (i->key->etype) {
+ case EXPR_PREFIX:
case EXPR_RANGE:
- range_expr_value_low(low, i);
- range_expr_value_high(high, i);
- if (mpz_cmp(left->key->value, low) >= 0 &&
- mpz_cmp(right->key->value, high) <= 0) {
- range = range_expr_alloc(&internal_location,
- expr_clone(left->key),
- expr_clone(right->key));
- goto out;
- }
- break;
- default:
- break;
- }
- }
-out:
- mpz_clear(low);
- mpz_clear(high);
-
- return range;
-}
-
-static struct expr *get_set_interval_end(const struct table *table,
- const char *set_name,
- struct expr *left)
-{
- struct expr *i, *range = NULL;
- struct set *set;
- mpz_t low, high;
+ range_expr_value_low(val, i);
+ if (left && mpz_cmp(left->key->value, val))
+ break;
- set = set_lookup(table, set_name);
- mpz_init2(low, set->key->len);
- mpz_init2(high, set->key->len);
+ range_expr_value_high(val, i);
+ if (right && mpz_cmp(right->key->value, val))
+ break;
- list_for_each_entry(i, &set->init->expressions, list) {
- switch (i->key->etype) {
- case EXPR_RANGE:
- range_expr_value_low(low, i);
- if (mpz_cmp(low, left->key->value) == 0) {
- range = range_expr_alloc(&internal_location,
- expr_clone(left->key),
- expr_clone(i->key->right));
- goto out;
- }
- break;
+ range = expr_clone(i->key);
+ goto out;
default:
break;
}
}
out:
- mpz_clear(low);
- mpz_clear(high);
+ mpz_clear(val);
return range;
}
@@ -764,14 +744,16 @@ int get_set_decompose(struct table *table, struct set *set)
errno = ENOENT;
return -1;
}
+ expr_free(left);
+ expr_free(i);
compound_expr_add(new_init, range);
left = NULL;
} else {
if (left) {
- range = get_set_interval_end(table,
- set->handle.set.name,
- left);
+ range = get_set_interval_find(table,
+ set->handle.set.name,
+ left, NULL);
if (range)
compound_expr_add(new_init, range);
else
@@ -782,7 +764,8 @@ int get_set_decompose(struct table *table, struct set *set)
}
}
if (left) {
- range = get_set_interval_end(table, set->handle.set.name, left);
+ range = get_set_interval_find(table, set->handle.set.name,
+ left, NULL);
if (range)
compound_expr_add(new_init, range);
else
@@ -1084,7 +1067,7 @@ void interval_map_decompose(struct expr *set)
prefix->comment = xstrdup(low->comment);
if (low->timeout)
prefix->timeout = low->timeout;
- if (low->left->expiration)
+ if (low->expiration)
prefix->expiration = low->expiration;
}
diff --git a/src/statement.c b/src/statement.c
index be35bcef..21a1bc8d 100644
--- a/src/statement.c
+++ b/src/statement.c
@@ -607,6 +607,13 @@ static void nat_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
break;
}
+ if (stmt->nat.type_flags & STMT_NAT_F_CONCAT)
+ nft_print(octx, " addr . port");
+ else if (stmt->nat.type_flags & STMT_NAT_F_PREFIX)
+ nft_print(octx, " prefix");
+ else if (stmt->nat.type_flags & STMT_NAT_F_INTERVAL)
+ nft_print(octx, " interval");
+
nft_print(octx, " to");
}
diff --git a/src/xt.c b/src/xt.c
index b0f5a30c..f39acf30 100644
--- a/src/xt.c
+++ b/src/xt.c
@@ -238,7 +238,7 @@ void netlink_parse_match(struct netlink_parse_ctx *ctx,
stmt->xt.name = strdup(name);
stmt->xt.type = NFT_XT_MATCH;
#endif
- list_add_tail(&stmt->list, &ctx->rule->stmts);
+ rule_stmt_append(ctx->rule, stmt);
}
void netlink_parse_target(struct netlink_parse_ctx *ctx,
@@ -283,7 +283,7 @@ void netlink_parse_target(struct netlink_parse_ctx *ctx,
stmt->xt.name = strdup(name);
stmt->xt.type = NFT_XT_TARGET;
#endif
- list_add_tail(&stmt->list, &ctx->rule->stmts);
+ rule_stmt_append(ctx->rule, stmt);
}
#ifdef HAVE_LIBXTABLES
diff --git a/tests/py/any/ct.t b/tests/py/any/ct.t
index f65d2759..cc09aebc 100644
--- a/tests/py/any/ct.t
+++ b/tests/py/any/ct.t
@@ -128,6 +128,8 @@ ct both zone 1;fail
ct original zone 1;ok
ct reply zone 1;ok
+ct id 12345;ok
+
ct zone set 1;ok
ct original zone set 1;ok
ct reply zone set 1;ok
diff --git a/tests/py/any/ct.t.payload b/tests/py/any/ct.t.payload
index 66159125..ccbddc89 100644
--- a/tests/py/any/ct.t.payload
+++ b/tests/py/any/ct.t.payload
@@ -520,3 +520,8 @@ ip test-ip4 output
[ bitwise reg 1 = (reg=1 & 0xfffffffe ) ^ 0x00000001 ]
[ ct set mark with reg 1 ]
+# ct id 12345
+ip test-ip4 output
+ [ ct load unknown => reg 1 ]
+ [ cmp eq reg 1 0x39300000 ]
+
diff --git a/tests/py/any/meta.t.json.output b/tests/py/any/meta.t.json.output
index 037f6718..74b934b8 100644
--- a/tests/py/any/meta.t.json.output
+++ b/tests/py/any/meta.t.json.output
@@ -620,7 +620,7 @@
}
},
"op": "==",
- "right": "1970-05-23 21:07:14"
+ "right": "1970-05-23 22:07:14"
}
},
{
diff --git a/tests/py/any/meta.t.payload b/tests/py/any/meta.t.payload
index 486d7aa5..2af244a9 100644
--- a/tests/py/any/meta.t.payload
+++ b/tests/py/any/meta.t.payload
@@ -99,14 +99,12 @@ ip test-ip4 input
# meta l4proto 33-45
ip test-ip4 input
[ meta load l4proto => reg 1 ]
- [ byteorder reg 1 = hton(reg 1, 2, 1) ]
[ cmp gte reg 1 0x00000021 ]
[ cmp lte reg 1 0x0000002d ]
# meta l4proto != 33-45
ip test-ip4 input
[ meta load l4proto => reg 1 ]
- [ byteorder reg 1 = hton(reg 1, 2, 1) ]
[ range neq reg 1 0x00000021 0x0000002d ]
# meta l4proto { 33, 55, 67, 88}
@@ -865,7 +863,6 @@ __set%d test-ip4 0
element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end] element 00000042 : 0 [end] element 00000059 : 1 [end]
ip test-ip4 input
[ meta load l4proto => reg 1 ]
- [ byteorder reg 1 = hton(reg 1, 2, 1) ]
[ lookup reg 1 set __set%d ]
# meta l4proto != { 33-55, 66-88}
@@ -874,7 +871,6 @@ __set%d test-ip4 0
element 00000000 : 1 [end] element 00000021 : 0 [end] element 00000038 : 1 [end] element 00000042 : 0 [end] element 00000059 : 1 [end]
ip test-ip4 input
[ meta load l4proto => reg 1 ]
- [ byteorder reg 1 = hton(reg 1, 2, 1) ]
[ lookup reg 1 set __set%d 0x1 ]
# meta skuid { 2001-2005, 3001-3005} accept
diff --git a/tests/py/inet/tcpopt.t b/tests/py/any/tcpopt.t
index b457691f..08b1dcb3 100644
--- a/tests/py/inet/tcpopt.t
+++ b/tests/py/any/tcpopt.t
@@ -1,5 +1,7 @@
:input;type filter hook input priority 0
+*ip;test-ip4;input
+*ip6;test-ip6;input
*inet;test-inet;input
tcp option eol kind 1;ok
@@ -19,6 +21,7 @@ tcp option sack0 left 1;ok;tcp option sack left 1
tcp option sack1 left 1;ok
tcp option sack2 left 1;ok
tcp option sack3 left 1;ok
+tcp option sack right 1;ok
tcp option sack0 right 1;ok;tcp option sack right 1
tcp option sack1 right 1;ok
tcp option sack2 right 1;ok
diff --git a/tests/py/inet/tcpopt.t.json b/tests/py/any/tcpopt.t.json
index 45e9c293..48eb339c 100644
--- a/tests/py/inet/tcpopt.t.json
+++ b/tests/py/any/tcpopt.t.json
@@ -8,7 +8,7 @@
"name": "eol"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -24,7 +24,7 @@
"name": "noop"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -40,7 +40,7 @@
"name": "maxseg"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -56,7 +56,7 @@
"name": "maxseg"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -72,7 +72,7 @@
"name": "maxseg"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -88,7 +88,7 @@
"name": "window"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -104,7 +104,7 @@
"name": "window"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -120,7 +120,7 @@
"name": "window"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -136,7 +136,7 @@
"name": "sack-permitted"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -152,7 +152,7 @@
"name": "sack-permitted"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -168,7 +168,7 @@
"name": "sack"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -184,7 +184,7 @@
"name": "sack"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -200,7 +200,7 @@
"name": "sack"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -216,7 +216,7 @@
"name": "sack0"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -232,7 +232,7 @@
"name": "sack1"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -248,7 +248,7 @@
"name": "sack2"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -264,7 +264,23 @@
"name": "sack3"
}
},
- "op": "==",
+ "op": "==",
+ "right": 1
+ }
+ }
+]
+
+# tcp option sack right 1
+[
+ {
+ "match": {
+ "left": {
+ "tcp option": {
+ "field": "right",
+ "name": "sack"
+ }
+ },
+ "op": "==",
"right": 1
}
}
@@ -280,7 +296,7 @@
"name": "sack0"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -296,7 +312,7 @@
"name": "sack1"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -312,7 +328,7 @@
"name": "sack2"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -328,7 +344,7 @@
"name": "sack3"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -344,7 +360,7 @@
"name": "timestamp"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -360,7 +376,7 @@
"name": "timestamp"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -376,7 +392,7 @@
"name": "timestamp"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -392,7 +408,7 @@
"name": "timestamp"
}
},
- "op": "==",
+ "op": "==",
"right": 1
}
}
@@ -407,7 +423,7 @@
"name": "window"
}
},
- "op": "==",
+ "op": "==",
"right": true
}
}
@@ -422,7 +438,7 @@
"name": "window"
}
},
- "op": "==",
+ "op": "==",
"right": false
}
}
diff --git a/tests/py/inet/tcpopt.t.json.output b/tests/py/any/tcpopt.t.json.output
index ad0d25f4..ad0d25f4 100644
--- a/tests/py/inet/tcpopt.t.json.output
+++ b/tests/py/any/tcpopt.t.json.output
diff --git a/tests/py/any/tcpopt.t.payload b/tests/py/any/tcpopt.t.payload
new file mode 100644
index 00000000..63751cf2
--- /dev/null
+++ b/tests/py/any/tcpopt.t.payload
@@ -0,0 +1,603 @@
+# tcp option eol kind 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 0 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option eol kind 1
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 0 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option eol kind 1
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 0 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option noop kind 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 1 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option noop kind 1
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 1 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option noop kind 1
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 1 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option maxseg kind 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 2 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option maxseg kind 1
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 2 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option maxseg kind 1
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 2 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option maxseg length 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 2 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option maxseg length 1
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 2 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option maxseg length 1
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 2 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option maxseg size 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 2b @ 2 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+
+# tcp option maxseg size 1
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 2b @ 2 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+
+# tcp option maxseg size 1
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 2b @ 2 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00000100 ]
+
+# tcp option window kind 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 3 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option window kind 1
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 3 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option window kind 1
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 3 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option window length 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 3 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option window length 1
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 3 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option window length 1
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 3 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option window count 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 3 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option window count 1
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 3 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option window count 1
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 3 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option sack-permitted kind 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 4 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option sack-permitted kind 1
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 4 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option sack-permitted kind 1
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 4 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option sack-permitted length 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 4 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option sack-permitted length 1
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 4 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option sack-permitted length 1
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 4 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option sack kind 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 5 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option sack kind 1
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 5 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option sack kind 1
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 5 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option sack length 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 5 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option sack length 1
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 5 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option sack length 1
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 5 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option sack left 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack left 1
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack left 1
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack0 left 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack0 left 1
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack0 left 1
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack1 left 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 10 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack1 left 1
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 10 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack1 left 1
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 10 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack2 left 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 18 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack2 left 1
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 18 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack2 left 1
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 18 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack3 left 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 26 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack3 left 1
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 26 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack3 left 1
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 26 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack right 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack right 1
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack right 1
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack0 right 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack0 right 1
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack0 right 1
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack1 right 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 14 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack1 right 1
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 14 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack1 right 1
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 14 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack2 right 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 22 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack2 right 1
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 22 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack2 right 1
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 22 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack3 right 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 30 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack3 right 1
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 30 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option sack3 right 1
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 5 + 30 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option timestamp kind 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 8 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option timestamp kind 1
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 8 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option timestamp kind 1
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 8 + 0 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option timestamp length 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 8 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option timestamp length 1
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 8 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option timestamp length 1
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 8 + 1 => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option timestamp tsval 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 8 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option timestamp tsval 1
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 8 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option timestamp tsval 1
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 8 + 2 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option timestamp tsecr 1
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 8 + 6 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option timestamp tsecr 1
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 8 + 6 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option timestamp tsecr 1
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 4b @ 8 + 6 => reg 1 ]
+ [ cmp eq reg 1 0x01000000 ]
+
+# tcp option window exists
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option window exists
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option window exists
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000001 ]
+
+# tcp option window missing
+ip
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# tcp option window missing
+ip6
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# tcp option window missing
+inet
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ]
+ [ cmp eq reg 1 0x00000000 ]
+
+# tcp option maxseg size set 1360
+ip
+ [ immediate reg 1 0x00005005 ]
+ [ exthdr write tcpopt reg 1 => 2b @ 2 + 2 ]
+
+# tcp option maxseg size set 1360
+ip6
+ [ immediate reg 1 0x00005005 ]
+ [ exthdr write tcpopt reg 1 => 2b @ 2 + 2 ]
+
+# tcp option maxseg size set 1360
+inet
+ [ immediate reg 1 0x00005005 ]
+ [ exthdr write tcpopt reg 1 => 2b @ 2 + 2 ]
+
diff --git a/tests/py/bridge/chains.t b/tests/py/bridge/chains.t
index 85dde73e..e071d9a3 100644
--- a/tests/py/bridge/chains.t
+++ b/tests/py/bridge/chains.t
@@ -1,8 +1,8 @@
# filter chains available are: prerouting, input, output, forward, postrouting
-:filter-pre;type filter hook input priority 0
+:filter-pre;type filter hook prerouting priority 0
:filter-output;type filter hook output priority 0
:filter-forward;type filter hook forward priority 0
:filter-input;type filter hook input priority 0
-:filter-post;type filter hook input priority 0
+:filter-post;type filter hook postrouting priority 0
*bridge;test-bridge;filter-pre,filter-output,filter-forward,filter-input,filter-post
diff --git a/tests/py/bridge/reject.t b/tests/py/bridge/reject.t
index ee7e93c8..f5ed2038 100644
--- a/tests/py/bridge/reject.t
+++ b/tests/py/bridge/reject.t
@@ -30,15 +30,13 @@ reject with icmpx type port-unreachable;ok;reject
ether type ipv6 reject with icmp type host-unreachable;fail
ether type ip6 reject with icmp type host-unreachable;fail
ether type ip reject with icmpv6 type no-route;fail
-ether type vlan reject;fail
+ether type vlan reject;ok
ether type arp reject;fail
-ether type vlan reject;fail
-ether type arp reject;fail
-ether type vlan reject with tcp reset;fail
+ether type vlan reject with tcp reset;ok
ether type arp reject with tcp reset;fail
ip protocol udp reject with tcp reset;fail
ether type ip reject with icmpx type admin-prohibited;ok
ether type ip6 reject with icmpx type admin-prohibited;ok
-ether type vlan reject with icmpx type admin-prohibited;fail
+ether type vlan reject with icmpx type admin-prohibited;ok
ether type arp reject with icmpx type admin-prohibited;fail
diff --git a/tests/py/bridge/reject.t.payload b/tests/py/bridge/reject.t.payload
index 0d10547b..7deb6fbf 100644
--- a/tests/py/bridge/reject.t.payload
+++ b/tests/py/bridge/reject.t.payload
@@ -118,3 +118,23 @@ bridge test-bridge input
[ cmp eq reg 1 0x0000dd86 ]
[ reject type 2 code 3 ]
+# ether type vlan reject
+bridge
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ reject type 2 code 1 ]
+
+# ether type vlan reject with tcp reset
+bridge
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ reject type 1 code 0 ]
+
+# ether type vlan reject with icmpx type admin-prohibited
+bridge
+ [ payload load 2b @ link header + 12 => reg 1 ]
+ [ cmp eq reg 1 0x00000081 ]
+ [ reject type 2 code 3 ]
+
diff --git a/tests/py/inet/dccp.t b/tests/py/inet/dccp.t
index f0dd788b..9a81bb2e 100644
--- a/tests/py/inet/dccp.t
+++ b/tests/py/inet/dccp.t
@@ -12,7 +12,6 @@ dccp sport {23, 24, 25};ok
dccp sport != {23, 24, 25};ok
dccp sport { 20-50 };ok
-dccp sport ftp-data - re-mail-ck;ok;dccp sport 20-50
dccp sport 20-50;ok
dccp sport { 20-50};ok
dccp sport != { 20-50};ok
diff --git a/tests/py/inet/dnat.t.payload b/tests/py/inet/dnat.t.payload
index b81caf7b..75cf1b77 100644
--- a/tests/py/inet/dnat.t.payload
+++ b/tests/py/inet/dnat.t.payload
@@ -7,7 +7,7 @@ inet test-inet prerouting
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x00005000 ]
[ immediate reg 1 0x0000901f ]
- [ redir proto_min reg 1 ]
+ [ redir proto_min reg 1 flags 0x2 ]
# iifname "eth0" tcp dport 443 dnat ip to 192.168.3.2
inet test-inet prerouting
@@ -30,7 +30,7 @@ inet test-inet prerouting
[ cmp eq reg 1 0x0000bb01 ]
[ immediate reg 1 0x0000adde 0x00000000 0x00000000 0xefbe0000 ]
[ immediate reg 2 0x00005b11 ]
- [ nat dnat ip6 addr_min reg 1 addr_max reg 0 proto_min reg 2 proto_max reg 0 ]
+ [ nat dnat ip6 addr_min reg 1 addr_max reg 0 proto_min reg 2 proto_max reg 0 flags 0x2 ]
# dnat ip to ct mark map { 0x00000014 : 1.2.3.4}
__map%d test-inet b size 1
diff --git a/tests/py/inet/ip.t b/tests/py/inet/ip.t
index 4eb69d73..86604a63 100644
--- a/tests/py/inet/ip.t
+++ b/tests/py/inet/ip.t
@@ -7,3 +7,5 @@
*netdev;test-netdev;ingress
ip saddr . ip daddr . ether saddr { 1.1.1.1 . 2.2.2.2 . ca:fe:ca:fe:ca:fe };ok
+ip saddr vmap { 10.0.1.0-10.0.1.255 : accept, 10.0.1.1-10.0.2.255 : drop };fail
+ip saddr vmap { 1.1.1.1-1.1.1.255 : accept, 1.1.1.0-1.1.2.1 : drop};fail
diff --git a/tests/py/inet/sets.t b/tests/py/inet/sets.t
index daf8f2d6..1c6f3235 100644
--- a/tests/py/inet/sets.t
+++ b/tests/py/inet/sets.t
@@ -16,3 +16,9 @@ ip saddr != @set2 drop;fail
ip6 daddr != @set2 accept;ok
ip6 daddr @set1 drop;fail
+
+!set3 type ipv4_addr . ipv4_addr . inet_service flags interval;ok
+?set3 10.0.0.0/8 . 192.168.1.3-192.168.1.9 . 1024-65535;ok
+
+ip saddr . ip daddr . tcp dport @set3 accept;ok
+ip daddr . tcp dport { 10.0.0.0/8 . 10-23, 192.168.1.1-192.168.3.8 . 80-443 } accept;ok
diff --git a/tests/py/inet/sets.t.json b/tests/py/inet/sets.t.json
index bcb638f2..58e19ef6 100644
--- a/tests/py/inet/sets.t.json
+++ b/tests/py/inet/sets.t.json
@@ -36,3 +36,38 @@
}
]
+# ip saddr . ip daddr . tcp dport @set3 accept
+[
+ {
+ "match": {
+ "left": {
+ "concat": [
+ {
+ "payload": {
+ "field": "saddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "daddr",
+ "protocol": "ip"
+ }
+ },
+ {
+ "payload": {
+ "field": "dport",
+ "protocol": "tcp"
+ }
+ }
+ ]
+ },
+ "op": "==",
+ "right": "@set3"
+ }
+ },
+ {
+ "accept": null
+ }
+]
+
diff --git a/tests/py/inet/sets.t.payload.bridge b/tests/py/inet/sets.t.payload.bridge
index f5aaab1d..92f5417c 100644
--- a/tests/py/inet/sets.t.payload.bridge
+++ b/tests/py/inet/sets.t.payload.bridge
@@ -13,3 +13,30 @@ bridge test-inet input
[ payload load 16b @ network header + 24 => reg 1 ]
[ lookup reg 1 set set2 0x1 ]
[ immediate reg 0 accept ]
+
+# ip saddr . ip daddr . tcp dport @set3 accept
+bridge
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ payload load 2b @ transport header + 2 => reg 10 ]
+ [ lookup reg 1 set set3 ]
+ [ immediate reg 0 accept ]
+
+# ip daddr . tcp dport { 10.0.0.0/8 . 10-23, 192.168.1.1-192.168.3.8 . 80-443 } accept
+__set%d test-inet 87
+__set%d test-inet 0
+ element 0000000a 00000a00 : 0 [end] element 0101a8c0 00005000 : 0 [end]
+bridge
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ payload load 2b @ transport header + 2 => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
+
diff --git a/tests/py/inet/sets.t.payload.inet b/tests/py/inet/sets.t.payload.inet
index 1584fc07..bd6e1b0f 100644
--- a/tests/py/inet/sets.t.payload.inet
+++ b/tests/py/inet/sets.t.payload.inet
@@ -14,4 +14,28 @@ inet test-inet input
[ lookup reg 1 set set2 0x1 ]
[ immediate reg 0 accept ]
+# ip saddr . ip daddr . tcp dport @set3 accept
+inet
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ payload load 2b @ transport header + 2 => reg 10 ]
+ [ lookup reg 1 set set3 ]
+ [ immediate reg 0 accept ]
+# ip daddr . tcp dport { 10.0.0.0/8 . 10-23, 192.168.1.1-192.168.3.8 . 80-443 } accept
+__set%d test-inet 87
+__set%d test-inet 0
+ element 0000000a 00000a00 : 0 [end] element 0101a8c0 00005000 : 0 [end]
+inet
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ payload load 2b @ transport header + 2 => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
diff --git a/tests/py/inet/sets.t.payload.netdev b/tests/py/inet/sets.t.payload.netdev
index 9c94e384..f3032d8e 100644
--- a/tests/py/inet/sets.t.payload.netdev
+++ b/tests/py/inet/sets.t.payload.netdev
@@ -14,3 +14,28 @@ netdev test-netdev ingress
[ lookup reg 1 set set2 0x1 ]
[ immediate reg 0 accept ]
+# ip saddr . ip daddr . tcp dport @ set3 accept
+inet
+ [ meta load nfproto => reg 1 ]
+ [ cmp eq reg 1 0x00000002 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ payload load 4b @ network header + 16 => reg 9 ]
+ [ payload load 2b @ transport header + 2 => reg 10 ]
+ [ lookup reg 1 set set3 ]
+ [ immediate reg 0 accept ]
+
+# ip daddr . tcp dport { 10.0.0.0/8 . 10-23, 192.168.1.1-192.168.3.8 . 80-443 } accept
+__set%d test-netdev 87
+__set%d test-netdev 0
+ element 0000000a 00000a00 : 0 [end] element 0101a8c0 00005000 : 0 [end]
+netdev
+ [ meta load protocol => reg 1 ]
+ [ cmp eq reg 1 0x00000008 ]
+ [ meta load l4proto => reg 1 ]
+ [ cmp eq reg 1 0x00000006 ]
+ [ payload load 4b @ network header + 16 => reg 1 ]
+ [ payload load 2b @ transport header + 2 => reg 9 ]
+ [ lookup reg 1 set __set%d ]
+ [ immediate reg 0 accept ]
diff --git a/tests/py/inet/tcpopt.t.payload b/tests/py/inet/tcpopt.t.payload
deleted file mode 100644
index 7e254ed3..00000000
--- a/tests/py/inet/tcpopt.t.payload
+++ /dev/null
@@ -1,200 +0,0 @@
-# tcp option eol kind 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 0 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option noop kind 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 1 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option maxseg kind 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 2 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option maxseg length 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 2 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option maxseg size 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 2b @ 2 + 2 => reg 1 ]
- [ cmp eq reg 1 0x00000100 ]
-
-# tcp option window kind 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 3 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option window length 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 3 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option window count 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 3 + 2 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack-permitted kind 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 4 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack-permitted length 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 4 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack kind 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 5 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack length 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 5 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack left 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack0 left 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack1 left 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 10 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack2 left 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 18 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack3 left 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 26 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack right 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack0 right 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack1 right 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 14 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack2 right 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 22 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack3 right 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 30 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option timestamp kind 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 8 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option timestamp length 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 8 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option timestamp tsval 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 8 + 2 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option timestamp tsecr 1
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 8 + 6 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option window exists
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option window missing
-inet test-inet input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 3 + 0 present => reg 1 ]
- [ cmp eq reg 1 0x00000000 ]
-
-# tcp option maxseg size set 1360
-inet test-inet input
- [ immediate reg 1 0x00005005 ]
- [ exthdr write tcpopt reg 1 => 2b @ 2 + 2 ]
diff --git a/tests/py/ip/dnat.t.payload.ip b/tests/py/ip/dnat.t.payload.ip
index 1b869d0a..0acbefb6 100644
--- a/tests/py/ip/dnat.t.payload.ip
+++ b/tests/py/ip/dnat.t.payload.ip
@@ -70,7 +70,7 @@ ip test-ip4 prerouting
[ cmp eq reg 1 0x00005100 ]
[ immediate reg 1 0x0203a8c0 ]
[ immediate reg 2 0x0000901f ]
- [ nat dnat ip addr_min reg 1 addr_max reg 0 proto_min reg 2 proto_max reg 0 ]
+ [ nat dnat ip addr_min reg 1 addr_max reg 0 proto_min reg 2 proto_max reg 0 flags 0x2 ]
# dnat to ct mark map { 0x00000014 : 1.2.3.4}
__map%d test-ip4 b
diff --git a/tests/py/ip/icmp.t b/tests/py/ip/icmp.t
index 6c05fb9d..cb3b3e35 100644
--- a/tests/py/ip/icmp.t
+++ b/tests/py/ip/icmp.t
@@ -28,8 +28,8 @@ icmp code 33-55;ok
icmp code != 33-55;ok
icmp code { 33-55};ok
icmp code != { 33-55};ok
-icmp code { 2, 4, 54, 33, 56};ok;icmp code { prot-unreachable, 4, 33, 54, 56}
-icmp code != { prot-unreachable, 4, 33, 54, 56};ok
+icmp code { 2, 4, 54, 33, 56};ok;icmp code { prot-unreachable, frag-needed, 33, 54, 56}
+icmp code != { prot-unreachable, frag-needed, 33, 54, 56};ok
icmp checksum 12343 accept;ok
icmp checksum != 12343 accept;ok
diff --git a/tests/py/ip/icmp.t.payload.ip b/tests/py/ip/icmp.t.payload.ip
index 27f22207..2185feb8 100644
--- a/tests/py/ip/icmp.t.payload.ip
+++ b/tests/py/ip/icmp.t.payload.ip
@@ -184,7 +184,7 @@ ip test-ip4 input
[ payload load 1b @ transport header + 1 => reg 1 ]
[ lookup reg 1 set __set%d ]
-# icmp code != { prot-unreachable, 4, 33, 54, 56}
+# icmp code != { prot-unreachable, frag-needed, 33, 54, 56}
__set%d test-ip4 3
__set%d test-ip4 0
element 00000002 : 0 [end] element 00000004 : 0 [end] element 00000036 : 0 [end] element 00000021 : 0 [end] element 00000038 : 0 [end]
diff --git a/tests/py/ip/masquerade.t.payload b/tests/py/ip/masquerade.t.payload
index 83351526..0ba8d5a8 100644
--- a/tests/py/ip/masquerade.t.payload
+++ b/tests/py/ip/masquerade.t.payload
@@ -130,7 +130,7 @@ ip test-ip4 postrouting
[ payload load 1b @ network header + 9 => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ immediate reg 1 0x00000004 ]
- [ masq proto_min reg 1 proto_max reg 0 ]
+ [ masq proto_min reg 1 proto_max reg 0 flags 0x2 ]
# ip protocol 6 masquerade to :1024-2048
ip test-ip4 postrouting
@@ -138,5 +138,5 @@ ip test-ip4 postrouting
[ cmp eq reg 1 0x00000006 ]
[ immediate reg 1 0x00000004 ]
[ immediate reg 2 0x00000008 ]
- [ masq proto_min reg 1 proto_max reg 2 ]
+ [ masq proto_min reg 1 proto_max reg 2 flags 0x2 ]
diff --git a/tests/py/ip/redirect.t.payload b/tests/py/ip/redirect.t.payload
index f208aacb..7f8a74b0 100644
--- a/tests/py/ip/redirect.t.payload
+++ b/tests/py/ip/redirect.t.payload
@@ -93,7 +93,7 @@ ip test-ip4 output
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x00001600 ]
[ immediate reg 1 0x00001600 ]
- [ redir proto_min reg 1 ]
+ [ redir proto_min reg 1 flags 0x2 ]
# udp dport 1234 redirect to :4321
ip test-ip4 output
@@ -102,7 +102,7 @@ ip test-ip4 output
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x0000d204 ]
[ immediate reg 1 0x0000e110 ]
- [ redir proto_min reg 1 ]
+ [ redir proto_min reg 1 flags 0x2 ]
# ip daddr 172.16.0.1 udp dport 9998 redirect to :6515
ip test-ip4 output
@@ -113,7 +113,7 @@ ip test-ip4 output
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x00000e27 ]
[ immediate reg 1 0x00007319 ]
- [ redir proto_min reg 1 ]
+ [ redir proto_min reg 1 flags 0x2 ]
# tcp dport 39128 redirect to :993
ip test-ip4 output
@@ -122,7 +122,7 @@ ip test-ip4 output
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x0000d898 ]
[ immediate reg 1 0x0000e103 ]
- [ redir proto_min reg 1 ]
+ [ redir proto_min reg 1 flags 0x2 ]
# ip protocol tcp redirect to :100-200
ip test-ip4 output
@@ -130,7 +130,7 @@ ip test-ip4 output
[ cmp eq reg 1 0x00000006 ]
[ immediate reg 1 0x00006400 ]
[ immediate reg 2 0x0000c800 ]
- [ redir proto_min reg 1 proto_max reg 2 ]
+ [ redir proto_min reg 1 proto_max reg 2 flags 0x2 ]
# tcp dport 9128 redirect to :993 random
ip test-ip4 output
@@ -139,7 +139,7 @@ ip test-ip4 output
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x0000a823 ]
[ immediate reg 1 0x0000e103 ]
- [ redir proto_min reg 1 flags 0x4 ]
+ [ redir proto_min reg 1 flags 0x6 ]
# tcp dport 9128 redirect to :993 fully-random
ip test-ip4 output
@@ -148,7 +148,7 @@ ip test-ip4 output
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x0000a823 ]
[ immediate reg 1 0x0000e103 ]
- [ redir proto_min reg 1 flags 0x10 ]
+ [ redir proto_min reg 1 flags 0x12 ]
# tcp dport 9128 redirect to :123 persistent
ip test-ip4 output
@@ -157,7 +157,7 @@ ip test-ip4 output
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x0000a823 ]
[ immediate reg 1 0x00007b00 ]
- [ redir proto_min reg 1 flags 0x8 ]
+ [ redir proto_min reg 1 flags 0xa ]
# tcp dport 9128 redirect to :123 random,persistent
ip test-ip4 output
@@ -166,7 +166,7 @@ ip test-ip4 output
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x0000a823 ]
[ immediate reg 1 0x00007b00 ]
- [ redir proto_min reg 1 flags 0xc ]
+ [ redir proto_min reg 1 flags 0xe ]
# tcp dport { 1, 2, 3, 4, 5, 6, 7, 8, 101, 202, 303, 1001, 2002, 3003} redirect
__set%d test-ip4 3
@@ -216,5 +216,5 @@ ip test-ip4 output
[ cmp eq reg 1 0x00000006 ]
[ payload load 2b @ transport header + 2 => reg 1 ]
[ lookup reg 1 set __map%d dreg 1 ]
- [ redir proto_min reg 1 ]
+ [ redir proto_min reg 1 flags 0x2 ]
diff --git a/tests/py/ip/snat.t b/tests/py/ip/snat.t
index 7281bf5f..c6e8a8e6 100644
--- a/tests/py/ip/snat.t
+++ b/tests/py/ip/snat.t
@@ -8,3 +8,7 @@ iifname "eth0" tcp dport {80, 90, 23} snat to 192.168.3.2;ok
iifname "eth0" tcp dport != {80, 90, 23} snat to 192.168.3.2;ok
iifname "eth0" tcp dport != 23-34 snat to 192.168.3.2;ok
+
+snat ip addr . port to ip saddr map { 10.141.11.4 : 192.168.2.3 . 80 };ok
+snat ip interval to ip saddr map { 10.141.11.4 : 192.168.2.2-192.168.2.4 };ok
+snat ip prefix to ip saddr map { 10.141.11.0/24 : 192.168.2.0/24 };ok
diff --git a/tests/py/ip/snat.t.payload b/tests/py/ip/snat.t.payload
index 789933ff..22befe15 100644
--- a/tests/py/ip/snat.t.payload
+++ b/tests/py/ip/snat.t.payload
@@ -60,3 +60,30 @@ ip test-ip4 postrouting
[ immediate reg 1 0x0203a8c0 ]
[ nat snat ip addr_min reg 1 addr_max reg 0 ]
+# snat ip addr . port to ip saddr map { 10.141.11.4 : 192.168.2.3 . 80 }
+__map%d test-ip4 b size 1
+__map%d test-ip4 0
+ element 040b8d0a : 0302a8c0 00005000 0 [end]
+ip
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat snat ip addr_min reg 1 addr_max reg 0 proto_min reg 9 proto_max reg 0 ]
+
+# snat ip interval to ip saddr map { 10.141.11.4 : 192.168.2.2-192.168.2.4 }
+__map%d test-ip4 b size 1
+__map%d test-ip4 0
+ element 040b8d0a : 0202a8c0 0402a8c0 0 [end]
+ip
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat snat ip addr_min reg 1 addr_max reg 9 ]
+
+# snat ip prefix to ip saddr map { 10.141.11.0/24 : 192.168.2.0/24 }
+__map%d test-ip4 f size 3
+__map%d test-ip4 0
+ element 00000000 : 1 [end] element 000b8d0a : 0002a8c0 ff02a8c0 0 [end] element 000c8d0a : 1 [end]
+ip
+ [ payload load 4b @ network header + 12 => reg 1 ]
+ [ lookup reg 1 set __map%d dreg 1 ]
+ [ nat snat ip addr_min reg 1 addr_max reg 9 flags 0x40 ]
+
diff --git a/tests/py/ip/tcpopt.t b/tests/py/ip/tcpopt.t
deleted file mode 100644
index 7ee50a89..00000000
--- a/tests/py/ip/tcpopt.t
+++ /dev/null
@@ -1,38 +0,0 @@
-:input;type filter hook input priority 0
-
-*ip;test-ip;input
-
-tcp option eol kind 1;ok
-tcp option noop kind 1;ok
-tcp option maxseg kind 1;ok
-tcp option maxseg length 1;ok
-tcp option maxseg size 1;ok
-tcp option window kind 1;ok
-tcp option window length 1;ok
-tcp option window count 1;ok
-tcp option sack-permitted kind 1;ok
-tcp option sack-permitted length 1;ok
-tcp option sack kind 1;ok
-tcp option sack length 1;ok
-tcp option sack left 1;ok
-tcp option sack0 left 1;ok;tcp option sack left 1
-tcp option sack1 left 1;ok
-tcp option sack2 left 1;ok
-tcp option sack3 left 1;ok
-tcp option sack right 1;ok
-tcp option sack0 right 1;ok;tcp option sack right 1
-tcp option sack1 right 1;ok
-tcp option sack2 right 1;ok
-tcp option sack3 right 1;ok
-tcp option timestamp kind 1;ok
-tcp option timestamp length 1;ok
-tcp option timestamp tsval 1;ok
-tcp option timestamp tsecr 1;ok
-
-tcp option foobar;fail
-tcp option foo bar;fail
-tcp option eol left;fail
-tcp option eol left 1;fail
-tcp option eol left 1;fail
-tcp option sack window;fail
-tcp option sack window 1;fail
diff --git a/tests/py/ip/tcpopt.t.json b/tests/py/ip/tcpopt.t.json
deleted file mode 100644
index d573dd1c..00000000
--- a/tests/py/ip/tcpopt.t.json
+++ /dev/null
@@ -1,416 +0,0 @@
-# tcp option eol kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "eol"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option noop kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "noop"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option maxseg kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "maxseg"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option maxseg length 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "length",
- "name": "maxseg"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option maxseg size 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "size",
- "name": "maxseg"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option window kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "window"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option window length 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "length",
- "name": "window"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option window count 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "count",
- "name": "window"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack-permitted kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "sack-permitted"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack-permitted length 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "length",
- "name": "sack-permitted"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "sack"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack length 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "length",
- "name": "sack"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack left 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "left",
- "name": "sack"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack0 left 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "left",
- "name": "sack"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack1 left 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "left",
- "name": "sack1"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack2 left 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "left",
- "name": "sack2"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack3 left 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "left",
- "name": "sack3"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack right 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "right",
- "name": "sack"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack0 right 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "right",
- "name": "sack0"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack1 right 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "right",
- "name": "sack1"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack2 right 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "right",
- "name": "sack2"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack3 right 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "right",
- "name": "sack3"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option timestamp kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "timestamp"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option timestamp length 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "length",
- "name": "timestamp"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option timestamp tsval 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "tsval",
- "name": "timestamp"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option timestamp tsecr 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "tsecr",
- "name": "timestamp"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
diff --git a/tests/py/ip/tcpopt.t.json.output b/tests/py/ip/tcpopt.t.json.output
deleted file mode 100644
index 81dd8ad8..00000000
--- a/tests/py/ip/tcpopt.t.json.output
+++ /dev/null
@@ -1,16 +0,0 @@
-# tcp option sack0 right 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "right",
- "name": "sack"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
diff --git a/tests/py/ip/tcpopt.t.payload b/tests/py/ip/tcpopt.t.payload
deleted file mode 100644
index b2e5bdb2..00000000
--- a/tests/py/ip/tcpopt.t.payload
+++ /dev/null
@@ -1,181 +0,0 @@
-# tcp option eol kind 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 0 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option noop kind 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 1 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option maxseg kind 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 2 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option maxseg length 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 2 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option maxseg size 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 2b @ 2 + 2 => reg 1 ]
- [ cmp eq reg 1 0x00000100 ]
-
-# tcp option window kind 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 3 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option window length 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 3 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option window count 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 3 + 2 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack-permitted kind 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 4 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack-permitted length 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 4 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack kind 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 5 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack length 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 5 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack left 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack0 left 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack1 left 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 10 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack2 left 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 18 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack3 left 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 26 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack right 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack0 right 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack1 right 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 14 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack2 right 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 22 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack3 right 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 30 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option timestamp kind 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 8 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option timestamp length 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 8 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option timestamp tsval 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 8 + 2 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option timestamp tsecr 1
-ip test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 8 + 6 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
diff --git a/tests/py/ip6/dnat.t b/tests/py/ip6/dnat.t
index db5fde58..28bd7ef9 100644
--- a/tests/py/ip6/dnat.t
+++ b/tests/py/ip6/dnat.t
@@ -5,5 +5,5 @@
tcp dport 80-90 dnat to [2001:838:35f:1::]-[2001:838:35f:2::]:80-100;ok
tcp dport 80-90 dnat to [2001:838:35f:1::]-[2001:838:35f:2::]:100;ok;tcp dport 80-90 dnat to [2001:838:35f:1::]-[2001:838:35f:2::]:100
tcp dport 80-90 dnat to [2001:838:35f:1::]:80;ok
-dnat to [2001:838:35f:1::]/64;ok;dnat to 2001:838:35f:1::-2001:838:35f:1:ffff:ffff:ffff:ffff
-dnat to 2001:838:35f:1::-2001:838:35f:1:ffff:ffff:ffff:ffff;ok
+dnat to [2001:838:35f:1::]/64;ok;dnat to 2001:838:35f:1::/64
+dnat to 2001:838:35f:1::-2001:838:35f:1:ffff:ffff:ffff:ffff;ok;dnat to 2001:838:35f:1::/64
diff --git a/tests/py/ip6/dnat.t.payload.ip6 b/tests/py/ip6/dnat.t.payload.ip6
index 985159e2..5906e0f8 100644
--- a/tests/py/ip6/dnat.t.payload.ip6
+++ b/tests/py/ip6/dnat.t.payload.ip6
@@ -9,7 +9,7 @@ ip6 test-ip6 prerouting
[ immediate reg 2 0x38080120 0x02005f03 0x00000000 0x00000000 ]
[ immediate reg 3 0x00005000 ]
[ immediate reg 4 0x00006400 ]
- [ nat dnat ip6 addr_min reg 1 addr_max reg 2 proto_min reg 3 proto_max reg 4 ]
+ [ nat dnat ip6 addr_min reg 1 addr_max reg 2 proto_min reg 3 proto_max reg 4 flags 0x2 ]
# tcp dport 80-90 dnat to [2001:838:35f:1::]-[2001:838:35f:2::]:100
ip6 test-ip6 prerouting
@@ -21,7 +21,7 @@ ip6 test-ip6 prerouting
[ immediate reg 1 0x38080120 0x01005f03 0x00000000 0x00000000 ]
[ immediate reg 2 0x38080120 0x02005f03 0x00000000 0x00000000 ]
[ immediate reg 3 0x00006400 ]
- [ nat dnat ip6 addr_min reg 1 addr_max reg 2 proto_min reg 3 proto_max reg 0 ]
+ [ nat dnat ip6 addr_min reg 1 addr_max reg 2 proto_min reg 3 proto_max reg 0 flags 0x2 ]
# tcp dport 80-90 dnat to [2001:838:35f:1::]:80
ip6 test-ip6 prerouting
@@ -32,7 +32,7 @@ ip6 test-ip6 prerouting
[ cmp lte reg 1 0x00005a00 ]
[ immediate reg 1 0x38080120 0x01005f03 0x00000000 0x00000000 ]
[ immediate reg 2 0x00005000 ]
- [ nat dnat ip6 addr_min reg 1 addr_max reg 0 proto_min reg 2 proto_max reg 0 ]
+ [ nat dnat ip6 addr_min reg 1 addr_max reg 0 proto_min reg 2 proto_max reg 0 flags 0x2 ]
# dnat to [2001:838:35f:1::]/64
ip6 test-ip6 prerouting
diff --git a/tests/py/ip6/masquerade.t.payload.ip6 b/tests/py/ip6/masquerade.t.payload.ip6
index 98657551..f9f6f074 100644
--- a/tests/py/ip6/masquerade.t.payload.ip6
+++ b/tests/py/ip6/masquerade.t.payload.ip6
@@ -130,7 +130,7 @@ ip6 test-ip6 postrouting
[ meta load l4proto => reg 1 ]
[ cmp eq reg 1 0x00000006 ]
[ immediate reg 1 0x00000004 ]
- [ masq proto_min reg 1 proto_max reg 0 ]
+ [ masq proto_min reg 1 proto_max reg 0 flags 0x2 ]
# meta l4proto 6 masquerade to :1024-2048
ip6 test-ip6 postrouting
@@ -138,5 +138,5 @@ ip6 test-ip6 postrouting
[ cmp eq reg 1 0x00000006 ]
[ immediate reg 1 0x00000004 ]
[ immediate reg 2 0x00000008 ]
- [ masq proto_min reg 1 proto_max reg 2 ]
+ [ masq proto_min reg 1 proto_max reg 2 flags 0x2 ]
diff --git a/tests/py/ip6/redirect.t.payload.ip6 b/tests/py/ip6/redirect.t.payload.ip6
index 8f85a570..104b9fd6 100644
--- a/tests/py/ip6/redirect.t.payload.ip6
+++ b/tests/py/ip6/redirect.t.payload.ip6
@@ -104,7 +104,7 @@ ip6 test-ip6 output
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x0000d204 ]
[ immediate reg 1 0x0000d204 ]
- [ redir proto_min reg 1 ]
+ [ redir proto_min reg 1 flags 0x2 ]
# ip6 daddr fe00::cafe udp dport 9998 redirect to :6515
ip6 test-ip6 output
@@ -115,7 +115,7 @@ ip6 test-ip6 output
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x00000e27 ]
[ immediate reg 1 0x00007319 ]
- [ redir proto_min reg 1 ]
+ [ redir proto_min reg 1 flags 0x2 ]
# ip6 nexthdr tcp redirect to :100-200
ip6 test-ip6 output
@@ -123,7 +123,7 @@ ip6 test-ip6 output
[ cmp eq reg 1 0x00000006 ]
[ immediate reg 1 0x00006400 ]
[ immediate reg 2 0x0000c800 ]
- [ redir proto_min reg 1 proto_max reg 2 ]
+ [ redir proto_min reg 1 proto_max reg 2 flags 0x2 ]
# tcp dport 39128 redirect to :993
ip6 test-ip6 output
@@ -132,7 +132,7 @@ ip6 test-ip6 output
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x0000d898 ]
[ immediate reg 1 0x0000e103 ]
- [ redir proto_min reg 1 ]
+ [ redir proto_min reg 1 flags 0x2 ]
# tcp dport 9128 redirect to :993 random
ip6 test-ip6 output
@@ -141,7 +141,7 @@ ip6 test-ip6 output
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x0000a823 ]
[ immediate reg 1 0x0000e103 ]
- [ redir proto_min reg 1 flags 0x4 ]
+ [ redir proto_min reg 1 flags 0x6 ]
# tcp dport 9128 redirect to :993 fully-random,persistent
ip6 test-ip6 output
@@ -150,7 +150,7 @@ ip6 test-ip6 output
[ payload load 2b @ transport header + 2 => reg 1 ]
[ cmp eq reg 1 0x0000a823 ]
[ immediate reg 1 0x0000e103 ]
- [ redir proto_min reg 1 flags 0x18 ]
+ [ redir proto_min reg 1 flags 0x1a ]
# tcp dport { 1, 2, 3, 4, 5, 6, 7, 8, 101, 202, 303, 1001, 2002, 3003} redirect
__set%d test-ip6 3
@@ -200,5 +200,5 @@ ip6 test-ip6 output
[ cmp eq reg 1 0x00000006 ]
[ payload load 2b @ transport header + 2 => reg 1 ]
[ lookup reg 1 set __map%d dreg 1 ]
- [ redir proto_min reg 1 ]
+ [ redir proto_min reg 1 flags 0x2 ]
diff --git a/tests/py/ip6/snat.t.payload.ip6 b/tests/py/ip6/snat.t.payload.ip6
index 537e6682..e7fd8ff8 100644
--- a/tests/py/ip6/snat.t.payload.ip6
+++ b/tests/py/ip6/snat.t.payload.ip6
@@ -9,7 +9,7 @@ ip6 test-ip6 postrouting
[ immediate reg 2 0x38080120 0x02005f03 0x00000000 0x00000000 ]
[ immediate reg 3 0x00005000 ]
[ immediate reg 4 0x00006400 ]
- [ nat snat ip6 addr_min reg 1 addr_max reg 2 proto_min reg 3 proto_max reg 4 ]
+ [ nat snat ip6 addr_min reg 1 addr_max reg 2 proto_min reg 3 proto_max reg 4 flags 0x2 ]
# tcp dport 80-90 snat to [2001:838:35f:1::]-[2001:838:35f:2::]:100
ip6 test-ip6 postrouting
@@ -21,5 +21,5 @@ ip6 test-ip6 postrouting
[ immediate reg 1 0x38080120 0x01005f03 0x00000000 0x00000000 ]
[ immediate reg 2 0x38080120 0x02005f03 0x00000000 0x00000000 ]
[ immediate reg 3 0x00006400 ]
- [ nat snat ip6 addr_min reg 1 addr_max reg 2 proto_min reg 3 proto_max reg 0 ]
+ [ nat snat ip6 addr_min reg 1 addr_max reg 2 proto_min reg 3 proto_max reg 0 flags 0x2 ]
diff --git a/tests/py/ip6/tcpopt.t b/tests/py/ip6/tcpopt.t
deleted file mode 100644
index 497f69fc..00000000
--- a/tests/py/ip6/tcpopt.t
+++ /dev/null
@@ -1,37 +0,0 @@
-:input;type filter hook input priority 0
-*ip6;test-ip6;input
-
-tcp option eol kind 1;ok
-tcp option noop kind 1;ok
-tcp option maxseg kind 1;ok
-tcp option maxseg length 1;ok
-tcp option maxseg size 1;ok
-tcp option window kind 1;ok
-tcp option window length 1;ok
-tcp option window count 1;ok
-tcp option sack-permitted kind 1;ok
-tcp option sack-permitted length 1;ok
-tcp option sack kind 1;ok
-tcp option sack length 1;ok
-tcp option sack left 1;ok
-tcp option sack0 left 1;ok;tcp option sack left 1
-tcp option sack1 left 1;ok
-tcp option sack2 left 1;ok
-tcp option sack3 left 1;ok
-tcp option sack right 1;ok
-tcp option sack0 right 1;ok;tcp option sack right 1
-tcp option sack1 right 1;ok
-tcp option sack2 right 1;ok
-tcp option sack3 right 1;ok
-tcp option timestamp kind 1;ok
-tcp option timestamp length 1;ok
-tcp option timestamp tsval 1;ok
-tcp option timestamp tsecr 1;ok
-
-tcp option foobar;fail
-tcp option foo bar;fail
-tcp option eol left;fail
-tcp option eol left 1;fail
-tcp option eol left 1;fail
-tcp option sack window;fail
-tcp option sack window 1;fail
diff --git a/tests/py/ip6/tcpopt.t.json b/tests/py/ip6/tcpopt.t.json
deleted file mode 100644
index d573dd1c..00000000
--- a/tests/py/ip6/tcpopt.t.json
+++ /dev/null
@@ -1,416 +0,0 @@
-# tcp option eol kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "eol"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option noop kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "noop"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option maxseg kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "maxseg"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option maxseg length 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "length",
- "name": "maxseg"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option maxseg size 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "size",
- "name": "maxseg"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option window kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "window"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option window length 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "length",
- "name": "window"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option window count 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "count",
- "name": "window"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack-permitted kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "sack-permitted"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack-permitted length 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "length",
- "name": "sack-permitted"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "sack"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack length 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "length",
- "name": "sack"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack left 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "left",
- "name": "sack"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack0 left 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "left",
- "name": "sack"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack1 left 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "left",
- "name": "sack1"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack2 left 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "left",
- "name": "sack2"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack3 left 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "left",
- "name": "sack3"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack right 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "right",
- "name": "sack"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack0 right 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "right",
- "name": "sack0"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack1 right 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "right",
- "name": "sack1"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack2 right 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "right",
- "name": "sack2"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option sack3 right 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "right",
- "name": "sack3"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option timestamp kind 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "kind",
- "name": "timestamp"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option timestamp length 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "length",
- "name": "timestamp"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option timestamp tsval 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "tsval",
- "name": "timestamp"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
-# tcp option timestamp tsecr 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "tsecr",
- "name": "timestamp"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
diff --git a/tests/py/ip6/tcpopt.t.json.output b/tests/py/ip6/tcpopt.t.json.output
deleted file mode 100644
index 81dd8ad8..00000000
--- a/tests/py/ip6/tcpopt.t.json.output
+++ /dev/null
@@ -1,16 +0,0 @@
-# tcp option sack0 right 1
-[
- {
- "match": {
- "left": {
- "tcp option": {
- "field": "right",
- "name": "sack"
- }
- },
- "op": "==",
- "right": 1
- }
- }
-]
-
diff --git a/tests/py/ip6/tcpopt.t.payload b/tests/py/ip6/tcpopt.t.payload
deleted file mode 100644
index 4b189197..00000000
--- a/tests/py/ip6/tcpopt.t.payload
+++ /dev/null
@@ -1,181 +0,0 @@
-# tcp option eol kind 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 0 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option noop kind 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 1 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option maxseg kind 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 2 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option maxseg length 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 2 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option maxseg size 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 2b @ 2 + 2 => reg 1 ]
- [ cmp eq reg 1 0x00000100 ]
-
-# tcp option window kind 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 3 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option window length 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 3 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option window count 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 3 + 2 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack-permitted kind 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 4 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack-permitted length 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 4 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack kind 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 5 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack length 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 5 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option sack left 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack0 left 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 2 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack1 left 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 10 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack2 left 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 18 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack3 left 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 26 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack right 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack0 right 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 6 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack1 right 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 14 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack2 right 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 22 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option sack3 right 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 5 + 30 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option timestamp kind 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 8 + 0 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option timestamp length 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 1b @ 8 + 1 => reg 1 ]
- [ cmp eq reg 1 0x00000001 ]
-
-# tcp option timestamp tsval 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 8 + 2 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
-
-# tcp option timestamp tsecr 1
-ip6 test-ip input
- [ meta load l4proto => reg 1 ]
- [ cmp eq reg 1 0x00000006 ]
- [ exthdr load tcpopt 4b @ 8 + 6 => reg 1 ]
- [ cmp eq reg 1 0x01000000 ]
diff --git a/tests/shell/run-tests.sh b/tests/shell/run-tests.sh
index 2c415489..26f8f46d 100755
--- a/tests/shell/run-tests.sh
+++ b/tests/shell/run-tests.sh
@@ -122,7 +122,7 @@ do
if [ "$DUMPGEN" == "y" ] && [ "$rc_got" == 0 ] && [ ! -f "${dumpfile}" ]; then
mkdir -p "${dumppath}"
- nft list ruleset > "${dumpfile}"
+ $NFT list ruleset > "${dumpfile}"
fi
else
((failed++))
diff --git a/tests/shell/testcases/flowtable/0006segfault_0 b/tests/shell/testcases/flowtable/0006segfault_0
index de590b77..fb7c52fe 100755
--- a/tests/shell/testcases/flowtable/0006segfault_0
+++ b/tests/shell/testcases/flowtable/0006segfault_0
@@ -9,6 +9,3 @@ $NFT add flowtable ip t f { hook ingress priority 10\; devices = { lo } }
$NFT add flowtable ip t f { hook ingress\; priority 10\; }
[[ $? -eq 1 ]] || exit 1
-
-$NFT add flowtable ip t f { hook ingress priority 10\; }
-[[ $? -eq 1 ]] || exit 1
diff --git a/tests/shell/testcases/maps/dumps/nat_addr_port.nft b/tests/shell/testcases/maps/dumps/nat_addr_port.nft
new file mode 100644
index 00000000..89c3bd14
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/nat_addr_port.nft
@@ -0,0 +1,129 @@
+table ip ipfoo {
+ map t1 {
+ typeof numgen inc mod 2 : ip daddr
+ }
+
+ map t2 {
+ typeof numgen inc mod 2 : ip daddr . tcp dport
+ }
+
+ map x {
+ type ipv4_addr : ipv4_addr
+ }
+
+ map y {
+ type ipv4_addr : ipv4_addr . inet_service
+ elements = { 192.168.7.2 : 10.1.1.1 . 4242 }
+ }
+
+ map z {
+ type ipv4_addr . inet_service : ipv4_addr . inet_service
+ elements = { 192.168.7.2 . 42 : 10.1.1.1 . 4242 }
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ iifname != "foobar" accept
+ dnat to ip daddr map @x
+ ip saddr 10.1.1.1 dnat to 10.2.3.4
+ ip saddr 10.1.1.2 tcp dport 42 dnat to 10.2.3.4:4242
+ meta l4proto tcp dnat ip addr . port to ip saddr map @y
+ dnat ip addr . port to ip saddr . tcp dport map @z
+ dnat to numgen inc mod 2 map @t1
+ meta l4proto tcp dnat ip addr . port to numgen inc mod 2 map @t2
+ }
+}
+table ip6 ip6foo {
+ map t1 {
+ typeof numgen inc mod 2 : ip6 daddr
+ }
+
+ map t2 {
+ typeof numgen inc mod 2 : ip6 daddr . tcp dport
+ }
+
+ map x {
+ type ipv6_addr : ipv6_addr
+ }
+
+ map y {
+ type ipv6_addr : ipv6_addr . inet_service
+ }
+
+ map z {
+ type ipv6_addr . inet_service : ipv6_addr . inet_service
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ iifname != "foobar" accept
+ dnat to ip6 daddr map @x
+ ip6 saddr dead::1 dnat to feed::1
+ ip6 saddr dead::2 tcp dport 42 dnat to [c0::1a]:4242
+ meta l4proto tcp dnat ip6 addr . port to ip6 saddr map @y
+ dnat ip6 addr . port to ip6 saddr . tcp dport map @z
+ dnat to numgen inc mod 2 map @t1
+ meta l4proto tcp dnat ip6 addr . port to numgen inc mod 2 map @t2
+ }
+}
+table inet inetfoo {
+ map t1v4 {
+ typeof numgen inc mod 2 : ip daddr
+ }
+
+ map t2v4 {
+ typeof numgen inc mod 2 : ip daddr . tcp dport
+ }
+
+ map t1v6 {
+ typeof numgen inc mod 2 : ip6 daddr
+ }
+
+ map t2v6 {
+ typeof numgen inc mod 2 : ip6 daddr . tcp dport
+ }
+
+ map x4 {
+ type ipv4_addr : ipv4_addr
+ }
+
+ map y4 {
+ type ipv4_addr : ipv4_addr . inet_service
+ }
+
+ map z4 {
+ type ipv4_addr . inet_service : ipv4_addr . inet_service
+ elements = { 192.168.7.2 . 42 : 10.1.1.1 . 4242 }
+ }
+
+ map x6 {
+ type ipv6_addr : ipv6_addr
+ }
+
+ map y6 {
+ type ipv6_addr : ipv6_addr . inet_service
+ }
+
+ map z6 {
+ type ipv6_addr . inet_service : ipv6_addr . inet_service
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ iifname != "foobar" accept
+ dnat ip to ip daddr map @x4
+ ip saddr 10.1.1.1 dnat ip to 10.2.3.4
+ ip saddr 10.1.1.2 tcp dport 42 dnat ip to 10.2.3.4:4242
+ meta l4proto tcp meta nfproto ipv4 dnat ip addr . port to ip saddr map @y4
+ meta nfproto ipv4 dnat ip addr . port to ip saddr . tcp dport map @z4
+ dnat ip to numgen inc mod 2 map @t1v4
+ meta l4proto tcp dnat ip addr . port to numgen inc mod 2 map @t2v4
+ dnat ip6 to ip6 daddr map @x6
+ ip6 saddr dead::1 dnat ip6 to feed::1
+ ip6 saddr dead::2 tcp dport 42 dnat ip6 to [c0::1a]:4242
+ meta l4proto tcp meta nfproto ipv6 dnat ip6 addr . port to ip6 saddr map @y6
+ meta nfproto ipv6 dnat ip6 addr . port to ip6 saddr . tcp dport map @z6
+ dnat ip6 to numgen inc mod 2 map @t1v6
+ meta l4proto tcp dnat ip6 addr . port to numgen inc mod 2 map @t2v6
+ }
+}
diff --git a/tests/shell/testcases/maps/dumps/typeof_maps_0.nft b/tests/shell/testcases/maps/dumps/typeof_maps_0.nft
index 4361ca3d..faa73cd1 100644
--- a/tests/shell/testcases/maps/dumps/typeof_maps_0.nft
+++ b/tests/shell/testcases/maps/dumps/typeof_maps_0.nft
@@ -9,8 +9,15 @@ table inet t {
elements = { 1 : 0x00000001, 4095 : 0x00004095 }
}
+ map m3 {
+ typeof ip saddr . ip daddr : meta mark
+ elements = { 1.2.3.4 . 5.6.7.8 : 0x00000001,
+ 2.3.4.5 . 6.7.8.9 : 0x00000002 }
+ }
+
chain c {
ct mark set osf name map @m1
meta mark set vlan id map @m2
+ meta mark set ip saddr . ip daddr map @m3
}
}
diff --git a/tests/shell/testcases/maps/dumps/typeof_maps_update_0.nft b/tests/shell/testcases/maps/dumps/typeof_maps_update_0.nft
new file mode 100644
index 00000000..698219cb
--- /dev/null
+++ b/tests/shell/testcases/maps/dumps/typeof_maps_update_0.nft
@@ -0,0 +1,21 @@
+table ip kube-nfproxy-v4 {
+ map sticky-set-svc-M53CN2XYVUHRQ7UB {
+ type ipv4_addr : mark
+ size 65535
+ timeout 6m
+ }
+
+ map sticky-set-svc-153CN2XYVUHRQ7UB {
+ typeof ip daddr : meta mark
+ size 65535
+ timeout 1m
+ }
+
+ chain k8s-nfproxy-sep-TMVEFT7EX55F4T62 {
+ update @sticky-set-svc-M53CN2XYVUHRQ7UB { ip saddr : 0x00000002 }
+ }
+
+ chain k8s-nfproxy-sep-GMVEFT7EX55F4T62 {
+ update @sticky-set-svc-153CN2XYVUHRQ7UB { ip saddr : 0x00000003 }
+ }
+}
diff --git a/tests/shell/testcases/maps/nat_addr_port b/tests/shell/testcases/maps/nat_addr_port
new file mode 100755
index 00000000..2804d48c
--- /dev/null
+++ b/tests/shell/testcases/maps/nat_addr_port
@@ -0,0 +1,207 @@
+#!/bin/bash
+
+# skeleton
+$NFT -f /dev/stdin <<EOF || exit 1
+table ip ipfoo {
+ map t1 {
+ typeof numgen inc mod 2 : ip daddr;
+ }
+
+ map t2 {
+ typeof numgen inc mod 2 : ip daddr . tcp dport
+ }
+
+ map x {
+ type ipv4_addr : ipv4_addr
+ }
+ map y {
+ type ipv4_addr : ipv4_addr . inet_service
+ elements = { 192.168.7.2 : 10.1.1.1 . 4242 }
+ }
+ map z {
+ type ipv4_addr . inet_service : ipv4_addr . inet_service
+ elements = { 192.168.7.2 . 42 : 10.1.1.1 . 4242 }
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta iifname != "foobar" accept
+ dnat to ip daddr map @x
+ ip saddr 10.1.1.1 dnat to 10.2.3.4
+ ip saddr 10.1.1.2 tcp dport 42 dnat to 10.2.3.4:4242
+ meta l4proto tcp dnat ip addr . port to ip saddr map @y
+ meta l4proto tcp dnat ip addr . port to ip saddr . tcp dport map @z
+ dnat ip to numgen inc mod 2 map @t1
+ meta l4proto tcp dnat ip addr . port to numgen inc mod 2 map @t2
+ }
+}
+EOF
+
+# should fail: rule has no test for l4 protocol
+$NFT add rule 'ip ipfoo c ip saddr 10.1.1.2 dnat to 10.2.3.4:4242' && exit 1
+
+# should fail: rule has no test for l4 protocol, but map has inet_service
+$NFT add rule 'ip ipfoo c dnat to ip daddr map @y' && exit 1
+
+# skeleton 6
+$NFT -f /dev/stdin <<EOF || exit 1
+table ip6 ip6foo {
+ map t1 {
+ typeof numgen inc mod 2 : ip6 daddr;
+ }
+
+ map t2 {
+ typeof numgen inc mod 2 : ip6 daddr . tcp dport
+ }
+
+ map x {
+ type ipv6_addr : ipv6_addr
+ }
+ map y {
+ type ipv6_addr : ipv6_addr . inet_service
+ }
+ map z {
+ type ipv6_addr . inet_service : ipv6_addr . inet_service
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta iifname != "foobar" accept
+ dnat to ip6 daddr map @x
+ ip6 saddr dead::1 dnat to feed::1
+ ip6 saddr dead::2 tcp dport 42 dnat to [c0::1a]:4242
+ meta l4proto tcp dnat ip6 addr . port to ip6 saddr map @y
+ meta l4proto tcp dnat ip6 addr . port to ip6 saddr . tcp dport map @z
+ dnat ip6 to numgen inc mod 2 map @t1
+ meta l4proto tcp dnat ip6 addr . port to numgen inc mod 2 map @t2
+ }
+}
+EOF
+
+# should fail: rule has no test for l4 protocol
+$NFT add rule 'ip6 ip6foo c ip6 saddr f0:0b::a3 dnat to [1c::3]:42' && exit 1
+
+# should fail: rule has no test for l4 protocol, but map has inet_service
+$NFT add rule 'ip6 ip6foo c dnat to ip daddr map @y' && exit 1
+
+# skeleton inet
+$NFT -f /dev/stdin <<EOF || exit 1
+table inet inetfoo {
+ map t1v4 {
+ typeof numgen inc mod 2 : ip daddr
+ }
+
+ map t2v4 {
+ typeof numgen inc mod 2 : ip daddr . tcp dport;
+ }
+
+ map t1v6 {
+ typeof numgen inc mod 2 : ip6 daddr;
+ }
+
+ map t2v6 {
+ typeof numgen inc mod 2 : ip6 daddr . tcp dport
+ }
+
+ map x4 {
+ type ipv4_addr : ipv4_addr
+ }
+ map y4 {
+ type ipv4_addr : ipv4_addr . inet_service
+ }
+ map z4 {
+ type ipv4_addr . inet_service : ipv4_addr . inet_service
+ elements = { 192.168.7.2 . 42 : 10.1.1.1 . 4242 }
+ }
+ map x6 {
+ type ipv6_addr : ipv6_addr
+ }
+ map y6 {
+ type ipv6_addr : ipv6_addr . inet_service
+ }
+ map z6 {
+ type ipv6_addr . inet_service : ipv6_addr . inet_service
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta iifname != "foobar" accept
+ dnat ip to ip daddr map @x4
+ ip saddr 10.1.1.1 dnat to 10.2.3.4
+ ip saddr 10.1.1.2 tcp dport 42 dnat to 10.2.3.4:4242
+ meta l4proto tcp dnat ip addr . port to ip saddr map @y4
+ meta l4proto tcp dnat ip addr . port to ip saddr . tcp dport map @z4
+ dnat ip to numgen inc mod 2 map @t1v4
+ meta l4proto tcp dnat ip addr . port to numgen inc mod 2 map @t2v4
+ dnat ip6 to ip6 daddr map @x6
+ ip6 saddr dead::1 dnat to feed::1
+ ip6 saddr dead::2 tcp dport 42 dnat to [c0::1a]:4242
+ meta l4proto tcp dnat ip6 addr . port to ip6 saddr map @y6
+ meta l4proto tcp dnat ip6 addr . port to ip6 saddr . tcp dport map @z6
+ dnat ip6 to numgen inc mod 2 map @t1v6
+ meta l4proto tcp dnat ip6 addr . port to numgen inc mod 2 map @t2v6
+ }
+}
+EOF
+
+# should fail: map has wrong family: 4->6
+$NFT add rule 'inet inetfoo c dnat to ip daddr map @x6' && exit 1
+
+# should fail: map has wrong family: 6->4
+$NFT add rule 'inet inetfoo c dnat to ip6 daddr map @x4' && exit 1
+
+# should fail: rule has no test for l4 protocol
+$NFT add rule 'inet inetfoo c ip6 saddr f0:0b::a3 dnat to [1c::3]:42' && exit 1
+
+# should fail: rule has no test for l4 protocol, but map has inet_service
+$NFT add rule 'inet inetfoo c dnat to ip daddr map @y4' && exit 1
+
+# should fail: rule has test for l4 protocol, but map has wrong family: 4->6
+$NFT add rule 'inet inetfoo c meta l4proto tcp dnat to ip daddr map @y6' && exit 1
+
+# should fail: rule has test for l4 protocol, but map has wrong family: 6->4
+$NFT add rule 'inet inetfoo c meta l4proto tcp dnat to ip6 daddr map @y4' && exit 1
+
+# fail: inet_service, but expect ipv4_addr
+$NFT -f /dev/stdin <<EOF && exit 1
+table inet inetfoo {
+ map a {
+ type ipv4_addr : inet_service
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta l4proto tcp dnat ip to ip saddr map @a
+ }
+}
+EOF
+
+# fail: maps to inet_service . inet_service, not addr . service
+$NFT -f /dev/stdin <<EOF && exit 1
+table inet inetfoo {
+ map b {
+ type ipv4_addr : inet_service . inet_service
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta l4proto tcp dnat ip to ip saddr map @a
+ }
+}
+EOF
+
+# fail: only accept exactly two sub-expressions: 'addr . service'
+$NFT -f /dev/stdin <<EOF && exit 1
+table inet inetfoo {
+ map b {
+ type ipv4_addr : inet_addr . inet_service . inet_service
+ }
+
+ chain c {
+ type nat hook prerouting priority dstnat; policy accept;
+ meta l4proto tcp dnat ip to ip saddr map @a
+ }
+}
+EOF
+
+exit 0
diff --git a/tests/shell/testcases/maps/typeof_maps_0 b/tests/shell/testcases/maps/typeof_maps_0
index 950bbf1c..e1c4bba9 100755
--- a/tests/shell/testcases/maps/typeof_maps_0
+++ b/tests/shell/testcases/maps/typeof_maps_0
@@ -16,9 +16,16 @@ EXPECTED="table inet t {
4095 : 0x4095 }
}
+ map m3 {
+ typeof ip saddr . ip daddr : meta mark
+ elements = { 1.2.3.4 . 5.6.7.8 : 0x00000001,
+ 2.3.4.5 . 6.7.8.9 : 0x00000002 }
+ }
+
chain c {
ct mark set osf name map @m1
ether type vlan meta mark set vlan id map @m2
+ meta mark set ip saddr . ip daddr map @m3
}
}"
diff --git a/tests/shell/testcases/maps/typeof_maps_update_0 b/tests/shell/testcases/maps/typeof_maps_update_0
new file mode 100755
index 00000000..c233b13f
--- /dev/null
+++ b/tests/shell/testcases/maps/typeof_maps_update_0
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# check update statement doesn't print "invalid dtype" on the data element.
+
+EXPECTED="table ip kube-nfproxy-v4 {
+ map sticky-set-svc-M53CN2XYVUHRQ7UB {
+ type ipv4_addr : mark
+ size 65535
+ timeout 6m
+ }
+
+ map sticky-set-svc-153CN2XYVUHRQ7UB {
+ typeof ip daddr : meta mark
+ size 65535
+ timeout 1m
+ }
+
+ chain k8s-nfproxy-sep-TMVEFT7EX55F4T62 {
+ update @sticky-set-svc-M53CN2XYVUHRQ7UB { ip saddr : 0x2 }
+ }
+ chain k8s-nfproxy-sep-GMVEFT7EX55F4T62 {
+ update @sticky-set-svc-153CN2XYVUHRQ7UB { ip saddr : 0x3 }
+ }
+}"
+
+set -e
+$NFT -f - <<< $EXPECTED
+
diff --git a/tests/shell/testcases/sets/0025anonymous_set_0 b/tests/shell/testcases/sets/0025anonymous_set_0
index 93a7c022..74777d8e 100755
--- a/tests/shell/testcases/sets/0025anonymous_set_0
+++ b/tests/shell/testcases/sets/0025anonymous_set_0
@@ -14,4 +14,4 @@ $NFT add rule t c ip daddr { \
}
#set : tcp ports
-$NFT add rule t c tcp dport { 22, 23 } counter
+$NFT add rule t c meta oifname \"doesntexist\" tcp dport { 22, 23 } counter
diff --git a/tests/shell/testcases/sets/0034get_element_0 b/tests/shell/testcases/sets/0034get_element_0
index c7e7298a..3343529b 100755
--- a/tests/shell/testcases/sets/0034get_element_0
+++ b/tests/shell/testcases/sets/0034get_element_0
@@ -2,43 +2,69 @@
RC=0
-check() { # (elems, expected)
- out=$($NFT get element ip t s "{ $1 }" 2>/dev/null)
+check() { # (set, elems, expected)
+ out=$($NFT get element ip t $1 "{ $2 }")
out=$(grep "elements =" <<< "$out")
out="${out#* \{ }"
out="${out% \}}"
- [[ "$out" == "$2" ]] && return
- echo "ERROR: asked for '$1', expecting '$2' but got '$out'"
+ [[ "$out" == "$3" ]] && return
+ echo "ERROR: asked for '$2' in set $1, expecting '$3' but got '$out'"
((RC++))
}
RULESET="add table ip t
add set ip t s { type inet_service; flags interval; }
add element ip t s { 10, 20-30, 40, 50-60 }
+add set ip t ips { type ipv4_addr; flags interval; }
+add element ip t ips { 10.0.0.1, 10.0.0.5-10.0.0.8 }
+add element ip t ips { 10.0.0.128/25, 10.0.1.0/24, 10.0.2.3-10.0.2.12 }
+add set ip t cs { type ipv4_addr . inet_service; flags interval; }
+add element ip t cs { 10.0.0.1 . 22, 10.1.0.0/16 . 1-1024 }
+add element ip t cs { 10.2.0.1-10.2.0.8 . 1024-65535 }
"
$NFT -f - <<< "$RULESET"
# simple cases, (non-)existing values and ranges
-check 10 10
-check 11 ""
-check 20-30 20-30
-check 15-18 ""
+check s 10 10
+check s 11 ""
+check s 20-30 20-30
+check s 15-18 ""
# multiple single elements, ranges smaller than present
-check "10, 40" "10, 40"
-check "22-24, 26-28" "20-30, 20-30"
-check 21-29 20-30
+check s "10, 40" "10, 40"
+check s "22-24, 26-28" "20-30, 20-30"
+check s 21-29 20-30
# mixed single elements and ranges
-check "10, 20" "10, 20-30"
-check "10, 22" "10, 20-30"
-check "10, 22-24" "10, 20-30"
+check s "10, 20" "10, 20-30"
+check s "10, 22" "10, 20-30"
+check s "10, 22-24" "10, 20-30"
# non-existing ranges matching elements
-check 10-40 ""
-check 10-20 ""
-check 10-25 ""
-check 25-55 ""
+check s 10-40 ""
+check s 10-20 ""
+check s 10-25 ""
+check s 25-55 ""
+
+# playing with IPs, ranges and prefixes
+check ips 10.0.0.1 10.0.0.1
+check ips 10.0.0.2 ""
+check ips 10.0.1.0/24 10.0.1.0/24
+check ips 10.0.1.2/31 10.0.1.0/24
+check ips 10.0.1.0 10.0.1.0/24
+check ips 10.0.1.3 10.0.1.0/24
+check ips 10.0.1.255 10.0.1.0/24
+check ips 10.0.2.3-10.0.2.12 10.0.2.3-10.0.2.12
+check ips 10.0.2.10 10.0.2.3-10.0.2.12
+check ips 10.0.2.12 10.0.2.3-10.0.2.12
+
+# test concatenated ranges, i.e. Pi, Pa and Po
+check cs "10.0.0.1 . 22" "10.0.0.1 . 22"
+check cs "10.0.0.1 . 23" ""
+check cs "10.0.0.2 . 22" ""
+check cs "10.1.0.1 . 42" "10.1.0.0/16 . 1-1024"
+check cs "10.1.1.0/24 . 10-20" "10.1.0.0/16 . 1-1024"
+check cs "10.2.0.3 . 20000" "10.2.0.1-10.2.0.8 . 1024-65535"
exit $RC
diff --git a/tests/shell/testcases/sets/0043concatenated_ranges_0 b/tests/shell/testcases/sets/0043concatenated_ranges_0
new file mode 100755
index 00000000..a783dacc
--- /dev/null
+++ b/tests/shell/testcases/sets/0043concatenated_ranges_0
@@ -0,0 +1,180 @@
+#!/bin/sh -e
+#
+# 0043concatenated_ranges_0 - Add, get, list, timeout for concatenated ranges
+#
+# Cycle over supported data types, forming concatenations of three fields, for
+# all possible permutations, and:
+# - add entries to set
+# - list them
+# - check that they can't be added again
+# - get entries by specifying a value matching ranges for all fields
+# - delete them
+# - add them with 1s timeout
+# - check that they can't be added again right away
+# - check that they are not listed after 1s, just once, for the first entry
+# - delete them
+# - make sure they can't be deleted again
+
+if [ "$(ps -o comm= $PPID)" = "run-tests.sh" ]; then
+ # Skip some permutations on a full test suite run to keep it quick
+ TYPES="ipv4_addr ipv6_addr ether_addr inet_service"
+else
+ TYPES="ipv4_addr ipv6_addr ether_addr inet_proto inet_service mark"
+fi
+
+RULESPEC_ipv4_addr="ip saddr"
+ELEMS_ipv4_addr="192.0.2.1 198.51.100.0/25 203.0.113.0-203.0.113.129"
+ADD_ipv4_addr="192.0.2.252/31"
+GET_ipv4_addr="198.51.100.127 198.51.100.0/25"
+
+RULESPEC_ipv6_addr="ip6 daddr"
+ELEMS_ipv6_addr="2001:db8:c0c:c0de::1-2001:db8:cacc::a 2001:db8::1 2001:db8:dada:da::/64"
+ADD_ipv6_addr="2001:db8::d1ca:d1ca"
+GET_ipv6_addr="2001:db8::1 2001:db8::1"
+
+RULESPEC_ether_addr="ether saddr"
+ELEMS_ether_addr="00:0a:c1:d1:f1:ed-00:0a:c1:dd:ec:af 00:0b:0c:ca:cc:10-c1:a0:c1:cc:10:00 f0:ca:cc:1a:b0:1a"
+ADD_ether_addr="00:be:1d:ed:ab:e1"
+GET_ether_addr="ac:c1:ac:c0:ce:c0 00:0b:0c:ca:cc:10-c1:a0:c1:cc:10:00"
+
+RULESPEC_inet_proto="meta l4proto"
+ELEMS_inet_proto="tcp udp icmp"
+ADD_inet_proto="sctp"
+GET_inet_proto="udp udp"
+
+RULESPEC_inet_service="tcp dport"
+ELEMS_inet_service="22-23 1024-32768 31337"
+ADD_inet_service="32769-65535"
+GET_inet_service="32768 1024-32768"
+
+RULESPEC_mark="mark"
+ELEMS_mark="0x00000064-0x000000c8 0x0000006f 0x0000fffd-0x0000ffff"
+ADD_mark="0x0000002a"
+GET_mark="0x0000006f 0x0000006f"
+
+tmp="$(mktemp)"
+trap "rm -f ${tmp}" EXIT
+
+render() {
+ eval "echo \"$(cat ${1})\""
+}
+
+cat <<'EOF' > "${tmp}"
+flush ruleset
+
+table inet filter {
+ set test {
+ type ${ta} . ${tb} . ${tc}
+ flags interval,timeout
+ elements = { ${a1} . ${b1} . ${c1} ,
+ ${a2} . ${b2} . ${c2} ,
+ ${a3} . ${b3} . ${c3} }
+ }
+
+ chain output {
+ type filter hook output priority 0; policy accept;
+ ${sa} . ${sb} . ${sc} @test counter
+ }
+}
+EOF
+
+timeout_tested=0
+for ta in ${TYPES}; do
+ eval a=\$ELEMS_${ta}
+ a1=${a%% *}; a2=$(expr "$a" : ".* \(.*\) .*"); a3=${a##* }
+ eval sa=\$RULESPEC_${ta}
+
+ for tb in ${TYPES}; do
+ [ "${tb}" = "${ta}" ] && continue
+ if [ "${tb}" = "ipv6_addr" ]; then
+ [ "${ta}" = "ipv4_addr" ] && continue
+ elif [ "${tb}" = "ipv4_addr" ]; then
+ [ "${ta}" = "ipv6_addr" ] && continue
+ fi
+
+ eval b=\$ELEMS_${tb}
+ b1=${b%% *}; b2=$(expr "$b" : ".* \(.*\) .*"); b3=${b##* }
+ eval sb=\$RULESPEC_${tb}
+
+ for tc in ${TYPES}; do
+ [ "${tc}" = "${ta}" ] && continue
+ [ "${tc}" = "${tb}" ] && continue
+ if [ "${tc}" = "ipv6_addr" ]; then
+ [ "${ta}" = "ipv4_addr" ] && continue
+ [ "${tb}" = "ipv4_addr" ] && continue
+ elif [ "${tc}" = "ipv4_addr" ]; then
+ [ "${ta}" = "ipv6_addr" ] && continue
+ [ "${tb}" = "ipv6_addr" ] && continue
+ fi
+
+ echo "TYPE: ${ta} ${tb} ${tc}"
+
+ eval c=\$ELEMS_${tc}
+ c1=${c%% *}; c2=$(expr "$c" : ".* \(.*\) .*"); c3=${c##* }
+ eval sc=\$RULESPEC_${tc}
+
+ render ${tmp} | ${NFT} -f -
+
+ [ $(${NFT} list set inet filter test | \
+ grep -c -e "${a1} . ${b1} . ${c1}" \
+ -e "${a2} . ${b2} . ${c2}" \
+ -e "${a3} . ${b3} . ${c3}") -eq 3 ]
+
+ ! ${NFT} "add element inet filter test \
+ { ${a1} . ${b1} . ${c1} };
+ add element inet filter test \
+ { ${a2} . ${b2} . ${c2} };
+ add element inet filter test \
+ { ${a3} . ${b3} . ${c3} }" 2>/dev/null
+
+ ${NFT} delete element inet filter test \
+ "{ ${a1} . ${b1} . ${c1} }"
+ ! ${NFT} delete element inet filter test \
+ "{ ${a1} . ${b1} . ${c1} }" 2>/dev/null
+
+ eval add_a=\$ADD_${ta}
+ eval add_b=\$ADD_${tb}
+ eval add_c=\$ADD_${tc}
+ ${NFT} add element inet filter test \
+ "{ ${add_a} . ${add_b} . ${add_c} timeout 1s}"
+ [ $(${NFT} list set inet filter test | \
+ grep -c "${add_a} . ${add_b} . ${add_c}") -eq 1 ]
+ ! ${NFT} add element inet filter test \
+ "{ ${add_a} . ${add_b} . ${add_c} timeout 1s}" \
+ 2>/dev/null
+
+ eval get_a=\$GET_${ta}
+ eval get_b=\$GET_${tb}
+ eval get_c=\$GET_${tc}
+ exp_a=${get_a##* }; get_a=${get_a%% *}
+ exp_b=${get_b##* }; get_b=${get_b%% *}
+ exp_c=${get_c##* }; get_c=${get_c%% *}
+ [ $(${NFT} get element inet filter test \
+ "{ ${get_a} . ${get_b} . ${get_c} }" | \
+ grep -c "${exp_a} . ${exp_b} . ${exp_c}") -eq 1 ]
+
+ ${NFT} "delete element inet filter test \
+ { ${a2} . ${b2} . ${c2} };
+ delete element inet filter test \
+ { ${a3} . ${b3} . ${c3} }"
+ ! ${NFT} "delete element inet filter test \
+ { ${a2} . ${b2} . ${c2} };
+ delete element inet filter test \
+ { ${a3} . ${b3} . ${c3} }" 2>/dev/null
+
+ if [ ${timeout_tested} -eq 1 ]; then
+ ${NFT} delete element inet filter test \
+ "{ ${add_a} . ${add_b} . ${add_c} }"
+ ! ${NFT} delete element inet filter test \
+ "{ ${add_a} . ${add_b} . ${add_c} }" \
+ 2>/dev/null
+ continue
+ fi
+
+ sleep 1
+ [ $(${NFT} list set inet filter test | \
+ grep -c "${add_a} . ${add_b} . ${add_c}") -eq 0 ]
+ timeout_tested=1
+ done
+ done
+done
diff --git a/tests/shell/testcases/sets/0044interval_overlap_0 b/tests/shell/testcases/sets/0044interval_overlap_0
new file mode 100755
index 00000000..fad92ddc
--- /dev/null
+++ b/tests/shell/testcases/sets/0044interval_overlap_0
@@ -0,0 +1,66 @@
+#!/bin/sh -e
+#
+# 0044interval_overlap_0 - Add overlapping and non-overlapping intervals
+#
+# Check that adding overlapping intervals to a set returns an error, unless:
+# - the inserted element overlaps entirely, that is, it's identical to an
+# existing one
+# - for concatenated ranges, the new element is less specific than any existing
+# overlapping element, as elements are evaluated in order of insertion
+
+# Accept Interval List
+intervals_simple="
+ y 0 - 2 0-2
+ y 0 - 2 0-2
+ n 0 - 1 0-2
+ n 0 - 3 0-2
+ y 3 - 10 0-2, 3-10
+ n 3 - 9 0-2, 3-10
+ n 4 - 10 0-2, 3-10
+ n 4 - 9 0-2, 3-10
+ y 20 - 30 0-2, 3-10, 20-30
+ y 11 - 12 0-2, 3-10, 11-12, 20-30
+ y 13 - 19 0-2, 3-10, 11-12, 13-19, 20-30
+ n 25 - 40 0-2, 3-10, 11-12, 13-19, 20-30
+ y 50 - 60 0-2, 3-10, 11-12, 13-19, 20-30, 50-60
+ y 31 - 49 0-2, 3-10, 11-12, 13-19, 20-30, 31-49, 50-60
+ n 59 - 60 0-2, 3-10, 11-12, 13-19, 20-30, 31-49, 50-60
+"
+
+intervals_concat="
+ y 0-2 . 0-3 0-2 . 0-3
+ y 0-2 . 0-3 0-2 . 0-3
+ n 0-1 . 0-2 0-2 . 0-3
+ y 10-20 . 30-40 0-2 . 0-3, 10-20 . 30-40
+ n 15-20 . 50-60 0-2 . 0-3, 10-20 . 30-40, 15-20 . 50-60
+ y 3-9 . 4-29 0-2 . 0-3, 10-20 . 30-40, 15-20 . 50-60, 3-9 . 4-29
+ y 3-9 . 4-29 0-2 . 0-3, 10-20 . 30-40, 15-20 . 50-60, 3-9 . 4-29
+ n 11-19 . 30-40 0-2 . 0-3, 10-20 . 30-40, 15-20 . 50-60, 3-9 . 4-29
+ y 15-20 . 49-61 0-2 . 0-3, 10-20 . 30-40, 15-20 . 50-60, 3-9 . 4-29, 15-20 . 49-61
+"
+
+$NFT add table t
+$NFT add set t s '{ type inet_service ; flags interval ; }'
+$NFT add set t c '{ type inet_service . inet_service ; flags interval ; }'
+
+IFS='
+'
+set="s"
+for t in ${intervals_simple} switch ${intervals_concat}; do
+ [ "${t}" = "switch" ] && set="c" && continue
+ [ -z "${pass}" ] && pass="${t}" && continue
+ [ -z "${interval}" ] && interval="${t}" && continue
+
+ if [ "${pass}" = "y" ]; then
+ $NFT add element t ${set} "{ ${interval} }"
+ else
+ ! $NFT add element t ${set} "{ ${interval} }" 2>/dev/null
+ fi
+ $NFT list set t ${set} | tr -d '\n\t' | tr -s ' ' | \
+ grep -q "elements = { ${t} }"
+
+ pass=
+ interval=
+done
+
+unset IFS
diff --git a/tests/shell/testcases/sets/0046netmap_0 b/tests/shell/testcases/sets/0046netmap_0
new file mode 100755
index 00000000..2804a4a2
--- /dev/null
+++ b/tests/shell/testcases/sets/0046netmap_0
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+EXPECTED="table ip x {
+ chain y {
+ type nat hook postrouting priority srcnat; policy accept;
+ snat ip prefix to ip saddr map { 10.141.11.0/24 : 192.168.2.0/24,
+ 10.141.12.0/24 : 192.168.3.0/24,
+ 10.141.13.0/24 : 192.168.4.0/24 }
+ }
+ }
+"
+
+set -e
+$NFT -f - <<< $EXPECTED
diff --git a/tests/shell/testcases/sets/0047nat_0 b/tests/shell/testcases/sets/0047nat_0
new file mode 100755
index 00000000..746a6b6d
--- /dev/null
+++ b/tests/shell/testcases/sets/0047nat_0
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+EXPECTED="table ip x {
+ map y {
+ type ipv4_addr : interval ipv4_addr
+ flags interval
+ elements = { 10.141.10.0/24 : 192.168.2.2-192.168.2.4,
+ 10.141.11.0/24 : 192.168.4.2-192.168.4.3 }
+ }
+
+ chain y {
+ type nat hook postrouting priority srcnat; policy accept;
+ snat ip interval to ip saddr map @y
+ }
+ }
+"
+
+set -e
+$NFT -f - <<< $EXPECTED
+$NFT add element x y { 10.141.12.0/24 : 192.168.5.10-192.168.5.20 }
diff --git a/tests/shell/testcases/sets/dumps/0025anonymous_set_0.nft b/tests/shell/testcases/sets/dumps/0025anonymous_set_0.nft
index 6204b00c..59636994 100644
--- a/tests/shell/testcases/sets/dumps/0025anonymous_set_0.nft
+++ b/tests/shell/testcases/sets/dumps/0025anonymous_set_0.nft
@@ -2,6 +2,6 @@ table ip t {
chain c {
type filter hook output priority filter; policy accept;
ip daddr { 192.168.0.1, 192.168.0.2, 192.168.0.3 }
- tcp dport { 22, 23 } counter packets 0 bytes 0
+ oifname "doesntexist" tcp dport { 22, 23 } counter packets 0 bytes 0
}
}
diff --git a/tests/shell/testcases/sets/dumps/0046netmap_0.nft b/tests/shell/testcases/sets/dumps/0046netmap_0.nft
new file mode 100644
index 00000000..e14c3395
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0046netmap_0.nft
@@ -0,0 +1,6 @@
+table ip x {
+ chain y {
+ type nat hook postrouting priority srcnat; policy accept;
+ snat ip prefix to ip saddr map { 10.141.11.0/24 : 192.168.2.0/24, 10.141.12.0/24 : 192.168.3.0/24, 10.141.13.0/24 : 192.168.4.0/24 }
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/0047nat_0.nft b/tests/shell/testcases/sets/dumps/0047nat_0.nft
new file mode 100644
index 00000000..70730ef3
--- /dev/null
+++ b/tests/shell/testcases/sets/dumps/0047nat_0.nft
@@ -0,0 +1,13 @@
+table ip x {
+ map y {
+ type ipv4_addr : interval ipv4_addr
+ flags interval
+ elements = { 10.141.10.0/24 : 192.168.2.2-192.168.2.4, 10.141.11.0/24 : 192.168.4.2/31,
+ 10.141.12.0/24 : 192.168.5.10-192.168.5.20 }
+ }
+
+ chain y {
+ type nat hook postrouting priority srcnat; policy accept;
+ snat ip interval to ip saddr map @y
+ }
+}
diff --git a/tests/shell/testcases/sets/dumps/typeof_sets_0.nft b/tests/shell/testcases/sets/dumps/typeof_sets_0.nft
index 44e11202..565369fb 100644
--- a/tests/shell/testcases/sets/dumps/typeof_sets_0.nft
+++ b/tests/shell/testcases/sets/dumps/typeof_sets_0.nft
@@ -9,6 +9,11 @@ table inet t {
elements = { 2, 3, 103 }
}
+ set s3 {
+ typeof meta ibrpvid
+ elements = { 2, 3, 103 }
+ }
+
chain c1 {
osf name @s1 accept
}
diff --git a/tests/shell/testcases/sets/typeof_sets_0 b/tests/shell/testcases/sets/typeof_sets_0
index 2a8b21c7..9b2712e5 100755
--- a/tests/shell/testcases/sets/typeof_sets_0
+++ b/tests/shell/testcases/sets/typeof_sets_0
@@ -15,6 +15,11 @@ EXPECTED="table inet t {
elements = { 2, 3, 103 }
}
+ set s3 {
+ typeof meta ibrpvid
+ elements = { 2, 3, 103 }
+ }
+
chain c1 {
osf name @s1 accept
}