nftables remove use of meta nfproto
Florian Westphal
maintainercover nftables remove use of meta nfproto
inet family (and others, e.g. bridge) lack context to figure out the layer 3 address type.
examples:
ct original saddr $addr
rt nexthop $addr
We can't use $addr, because it might be a set reference, e.g.
ct original saddr @whitelist
currently implemented workaround is to use 'meta nfproto' to provide the l3 context, e.g.
meta nfproto ip rt nexthop 10.2.3.4
i.e. users need to fill dependency manually.
Pablo suggested to instead specify ip saddr, ip6 saddr:
ct original ip saddr $address
and then let nft handle the dependency injection.
This series does just that.
Old syntax is preserved.
doc/nft.xml | 23 ++++++++--- include/ct.h | 3 - include/expression.h | 2 src/ct.c | 70 ++++++++++++++++++++++++---------- src/evaluate.c | 92 +++++++++++++++++++++++++++++++++++---------- src/netlink_delinearize.c | 52 +++++++++++-------------- src/parser_bison.y | 42 ++++++++++++++++++-- src/rt.c | 14 ++++++ tests/py/bridge/icmpX.t | 4 - tests/py/inet/ct.t | 7 ++- tests/py/inet/ct.t.payload | 4 - tests/py/inet/icmpX.t | 4 - tests/py/inet/rt.t | 10 +++- tests/py/inet/rt.t.payload | 4 - tests/py/ip/ct.t | 18 ++++---- tests/py/ip/ct.t.payload | 16 +++---- tests/py/ip/rt.t | 3 - tests/py/ip6/rt0.t | 2 18 files changed, 260 insertions(+), 110 deletions(-)
Florian Westphal
maintainerPATCH 1/10 src: add alternate syntax for ct saddr
current syntax is:
ct original saddr $address
problem is that in inet, bridge etc. we lack context to figure out if this should fetch ipv6 or ipv4 from the conntrack structure.
$address might not exist, rhs could e.g. be a set reference.
One way to do this is to have users manually specifiy the dependeny:
ct l3proto ipv4 ct original saddr $address
Thats ugly, and, moreover, only needed for table families other than ip or ipv6.
Pablo suggested to instead specify ip saddr, ip6 saddr:
ct original ip saddr $address
and let nft handle the dependency injection.
This adds the required parts to the scanner and the grammar, next commit adds code to eval step to make use of this.
--- include/ct.h | 3 ++- include/expression.h | 1 + src/ct.c | 3 ++- src/netlink_delinearize.c | 2 +- src/parser_bison.y | 18 +++++++++++++++--- 5 files changed, 21 insertions(+), 6 deletions(-)
include/ct.h +2 -1
@@ -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);
include/expression.h +1 -0
@@ -301,6 +301,7 @@ struct expr {/* EXPR_CT */ enum nft_ct_keys key;int8_t direction; +uint8_t nfproto; } ct;struct {/* EXPR_NUMGEN */
src/ct.c +2 -1
@@ -335,7 +335,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,6 +344,7 @@ 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_PROTOCOL :
src/netlink_delinearize.c +1 -1
@@ -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);
src/parser_bison.y +15 -3
@@ -668,7 +668,7 @@ static void location_update(struct location *loc, struct location *rhs, int n) %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
@@ -3258,11 +3258,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); } ;
@@ -3296,6 +3300,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; }
Signature · 1 line
2.13.5
Florian Westphal
maintainerPATCH 2/10 src: ct: store proto base of ct key, if any
In reply to Florian Westphalct keys can match on network and tranasport header protocol elements, such as port numbers or ip addresses.
Store this base type so a followup commit can store and kill dependencies, e.g. if bsae is network header we might be able to kill an earlier expression because the dependency is implicit.
--- include/expression.h | 1 + src/ct.c | 13 +++++++++++++ 2 files changed, 14 insertions(+)
include/expression.h +1 -0
@@ -300,6 +300,7 @@ struct expr {struct {/* EXPR_CT */ enum nft_ct_keys key; +enum proto_bases base;int8_t direction;uint8_t nfproto; } ct;
src/ct.c +13 -0
@@ -347,8 +347,21 @@ struct expr *ct_expr_alloc(const struct location *loc, enum nft_ct_keys key, 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 ;
Signature · 1 line
2.13.5
Florian Westphal
maintainerPATCH 3/10 src: ct: add eval part to inject dependencies for ct saddr/daddr
In reply to Florian Westphalnft has enough context to determine if a dependeny is needed.
add rule ip filter ct original ip6 saddr
allows nft to generate an error due to conflicting bases (ip vs ip6).
add rule inet filter ct original ip6 saddr allows nft to inject an ipv6 dependency expression.
add rule inet filter ct original saddr
will print an error and will suggest to add ip/ip6 keyword.
Delinerize and print support will be added in followup patches.
--- src/ct.c | 26 +++++++++++----------- src/evaluate.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 77 insertions(+), 19 deletions(-)
src/ct.c +13 -13
@@ -308,21 +308,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 = {
@@ -374,10 +374,11 @@ 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) expr->dtype = &ipaddr_type;else if (desc == &proto_ip6)
@@ -387,7 +388,6 @@ void ct_expr_update_type(struct proto_ctx *ctx, struct expr *expr)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;
src/evaluate.c +64 -6
91 lines not on this page · raw message
Signature · 1 line
2.13.5
Florian Westphal
maintainerPATCH 4/10 src: unifiy meta and ct postprocessing
In reply to Florian WestphalQuoted 1 line
From postprocess point of view meta and ct are logically the same,
except that their storage area overlaps (union type), so if we extract the relevant fields we can move all of it into a single helper and support dependency store/kill for both expressions.
--- src/netlink_delinearize.c | 50 +++++++++++++++++++++-------------------------- 1 file changed, 22 insertions(+), 28 deletions(-)
src/netlink_delinearize.c +22 -28
@@ -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 */
Signature · 1 line
2.13.5
Florian Westphal
maintainerPATCH 5/10 tests: update inet/bridge icmp test case
In reply to Florian Westphalafter previous change nft now culls the dependency chain:
'icmpv6 type echo-request' is shown as-is, and not
'meta nfproto ipv6 meta l4proto 58 icmpv6 type echo-request' anymore.
--- tests/py/bridge/icmpX.t | 4 ++-- tests/py/inet/icmpX.t | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-)
tests/py/bridge/icmpX.t +2 -2
@@ -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
tests/py/inet/icmpX.t +2 -2
@@ -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
Signature · 1 line
2.13.5
Florian Westphal
maintainerPATCH 6/10 src: ct: print nfproto name for some header fields
In reply to Florian Westphalthis prints "original saddr|daddr $NFPROTO" to make output symmetric with the syntax that we now prefer on input side.
--- src/ct.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-)
src/ct.c +23 -5
@@ -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,10 @@ static const struct ct_template ct_templates[] = { BYTEORDER_HOST_ENDIAN, 32), }; -static void ct_print (enum nft_ct_keys key,int8_t dir) +static void ct_print (enum nft_ct_keys key,int8_t dir,uint8_t nfproto) {const struct symbolic_constant *s; +const struct proto_desc *desc;printf ("ct " );if (dir <0 )
@@ -283,13 +286,25 @@ static void ct_print(enum nft_ct_keys key, int8_t dir)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:printf ("%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); +ct_print (expr->ct.key, expr->ct.direction, expr->ct.nfproto); }static bool ct_expr_cmp (const struct expr *e1,const struct expr *e2)
@@ -379,10 +394,13 @@ void ct_expr_update_type(struct proto_ctx *ctx, struct expr *expr)switch (expr->ct.key) {case NFT_CT_SRC :case NFT_CT_DST : -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 ;
@@ -399,7 +417,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); +ct_print (stmt->ct.key, stmt->ct.direction,0 );printf (" set " );expr_print (stmt->ct.expr, octx); }
Signature · 1 line
2.13.5
Florian Westphal
maintainerPATCH 7/10 tests: ct: adjust test case commands
In reply to Florian Westphaluse 'ip saddr', 'ip6 saddr', etc.
--- tests/py/inet/ct.t | 7 +++++-- tests/py/inet/ct.t.payload | 4 ++-- tests/py/ip/ct.t | 18 +++++++++--------- tests/py/ip/ct.t.payload | 16 ++++++++-------- 4 files changed, 24 insertions(+), 21 deletions(-)
tests/py/inet/ct.t +5 -2
@@ -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
tests/py/inet/ct.t.payload +2 -2
@@ -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 ]
tests/py/ip/ct.t +9 -9
@@ -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
tests/py/ip/ct.t.payload +8 -8
@@ -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 ]
Signature · 1 line
2.13.5
Florian Westphal
maintainerPATCH 8/10 src: rt: add keyword distinction for nexthop vs nexthop6
In reply to Florian Westphalthe rt expression currently always sets NFT_RT_NEXTHOP4 and then uses the network base to determine if its really supposed to be NEXTHOP6.
For inet, this will fail because the network base is not known, so this currently enforces need for "meta nfproto" to dermine the type.
Allow following syntax instead:
rt ip nexthop
rt ip6 nexthop
There is no need for a dependency anymore, as rt expression checks the hook protocol, ie. NEXTHOP4 will break if the hook pf is not NFPROTO_IPV4.
--- src/evaluate.c | 22 +++++++++------------- src/parser_bison.y | 24 +++++++++++++++++++++++- src/rt.c | 14 +++++++++++++- 3 files changed, 45 insertions(+), 15 deletions(-)
src/evaluate.c +9 -13
@@ -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 ;
src/parser_bison.y +23 -1
@@ -664,7 +664,7 @@ 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
@@ -3245,10 +3245,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; }
src/rt.c +13 -1
@@ -82,7 +82,19 @@ static const struct rt_template rt_templates[] = {static void rt_expr_print (const struct expr *expr,struct output_ctx *octx) { -printf ("rt %s" , rt_templates[expr->rt.key].token); +printf ("rt " ); + +switch (expr->rt.key) { +case NFT_RT_NEXTHOP4 : +printf ("ip " ); +break ; +case NFT_RT_NEXTHOP6 : +printf ("ip6 " ); +break ; +default : +break ; + } +printf ("%s" , rt_templates[expr->rt.key].token); }static bool rt_expr_cmp (const struct expr *e1,const struct expr *e2)
Signature · 1 line
2.13.5
Florian Westphal
maintainerPATCH 9/10 tests: rt: fix test cases
In reply to Florian Westphalnfproto meta dependency is no longer needed, keep one test since we still support this syntax.
When meta is not provided, no need to add a dependency because nft_rt already checks pf number before checking skb->dst.
--- tests/py/inet/rt.t | 10 ++++++++-- tests/py/inet/rt.t.payload | 4 +--- tests/py/ip/rt.t | 3 ++- tests/py/ip6/rt0.t | 2 +- 4 files changed, 12 insertions(+), 7 deletions(-)
tests/py/inet/rt.t +8 -2
@@ -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
tests/py/inet/rt.t.payload +1 -3
@@ -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 ]
tests/py/ip/rt.t +2 -1
@@ -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
tests/py/ip6/rt0.t +1 -1
@@ -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
Signature · 1 line
2.13.5
Florian Westphal
maintainerPATCH 10/10 doc: update man page
In reply to Florian Westphalyou can now use "rt ip|ip6 nexthop" and "ct original|reply ip|ip6 saddr|daddr" to tell nft if you want to match ipv4 or ipv6.
--- doc/nft.xml | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-)
doc/nft.xml +18 -5
@@ -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">
Signature · 1 line
2.13.5
Quoted 20 lines · Florian Westphal
inet family (and others, e.g. bridge) lack context to figure out the layer 3 address type.
examples:
ct original saddr $addr
rt nexthop $addrWe can't use $addr, because it might be a set reference, e.g.
ct original saddr @whitelist
currently implemented workaround is to use 'meta nfproto' to provide the l3 context, e.g.
meta nfproto ip rt nexthop 10.2.3.4
i.e. users need to fill dependency manually.
Pablo suggested to instead specify ip saddr, ip6 saddr:
Quoted 7 lines
ct original ip saddr $address
and then let nft handle the dependency injection.
This series does just that.
Old syntax is preserved.
Nice series, thanks Florian.