summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/nft.xml23
-rw-r--r--include/ct.h3
-rw-r--r--include/expression.h2
-rw-r--r--src/ct.c71
-rw-r--r--src/evaluate.c92
-rw-r--r--src/netlink_delinearize.c52
-rw-r--r--src/parser_bison.y42
-rw-r--r--src/rt.c15
-rw-r--r--tests/py/bridge/icmpX.t4
-rw-r--r--tests/py/inet/ct.t7
-rw-r--r--tests/py/inet/ct.t.payload4
-rw-r--r--tests/py/inet/icmpX.t4
-rw-r--r--tests/py/inet/rt.t10
-rw-r--r--tests/py/inet/rt.t.payload4
-rw-r--r--tests/py/ip/ct.t18
-rw-r--r--tests/py/ip/ct.t.payload16
-rw-r--r--tests/py/ip/rt.t3
-rw-r--r--tests/py/ip6/rt0.t2
18 files changed, 262 insertions, 110 deletions
diff --git a/doc/nft.xml b/doc/nft.xml
index 9d97a782..c0f42ddc 100644
--- a/doc/nft.xml
+++ b/doc/nft.xml
@@ -608,7 +608,6 @@ filter input iif $int_ifs accept
hybrid IPv4/IPv6 tables. The <literal>meta</literal> expression <literal>nfproto</literal>
keyword can be used to test which family (ipv4 or ipv6) context the packet is being processed in.
-
When no address family is specified, <literal>ip</literal> is used by default.
</para>
@@ -2905,8 +2904,8 @@ filter output rt classid 10
# IP family dependent rt expressions
ip filter output rt nexthop 192.168.0.1
ip6 filter output rt nexthop fd00::1
-inet filter meta nfproto ipv4 output rt nexthop 192.168.0.1
-inet filter meta nfproto ipv6 output rt nexthop fd00::1
+inet filter output rt ip nexthop 192.168.0.1
+inet filter output rt ip6 nexthop fd00::1
</programlisting>
</example>
</para>
@@ -4025,8 +4024,6 @@ ip6 filter input frag more-fragments 1 counter
<group choice="req">
<arg>l3proto</arg>
<arg>protocol</arg>
- <arg>saddr</arg>
- <arg>daddr</arg>
<arg>proto-src</arg>
<arg>proto-dst</arg>
<arg>bytes</arg>
@@ -4035,6 +4032,22 @@ ip6 filter input frag more-fragments 1 counter
<arg>zone</arg>
</group>
</cmdsynopsis>
+ <cmdsynopsis>
+ <command>ct</command>
+ <group choice="req">
+ <arg>original</arg>
+ <arg>reply</arg>
+ </group>
+ <group choice="req">
+ <arg>ip</arg>
+ <arg>ip6</arg>
+ </group>
+ <group choice="req">
+ <arg>saddr</arg>
+ <arg>daddr</arg>
+ </group>
+ </cmdsynopsis>
+
</para>
<para>
<table frame="all">
diff --git a/include/ct.h b/include/ct.h
index d9a11a3f..ec5d55d8 100644
--- a/include/ct.h
+++ b/include/ct.h
@@ -24,7 +24,8 @@ struct ct_template {
}
extern struct expr *ct_expr_alloc(const struct location *loc,
- enum nft_ct_keys key, int8_t direction);
+ enum nft_ct_keys key, int8_t direction,
+ uint8_t nfproto);
extern void ct_expr_update_type(struct proto_ctx *ctx, struct expr *expr);
extern struct stmt *notrack_stmt_alloc(const struct location *loc);
diff --git a/include/expression.h b/include/expression.h
index ce6b702a..215cbc98 100644
--- a/include/expression.h
+++ b/include/expression.h
@@ -300,7 +300,9 @@ struct expr {
struct {
/* EXPR_CT */
enum nft_ct_keys key;
+ enum proto_bases base;
int8_t direction;
+ uint8_t nfproto;
} ct;
struct {
/* EXPR_NUMGEN */
diff --git a/src/ct.c b/src/ct.c
index b2faf627..58b873e7 100644
--- a/src/ct.c
+++ b/src/ct.c
@@ -16,6 +16,8 @@
#include <inttypes.h>
#include <string.h>
+#include <netinet/ip.h>
+#include <linux/netfilter.h>
#include <linux/netfilter/nf_tables.h>
#include <linux/netfilter/nf_conntrack_common.h>
#include <linux/netfilter/nf_conntrack_tuple_common.h>
@@ -269,9 +271,11 @@ static const struct ct_template ct_templates[] = {
BYTEORDER_HOST_ENDIAN, 32),
};
-static void ct_print(enum nft_ct_keys key, int8_t dir, struct output_ctx *octx)
+static void ct_print(enum nft_ct_keys key, int8_t dir, uint8_t nfproto,
+ struct output_ctx *octx)
{
const struct symbolic_constant *s;
+ const struct proto_desc *desc;
nft_print(octx, "ct ");
if (dir < 0)
@@ -283,13 +287,25 @@ static void ct_print(enum nft_ct_keys key, int8_t dir, struct output_ctx *octx)
break;
}
}
+
+ switch (key) {
+ case NFT_CT_SRC: /* fallthrough */
+ case NFT_CT_DST:
+ desc = proto_find_upper(&proto_inet, nfproto);
+ if (desc)
+ printf("%s ", desc->name);
+ break;
+ default:
+ break;
+ }
+
done:
nft_print(octx, "%s", ct_templates[key].token);
}
static void ct_expr_print(const struct expr *expr, struct output_ctx *octx)
{
- ct_print(expr->ct.key, expr->ct.direction, octx);
+ ct_print(expr->ct.key, expr->ct.direction, expr->ct.nfproto, octx);
}
static bool ct_expr_cmp(const struct expr *e1, const struct expr *e2)
@@ -308,21 +324,21 @@ static void ct_expr_clone(struct expr *new, const struct expr *expr)
static void ct_expr_pctx_update(struct proto_ctx *ctx, const struct expr *expr)
{
const struct expr *left = expr->left, *right = expr->right;
- const struct proto_desc *base, *desc;
+ const struct proto_desc *base = NULL, *desc;
+ uint32_t nhproto;
assert(expr->op == OP_EQ);
- switch (left->ct.key) {
- case NFT_CT_PROTOCOL:
- base = ctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
- desc = proto_find_upper(base, mpz_get_uint32(right->value));
+ nhproto = mpz_get_uint32(right->value);
- proto_ctx_update(ctx, PROTO_BASE_TRANSPORT_HDR,
- &expr->location, desc);
- break;
- default:
- break;
- }
+ base = ctx->protocol[left->ct.base].desc;
+ if (!base)
+ return;
+ desc = proto_find_upper(base, nhproto);
+ if (!desc)
+ return;
+
+ proto_ctx_update(ctx, left->ct.base + 1, &expr->location, desc);
}
static const struct expr_ops ct_expr_ops = {
@@ -335,7 +351,7 @@ static const struct expr_ops ct_expr_ops = {
};
struct expr *ct_expr_alloc(const struct location *loc, enum nft_ct_keys key,
- int8_t direction)
+ int8_t direction, uint8_t nfproto)
{
const struct ct_template *tmpl = &ct_templates[key];
struct expr *expr;
@@ -344,10 +360,24 @@ struct expr *ct_expr_alloc(const struct location *loc, enum nft_ct_keys key,
tmpl->byteorder, tmpl->len);
expr->ct.key = key;
expr->ct.direction = direction;
+ expr->ct.nfproto = nfproto;
switch (key) {
+ case NFT_CT_SRC:
+ case NFT_CT_DST:
+ expr->ct.base = PROTO_BASE_NETWORK_HDR;
+ break;
+ case NFT_CT_PROTO_SRC:
+ case NFT_CT_PROTO_DST:
+ expr->ct.base = PROTO_BASE_TRANSPORT_HDR;
+ break;
case NFT_CT_PROTOCOL:
expr->flags = EXPR_F_PROTOCOL;
+ expr->ct.base = PROTO_BASE_NETWORK_HDR;
+ break;
+ case NFT_CT_L3PROTOCOL:
+ expr->flags = EXPR_F_PROTOCOL;
+ expr->ct.base = PROTO_BASE_LL_HDR;
break;
default:
break;
@@ -360,20 +390,23 @@ void ct_expr_update_type(struct proto_ctx *ctx, struct expr *expr)
{
const struct proto_desc *desc;
+ desc = ctx->protocol[expr->ct.base].desc;
+
switch (expr->ct.key) {
case NFT_CT_SRC:
case NFT_CT_DST:
- desc = ctx->protocol[PROTO_BASE_NETWORK_HDR].desc;
- if (desc == &proto_ip)
+ if (desc == &proto_ip) {
expr->dtype = &ipaddr_type;
- else if (desc == &proto_ip6)
+ expr->ct.nfproto = NFPROTO_IPV4;
+ } else if (desc == &proto_ip6) {
expr->dtype = &ip6addr_type;
+ expr->ct.nfproto = NFPROTO_IPV6;
+ }
expr->len = expr->dtype->size;
break;
case NFT_CT_PROTO_SRC:
case NFT_CT_PROTO_DST:
- desc = ctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc;
if (desc == NULL)
break;
expr->dtype = &inet_service_type;
@@ -385,7 +418,7 @@ void ct_expr_update_type(struct proto_ctx *ctx, struct expr *expr)
static void ct_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
{
- ct_print(stmt->ct.key, stmt->ct.direction, octx);
+ ct_print(stmt->ct.key, stmt->ct.direction, 0, octx);
nft_print(octx, " set ");
expr_print(stmt->ct.expr, octx);
}
diff --git a/src/evaluate.c b/src/evaluate.c
index c796c3c3..ca9180b7 100644
--- a/src/evaluate.c
+++ b/src/evaluate.c
@@ -662,32 +662,28 @@ static int expr_evaluate_payload(struct eval_ctx *ctx, struct expr **exprp)
return 0;
}
-static int expr_error_base(struct list_head *msgs, const struct expr *e)
-{
- return expr_error(msgs, e,
- "meta nfproto ipv4 or ipv6 must be specified "
- "before %s expression", e->ops->name);
-}
-
/*
* RT expression: validate protocol dependencies.
*/
static int expr_evaluate_rt(struct eval_ctx *ctx, struct expr **expr)
{
- const struct proto_desc *base;
+ static const char emsg[] = "cannot determine ip protocol version, use \"ip nexthop\" or \"ip6 nexthop\" instead";
struct expr *rt = *expr;
rt_expr_update_type(&ctx->pctx, rt);
- base = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
switch (rt->rt.key) {
case NFT_RT_NEXTHOP4:
- if (base != &proto_ip)
- return expr_error_base(ctx->msgs, rt);
+ if (rt->dtype != &ipaddr_type)
+ return expr_error(ctx->msgs, rt, "%s", emsg);
+ if (ctx->pctx.family == NFPROTO_IPV6)
+ return expr_error(ctx->msgs, rt, "%s nexthop will not match", "ip");
break;
case NFT_RT_NEXTHOP6:
- if (base != &proto_ip6)
- return expr_error_base(ctx->msgs, rt);
+ if (rt->dtype != &ip6addr_type)
+ return expr_error(ctx->msgs, rt, "%s", emsg);
+ if (ctx->pctx.family == NFPROTO_IPV4)
+ return expr_error(ctx->msgs, rt, "%s nexthop will not match", "ip6");
break;
default:
break;
@@ -696,27 +692,85 @@ static int expr_evaluate_rt(struct eval_ctx *ctx, struct expr **expr)
return expr_evaluate_primary(ctx, expr);
}
+static int ct_gen_nh_dependency(struct eval_ctx *ctx, struct expr *ct)
+{
+ const struct proto_desc *base, *base_now;
+ struct expr *left, *right, *dep;
+ struct stmt *nstmt = NULL;
+
+ base_now = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
+
+ switch (ct->ct.nfproto) {
+ case NFPROTO_IPV4:
+ base = &proto_ip;
+ break;
+ case NFPROTO_IPV6:
+ base = &proto_ip6;
+ break;
+ default:
+ base = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
+ if (base == &proto_ip)
+ ct->ct.nfproto = NFPROTO_IPV4;
+ else if (base == &proto_ip)
+ ct->ct.nfproto = NFPROTO_IPV6;
+
+ if (base)
+ break;
+
+ return expr_error(ctx->msgs, ct,
+ "cannot determine ip protocol version, use \"ip %1$caddr\" or \"ip6 %1$caddr\" instead",
+ ct->ct.key == NFT_CT_SRC ? 's' : 'd');
+ }
+
+ /* no additional dependency needed? */
+ if (base == base_now)
+ return 0;
+
+ if (base_now && base_now != base)
+ return expr_error(ctx->msgs, ct,
+ "conflicting dependencies: %s vs. %s\n",
+ base->name,
+ ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc->name);
+ switch (ctx->pctx.family) {
+ case NFPROTO_IPV4:
+ case NFPROTO_IPV6:
+ return 0;
+ }
+
+ left = ct_expr_alloc(&ct->location, NFT_CT_L3PROTOCOL, ct->ct.direction, ct->ct.nfproto);
+
+ right = constant_expr_alloc(&ct->location, left->dtype,
+ left->dtype->byteorder, left->len,
+ constant_data_ptr(ct->ct.nfproto, left->len));
+ dep = relational_expr_alloc(&ct->location, OP_EQ, left, right);
+
+ left->ops->pctx_update(&ctx->pctx, dep);
+
+ nstmt = expr_stmt_alloc(&dep->location, dep);
+
+ list_add_tail(&nstmt->list, &ctx->stmt->list);
+ return 0;
+}
+
/*
* CT expression: update the protocol dependant types bases on the protocol
* context.
*/
static int expr_evaluate_ct(struct eval_ctx *ctx, struct expr **expr)
{
- const struct proto_desc *base;
struct expr *ct = *expr;
- ct_expr_update_type(&ctx->pctx, ct);
-
- base = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc;
switch (ct->ct.key) {
case NFT_CT_SRC:
case NFT_CT_DST:
- if (base != &proto_ip && base != &proto_ip6)
- return expr_error_base(ctx->msgs, ct);
+ ct_gen_nh_dependency(ctx, ct);
+ break;
default:
break;
}
+ ct_expr_update_type(&ctx->pctx, ct);
+
return expr_evaluate_primary(ctx, expr);
}
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 42206ebc..44328879 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -716,7 +716,7 @@ static void netlink_parse_ct_expr(struct netlink_parse_ctx *ctx,
dir = nftnl_expr_get_u8(nle, NFTNL_EXPR_CT_DIR);
key = nftnl_expr_get_u32(nle, NFTNL_EXPR_CT_KEY);
- expr = ct_expr_alloc(loc, key, dir);
+ expr = ct_expr_alloc(loc, key, dir, NFPROTO_UNSPEC);
dreg = netlink_parse_register(nle, NFTNL_EXPR_CT_DREG);
netlink_set_register(ctx, dreg, expr);
@@ -1385,12 +1385,29 @@ static void payload_match_postprocess(struct rule_pp_ctx *ctx,
}
}
-static void ct_meta_common_postprocess(const struct expr *expr)
+static void ct_meta_common_postprocess(struct rule_pp_ctx *ctx,
+ const struct expr *expr,
+ enum proto_bases base)
{
const struct expr *left = expr->left;
struct expr *right = expr->right;
switch (expr->op) {
+ case OP_EQ:
+ if (expr->right->ops->type == EXPR_RANGE)
+ break;
+
+ expr->left->ops->pctx_update(&ctx->pctx, expr);
+
+ if (ctx->pdctx.pbase == PROTO_BASE_INVALID &&
+ left->flags & EXPR_F_PROTOCOL) {
+ payload_dependency_store(&ctx->pdctx, ctx->stmt, base);
+ } else if (ctx->pdctx.pbase < PROTO_BASE_TRANSPORT_HDR) {
+ __payload_dependency_kill(&ctx->pdctx, base);
+ if (left->flags & EXPR_F_PROTOCOL)
+ payload_dependency_store(&ctx->pdctx, ctx->stmt, base);
+ }
+ break;
case OP_NEQ:
if (right->ops->type != EXPR_SET && right->ops->type != EXPR_SET_REF)
break;
@@ -1406,40 +1423,17 @@ static void ct_meta_common_postprocess(const struct expr *expr)
static void meta_match_postprocess(struct rule_pp_ctx *ctx,
const struct expr *expr)
{
- struct expr *left = expr->left;
-
- switch (expr->op) {
- case OP_EQ:
- if (expr->right->ops->type == EXPR_RANGE)
- break;
-
- expr->left->ops->pctx_update(&ctx->pctx, expr);
+ const struct expr *left = expr->left;
- if (ctx->pdctx.pbase == PROTO_BASE_INVALID &&
- left->flags & EXPR_F_PROTOCOL)
- payload_dependency_store(&ctx->pdctx, ctx->stmt,
- left->meta.base);
- break;
- default:
- ct_meta_common_postprocess(expr);
- break;
- }
+ ct_meta_common_postprocess(ctx, expr, left->meta.base);
}
static void ct_match_postprocess(struct rule_pp_ctx *ctx,
const struct expr *expr)
{
- switch (expr->op) {
- case OP_EQ:
- if (expr->right->ops->type == EXPR_RANGE)
- break;
+ const struct expr *left = expr->left;
- expr->left->ops->pctx_update(&ctx->pctx, expr);
- break;
- default:
- ct_meta_common_postprocess(expr);
- break;
- }
+ ct_meta_common_postprocess(ctx, expr, left->ct.base);
}
/* Convert a bitmask to a prefix length */
diff --git a/src/parser_bison.y b/src/parser_bison.y
index 75a77358..f996d9d9 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -665,11 +665,11 @@ static void location_update(struct location *loc, struct location *rhs, int n)
%type <expr> rt_expr
%destructor { expr_free($$); } rt_expr
-%type <val> rt_key
+%type <val> rt_key_proto rt_key
%type <expr> ct_expr
%destructor { expr_free($$); } ct_expr
-%type <val> ct_key ct_dir ct_key_dir_optional ct_key_dir
+%type <val> ct_key ct_dir ct_key_dir_optional ct_key_dir ct_key_proto ct_key_proto_field
%type <expr> fib_expr
%destructor { expr_free($$); } fib_expr
@@ -3246,10 +3246,32 @@ hash_expr : JHASH expr MOD NUM SEED NUM offset_opt
}
;
+rt_key_proto : IP { $$ = NFPROTO_IPV4; }
+ | IP6 { $$ = NFPROTO_IPV6; }
+ ;
+
rt_expr : RT rt_key
{
$$ = rt_expr_alloc(&@$, $2, true);
}
+ | RT rt_key_proto rt_key
+ {
+ enum nft_rt_keys rtk = $3;
+
+ switch ($2) {
+ case NFPROTO_IPV4:
+ break;
+ case NFPROTO_IPV6:
+ if ($3 == NFT_RT_NEXTHOP4)
+ rtk = NFT_RT_NEXTHOP6;
+ break;
+ default:
+ YYERROR;
+ break;
+ }
+
+ $$ = rt_expr_alloc(&@$, rtk, false);
+ }
;
rt_key : CLASSID { $$ = NFT_RT_CLASSID; }
@@ -3259,11 +3281,15 @@ rt_key : CLASSID { $$ = NFT_RT_CLASSID; }
ct_expr : CT ct_key
{
- $$ = ct_expr_alloc(&@$, $2, -1);
+ $$ = ct_expr_alloc(&@$, $2, -1, NFPROTO_UNSPEC);
}
| CT ct_dir ct_key_dir
{
- $$ = ct_expr_alloc(&@$, $3, $2);
+ $$ = ct_expr_alloc(&@$, $3, $2, NFPROTO_UNSPEC);
+ }
+ | CT ct_dir ct_key_proto ct_key_proto_field
+ {
+ $$ = ct_expr_alloc(&@$, $4, $2, $3);
}
;
@@ -3297,6 +3323,14 @@ ct_key_dir : SADDR { $$ = NFT_CT_SRC; }
| ct_key_dir_optional
;
+ct_key_proto : IP { $$ = NFPROTO_IPV4; }
+ | IP6 { $$ = NFPROTO_IPV6; }
+ ;
+
+ct_key_proto_field : SADDR { $$ = NFT_CT_SRC; }
+ | DADDR { $$ = NFT_CT_DST; }
+ ;
+
ct_key_dir_optional : BYTES { $$ = NFT_CT_BYTES; }
| PACKETS { $$ = NFT_CT_PKTS; }
| AVGPKT { $$ = NFT_CT_AVGPKT; }
diff --git a/src/rt.c b/src/rt.c
index 9ad9e398..041dbc2f 100644
--- a/src/rt.c
+++ b/src/rt.c
@@ -82,7 +82,20 @@ static const struct rt_template rt_templates[] = {
static void rt_expr_print(const struct expr *expr, struct output_ctx *octx)
{
- nft_print(octx, "rt %s", rt_templates[expr->rt.key].token);
+ const char *ip = "";
+
+ switch (expr->rt.key) {
+ case NFT_RT_NEXTHOP4:
+ ip = "ip ";
+ break;
+ case NFT_RT_NEXTHOP6:
+ ip = "ip6 ";
+ break;
+ default:
+ break;
+ }
+
+ nft_print(octx, "rt %s%s", ip, rt_templates[expr->rt.key].token);
}
static bool rt_expr_cmp(const struct expr *e1, const struct expr *e2)
diff --git a/tests/py/bridge/icmpX.t b/tests/py/bridge/icmpX.t
index 0a1019c3..8c0a5979 100644
--- a/tests/py/bridge/icmpX.t
+++ b/tests/py/bridge/icmpX.t
@@ -3,6 +3,6 @@
*bridge;test-bridge;input
ip protocol icmp icmp type echo-request;ok;icmp type echo-request
-icmp type echo-request;ok;ether type ip meta l4proto 1 icmp type echo-request
+icmp type echo-request;ok
ip6 nexthdr icmpv6 icmpv6 type echo-request;ok;icmpv6 type echo-request
-icmpv6 type echo-request;ok;ether type ip6 meta l4proto 58 icmpv6 type echo-request
+icmpv6 type echo-request;ok
diff --git a/tests/py/inet/ct.t b/tests/py/inet/ct.t
index c56c3bc8..1a656aa4 100644
--- a/tests/py/inet/ct.t
+++ b/tests/py/inet/ct.t
@@ -3,8 +3,11 @@
*inet;test-inet;input
-meta nfproto ipv4 ct original saddr 1.2.3.4;ok
-meta nfproto ipv6 ct original saddr ::1;ok
+meta nfproto ipv4 ct original saddr 1.2.3.4;ok;ct original ip saddr 1.2.3.4
+ct original ip6 saddr ::1;ok
# missing protocol context
ct original saddr ::1;fail
+
+# wrong protocol context
+ct original ip saddr ::1;fail
diff --git a/tests/py/inet/ct.t.payload b/tests/py/inet/ct.t.payload
index 21c74581..97128ecc 100644
--- a/tests/py/inet/ct.t.payload
+++ b/tests/py/inet/ct.t.payload
@@ -5,9 +5,9 @@ ip test-ip4 output
[ ct load src => reg 1 , dir original ]
[ cmp eq reg 1 0x04030201 ]
-# meta nfproto ipv6 ct original saddr ::1
+# ct original ip6 saddr ::1
inet test-inet input
- [ meta load nfproto => reg 1 ]
+ [ ct load l3protocol => reg 1 , dir original ]
[ cmp eq reg 1 0x0000000a ]
[ ct load src => reg 1 , dir original ]
[ cmp eq reg 1 0x00000000 0x00000000 0x00000000 0x01000000 ]
diff --git a/tests/py/inet/icmpX.t b/tests/py/inet/icmpX.t
index 7617e701..1b467a18 100644
--- a/tests/py/inet/icmpX.t
+++ b/tests/py/inet/icmpX.t
@@ -3,6 +3,6 @@
*inet;test-inet;input
ip protocol icmp icmp type echo-request;ok;icmp type echo-request
-icmp type echo-request;ok;meta nfproto ipv4 meta l4proto 1 icmp type echo-request
+icmp type echo-request;ok
ip6 nexthdr icmpv6 icmpv6 type echo-request;ok;icmpv6 type echo-request
-icmpv6 type echo-request;ok;meta nfproto ipv6 meta l4proto 58 icmpv6 type echo-request
+icmpv6 type echo-request;ok
diff --git a/tests/py/inet/rt.t b/tests/py/inet/rt.t
index 9543738b..23608ab2 100644
--- a/tests/py/inet/rt.t
+++ b/tests/py/inet/rt.t
@@ -4,7 +4,13 @@
rt nexthop 192.168.0.1;fail
rt nexthop fd00::1;fail
-meta nfproto ipv4 rt nexthop 192.168.0.1;ok
-meta nfproto ipv6 rt nexthop fd00::1;ok
+
+meta nfproto ipv4 rt nexthop 192.168.0.1;ok;meta nfproto ipv4 rt ip nexthop 192.168.0.1
+rt ip6 nexthop fd00::1;ok
+
+# missing context
+rt nexthop fd00::1;fail
+# wrong context
+rt ip nexthop fd00::1;fail
tcp option maxseg size set rt mtu;ok
diff --git a/tests/py/inet/rt.t.payload b/tests/py/inet/rt.t.payload
index 928e0095..84dea12c 100644
--- a/tests/py/inet/rt.t.payload
+++ b/tests/py/inet/rt.t.payload
@@ -5,10 +5,8 @@ inet test-inet output
[ rt load nexthop4 => reg 1 ]
[ cmp eq reg 1 0x0100a8c0 ]
-# meta nfproto ipv6 rt nexthop fd00::1
+# rt ip6 nexthop fd00::1
inet test-inet output
- [ meta load nfproto => reg 1 ]
- [ cmp eq reg 1 0x0000000a ]
[ rt load nexthop6 => reg 1 ]
[ cmp eq reg 1 0x000000fd 0x00000000 0x00000000 0x01000000 ]
diff --git a/tests/py/ip/ct.t b/tests/py/ip/ct.t
index d0f16c51..d3247f79 100644
--- a/tests/py/ip/ct.t
+++ b/tests/py/ip/ct.t
@@ -2,16 +2,16 @@
*ip;test-ip4;output
-ct original saddr 192.168.0.1;ok
-ct reply saddr 192.168.0.1;ok
-ct original daddr 192.168.0.1;ok
-ct reply daddr 192.168.0.1;ok
+ct original ip saddr 192.168.0.1;ok
+ct reply ip saddr 192.168.0.1;ok
+ct original ip daddr 192.168.0.1;ok
+ct reply ip daddr 192.168.0.1;ok
# same, but with a netmask
-ct original saddr 192.168.1.0/24;ok
-ct reply saddr 192.168.1.0/24;ok
-ct original daddr 192.168.1.0/24;ok
-ct reply daddr 192.168.1.0/24;ok
+ct original ip saddr 192.168.1.0/24;ok
+ct reply ip saddr 192.168.1.0/24;ok
+ct original ip daddr 192.168.1.0/24;ok
+ct reply ip daddr 192.168.1.0/24;ok
ct l3proto ipv4;ok
ct l3proto foobar;fail
@@ -20,4 +20,4 @@ ct protocol 6 ct original proto-dst 22;ok
ct original protocol 17 ct reply proto-src 53;ok;ct protocol 17 ct reply proto-src 53
# wrong address family
-ct reply daddr dead::beef;fail
+ct reply ip daddr dead::beef;fail
diff --git a/tests/py/ip/ct.t.payload b/tests/py/ip/ct.t.payload
index 56633a24..b7cd130d 100644
--- a/tests/py/ip/ct.t.payload
+++ b/tests/py/ip/ct.t.payload
@@ -1,42 +1,42 @@
-# ct original saddr 192.168.0.1
+# ct original ip saddr 192.168.0.1
ip test-ip4 output
[ ct load src => reg 1 , dir original ]
[ cmp eq reg 1 0x0100a8c0 ]
-# ct reply saddr 192.168.0.1
+# ct reply ip saddr 192.168.0.1
ip test-ip4 output
[ ct load src => reg 1 , dir reply ]
[ cmp eq reg 1 0x0100a8c0 ]
-# ct original daddr 192.168.0.1
+# ct original ip daddr 192.168.0.1
ip test-ip4 output
[ ct load dst => reg 1 , dir original ]
[ cmp eq reg 1 0x0100a8c0 ]
-# ct reply daddr 192.168.0.1
+# ct reply ip daddr 192.168.0.1
ip test-ip4 output
[ ct load dst => reg 1 , dir reply ]
[ cmp eq reg 1 0x0100a8c0 ]
-# ct original saddr 192.168.1.0/24
+# ct original ip saddr 192.168.1.0/24
ip test-ip4 output
[ ct load src => reg 1 , dir original ]
[ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0001a8c0 ]
-# ct reply saddr 192.168.1.0/24
+# ct reply ip saddr 192.168.1.0/24
ip test-ip4 output
[ ct load src => reg 1 , dir reply ]
[ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0001a8c0 ]
-# ct original daddr 192.168.1.0/24
+# ct original ip daddr 192.168.1.0/24
ip test-ip4 output
[ ct load dst => reg 1 , dir original ]
[ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
[ cmp eq reg 1 0x0001a8c0 ]
-# ct reply daddr 192.168.1.0/24
+# ct reply ip daddr 192.168.1.0/24
ip test-ip4 output
[ ct load dst => reg 1 , dir reply ]
[ bitwise reg 1 = (reg=1 & 0x00ffffff ) ^ 0x00000000 ]
diff --git a/tests/py/ip/rt.t b/tests/py/ip/rt.t
index 99750c5d..986bf341 100644
--- a/tests/py/ip/rt.t
+++ b/tests/py/ip/rt.t
@@ -2,5 +2,6 @@
*ip;test-ip4;output
-rt nexthop 192.168.0.1;ok
+rt nexthop 192.168.0.1;ok;rt ip nexthop 192.168.0.1
rt nexthop fd00::1;fail
+rt ip6 nexthop fd00::1;fail
diff --git a/tests/py/ip6/rt0.t b/tests/py/ip6/rt0.t
index 92614de3..1d50a89c 100644
--- a/tests/py/ip6/rt0.t
+++ b/tests/py/ip6/rt0.t
@@ -3,4 +3,4 @@
*ip6;test-ip6;output
rt nexthop 192.168.0.1;fail
-rt nexthop fd00::1;ok
+rt nexthop fd00::1;ok;rt ip6 nexthop fd00::1