From patchwork Mon Oct 17 11:03:53 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pablo Neira Ayuso X-Patchwork-Id: 1690839 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=2620:137:e000::1:20; helo=out1.vger.email; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Received: from out1.vger.email (out1.vger.email [IPv6:2620:137:e000::1:20]) by legolas.ozlabs.org (Postfix) with ESMTP id 4MrYz868vLz23kV for ; Mon, 17 Oct 2022 22:04:20 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229506AbiJQLET (ORCPT ); Mon, 17 Oct 2022 07:04:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34284 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229815AbiJQLES (ORCPT ); Mon, 17 Oct 2022 07:04:18 -0400 Received: from mail.netfilter.org (mail.netfilter.org [217.70.188.207]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 56A5710C8 for ; Mon, 17 Oct 2022 04:04:16 -0700 (PDT) From: Pablo Neira Ayuso To: netfilter-devel@vger.kernel.org Subject: [PATCH nft,v2 01/16] src: add eval_proto_ctx() Date: Mon, 17 Oct 2022 13:03:53 +0200 Message-Id: <20221017110408.742223-2-pablo@netfilter.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221017110408.742223-1-pablo@netfilter.org> References: <20221017110408.742223-1-pablo@netfilter.org> MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Add eval_proto_ctx() to access protocol context (struct proto_ctx). Rename struct proto_ctx field to _pctx to highlight that this field is internal and the helper function should be used. This patch comes in preparation for supporting outer and inner protocol context. Signed-off-by: Pablo Neira Ayuso --- include/proto.h | 3 + include/rule.h | 2 +- src/evaluate.c | 188 +++++++++++++++++++++++++++++------------------- src/payload.c | 58 +++++++++------ 4 files changed, 154 insertions(+), 97 deletions(-) diff --git a/include/proto.h b/include/proto.h index 35e760c7e16e..6a9289b17f05 100644 --- a/include/proto.h +++ b/include/proto.h @@ -413,4 +413,7 @@ extern const struct datatype icmp6_type_type; extern const struct datatype dscp_type; extern const struct datatype ecn_type; +struct eval_ctx; +struct proto_ctx *eval_proto_ctx(struct eval_ctx *ctx); + #endif /* NFTABLES_PROTO_H */ diff --git a/include/rule.h b/include/rule.h index ad9f91273722..795951326886 100644 --- a/include/rule.h +++ b/include/rule.h @@ -768,7 +768,7 @@ struct eval_ctx { struct set *set; struct stmt *stmt; struct expr_ctx ectx; - struct proto_ctx pctx; + struct proto_ctx _pctx; }; extern int cmd_evaluate(struct eval_ctx *ctx, struct cmd *cmd); diff --git a/src/evaluate.c b/src/evaluate.c index 0bf6a0d1b110..7f371dc5f569 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -39,6 +39,11 @@ #include #include +struct proto_ctx *eval_proto_ctx(struct eval_ctx *ctx) +{ + return &ctx->_pctx; +} + static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr); static const char * const byteorder_names[] = { @@ -427,11 +432,13 @@ conflict_resolution_gen_dependency(struct eval_ctx *ctx, int protocol, const struct proto_hdr_template *tmpl; const struct proto_desc *desc = NULL; struct expr *dep, *left, *right; + struct proto_ctx *pctx; struct stmt *stmt; assert(expr->payload.base == PROTO_BASE_LL_HDR); - desc = ctx->pctx.protocol[base].desc; + pctx = eval_proto_ctx(ctx); + desc = pctx->protocol[base].desc; tmpl = &desc->templates[desc->protocol_key]; left = payload_expr_alloc(&expr->location, desc, desc->protocol_key); @@ -577,6 +584,7 @@ static int expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp) const struct proto_desc *base, *dependency = NULL; enum proto_bases pb = PROTO_BASE_NETWORK_HDR; struct expr *expr = *exprp; + struct proto_ctx *pctx; struct stmt *nstmt; switch (expr->exthdr.op) { @@ -594,7 +602,8 @@ static int expr_evaluate_exthdr(struct eval_ctx *ctx, struct expr **exprp) assert(dependency); - base = ctx->pctx.protocol[pb].desc; + pctx = eval_proto_ctx(ctx); + base = pctx->protocol[pb].desc; if (base == dependency) return __expr_evaluate_exthdr(ctx, exprp); @@ -657,8 +666,11 @@ static int resolve_protocol_conflict(struct eval_ctx *ctx, { enum proto_bases base = payload->payload.base; struct stmt *nstmt = NULL; + struct proto_ctx *pctx; int link, err; + pctx = eval_proto_ctx(ctx); + if (payload->payload.base == PROTO_BASE_LL_HDR) { if (proto_is_dummy(desc)) { err = meta_iiftype_gen_dependency(ctx, payload, &nstmt); @@ -671,8 +683,8 @@ static int resolve_protocol_conflict(struct eval_ctx *ctx, unsigned int i; /* payload desc stored in the L2 header stack? No conflict. */ - for (i = 0; i < ctx->pctx.stacked_ll_count; i++) { - if (ctx->pctx.stacked_ll[i] == payload->payload.desc) + for (i = 0; i < pctx->stacked_ll_count; i++) { + if (pctx->stacked_ll[i] == payload->payload.desc) return 0; } } @@ -680,7 +692,7 @@ static int resolve_protocol_conflict(struct eval_ctx *ctx, assert(base <= PROTO_BASE_MAX); /* This payload and the existing context don't match, conflict. */ - if (ctx->pctx.protocol[base + 1].desc != NULL) + if (pctx->protocol[base + 1].desc != NULL) return 1; link = proto_find_num(desc, payload->payload.desc); @@ -691,8 +703,8 @@ static int resolve_protocol_conflict(struct eval_ctx *ctx, if (base == PROTO_BASE_LL_HDR) { unsigned int i; - for (i = 0; i < ctx->pctx.stacked_ll_count; i++) - payload->payload.offset += ctx->pctx.stacked_ll[i]->length; + for (i = 0; i < pctx->stacked_ll_count; i++) + payload->payload.offset += pctx->stacked_ll[i]->length; } rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt); @@ -710,19 +722,22 @@ static int __expr_evaluate_payload(struct eval_ctx *ctx, struct expr *expr) struct expr *payload = expr; enum proto_bases base = payload->payload.base; const struct proto_desc *desc; + struct proto_ctx *pctx; struct stmt *nstmt; int err; if (expr->etype == EXPR_PAYLOAD && expr->payload.is_raw) return 0; - desc = ctx->pctx.protocol[base].desc; + pctx = eval_proto_ctx(ctx); + desc = pctx->protocol[base].desc; if (desc == NULL) { if (payload_gen_dependency(ctx, payload, &nstmt) < 0) return -1; rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt); - desc = ctx->pctx.protocol[base].desc; + + desc = pctx->protocol[base].desc; if (desc == expr->payload.desc) goto check_icmp; @@ -738,15 +753,16 @@ static int __expr_evaluate_payload(struct eval_ctx *ctx, struct expr *expr) desc->name, payload->payload.desc->name); - payload->payload.offset += ctx->pctx.stacked_ll[0]->length; + payload->payload.offset += pctx->stacked_ll[0]->length; rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt); return 1; } + goto check_icmp; } if (payload->payload.base == desc->base && - proto_ctx_is_ambiguous(&ctx->pctx, base)) { - desc = proto_ctx_find_conflict(&ctx->pctx, base, payload->payload.desc); + proto_ctx_is_ambiguous(pctx, base)) { + desc = proto_ctx_find_conflict(pctx, base, payload->payload.desc); assert(desc); return expr_error(ctx->msgs, payload, @@ -764,8 +780,8 @@ static int __expr_evaluate_payload(struct eval_ctx *ctx, struct expr *expr) if (desc->base == PROTO_BASE_LL_HDR) { unsigned int i; - for (i = 0; i < ctx->pctx.stacked_ll_count; i++) - payload->payload.offset += ctx->pctx.stacked_ll[i]->length; + for (i = 0; i < pctx->stacked_ll_count; i++) + payload->payload.offset += pctx->stacked_ll[i]->length; } check_icmp: if (desc != &proto_icmp && desc != &proto_icmp6) @@ -792,13 +808,13 @@ check_icmp: if (err <= 0) return err; - desc = ctx->pctx.protocol[base].desc; + desc = pctx->protocol[base].desc; if (desc == payload->payload.desc) return 0; } return expr_error(ctx->msgs, payload, "conflicting protocols specified: %s vs. %s", - ctx->pctx.protocol[base].desc->name, + pctx->protocol[base].desc->name, payload->payload.desc->name); } @@ -836,20 +852,22 @@ static int expr_evaluate_rt(struct eval_ctx *ctx, struct expr **expr) { static const char emsg[] = "cannot determine ip protocol version, use \"ip nexthop\" or \"ip6 nexthop\" instead"; struct expr *rt = *expr; + struct proto_ctx *pctx; - rt_expr_update_type(&ctx->pctx, rt); + pctx = eval_proto_ctx(ctx); + rt_expr_update_type(pctx, rt); switch (rt->rt.key) { case NFT_RT_NEXTHOP4: if (rt->dtype != &ipaddr_type) return expr_error(ctx->msgs, rt, "%s", emsg); - if (ctx->pctx.family == NFPROTO_IPV6) + if (pctx->family == NFPROTO_IPV6) return expr_error(ctx->msgs, rt, "%s nexthop will not match", "ip"); break; case NFT_RT_NEXTHOP6: if (rt->dtype != &ip6addr_type) return expr_error(ctx->msgs, rt, "%s", emsg); - if (ctx->pctx.family == NFPROTO_IPV4) + if (pctx->family == NFPROTO_IPV4) return expr_error(ctx->msgs, rt, "%s nexthop will not match", "ip6"); break; default: @@ -864,8 +882,10 @@ 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; + struct proto_ctx *pctx; - base_now = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc; + pctx = eval_proto_ctx(ctx); + base_now = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc; switch (ct->ct.nfproto) { case NFPROTO_IPV4: @@ -875,7 +895,7 @@ static int ct_gen_nh_dependency(struct eval_ctx *ctx, struct expr *ct) base = &proto_ip6; break; default: - base = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc; + base = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc; if (base == &proto_ip) ct->ct.nfproto = NFPROTO_IPV4; else if (base == &proto_ip) @@ -897,8 +917,8 @@ static int ct_gen_nh_dependency(struct eval_ctx *ctx, struct expr *ct) 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) { + pctx->protocol[PROTO_BASE_NETWORK_HDR].desc->name); + switch (pctx->family) { case NFPROTO_IPV4: case NFPROTO_IPV6: return 0; @@ -911,7 +931,7 @@ static int ct_gen_nh_dependency(struct eval_ctx *ctx, struct expr *ct) constant_data_ptr(ct->ct.nfproto, left->len)); dep = relational_expr_alloc(&ct->location, OP_EQ, left, right); - relational_expr_pctx_update(&ctx->pctx, dep); + relational_expr_pctx_update(pctx, dep); nstmt = expr_stmt_alloc(&dep->location, dep); rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt); @@ -927,8 +947,10 @@ static int expr_evaluate_ct(struct eval_ctx *ctx, struct expr **expr) { const struct proto_desc *base, *error; struct expr *ct = *expr; + struct proto_ctx *pctx; - base = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc; + pctx = eval_proto_ctx(ctx); + base = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc; switch (ct->ct.key) { case NFT_CT_SRC: @@ -953,13 +975,13 @@ static int expr_evaluate_ct(struct eval_ctx *ctx, struct expr **expr) break; } - ct_expr_update_type(&ctx->pctx, ct); + ct_expr_update_type(pctx, ct); return expr_evaluate_primary(ctx, expr); err_conflict: return stmt_binary_error(ctx, ct, - &ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR], + &pctx->protocol[PROTO_BASE_NETWORK_HDR], "conflicting protocols specified: %s vs. %s", base->name, error->name); } @@ -2113,6 +2135,7 @@ static bool range_needs_swap(const struct expr *range) static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr) { struct expr *rel = *expr, *left, *right; + struct proto_ctx *pctx; struct expr *range; int ret; @@ -2120,6 +2143,8 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr) return -1; left = rel->left; + pctx = eval_proto_ctx(ctx); + if (rel->right->etype == EXPR_RANGE && lhs_is_meta_hour(rel->left)) { ret = __expr_evaluate_range(ctx, &rel->right); if (ret) @@ -2187,7 +2212,7 @@ static int expr_evaluate_relational(struct eval_ctx *ctx, struct expr **expr) * Update protocol context for payload and meta iiftype * equality expressions. */ - relational_expr_pctx_update(&ctx->pctx, rel); + relational_expr_pctx_update(pctx, rel); /* fall through */ case OP_NEQ: @@ -2299,11 +2324,12 @@ static int expr_evaluate_fib(struct eval_ctx *ctx, struct expr **exprp) static int expr_evaluate_meta(struct eval_ctx *ctx, struct expr **exprp) { + struct proto_ctx *pctx = eval_proto_ctx(ctx); struct expr *meta = *exprp; switch (meta->meta.key) { case NFT_META_NFPROTO: - if (ctx->pctx.family != NFPROTO_INET && + if (pctx->family != NFPROTO_INET && meta->flags & EXPR_F_PROTOCOL) return expr_error(ctx->msgs, meta, "meta nfproto is only useful in the inet family"); @@ -2370,9 +2396,10 @@ static int expr_evaluate_variable(struct eval_ctx *ctx, struct expr **exprp) static int expr_evaluate_xfrm(struct eval_ctx *ctx, struct expr **exprp) { + struct proto_ctx *pctx = eval_proto_ctx(ctx); struct expr *expr = *exprp; - switch (ctx->pctx.family) { + switch (pctx->family) { case NFPROTO_IPV4: case NFPROTO_IPV6: case NFPROTO_INET: @@ -2815,9 +2842,10 @@ static int reject_payload_gen_dependency_tcp(struct eval_ctx *ctx, struct stmt *stmt, struct expr **payload) { + struct proto_ctx *pctx = eval_proto_ctx(ctx); const struct proto_desc *desc; - desc = ctx->pctx.protocol[PROTO_BASE_TRANSPORT_HDR].desc; + desc = pctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc; if (desc != NULL) return 0; *payload = payload_expr_alloc(&stmt->location, &proto_tcp, @@ -2829,9 +2857,10 @@ static int reject_payload_gen_dependency_family(struct eval_ctx *ctx, struct stmt *stmt, struct expr **payload) { + struct proto_ctx *pctx = eval_proto_ctx(ctx); const struct proto_desc *base; - base = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc; + base = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc; if (base != NULL) return 0; @@ -2898,6 +2927,7 @@ static int stmt_evaluate_reject_inet_family(struct eval_ctx *ctx, struct stmt *stmt, const struct proto_desc *desc) { + struct proto_ctx *pctx = eval_proto_ctx(ctx); const struct proto_desc *base; int protocol; @@ -2907,7 +2937,7 @@ static int stmt_evaluate_reject_inet_family(struct eval_ctx *ctx, case NFT_REJECT_ICMPX_UNREACH: break; case NFT_REJECT_ICMP_UNREACH: - base = ctx->pctx.protocol[PROTO_BASE_LL_HDR].desc; + base = pctx->protocol[PROTO_BASE_LL_HDR].desc; protocol = proto_find_num(base, desc); switch (protocol) { case NFPROTO_IPV4: @@ -2915,14 +2945,14 @@ static int stmt_evaluate_reject_inet_family(struct eval_ctx *ctx, if (stmt->reject.family == NFPROTO_IPV4) break; return stmt_binary_error(ctx, stmt->reject.expr, - &ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR], + &pctx->protocol[PROTO_BASE_NETWORK_HDR], "conflicting protocols specified: ip vs ip6"); case NFPROTO_IPV6: case __constant_htons(ETH_P_IPV6): if (stmt->reject.family == NFPROTO_IPV6) break; return stmt_binary_error(ctx, stmt->reject.expr, - &ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR], + &pctx->protocol[PROTO_BASE_NETWORK_HDR], "conflicting protocols specified: ip vs ip6"); default: return stmt_error(ctx, stmt, @@ -2937,9 +2967,10 @@ static int stmt_evaluate_reject_inet_family(struct eval_ctx *ctx, static int stmt_evaluate_reject_inet(struct eval_ctx *ctx, struct stmt *stmt, struct expr *expr) { + struct proto_ctx *pctx = eval_proto_ctx(ctx); const struct proto_desc *desc; - desc = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc; + desc = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc; if (desc != NULL && stmt_evaluate_reject_inet_family(ctx, stmt, desc) < 0) return -1; @@ -2954,13 +2985,14 @@ static int stmt_evaluate_reject_bridge_family(struct eval_ctx *ctx, struct stmt *stmt, const struct proto_desc *desc) { + struct proto_ctx *pctx = eval_proto_ctx(ctx); const struct proto_desc *base; int protocol; switch (stmt->reject.type) { case NFT_REJECT_ICMPX_UNREACH: case NFT_REJECT_TCP_RST: - base = ctx->pctx.protocol[PROTO_BASE_LL_HDR].desc; + base = pctx->protocol[PROTO_BASE_LL_HDR].desc; protocol = proto_find_num(base, desc); switch (protocol) { case __constant_htons(ETH_P_IP): @@ -2968,29 +3000,29 @@ static int stmt_evaluate_reject_bridge_family(struct eval_ctx *ctx, break; default: return stmt_binary_error(ctx, stmt, - &ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR], + &pctx->protocol[PROTO_BASE_NETWORK_HDR], "cannot reject this network family"); } break; case NFT_REJECT_ICMP_UNREACH: - base = ctx->pctx.protocol[PROTO_BASE_LL_HDR].desc; + base = pctx->protocol[PROTO_BASE_LL_HDR].desc; protocol = proto_find_num(base, desc); switch (protocol) { case __constant_htons(ETH_P_IP): if (NFPROTO_IPV4 == stmt->reject.family) break; return stmt_binary_error(ctx, stmt->reject.expr, - &ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR], + &pctx->protocol[PROTO_BASE_NETWORK_HDR], "conflicting protocols specified: ip vs ip6"); case __constant_htons(ETH_P_IPV6): if (NFPROTO_IPV6 == stmt->reject.family) break; return stmt_binary_error(ctx, stmt->reject.expr, - &ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR], + &pctx->protocol[PROTO_BASE_NETWORK_HDR], "conflicting protocols specified: ip vs ip6"); default: return stmt_binary_error(ctx, stmt, - &ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR], + &pctx->protocol[PROTO_BASE_NETWORK_HDR], "cannot reject this network family"); } break; @@ -3002,14 +3034,15 @@ static int stmt_evaluate_reject_bridge_family(struct eval_ctx *ctx, static int stmt_evaluate_reject_bridge(struct eval_ctx *ctx, struct stmt *stmt, struct expr *expr) { + struct proto_ctx *pctx = eval_proto_ctx(ctx); const struct proto_desc *desc; - desc = ctx->pctx.protocol[PROTO_BASE_LL_HDR].desc; + desc = pctx->protocol[PROTO_BASE_LL_HDR].desc; if (desc != &proto_eth && desc != &proto_vlan && desc != &proto_netdev) return __stmt_binary_error(ctx, &stmt->location, NULL, "cannot reject from this link layer protocol"); - desc = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc; + desc = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc; if (desc != NULL && stmt_evaluate_reject_bridge_family(ctx, stmt, desc) < 0) return -1; @@ -3023,7 +3056,9 @@ static int stmt_evaluate_reject_bridge(struct eval_ctx *ctx, struct stmt *stmt, static int stmt_evaluate_reject_family(struct eval_ctx *ctx, struct stmt *stmt, struct expr *expr) { - switch (ctx->pctx.family) { + struct proto_ctx *pctx = eval_proto_ctx(ctx); + + switch (pctx->family) { case NFPROTO_ARP: return stmt_error(ctx, stmt, "cannot use reject with arp"); case NFPROTO_IPV4: @@ -3037,7 +3072,7 @@ static int stmt_evaluate_reject_family(struct eval_ctx *ctx, struct stmt *stmt, return stmt_binary_error(ctx, stmt->reject.expr, stmt, "abstracted ICMP unreachable not supported"); case NFT_REJECT_ICMP_UNREACH: - if (stmt->reject.family == ctx->pctx.family) + if (stmt->reject.family == pctx->family) break; return stmt_binary_error(ctx, stmt->reject.expr, stmt, "conflicting protocols specified: ip vs ip6"); @@ -3061,28 +3096,29 @@ static int stmt_evaluate_reject_family(struct eval_ctx *ctx, struct stmt *stmt, static int stmt_evaluate_reject_default(struct eval_ctx *ctx, struct stmt *stmt) { - int protocol; + struct proto_ctx *pctx = eval_proto_ctx(ctx); const struct proto_desc *desc, *base; + int protocol; - switch (ctx->pctx.family) { + switch (pctx->family) { case NFPROTO_IPV4: case NFPROTO_IPV6: stmt->reject.type = NFT_REJECT_ICMP_UNREACH; - stmt->reject.family = ctx->pctx.family; - if (ctx->pctx.family == NFPROTO_IPV4) + stmt->reject.family = pctx->family; + if (pctx->family == NFPROTO_IPV4) stmt->reject.icmp_code = ICMP_PORT_UNREACH; else stmt->reject.icmp_code = ICMP6_DST_UNREACH_NOPORT; break; case NFPROTO_INET: - desc = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc; + desc = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc; if (desc == NULL) { stmt->reject.type = NFT_REJECT_ICMPX_UNREACH; stmt->reject.icmp_code = NFT_REJECT_ICMPX_PORT_UNREACH; break; } stmt->reject.type = NFT_REJECT_ICMP_UNREACH; - base = ctx->pctx.protocol[PROTO_BASE_LL_HDR].desc; + base = pctx->protocol[PROTO_BASE_LL_HDR].desc; protocol = proto_find_num(base, desc); switch (protocol) { case NFPROTO_IPV4: @@ -3099,14 +3135,14 @@ static int stmt_evaluate_reject_default(struct eval_ctx *ctx, break; case NFPROTO_BRIDGE: case NFPROTO_NETDEV: - desc = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc; + desc = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc; if (desc == NULL) { stmt->reject.type = NFT_REJECT_ICMPX_UNREACH; stmt->reject.icmp_code = NFT_REJECT_ICMPX_PORT_UNREACH; break; } stmt->reject.type = NFT_REJECT_ICMP_UNREACH; - base = ctx->pctx.protocol[PROTO_BASE_LL_HDR].desc; + base = pctx->protocol[PROTO_BASE_LL_HDR].desc; protocol = proto_find_num(base, desc); switch (protocol) { case __constant_htons(ETH_P_IP): @@ -3142,9 +3178,9 @@ static int stmt_evaluate_reject_icmp(struct eval_ctx *ctx, struct stmt *stmt) static int stmt_evaluate_reset(struct eval_ctx *ctx, struct stmt *stmt) { - int protonum; + struct proto_ctx *pctx = eval_proto_ctx(ctx); const struct proto_desc *desc, *base; - struct proto_ctx *pctx = &ctx->pctx; + int protonum; desc = pctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc; if (desc == NULL) @@ -3161,7 +3197,7 @@ static int stmt_evaluate_reset(struct eval_ctx *ctx, struct stmt *stmt) default: if (stmt->reject.type == NFT_REJECT_TCP_RST) { return stmt_binary_error(ctx, stmt, - &ctx->pctx.protocol[PROTO_BASE_TRANSPORT_HDR], + &pctx->protocol[PROTO_BASE_TRANSPORT_HDR], "you cannot use tcp reset with this protocol"); } break; @@ -3189,13 +3225,14 @@ static int stmt_evaluate_reject(struct eval_ctx *ctx, struct stmt *stmt) static int nat_evaluate_family(struct eval_ctx *ctx, struct stmt *stmt) { + struct proto_ctx *pctx = eval_proto_ctx(ctx); const struct proto_desc *nproto; - switch (ctx->pctx.family) { + switch (pctx->family) { case NFPROTO_IPV4: case NFPROTO_IPV6: if (stmt->nat.family == NFPROTO_UNSPEC) - stmt->nat.family = ctx->pctx.family; + stmt->nat.family = pctx->family; return 0; case NFPROTO_INET: if (!stmt->nat.addr) { @@ -3205,7 +3242,7 @@ static int nat_evaluate_family(struct eval_ctx *ctx, struct stmt *stmt) if (stmt->nat.family != NFPROTO_UNSPEC) return 0; - nproto = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc; + nproto = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc; if (nproto == &proto_ip) stmt->nat.family = NFPROTO_IPV4; @@ -3234,7 +3271,7 @@ static const struct datatype *get_addr_dtype(uint8_t family) static int evaluate_addr(struct eval_ctx *ctx, struct stmt *stmt, struct expr **expr) { - struct proto_ctx *pctx = &ctx->pctx; + struct proto_ctx *pctx = eval_proto_ctx(ctx); const struct datatype *dtype; dtype = get_addr_dtype(pctx->family); @@ -3287,7 +3324,7 @@ static bool nat_evaluate_addr_has_th_expr(const struct expr *map) static int nat_evaluate_transport(struct eval_ctx *ctx, struct stmt *stmt, struct expr **expr) { - struct proto_ctx *pctx = &ctx->pctx; + struct proto_ctx *pctx = eval_proto_ctx(ctx); if (pctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc == NULL && !nat_evaluate_addr_has_th_expr(stmt->nat.addr)) @@ -3303,16 +3340,17 @@ static int nat_evaluate_transport(struct eval_ctx *ctx, struct stmt *stmt, static int stmt_evaluate_l3proto(struct eval_ctx *ctx, struct stmt *stmt, uint8_t family) { + struct proto_ctx *pctx = eval_proto_ctx(ctx); const struct proto_desc *nproto; - nproto = ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc; + nproto = pctx->protocol[PROTO_BASE_NETWORK_HDR].desc; if ((nproto == &proto_ip && family != NFPROTO_IPV4) || (nproto == &proto_ip6 && family != NFPROTO_IPV6)) return stmt_binary_error(ctx, stmt, - &ctx->pctx.protocol[PROTO_BASE_NETWORK_HDR], + &pctx->protocol[PROTO_BASE_NETWORK_HDR], "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, + pctx->protocol[PROTO_BASE_NETWORK_HDR].desc->name, family2str(family), stmt->ops->name); return 0; @@ -3322,10 +3360,11 @@ static int stmt_evaluate_addr(struct eval_ctx *ctx, struct stmt *stmt, uint8_t family, struct expr **addr) { + struct proto_ctx *pctx = eval_proto_ctx(ctx); const struct datatype *dtype; int err; - if (ctx->pctx.family == NFPROTO_INET) { + if (pctx->family == NFPROTO_INET) { dtype = get_addr_dtype(family); if (dtype->size == 0) return stmt_error(ctx, stmt, @@ -3342,7 +3381,7 @@ static int stmt_evaluate_addr(struct eval_ctx *ctx, struct stmt *stmt, static int stmt_evaluate_nat_map(struct eval_ctx *ctx, struct stmt *stmt) { - struct proto_ctx *pctx = &ctx->pctx; + struct proto_ctx *pctx = eval_proto_ctx(ctx); struct expr *one, *two, *data, *tmp; const struct datatype *dtype; int addr_type, err; @@ -3491,13 +3530,14 @@ static int stmt_evaluate_nat(struct eval_ctx *ctx, struct stmt *stmt) static int stmt_evaluate_tproxy(struct eval_ctx *ctx, struct stmt *stmt) { + struct proto_ctx *pctx = eval_proto_ctx(ctx); int err; - switch (ctx->pctx.family) { + switch (pctx->family) { case NFPROTO_IPV4: case NFPROTO_IPV6: /* fallthrough */ if (stmt->tproxy.family == NFPROTO_UNSPEC) - stmt->tproxy.family = ctx->pctx.family; + stmt->tproxy.family = pctx->family; break; case NFPROTO_INET: break; @@ -3506,7 +3546,7 @@ static int stmt_evaluate_tproxy(struct eval_ctx *ctx, struct stmt *stmt) "tproxy is only supported for IPv4/IPv6/INET"); } - if (ctx->pctx.protocol[PROTO_BASE_TRANSPORT_HDR].desc == NULL) + if (pctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc == NULL) return stmt_error(ctx, stmt, "Transparent proxy support requires" " transport protocol match"); @@ -3616,9 +3656,10 @@ static int stmt_evaluate_optstrip(struct eval_ctx *ctx, struct stmt *stmt) static int stmt_evaluate_dup(struct eval_ctx *ctx, struct stmt *stmt) { + struct proto_ctx *pctx = eval_proto_ctx(ctx); int err; - switch (ctx->pctx.family) { + switch (pctx->family) { case NFPROTO_IPV4: case NFPROTO_IPV6: if (stmt->dup.to == NULL) @@ -3658,10 +3699,11 @@ static int stmt_evaluate_dup(struct eval_ctx *ctx, struct stmt *stmt) static int stmt_evaluate_fwd(struct eval_ctx *ctx, struct stmt *stmt) { + struct proto_ctx *pctx = eval_proto_ctx(ctx); const struct datatype *dtype; int err, len; - switch (ctx->pctx.family) { + switch (pctx->family) { case NFPROTO_NETDEV: if (stmt->fwd.dev == NULL) return stmt_error(ctx, stmt, @@ -4487,7 +4529,7 @@ static int rule_evaluate(struct eval_ctx *ctx, struct rule *rule, struct stmt *stmt, *tstmt = NULL; struct error_record *erec; - proto_ctx_init(&ctx->pctx, rule->handle.family, ctx->nft->debug_mask); + proto_ctx_init(&ctx->_pctx, rule->handle.family, ctx->nft->debug_mask); memset(&ctx->ectx, 0, sizeof(ctx->ectx)); ctx->rule = rule; diff --git a/src/payload.c b/src/payload.c index 2c0d0ac9e8ae..07f02359a7e7 100644 --- a/src/payload.c +++ b/src/payload.c @@ -391,9 +391,11 @@ static int payload_add_dependency(struct eval_ctx *ctx, { const struct proto_hdr_template *tmpl; struct expr *dep, *left, *right; + struct proto_ctx *pctx; struct stmt *stmt; - int protocol = proto_find_num(desc, upper); + int protocol; + protocol = proto_find_num(desc, upper); if (protocol < 0) return expr_error(ctx->msgs, expr, "conflicting protocols specified: %s vs. %s", @@ -415,15 +417,17 @@ static int payload_add_dependency(struct eval_ctx *ctx, return expr_error(ctx->msgs, expr, "dependency statement is invalid"); } - relational_expr_pctx_update(&ctx->pctx, dep); + + pctx = eval_proto_ctx(ctx); + relational_expr_pctx_update(pctx, dep); *res = stmt; return 0; } static const struct proto_desc * -payload_get_get_ll_hdr(const struct eval_ctx *ctx) +payload_get_get_ll_hdr(const struct proto_ctx *pctx) { - switch (ctx->pctx.family) { + switch (pctx->family) { case NFPROTO_INET: return &proto_inet; case NFPROTO_BRIDGE: @@ -440,9 +444,11 @@ payload_get_get_ll_hdr(const struct eval_ctx *ctx) static const struct proto_desc * payload_gen_special_dependency(struct eval_ctx *ctx, const struct expr *expr) { + struct proto_ctx *pctx = eval_proto_ctx(ctx); + switch (expr->payload.base) { case PROTO_BASE_LL_HDR: - return payload_get_get_ll_hdr(ctx); + return payload_get_get_ll_hdr(pctx); case PROTO_BASE_TRANSPORT_HDR: if (expr->payload.desc == &proto_icmp || expr->payload.desc == &proto_icmp6 || @@ -450,9 +456,9 @@ payload_gen_special_dependency(struct eval_ctx *ctx, const struct expr *expr) const struct proto_desc *desc, *desc_upper; struct stmt *nstmt; - desc = ctx->pctx.protocol[PROTO_BASE_LL_HDR].desc; + desc = pctx->protocol[PROTO_BASE_LL_HDR].desc; if (!desc) { - desc = payload_get_get_ll_hdr(ctx); + desc = payload_get_get_ll_hdr(pctx); if (!desc) break; } @@ -502,11 +508,14 @@ payload_gen_special_dependency(struct eval_ctx *ctx, const struct expr *expr) int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr, struct stmt **res) { - const struct hook_proto_desc *h = &hook_proto_desc[ctx->pctx.family]; + const struct hook_proto_desc *h; const struct proto_desc *desc; + struct proto_ctx *pctx; struct stmt *stmt; uint16_t type; + pctx = eval_proto_ctx(ctx); + h = &hook_proto_desc[pctx->family]; if (expr->payload.base < h->base) { if (expr->payload.base < h->base - 1) return expr_error(ctx->msgs, expr, @@ -527,7 +536,7 @@ int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr, return 0; } - desc = ctx->pctx.protocol[expr->payload.base - 1].desc; + desc = pctx->protocol[expr->payload.base - 1].desc; /* Special case for mixed IPv4/IPv6 and bridge tables */ if (desc == NULL) desc = payload_gen_special_dependency(ctx, expr); @@ -538,7 +547,7 @@ int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr, "no %s protocol specified", proto_base_names[expr->payload.base - 1]); - if (ctx->pctx.family == NFPROTO_BRIDGE && desc == &proto_eth) { + if (pctx->family == NFPROTO_BRIDGE && desc == &proto_eth) { /* prefer netdev proto, which adds dependencies based * on skb->protocol. * @@ -563,11 +572,13 @@ int exthdr_gen_dependency(struct eval_ctx *ctx, const struct expr *expr, enum proto_bases pb, struct stmt **res) { const struct proto_desc *desc; + struct proto_ctx *pctx; - desc = ctx->pctx.protocol[pb].desc; + pctx = eval_proto_ctx(ctx); + desc = pctx->protocol[pb].desc; if (desc == NULL) { if (expr->exthdr.op == NFT_EXTHDR_OP_TCPOPT) { - switch (ctx->pctx.family) { + switch (pctx->family) { case NFPROTO_NETDEV: case NFPROTO_BRIDGE: case NFPROTO_INET: @@ -1226,6 +1237,7 @@ __payload_gen_icmp_echo_dependency(struct eval_ctx *ctx, const struct expr *expr int payload_gen_icmp_dependency(struct eval_ctx *ctx, const struct expr *expr, struct stmt **res) { + struct proto_ctx *pctx = eval_proto_ctx(ctx); const struct proto_hdr_template *tmpl; const struct proto_desc *desc; struct stmt *stmt = NULL; @@ -1242,11 +1254,11 @@ int payload_gen_icmp_dependency(struct eval_ctx *ctx, const struct expr *expr, break; case PROTO_ICMP_ECHO: /* do not test ICMP_ECHOREPLY here: its 0 */ - if (ctx->pctx.th_dep.icmp.type == ICMP_ECHO) + if (pctx->th_dep.icmp.type == ICMP_ECHO) goto done; type = ICMP_ECHO; - if (ctx->pctx.th_dep.icmp.type) + if (pctx->th_dep.icmp.type) goto bad_proto; stmt = __payload_gen_icmp_echo_dependency(ctx, expr, @@ -1257,21 +1269,21 @@ int payload_gen_icmp_dependency(struct eval_ctx *ctx, const struct expr *expr, case PROTO_ICMP_MTU: case PROTO_ICMP_ADDRESS: type = icmp_dep_to_type(tmpl->icmp_dep); - if (ctx->pctx.th_dep.icmp.type == type) + if (pctx->th_dep.icmp.type == type) goto done; - if (ctx->pctx.th_dep.icmp.type) + if (pctx->th_dep.icmp.type) goto bad_proto; stmt = __payload_gen_icmp_simple_dependency(ctx, expr, &icmp_type_type, desc, type); break; case PROTO_ICMP6_ECHO: - if (ctx->pctx.th_dep.icmp.type == ICMP6_ECHO_REQUEST || - ctx->pctx.th_dep.icmp.type == ICMP6_ECHO_REPLY) + if (pctx->th_dep.icmp.type == ICMP6_ECHO_REQUEST || + pctx->th_dep.icmp.type == ICMP6_ECHO_REPLY) goto done; type = ICMP6_ECHO_REQUEST; - if (ctx->pctx.th_dep.icmp.type) + if (pctx->th_dep.icmp.type) goto bad_proto; stmt = __payload_gen_icmp_echo_dependency(ctx, expr, @@ -1284,9 +1296,9 @@ int payload_gen_icmp_dependency(struct eval_ctx *ctx, const struct expr *expr, case PROTO_ICMP6_MGMQ: case PROTO_ICMP6_PPTR: type = icmp_dep_to_type(tmpl->icmp_dep); - if (ctx->pctx.th_dep.icmp.type == type) + if (pctx->th_dep.icmp.type == type) goto done; - if (ctx->pctx.th_dep.icmp.type) + if (pctx->th_dep.icmp.type) goto bad_proto; stmt = __payload_gen_icmp_simple_dependency(ctx, expr, &icmp6_type_type, @@ -1297,7 +1309,7 @@ int payload_gen_icmp_dependency(struct eval_ctx *ctx, const struct expr *expr, BUG("Unhandled icmp dependency code"); } - ctx->pctx.th_dep.icmp.type = type; + pctx->th_dep.icmp.type = type; if (stmt_evaluate(ctx, stmt) < 0) return expr_error(ctx->msgs, expr, @@ -1308,5 +1320,5 @@ done: bad_proto: return expr_error(ctx->msgs, expr, "incompatible icmp match: rule has %d, need %u", - ctx->pctx.th_dep.icmp.type, type); + pctx->th_dep.icmp.type, type); } From patchwork Mon Oct 17 11:03:54 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pablo Neira Ayuso X-Patchwork-Id: 1690838 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=2620:137:e000::1:20; helo=out1.vger.email; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Received: from out1.vger.email (out1.vger.email [IPv6:2620:137:e000::1:20]) by legolas.ozlabs.org (Postfix) with ESMTP id 4MrYz82kc4z23jp for ; Mon, 17 Oct 2022 22:04:20 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230119AbiJQLET (ORCPT ); Mon, 17 Oct 2022 07:04:19 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34280 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229506AbiJQLES (ORCPT ); Mon, 17 Oct 2022 07:04:18 -0400 Received: from mail.netfilter.org (mail.netfilter.org [217.70.188.207]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 1C40B2725 for ; Mon, 17 Oct 2022 04:04:17 -0700 (PDT) From: Pablo Neira Ayuso To: netfilter-devel@vger.kernel.org Subject: [PATCH nft,v2 02/16] src: add dl_proto_ctx() Date: Mon, 17 Oct 2022 13:03:54 +0200 Message-Id: <20221017110408.742223-3-pablo@netfilter.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221017110408.742223-1-pablo@netfilter.org> References: <20221017110408.742223-1-pablo@netfilter.org> MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Add dl_proto_ctx() to access protocol context (struct proto_ctx and struct payload_dep_ctx) from the delinearize path. This patch comes in preparation for supporting outer and inner protocol context. Signed-off-by: Pablo Neira Ayuso --- include/netlink.h | 8 ++- src/netlink_delinearize.c | 116 ++++++++++++++++++++++---------------- src/xt.c | 8 ++- 3 files changed, 78 insertions(+), 54 deletions(-) diff --git a/include/netlink.h b/include/netlink.h index 63d07edf419e..4823f1e65d67 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -49,9 +49,13 @@ struct netlink_parse_ctx { #define RULE_PP_REMOVE_OP_AND (RULE_PP_IN_CONCATENATION | \ RULE_PP_IN_SET_ELEM) -struct rule_pp_ctx { +struct dl_proto_ctx { struct proto_ctx pctx; struct payload_dep_ctx pdctx; +}; + +struct rule_pp_ctx { + struct dl_proto_ctx _dl; struct stmt *stmt; unsigned int flags; }; @@ -246,4 +250,6 @@ struct nft_expr_loc { struct nft_expr_loc *nft_expr_loc_find(const struct nftnl_expr *nle, struct netlink_linearize_ctx *ctx); +struct dl_proto_ctx *dl_proto_ctx(struct rule_pp_ctx *ctx); + #endif /* NFTABLES_NETLINK_H */ diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index 828ad12d7536..d5e1c4097f90 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -30,6 +30,11 @@ #include #include +struct dl_proto_ctx *dl_proto_ctx(struct rule_pp_ctx *ctx) +{ + return &ctx->_dl; +} + static int netlink_parse_expr(const struct nftnl_expr *nle, struct netlink_parse_ctx *ctx); @@ -1876,11 +1881,12 @@ static void payload_match_expand(struct rule_pp_ctx *ctx, { struct expr *left = payload, *right = expr->right, *tmp; struct list_head list = LIST_HEAD_INIT(list); - struct stmt *nstmt; - struct expr *nexpr = NULL; + struct dl_proto_ctx *dl = dl_proto_ctx(ctx); enum proto_bases base = left->payload.base; + struct expr *nexpr = NULL; + struct stmt *nstmt; - payload_expr_expand(&list, left, &ctx->pctx); + payload_expr_expand(&list, left, &dl->pctx); list_for_each_entry(left, &list, list) { tmp = constant_expr_splice(right, left->len); @@ -1895,7 +1901,7 @@ static void payload_match_expand(struct rule_pp_ctx *ctx, nexpr = relational_expr_alloc(&expr->location, expr->op, left, tmp); if (expr->op == OP_EQ) - relational_expr_pctx_update(&ctx->pctx, nexpr); + relational_expr_pctx_update(&dl->pctx, nexpr); nstmt = expr_stmt_alloc(&ctx->stmt->location, nexpr); list_add_tail(&nstmt->list, &ctx->stmt->list); @@ -1904,17 +1910,17 @@ static void payload_match_expand(struct rule_pp_ctx *ctx, assert(left->payload.base); assert(base == left->payload.base); - if (payload_is_stacked(ctx->pctx.protocol[base].desc, nexpr)) + if (payload_is_stacked(dl->pctx.protocol[base].desc, nexpr)) base--; /* Remember the first payload protocol expression to * kill it later on if made redundant by a higher layer * payload expression. */ - payload_dependency_kill(&ctx->pdctx, nexpr->left, - ctx->pctx.family); + payload_dependency_kill(&dl->pdctx, nexpr->left, + dl->pctx.family); if (expr->op == OP_EQ && left->flags & EXPR_F_PROTOCOL) - payload_dependency_store(&ctx->pdctx, nstmt, base); + payload_dependency_store(&dl->pdctx, nstmt, base); } list_del(&ctx->stmt->list); stmt_free(ctx->stmt); @@ -1923,6 +1929,7 @@ static void payload_match_expand(struct rule_pp_ctx *ctx, static void payload_icmp_check(struct rule_pp_ctx *rctx, struct expr *expr, const struct expr *value) { + struct dl_proto_ctx *dl = dl_proto_ctx(rctx); const struct proto_hdr_template *tmpl; const struct proto_desc *desc; uint8_t icmp_type; @@ -1937,10 +1944,10 @@ static void payload_icmp_check(struct rule_pp_ctx *rctx, struct expr *expr, cons /* icmp(v6) type is 8 bit, if value is smaller or larger, this is not * a protocol dependency. */ - if (expr->len != 8 || value->len != 8 || rctx->pctx.th_dep.icmp.type) + if (expr->len != 8 || value->len != 8 || dl->pctx.th_dep.icmp.type) return; - desc = rctx->pctx.protocol[expr->payload.base].desc; + desc = dl->pctx.protocol[expr->payload.base].desc; if (desc == NULL) return; @@ -1968,7 +1975,7 @@ static void payload_icmp_check(struct rule_pp_ctx *rctx, struct expr *expr, cons expr->payload.desc = desc; expr->payload.tmpl = tmpl; - rctx->pctx.th_dep.icmp.type = icmp_type; + dl->pctx.th_dep.icmp.type = icmp_type; return; } } @@ -1977,6 +1984,8 @@ static void payload_match_postprocess(struct rule_pp_ctx *ctx, struct expr *expr, struct expr *payload) { + struct dl_proto_ctx *dl = dl_proto_ctx(ctx); + switch (expr->op) { case OP_EQ: case OP_NEQ: @@ -2000,10 +2009,10 @@ static void payload_match_postprocess(struct rule_pp_ctx *ctx, } /* Fall through */ default: - payload_expr_complete(payload, &ctx->pctx); + payload_expr_complete(payload, &dl->pctx); expr_set_type(expr->right, payload->dtype, payload->byteorder); - payload_dependency_kill(&ctx->pdctx, payload, ctx->pctx.family); + payload_dependency_kill(&dl->pdctx, payload, dl->pctx.family); break; } } @@ -2111,6 +2120,7 @@ static void ct_meta_common_postprocess(struct rule_pp_ctx *ctx, const struct expr *expr, enum proto_bases base) { + struct dl_proto_ctx *dl = dl_proto_ctx(ctx); const struct expr *left = expr->left; struct expr *right = expr->right; @@ -2124,16 +2134,16 @@ static void ct_meta_common_postprocess(struct rule_pp_ctx *ctx, expr->right->etype == EXPR_SET_REF) break; - relational_expr_pctx_update(&ctx->pctx, expr); + relational_expr_pctx_update(&dl->pctx, expr); if (base < PROTO_BASE_TRANSPORT_HDR) { - if (payload_dependency_exists(&ctx->pdctx, base) && - meta_may_dependency_kill(&ctx->pdctx, - ctx->pctx.family, expr)) - payload_dependency_release(&ctx->pdctx, base); + if (payload_dependency_exists(&dl->pdctx, base) && + meta_may_dependency_kill(&dl->pdctx, + dl->pctx.family, expr)) + payload_dependency_release(&dl->pdctx, base); if (left->flags & EXPR_F_PROTOCOL) - payload_dependency_store(&ctx->pdctx, ctx->stmt, base); + payload_dependency_store(&dl->pdctx, ctx->stmt, base); } break; default: @@ -2264,13 +2274,14 @@ static void __binop_postprocess(struct rule_pp_ctx *ctx, struct expr *mask, struct expr **expr_binop) { + struct dl_proto_ctx *dl = dl_proto_ctx(ctx); struct expr *binop = *expr_binop; unsigned int shift; assert(binop->etype == EXPR_BINOP); if ((left->etype == EXPR_PAYLOAD && - payload_expr_trim(left, mask, &ctx->pctx, &shift)) || + payload_expr_trim(left, mask, &dl->pctx, &shift)) || (left->etype == EXPR_EXTHDR && exthdr_find_template(left, mask, &shift))) { struct expr *right = NULL; @@ -2522,6 +2533,7 @@ static struct expr *expr_postprocess_string(struct expr *expr) static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp) { + struct dl_proto_ctx *dl = dl_proto_ctx(ctx); struct expr *expr = *exprp, *i; switch (expr->etype) { @@ -2639,8 +2651,8 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp) } break; case EXPR_PAYLOAD: - payload_expr_complete(expr, &ctx->pctx); - payload_dependency_kill(&ctx->pdctx, expr, ctx->pctx.family); + payload_expr_complete(expr, &dl->pctx); + payload_dependency_kill(&dl->pdctx, expr, dl->pctx.family); break; case EXPR_VALUE: // FIXME @@ -2669,7 +2681,7 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp) ctx->flags &= ~RULE_PP_IN_SET_ELEM; break; case EXPR_EXTHDR: - exthdr_dependency_kill(&ctx->pdctx, expr, ctx->pctx.family); + exthdr_dependency_kill(&dl->pdctx, expr, dl->pctx.family); break; case EXPR_SET_REF: case EXPR_META: @@ -2686,7 +2698,7 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp) expr_postprocess(ctx, &expr->hash.expr); break; case EXPR_CT: - ct_expr_update_type(&ctx->pctx, expr); + ct_expr_update_type(&dl->pctx, expr); break; default: BUG("unknown expression type %s\n", expr_name(expr)); @@ -2695,27 +2707,28 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp) static void stmt_reject_postprocess(struct rule_pp_ctx *rctx) { + struct dl_proto_ctx *dl = dl_proto_ctx(rctx); const struct proto_desc *desc, *base; struct stmt *stmt = rctx->stmt; int protocol; - switch (rctx->pctx.family) { + switch (dl->pctx.family) { case NFPROTO_IPV4: - stmt->reject.family = rctx->pctx.family; + stmt->reject.family = dl->pctx.family; datatype_set(stmt->reject.expr, &icmp_code_type); if (stmt->reject.type == NFT_REJECT_TCP_RST && - payload_dependency_exists(&rctx->pdctx, + payload_dependency_exists(&dl->pdctx, PROTO_BASE_TRANSPORT_HDR)) - payload_dependency_release(&rctx->pdctx, + payload_dependency_release(&dl->pdctx, PROTO_BASE_TRANSPORT_HDR); break; case NFPROTO_IPV6: - stmt->reject.family = rctx->pctx.family; + stmt->reject.family = dl->pctx.family; datatype_set(stmt->reject.expr, &icmpv6_code_type); if (stmt->reject.type == NFT_REJECT_TCP_RST && - payload_dependency_exists(&rctx->pdctx, + payload_dependency_exists(&dl->pdctx, PROTO_BASE_TRANSPORT_HDR)) - payload_dependency_release(&rctx->pdctx, + payload_dependency_release(&dl->pdctx, PROTO_BASE_TRANSPORT_HDR); break; case NFPROTO_INET: @@ -2731,8 +2744,8 @@ static void stmt_reject_postprocess(struct rule_pp_ctx *rctx) */ stmt->reject.verbose_print = 1; - base = rctx->pctx.protocol[PROTO_BASE_LL_HDR].desc; - desc = rctx->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc; + base = dl->pctx.protocol[PROTO_BASE_LL_HDR].desc; + desc = dl->pctx.protocol[PROTO_BASE_NETWORK_HDR].desc; protocol = proto_find_num(base, desc); switch (protocol) { case NFPROTO_IPV4: /* INET */ @@ -2749,8 +2762,8 @@ static void stmt_reject_postprocess(struct rule_pp_ctx *rctx) break; } - if (payload_dependency_exists(&rctx->pdctx, PROTO_BASE_NETWORK_HDR)) - payload_dependency_release(&rctx->pdctx, + if (payload_dependency_exists(&dl->pdctx, PROTO_BASE_NETWORK_HDR)) + payload_dependency_release(&dl->pdctx, PROTO_BASE_NETWORK_HDR); break; default: @@ -2794,23 +2807,24 @@ static bool expr_may_merge_range(struct expr *expr, struct expr *prev, static void expr_postprocess_range(struct rule_pp_ctx *ctx, enum ops op) { + struct dl_proto_ctx *dl = dl_proto_ctx(ctx); struct stmt *nstmt, *stmt = ctx->stmt; struct expr *nexpr, *rel; - nexpr = range_expr_alloc(&ctx->pdctx.prev->location, - expr_clone(ctx->pdctx.prev->expr->right), + nexpr = range_expr_alloc(&dl->pdctx.prev->location, + expr_clone(dl->pdctx.prev->expr->right), expr_clone(stmt->expr->right)); expr_set_type(nexpr, stmt->expr->right->dtype, stmt->expr->right->byteorder); - rel = relational_expr_alloc(&ctx->pdctx.prev->location, op, + rel = relational_expr_alloc(&dl->pdctx.prev->location, op, expr_clone(stmt->expr->left), nexpr); nstmt = expr_stmt_alloc(&stmt->location, rel); list_add_tail(&nstmt->list, &stmt->list); - list_del(&ctx->pdctx.prev->list); - stmt_free(ctx->pdctx.prev); + list_del(&dl->pdctx.prev->list); + stmt_free(dl->pdctx.prev); list_del(&stmt->list); stmt_free(stmt); @@ -2819,26 +2833,28 @@ static void expr_postprocess_range(struct rule_pp_ctx *ctx, enum ops op) static void stmt_expr_postprocess(struct rule_pp_ctx *ctx) { + struct dl_proto_ctx *dl = dl_proto_ctx(ctx); enum ops op; expr_postprocess(ctx, &ctx->stmt->expr); - if (ctx->pdctx.prev && ctx->stmt && - ctx->stmt->ops->type == ctx->pdctx.prev->ops->type && - expr_may_merge_range(ctx->stmt->expr, ctx->pdctx.prev->expr, &op)) + if (dl->pdctx.prev && ctx->stmt && + ctx->stmt->ops->type == dl->pdctx.prev->ops->type && + expr_may_merge_range(ctx->stmt->expr, dl->pdctx.prev->expr, &op)) expr_postprocess_range(ctx, op); } static void stmt_payload_binop_pp(struct rule_pp_ctx *ctx, struct expr *binop) { + struct dl_proto_ctx *dl = dl_proto_ctx(ctx); struct expr *payload = binop->left; struct expr *mask = binop->right; unsigned int shift; assert(payload->etype == EXPR_PAYLOAD); - if (payload_expr_trim(payload, mask, &ctx->pctx, &shift)) { + if (payload_expr_trim(payload, mask, &dl->pctx, &shift)) { binop_adjust(binop, mask, shift); - payload_expr_complete(payload, &ctx->pctx); + payload_expr_complete(payload, &dl->pctx); expr_set_type(mask, payload->dtype, payload->byteorder); } @@ -3047,7 +3063,7 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r struct expr *expr; memset(&rctx, 0, sizeof(rctx)); - proto_ctx_init(&rctx.pctx, rule->handle.family, ctx->debug_mask); + proto_ctx_init(&rctx._dl.pctx, rule->handle.family, ctx->debug_mask); list_for_each_entry_safe(stmt, next, &rule->stmts, list) { enum stmt_types type = stmt->ops->type; @@ -3084,7 +3100,7 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r if (stmt->nat.addr != NULL) expr_postprocess(&rctx, &stmt->nat.addr); if (stmt->nat.proto != NULL) { - payload_dependency_reset(&rctx.pdctx); + payload_dependency_reset(&rctx._dl.pdctx); expr_postprocess(&rctx, &stmt->nat.proto); } break; @@ -3092,7 +3108,7 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r if (stmt->tproxy.addr) expr_postprocess(&rctx, &stmt->tproxy.addr); if (stmt->tproxy.port) { - payload_dependency_reset(&rctx.pdctx); + payload_dependency_reset(&rctx._dl.pdctx); expr_postprocess(&rctx, &stmt->tproxy.port); } break; @@ -3130,9 +3146,9 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r break; } - rctx.pdctx.prev = rctx.stmt; + rctx._dl.pdctx.prev = rctx.stmt; - rule_maybe_reset_payload_deps(&rctx.pdctx, type); + rule_maybe_reset_payload_deps(&rctx._dl.pdctx, type); } } diff --git a/src/xt.c b/src/xt.c index 789de9926261..fa8dd4fe4176 100644 --- a/src/xt.c +++ b/src/xt.c @@ -305,11 +305,13 @@ static bool is_watcher(uint32_t family, struct stmt *stmt) void stmt_xt_postprocess(struct rule_pp_ctx *rctx, struct stmt *stmt, struct rule *rule) { - if (is_watcher(rctx->pctx.family, stmt)) + struct dl_proto_ctx *dl = dl_proto_ctx(rctx); + + if (is_watcher(dl->pctx.family, stmt)) stmt->xt.type = NFT_XT_WATCHER; - stmt->xt.proto = xt_proto(&rctx->pctx); - stmt->xt.entry = xt_entry_alloc(&stmt->xt, rctx->pctx.family); + stmt->xt.proto = xt_proto(&dl->pctx); + stmt->xt.entry = xt_entry_alloc(&stmt->xt, dl->pctx.family); } static int nft_xt_compatible_revision(const char *name, uint8_t rev, int opt) From patchwork Mon Oct 17 11:03:55 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pablo Neira Ayuso X-Patchwork-Id: 1690844 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=2620:137:e000::1:20; helo=out1.vger.email; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Received: from out1.vger.email (out1.vger.email [IPv6:2620:137:e000::1:20]) by legolas.ozlabs.org (Postfix) with ESMTP id 4MrYzH6911z23kW for ; Mon, 17 Oct 2022 22:04:27 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230147AbiJQLE0 (ORCPT ); Mon, 17 Oct 2022 07:04:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34434 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230145AbiJQLEU (ORCPT ); Mon, 17 Oct 2022 07:04:20 -0400 Received: from mail.netfilter.org (mail.netfilter.org [217.70.188.207]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 6787625D6 for ; Mon, 17 Oct 2022 04:04:17 -0700 (PDT) From: Pablo Neira Ayuso To: netfilter-devel@vger.kernel.org Subject: [PATCH nft,v2 03/16] src: add vxlan matching support Date: Mon, 17 Oct 2022 13:03:55 +0200 Message-Id: <20221017110408.742223-4-pablo@netfilter.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221017110408.742223-1-pablo@netfilter.org> References: <20221017110408.742223-1-pablo@netfilter.org> MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org This patch adds the initial infrastructure to support for inner header tunnel matching and its first user: vxlan. A new struct proto_desc field for payload and meta expression to specify that the expression refers to inner header matching is used. The existing codebase to generate bytecode is fully reused, allowing for reusing existing supported layer 2, 3 and 4 protocols. Syntax requires to specify vxlan before the inner protocol field: ... vxlan ip protocol udp ... vxlan ip saddr 1.2.3.0/24 This also works with concatenations and anonymous sets, eg. ... vxlan ip saddr . vxlan ip daddr { 1.2.3.4 . 4.3.2.1 } You have to restrict vxlan matching to udp traffic, otherwise it complains on missing transport protocol dependency, e.g. ... udp dport 4789 vxlan ip daddr 1.2.3.4 The bytecode that is generated uses the new inner expression: # nft --debug=netlink add rule netdev x y udp dport 4789 vxlan ip saddr 1.2.3.4 netdev x y [ meta load l4proto => reg 1 ] [ cmp eq reg 1 0x00000011 ] [ payload load 2b @ transport header + 2 => reg 1 ] [ cmp eq reg 1 0x0000b512 ] [ inner type 1 hdrsize 8 flags f [ meta load protocol => reg 1 ] ] [ cmp eq reg 1 0x00000008 ] [ inner type 1 hdrsize 8 flags f [ payload load 4b @ network header + 12 => reg 1 ] ] [ cmp eq reg 1 0x04030201 ] JSON support is not included in this patch. Signed-off-by: Pablo Neira Ayuso --- include/expression.h | 2 + include/linux/netfilter/nf_tables.h | 27 +++++ include/netlink.h | 5 +- include/payload.h | 2 + include/proto.h | 23 ++++- include/rule.h | 3 +- src/evaluate.c | 83 +++++++++++++-- src/expression.c | 1 + src/meta.c | 21 +++- src/netlink_delinearize.c | 155 ++++++++++++++++++++++++++-- src/netlink_linearize.c | 80 ++++++++++++-- src/parser_bison.y | 53 ++++++++++ src/payload.c | 37 ++++++- src/proto.c | 52 ++++++++++ src/rule.c | 3 +- src/scanner.l | 3 + 16 files changed, 521 insertions(+), 29 deletions(-) diff --git a/include/expression.h b/include/expression.h index 3f06a38ae2d3..1f58a68c329f 100644 --- a/include/expression.h +++ b/include/expression.h @@ -316,6 +316,7 @@ struct expr { /* EXPR_PAYLOAD */ const struct proto_desc *desc; const struct proto_hdr_template *tmpl; + const struct proto_desc *inner_desc; enum proto_bases base; unsigned int offset; bool is_raw; @@ -334,6 +335,7 @@ struct expr { /* EXPR_META */ enum nft_meta_keys key; enum proto_bases base; + const struct proto_desc *inner_desc; } meta; struct { /* SOCKET */ diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h index 466fd3f4447c..e4b739d57480 100644 --- a/include/linux/netfilter/nf_tables.h +++ b/include/linux/netfilter/nf_tables.h @@ -760,6 +760,7 @@ enum nft_payload_bases { NFT_PAYLOAD_NETWORK_HEADER, NFT_PAYLOAD_TRANSPORT_HEADER, NFT_PAYLOAD_INNER_HEADER, + NFT_PAYLOAD_TUN_HEADER, }; /** @@ -779,6 +780,32 @@ enum nft_payload_csum_flags { NFT_PAYLOAD_L4CSUM_PSEUDOHDR = (1 << 0), }; +enum nft_inner_type { + NFT_INNER_UNSPEC = 0, + NFT_INNER_VXLAN, + NFT_INNER_GENEVE, +}; + +enum nft_inner_flags { + NFT_INNER_HDRSIZE = (1 << 0), + NFT_INNER_LL = (1 << 1), + NFT_INNER_NH = (1 << 2), + NFT_INNER_TH = (1 << 3), +}; +#define NFT_INNER_MASK (NFT_INNER_HDRSIZE | NFT_INNER_LL | \ + NFT_INNER_NH | NFT_INNER_TH) + +enum nft_inner_attributes { + NFTA_INNER_UNSPEC, + NFTA_INNER_NUM, + NFTA_INNER_TYPE, + NFTA_INNER_FLAGS, + NFTA_INNER_HDRSIZE, + NFTA_INNER_EXPR, + __NFTA_INNER_MAX +}; +#define NFTA_INNER_MAX (__NFTA_INNER_MAX - 1) + /** * enum nft_payload_attributes - nf_tables payload expression netlink attributes * diff --git a/include/netlink.h b/include/netlink.h index 4823f1e65d67..5a7f6a1e28ef 100644 --- a/include/netlink.h +++ b/include/netlink.h @@ -40,6 +40,8 @@ struct netlink_parse_ctx { struct expr *registers[MAX_REGS + 1]; unsigned int debug_mask; struct netlink_ctx *nlctx; + bool inner; + uint8_t inner_reg; }; @@ -55,7 +57,8 @@ struct dl_proto_ctx { }; struct rule_pp_ctx { - struct dl_proto_ctx _dl; + struct dl_proto_ctx _dl[2]; + struct dl_proto_ctx *dl; struct stmt *stmt; unsigned int flags; }; diff --git a/include/payload.h b/include/payload.h index 378699283c0a..aac553ee6b89 100644 --- a/include/payload.h +++ b/include/payload.h @@ -67,4 +67,6 @@ extern void payload_expr_complete(struct expr *expr, bool payload_expr_cmp(const struct expr *e1, const struct expr *e2); +const struct proto_desc *find_proto_desc(const struct nftnl_udata *ud); + #endif /* NFTABLES_PAYLOAD_H */ diff --git a/include/proto.h b/include/proto.h index 6a9289b17f05..5bb7562db94b 100644 --- a/include/proto.h +++ b/include/proto.h @@ -96,6 +96,7 @@ enum proto_desc_id { PROTO_DESC_ARP, PROTO_DESC_VLAN, PROTO_DESC_ETHER, + PROTO_DESC_VXLAN, __PROTO_DESC_MAX }; #define PROTO_DESC_MAX (__PROTO_DESC_MAX - 1) @@ -131,7 +132,11 @@ struct proto_desc { uint32_t filter; } format; unsigned int pseudohdr[PROTO_HDRS_MAX]; - + struct { + uint32_t hdrsize; + uint32_t flags; + enum nft_inner_type type; + } inner; }; #define PROTO_LINK(__num, __desc) { .num = (__num), .desc = (__desc), } @@ -216,6 +221,8 @@ extern const struct proto_desc *proto_find_upper(const struct proto_desc *base, unsigned int num); extern int proto_find_num(const struct proto_desc *base, const struct proto_desc *desc); +const struct proto_desc *proto_find_inner(uint32_t type, uint32_t hdrsize, + uint32_t flags); extern const struct proto_desc *proto_find_desc(enum proto_desc_id desc_id); @@ -263,6 +270,7 @@ enum ip_hdr_fields { IPHDR_SADDR, IPHDR_DADDR, }; +#define IPHDR_MAX IPHDR_DADDR enum icmp_hdr_fields { ICMPHDR_INVALID, @@ -376,6 +384,19 @@ enum th_hdr_fields { THDR_DPORT, }; +struct vxlanhdr { + uint32_t vx_flags; + uint32_t vx_vni; +}; + +enum vxlan_hdr_fields { + VXLANHDR_INVALID, + VXLANHDR_VNI, + VXLANHDR_FLAGS, +}; + +extern const struct proto_desc proto_vxlan; + extern const struct proto_desc proto_icmp; extern const struct proto_desc proto_igmp; extern const struct proto_desc proto_ah; diff --git a/include/rule.h b/include/rule.h index 795951326886..48bef290c86e 100644 --- a/include/rule.h +++ b/include/rule.h @@ -768,7 +768,8 @@ struct eval_ctx { struct set *set; struct stmt *stmt; struct expr_ctx ectx; - struct proto_ctx _pctx; + struct proto_ctx _pctx[2]; + const struct proto_desc *inner_desc; }; extern int cmd_evaluate(struct eval_ctx *ctx, struct cmd *cmd); diff --git a/src/evaluate.c b/src/evaluate.c index 7f371dc5f569..6e3b6f187c83 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -41,7 +41,9 @@ struct proto_ctx *eval_proto_ctx(struct eval_ctx *ctx) { - return &ctx->_pctx; + uint8_t idx = ctx->inner_desc ? 1 : 0; + + return &ctx->_pctx[idx]; } static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr); @@ -452,6 +454,9 @@ conflict_resolution_gen_dependency(struct eval_ctx *ctx, int protocol, return expr_error(ctx->msgs, expr, "dependency statement is invalid"); + if (ctx->inner_desc) + left->payload.inner_desc = ctx->inner_desc; + *res = stmt; return 0; } @@ -651,6 +656,9 @@ static int meta_iiftype_gen_dependency(struct eval_ctx *ctx, return expr_error(ctx->msgs, payload, "dependency statement is invalid"); + if (ctx->inner_desc) + nstmt->expr->left->meta.inner_desc = ctx->inner_desc; + *res = nstmt; return 0; } @@ -673,12 +681,16 @@ static int resolve_protocol_conflict(struct eval_ctx *ctx, if (payload->payload.base == PROTO_BASE_LL_HDR) { if (proto_is_dummy(desc)) { - err = meta_iiftype_gen_dependency(ctx, payload, &nstmt); - if (err < 0) - return err; - - desc = payload->payload.desc; - rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt); + if (ctx->inner_desc) { + proto_ctx_update(pctx, PROTO_BASE_LL_HDR, &payload->location, &proto_eth); + } else { + err = meta_iiftype_gen_dependency(ctx, payload, &nstmt); + if (err < 0) + return err; + + desc = payload->payload.desc; + rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt); + } } else { unsigned int i; @@ -845,6 +857,48 @@ static int expr_evaluate_payload(struct eval_ctx *ctx, struct expr **exprp) return 0; } +static int expr_evaluate_inner(struct eval_ctx *ctx, struct expr **exprp) +{ + struct proto_ctx *pctx = eval_proto_ctx(ctx); + const struct proto_desc *desc; + struct expr *expr = *exprp; + int ret; + + desc = pctx->protocol[expr->payload.inner_desc->base - 1].desc; + if (!desc) { + return expr_error(ctx->msgs, expr, + "no transport protocol specified"); + } + + if (proto_find_num(desc, expr->payload.inner_desc) < 0) { + return expr_error(ctx->msgs, expr, + "unexpected transport protocol %s", + desc->name); + } + + proto_ctx_update(pctx, PROTO_BASE_INNER_HDR, &expr->location, + expr->payload.inner_desc); + + if (expr->payload.base != PROTO_BASE_INNER_HDR) + ctx->inner_desc = expr->payload.inner_desc; + + ret = expr_evaluate_payload(ctx, exprp); + + return ret; +} + +static int expr_evaluate_payload_inner(struct eval_ctx *ctx, struct expr **exprp) +{ + int ret; + + if ((*exprp)->payload.inner_desc) + ret = expr_evaluate_inner(ctx, exprp); + else + ret = expr_evaluate_payload(ctx, exprp); + + return ret; +} + /* * RT expression: validate protocol dependencies. */ @@ -1390,6 +1444,8 @@ static int expr_evaluate_concat(struct eval_ctx *ctx, struct expr **expr) size += netlink_padded_len(dsize); if (key) key = list_next_entry(key, list); + + ctx->inner_desc = NULL; } (*expr)->flags |= flags; @@ -2465,7 +2521,7 @@ static int expr_evaluate(struct eval_ctx *ctx, struct expr **expr) case EXPR_FIB: return expr_evaluate_fib(ctx, expr); case EXPR_PAYLOAD: - return expr_evaluate_payload(ctx, expr); + return expr_evaluate_payload_inner(ctx, expr); case EXPR_RT: return expr_evaluate_rt(ctx, expr); case EXPR_CT: @@ -2673,6 +2729,11 @@ static int stmt_evaluate_payload(struct eval_ctx *ctx, struct stmt *stmt) mpz_t bitmask, ff; bool need_csum; + if (stmt->payload.expr->payload.inner_desc) { + return expr_error(ctx->msgs, stmt->payload.expr, + "payload statement for this expression is not supported"); + } + if (__expr_evaluate_payload(ctx, stmt->payload.expr) < 0) return -1; @@ -4529,7 +4590,9 @@ static int rule_evaluate(struct eval_ctx *ctx, struct rule *rule, struct stmt *stmt, *tstmt = NULL; struct error_record *erec; - proto_ctx_init(&ctx->_pctx, rule->handle.family, ctx->nft->debug_mask); + proto_ctx_init(&ctx->_pctx[0], rule->handle.family, ctx->nft->debug_mask); + /* use NFPROTO_BRIDGE to set up proto_eth as base protocol. */ + proto_ctx_init(&ctx->_pctx[1], NFPROTO_BRIDGE, ctx->nft->debug_mask); memset(&ctx->ectx, 0, sizeof(ctx->ectx)); ctx->rule = rule; @@ -4544,6 +4607,8 @@ static int rule_evaluate(struct eval_ctx *ctx, struct rule *rule, return -1; if (stmt->flags & STMT_F_TERMINAL) tstmt = stmt; + + ctx->inner_desc = NULL; } erec = rule_postprocess(rule); diff --git a/src/expression.c b/src/expression.c index 7390089cf57d..ce7fef091764 100644 --- a/src/expression.c +++ b/src/expression.c @@ -29,6 +29,7 @@ extern const struct expr_ops ct_expr_ops; extern const struct expr_ops fib_expr_ops; extern const struct expr_ops hash_expr_ops; +extern const struct expr_ops inner_expr_ops; extern const struct expr_ops meta_expr_ops; extern const struct expr_ops numgen_expr_ops; extern const struct expr_ops osf_expr_ops; diff --git a/src/meta.c b/src/meta.c index 257bbc9fe97b..bd8a41ba3a03 100644 --- a/src/meta.c +++ b/src/meta.c @@ -734,6 +734,7 @@ static void meta_expr_clone(struct expr *new, const struct expr *expr) { new->meta.key = expr->meta.key; new->meta.base = expr->meta.base; + new->meta.inner_desc = expr->meta.inner_desc; } /** @@ -807,13 +808,19 @@ static void meta_expr_pctx_update(struct proto_ctx *ctx, } #define NFTNL_UDATA_META_KEY 0 -#define NFTNL_UDATA_META_MAX 1 +#define NFTNL_UDATA_META_INNER_DESC 1 +#define NFTNL_UDATA_META_MAX 2 static int meta_expr_build_udata(struct nftnl_udata_buf *udbuf, const struct expr *expr) { nftnl_udata_put_u32(udbuf, NFTNL_UDATA_META_KEY, expr->meta.key); + if (expr->meta.inner_desc) { + nftnl_udata_put_u32(udbuf, NFTNL_UDATA_META_INNER_DESC, + expr->meta.inner_desc->id); + } + return 0; } @@ -825,6 +832,7 @@ static int meta_parse_udata(const struct nftnl_udata *attr, void *data) switch (type) { case NFTNL_UDATA_META_KEY: + case NFTNL_UDATA_META_INNER_DESC: if (len != sizeof(uint32_t)) return -1; break; @@ -839,6 +847,8 @@ static int meta_parse_udata(const struct nftnl_udata *attr, void *data) static struct expr *meta_expr_parse_udata(const struct nftnl_udata *attr) { const struct nftnl_udata *ud[NFTNL_UDATA_META_MAX + 1] = {}; + const struct proto_desc *desc; + struct expr *expr; uint32_t key; int err; @@ -852,7 +862,14 @@ static struct expr *meta_expr_parse_udata(const struct nftnl_udata *attr) key = nftnl_udata_get_u32(ud[NFTNL_UDATA_META_KEY]); - return meta_expr_alloc(&internal_location, key); + expr = meta_expr_alloc(&internal_location, key); + + if (ud[NFTNL_UDATA_META_INNER_DESC]) { + desc = find_proto_desc(ud[NFTNL_UDATA_META_INNER_DESC]); + expr->meta.inner_desc = desc; + } + + return expr; } const struct expr_ops meta_expr_ops = { diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index d5e1c4097f90..897ff776f62f 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -32,7 +32,7 @@ struct dl_proto_ctx *dl_proto_ctx(struct rule_pp_ctx *ctx) { - return &ctx->_dl; + return ctx->dl; } static int netlink_parse_expr(const struct nftnl_expr *nle, @@ -618,6 +618,10 @@ static void netlink_parse_payload_expr(struct netlink_parse_ctx *ctx, struct expr *expr; base = nftnl_expr_get_u32(nle, NFTNL_EXPR_PAYLOAD_BASE) + 1; + + if (base == NFT_PAYLOAD_TUN_HEADER + 1) + base = NFT_PAYLOAD_INNER_HEADER + 1; + offset = nftnl_expr_get_u32(nle, NFTNL_EXPR_PAYLOAD_OFFSET) * BITS_PER_BYTE; len = nftnl_expr_get_u32(nle, NFTNL_EXPR_PAYLOAD_LEN) * BITS_PER_BYTE; @@ -625,9 +629,80 @@ static void netlink_parse_payload_expr(struct netlink_parse_ctx *ctx, payload_init_raw(expr, base, offset, len); dreg = netlink_parse_register(nle, NFTNL_EXPR_PAYLOAD_DREG); + + if (ctx->inner) + ctx->inner_reg = dreg; + netlink_set_register(ctx, dreg, expr); } +static void netlink_parse_inner(struct netlink_parse_ctx *ctx, + const struct location *loc, + const struct nftnl_expr *nle) +{ + const struct proto_desc *inner_desc; + const struct nftnl_expr *inner_nle; + uint32_t hdrsize, flags, type; + struct expr *expr; + + hdrsize = nftnl_expr_get_u32(nle, NFTNL_EXPR_INNER_HDRSIZE); + type = nftnl_expr_get_u32(nle, NFTNL_EXPR_INNER_TYPE); + flags = nftnl_expr_get_u32(nle, NFTNL_EXPR_INNER_FLAGS); + + inner_nle = nftnl_expr_get(nle, NFTNL_EXPR_INNER_EXPR, NULL); + if (!inner_nle) { + netlink_error(ctx, loc, "Could not parse inner expression"); + return; + } + + inner_desc = proto_find_inner(type, hdrsize, flags); + + ctx->inner = true; + if (netlink_parse_expr(inner_nle, ctx) < 0) { + ctx->inner = false; + return; + } + ctx->inner = false; + + expr = netlink_get_register(ctx, loc, ctx->inner_reg); + assert(expr); + + if (expr->etype == EXPR_PAYLOAD && + expr->payload.base == PROTO_BASE_INNER_HDR) { + const struct proto_hdr_template *tmpl; + unsigned int i; + + for (i = 1; i < array_size(inner_desc->templates); i++) { + tmpl = &inner_desc->templates[i]; + + if (tmpl->len == 0) + return; + + if (tmpl->offset != expr->payload.offset || + tmpl->len != expr->len) + continue; + + expr->payload.desc = inner_desc; + expr->payload.tmpl = tmpl; + break; + } + } + + switch (expr->etype) { + case EXPR_PAYLOAD: + expr->payload.inner_desc = inner_desc; + break; + case EXPR_META: + expr->meta.inner_desc = inner_desc; + break; + default: + assert(0); + break; + } + + netlink_set_register(ctx, ctx->inner_reg, expr); +} + static void netlink_parse_payload_stmt(struct netlink_parse_ctx *ctx, const struct location *loc, const struct nftnl_expr *nle) @@ -784,6 +859,9 @@ static void netlink_parse_meta_expr(struct netlink_parse_ctx *ctx, expr = meta_expr_alloc(loc, key); dreg = netlink_parse_register(nle, NFTNL_EXPR_META_DREG); + if (ctx->inner) + ctx->inner_reg = dreg; + netlink_set_register(ctx, dreg, expr); } @@ -1777,6 +1855,7 @@ static const struct expr_handler netlink_parsers[] = { { .name = "bitwise", .parse = netlink_parse_bitwise }, { .name = "byteorder", .parse = netlink_parse_byteorder }, { .name = "payload", .parse = netlink_parse_payload }, + { .name = "inner", .parse = netlink_parse_inner }, { .name = "exthdr", .parse = netlink_parse_exthdr }, { .name = "meta", .parse = netlink_parse_meta }, { .name = "socket", .parse = netlink_parse_socket }, @@ -1910,6 +1989,14 @@ static void payload_match_expand(struct rule_pp_ctx *ctx, assert(left->payload.base); assert(base == left->payload.base); + if (expr->left->payload.inner_desc) { + if (expr->left->payload.inner_desc == expr->left->payload.desc) { + nexpr->left->payload.desc = expr->left->payload.desc; + nexpr->left->payload.tmpl = expr->left->payload.tmpl; + } + nexpr->left->payload.inner_desc = expr->left->payload.inner_desc; + } + if (payload_is_stacked(dl->pctx.protocol[base].desc, nexpr)) base--; @@ -3056,19 +3143,75 @@ rule_maybe_reset_payload_deps(struct payload_dep_ctx *pdctx, enum stmt_types t) payload_dependency_reset(pdctx); } +static bool has_inner_desc(const struct expr *expr) +{ + struct expr *i; + + switch (expr->etype) { + case EXPR_BINOP: + return has_inner_desc(expr->left); + case EXPR_CONCAT: + list_for_each_entry(i, &expr->expressions, list) { + if (has_inner_desc(i)) + return true; + } + break; + case EXPR_META: + return expr->meta.inner_desc; + case EXPR_PAYLOAD: + return expr->payload.inner_desc; + case EXPR_SET_ELEM: + return has_inner_desc(expr->key); + default: + break; + } + + return false; +} + +static struct dl_proto_ctx *rule_update_dl_proto_ctx(struct rule_pp_ctx *rctx) +{ + const struct stmt *stmt = rctx->stmt; + bool inner = false; + + switch (stmt->ops->type) { + case STMT_EXPRESSION: + if (has_inner_desc(stmt->expr->left)) + inner = true; + break; + case STMT_SET: + if (has_inner_desc(stmt->set.key)) + inner = true; + break; + default: + break; + } + + if (inner) + rctx->dl = &rctx->_dl[1]; + else + rctx->dl = &rctx->_dl[0]; + + return rctx->dl; +} + static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *rule) { struct stmt *stmt, *next; + struct dl_proto_ctx *dl; struct rule_pp_ctx rctx; struct expr *expr; memset(&rctx, 0, sizeof(rctx)); - proto_ctx_init(&rctx._dl.pctx, rule->handle.family, ctx->debug_mask); + proto_ctx_init(&rctx._dl[0].pctx, rule->handle.family, ctx->debug_mask); + /* use NFPROTO_BRIDGE to set up proto_eth as base protocol. */ + proto_ctx_init(&rctx._dl[1].pctx, NFPROTO_BRIDGE, ctx->debug_mask); list_for_each_entry_safe(stmt, next, &rule->stmts, list) { enum stmt_types type = stmt->ops->type; rctx.stmt = stmt; + dl = rule_update_dl_proto_ctx(&rctx); switch (type) { case STMT_EXPRESSION: @@ -3100,7 +3243,7 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r if (stmt->nat.addr != NULL) expr_postprocess(&rctx, &stmt->nat.addr); if (stmt->nat.proto != NULL) { - payload_dependency_reset(&rctx._dl.pdctx); + payload_dependency_reset(&dl->pdctx); expr_postprocess(&rctx, &stmt->nat.proto); } break; @@ -3108,7 +3251,7 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r if (stmt->tproxy.addr) expr_postprocess(&rctx, &stmt->tproxy.addr); if (stmt->tproxy.port) { - payload_dependency_reset(&rctx._dl.pdctx); + payload_dependency_reset(&dl->pdctx); expr_postprocess(&rctx, &stmt->tproxy.port); } break; @@ -3146,9 +3289,9 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r break; } - rctx._dl.pdctx.prev = rctx.stmt; + dl->pdctx.prev = rctx.stmt; - rule_maybe_reset_payload_deps(&rctx._dl.pdctx, type); + rule_maybe_reset_payload_deps(&dl->pdctx, type); } } diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c index c8bbcb7452b0..b5a3c855aabd 100644 --- a/src/netlink_linearize.c +++ b/src/netlink_linearize.c @@ -178,9 +178,8 @@ static void netlink_gen_hash(struct netlink_linearize_ctx *ctx, nft_rule_add_expr(ctx, nle, &expr->location); } -static void netlink_gen_payload(struct netlink_linearize_ctx *ctx, - const struct expr *expr, - enum nft_registers dreg) +static struct nftnl_expr * +__netlink_gen_payload(const struct expr *expr, enum nft_registers dreg) { struct nftnl_expr *nle; @@ -193,6 +192,72 @@ static void netlink_gen_payload(struct netlink_linearize_ctx *ctx, nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_LEN, div_round_up(expr->len, BITS_PER_BYTE)); + return nle; +} + +static struct nftnl_expr * +__netlink_gen_meta(const struct expr *expr, enum nft_registers dreg) +{ + struct nftnl_expr *nle; + + nle = alloc_nft_expr("meta"); + netlink_put_register(nle, NFTNL_EXPR_META_DREG, dreg); + nftnl_expr_set_u32(nle, NFTNL_EXPR_META_KEY, expr->meta.key); + + return nle; +} + +static struct nftnl_expr *netlink_gen_inner_expr(const struct expr *expr, + enum nft_registers dreg) +{ + struct expr *_expr = (struct expr *)expr; + struct nftnl_expr *nle; + + switch (expr->etype) { + case EXPR_PAYLOAD: + if (expr->payload.base == NFT_PAYLOAD_INNER_HEADER + 1) + _expr->payload.base = NFT_PAYLOAD_TUN_HEADER + 1; + + nle = __netlink_gen_payload(expr, dreg); + break; + case EXPR_META: + nle = __netlink_gen_meta(expr, dreg); + break; + default: + assert(0); + break; + } + + return nle; +} + +static void netlink_gen_inner(struct netlink_linearize_ctx *ctx, + const struct expr *expr, + enum nft_registers dreg, + const struct proto_desc *desc) +{ + struct nftnl_expr *nle; + + nle = alloc_nft_expr("inner"); + nftnl_expr_set_u32(nle, NFTNL_EXPR_INNER_HDRSIZE, desc->inner.hdrsize); + nftnl_expr_set_u32(nle, NFTNL_EXPR_INNER_FLAGS, desc->inner.flags); + nftnl_expr_set_u32(nle, NFTNL_EXPR_INNER_TYPE, desc->inner.type); + nftnl_expr_set(nle, NFTNL_EXPR_INNER_EXPR, netlink_gen_inner_expr(expr, dreg), 0); + nft_rule_add_expr(ctx, nle, &expr->location); +} + +static void netlink_gen_payload(struct netlink_linearize_ctx *ctx, + const struct expr *expr, + enum nft_registers dreg) +{ + struct nftnl_expr *nle; + + if (expr->payload.inner_desc) { + netlink_gen_inner(ctx, expr, dreg, expr->payload.inner_desc); + return; + } + + nle = __netlink_gen_payload(expr, dreg); nft_rule_add_expr(ctx, nle, &expr->location); } @@ -221,9 +286,12 @@ static void netlink_gen_meta(struct netlink_linearize_ctx *ctx, { struct nftnl_expr *nle; - nle = alloc_nft_expr("meta"); - netlink_put_register(nle, NFTNL_EXPR_META_DREG, dreg); - nftnl_expr_set_u32(nle, NFTNL_EXPR_META_KEY, expr->meta.key); + if (expr->meta.inner_desc) { + netlink_gen_inner(ctx, expr, dreg, expr->meta.inner_desc); + return; + } + + nle = __netlink_gen_meta(expr, dreg); nft_rule_add_expr(ctx, nle, &expr->location); } diff --git a/src/parser_bison.y b/src/parser_bison.y index 760c23cf3322..213254ecc5f0 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -439,6 +439,9 @@ int nft_lex(void *, void *, void *); %token DCCP "dccp" +%token VXLAN "vxlan" +%token VNI "vni" + %token SCTP "sctp" %token CHUNK "chunk" %token DATA "data" @@ -897,6 +900,10 @@ int nft_lex(void *, void *, void *); %type tcpopt_field_maxseg tcpopt_field_mptcp tcpopt_field_sack tcpopt_field_tsopt tcpopt_field_window %type tcp_hdr_option_kind_and_field +%type inner_eth_expr inner_inet_expr inner_expr vxlan_hdr_expr +%destructor { expr_free($$); } inner_eth_expr inner_inet_expr inner_expr vxlan_hdr_expr +%type vxlan_hdr_field + %type optstrip_stmt %destructor { stmt_free($$); } optstrip_stmt @@ -5311,6 +5318,7 @@ payload_expr : payload_raw_expr | dccp_hdr_expr | sctp_hdr_expr | th_hdr_expr + | vxlan_hdr_expr ; payload_raw_expr : AT payload_base_spec COMMA NUM COMMA NUM close_scope_at @@ -5562,6 +5570,51 @@ tcp_hdr_expr : TCP tcp_hdr_field } ; +inner_inet_expr : ip_hdr_expr + | icmp_hdr_expr + | igmp_hdr_expr + | ip6_hdr_expr + | icmp6_hdr_expr + | auth_hdr_expr + | esp_hdr_expr + | comp_hdr_expr + | udp_hdr_expr + | udplite_hdr_expr + | tcp_hdr_expr close_scope_tcp + | dccp_hdr_expr + | sctp_hdr_expr + | th_hdr_expr + ; + +inner_eth_expr : eth_hdr_expr + | vlan_hdr_expr + | arp_hdr_expr + ; + +inner_expr : inner_eth_expr + | inner_inet_expr + ; + +vxlan_hdr_expr : VXLAN vxlan_hdr_field + { + struct expr *expr; + + expr = payload_expr_alloc(&@$, &proto_vxlan, $2); + expr->payload.inner_desc = &proto_vxlan; + $$ = expr; + } + | VXLAN inner_expr + { + $$ = $2; + $$->location = @$; + $$->payload.inner_desc = &proto_vxlan; + } + ; + +vxlan_hdr_field : VNI { $$ = VXLANHDR_VNI; } + | FLAGS { $$ = VXLANHDR_FLAGS; } + ; + optstrip_stmt : RESET TCP OPTION tcp_hdr_option_type close_scope_tcp { $$ = optstrip_stmt_alloc(&@$, tcpopt_expr_alloc(&@$, diff --git a/src/payload.c b/src/payload.c index 07f02359a7e7..7abb5f5cbf51 100644 --- a/src/payload.c +++ b/src/payload.c @@ -47,6 +47,10 @@ static void payload_expr_print(const struct expr *expr, struct output_ctx *octx) const struct proto_desc *desc; const struct proto_hdr_template *tmpl; + if (expr->payload.inner_desc && + expr->payload.inner_desc != expr->payload.desc) + nft_print(octx, "%s ", expr->payload.inner_desc->name); + desc = expr->payload.desc; tmpl = expr->payload.tmpl; if (payload_is_known(expr)) @@ -67,6 +71,7 @@ bool payload_expr_cmp(const struct expr *e1, const struct expr *e2) static void payload_expr_clone(struct expr *new, const struct expr *expr) { + new->payload.inner_desc = expr->payload.inner_desc; new->payload.desc = expr->payload.desc; new->payload.tmpl = expr->payload.tmpl; new->payload.base = expr->payload.base; @@ -132,7 +137,8 @@ static void payload_expr_pctx_update(struct proto_ctx *ctx, #define NFTNL_UDATA_SET_KEY_PAYLOAD_BASE 2 #define NFTNL_UDATA_SET_KEY_PAYLOAD_OFFSET 3 #define NFTNL_UDATA_SET_KEY_PAYLOAD_LEN 4 -#define NFTNL_UDATA_SET_KEY_PAYLOAD_MAX 5 +#define NFTNL_UDATA_SET_KEY_PAYLOAD_INNER_DESC 5 +#define NFTNL_UDATA_SET_KEY_PAYLOAD_MAX 6 static unsigned int expr_payload_type(const struct proto_desc *desc, const struct proto_hdr_template *tmpl) @@ -162,10 +168,15 @@ static int payload_expr_build_udata(struct nftnl_udata_buf *udbuf, if (expr->dtype->type == TYPE_INTEGER) nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_KEY_PAYLOAD_LEN, expr->len); + if (expr->payload.inner_desc) { + nftnl_udata_put_u32(udbuf, NFTNL_UDATA_SET_KEY_PAYLOAD_INNER_DESC, + expr->payload.inner_desc->id); + } + return 0; } -static const struct proto_desc *find_proto_desc(const struct nftnl_udata *ud) +const struct proto_desc *find_proto_desc(const struct nftnl_udata *ud) { return proto_find_desc(nftnl_udata_get_u32(ud)); } @@ -182,6 +193,7 @@ static int payload_parse_udata(const struct nftnl_udata *attr, void *data) case NFTNL_UDATA_SET_KEY_PAYLOAD_BASE: case NFTNL_UDATA_SET_KEY_PAYLOAD_OFFSET: case NFTNL_UDATA_SET_KEY_PAYLOAD_LEN: + case NFTNL_UDATA_SET_KEY_PAYLOAD_INNER_DESC: if (len != sizeof(uint32_t)) return -1; break; @@ -245,6 +257,11 @@ static struct expr *payload_expr_parse_udata(const struct nftnl_udata *attr) expr->dtype = dtype; } + if (ud[NFTNL_UDATA_SET_KEY_PAYLOAD_INNER_DESC]) { + desc = find_proto_desc(ud[NFTNL_UDATA_SET_KEY_PAYLOAD_INNER_DESC]); + expr->payload.inner_desc = desc; + } + return expr; } @@ -418,6 +435,13 @@ static int payload_add_dependency(struct eval_ctx *ctx, "dependency statement is invalid"); } + if (ctx->inner_desc) { + if (tmpl->meta_key) + left->meta.inner_desc = ctx->inner_desc; + else + left->payload.inner_desc = ctx->inner_desc; + } + pctx = eval_proto_ctx(ctx); relational_expr_pctx_update(pctx, dep); *res = stmt; @@ -1109,6 +1133,10 @@ raw: new = payload_expr_alloc(&expr->location, NULL, 0); payload_init_raw(new, expr->payload.base, payload_offset, expr->len); + + if (expr->payload.inner_desc) + new->dtype = &integer_type; + list_add_tail(&new->list, list); } @@ -1130,6 +1158,9 @@ bool payload_can_merge(const struct expr *e1, const struct expr *e2) { unsigned int total; + if (e1->payload.inner_desc != e2->payload.inner_desc) + return false; + if (!payload_is_adjacent(e1, e2)) return false; @@ -1186,6 +1217,8 @@ struct expr *payload_expr_join(const struct expr *e1, const struct expr *e2) expr->payload.base = e1->payload.base; expr->payload.offset = e1->payload.offset; expr->len = e1->len + e2->len; + expr->payload.inner_desc = e1->payload.inner_desc; + return expr; } diff --git a/src/proto.c b/src/proto.c index c8b3361bbee6..1e0476bacffe 100644 --- a/src/proto.c +++ b/src/proto.c @@ -88,6 +88,27 @@ int proto_find_num(const struct proto_desc *base, return -1; } +static const struct proto_desc *inner_protocols[] = { + &proto_vxlan, +}; + +const struct proto_desc *proto_find_inner(uint32_t type, uint32_t hdrsize, + uint32_t flags) +{ + const struct proto_desc *desc; + unsigned int i; + + for (i = 0; i < array_size(inner_protocols); i++) { + desc = inner_protocols[i]; + if (desc->inner.type == type && + desc->inner.hdrsize == hdrsize && + desc->inner.flags == flags) + return inner_protocols[i]; + } + + return &proto_unknown; +} + static const struct dev_proto_desc dev_proto_desc[] = { DEV_PROTO_DESC(ARPHRD_ETHER, &proto_eth), }; @@ -228,6 +249,8 @@ void proto_ctx_update(struct proto_ctx *ctx, enum proto_bases base, ctx->protocol[base].protos[i].location = *loc; } break; + case PROTO_BASE_INNER_HDR: + break; default: BUG("unknown protocol base %d", base); } @@ -513,6 +536,9 @@ const struct proto_desc proto_udp = { [UDPHDR_LENGTH] = UDPHDR_FIELD("length", len), [UDPHDR_CHECKSUM] = UDPHDR_FIELD("checksum", check), }, + .protocols = { + PROTO_LINK(0, &proto_vxlan), + }, }; const struct proto_desc proto_udplite = { @@ -1135,6 +1161,31 @@ const struct proto_desc proto_eth = { }; +/* + * VXLAN + */ + +const struct proto_desc proto_vxlan = { + .name = "vxlan", + .id = PROTO_DESC_VXLAN, + .base = PROTO_BASE_INNER_HDR, + .templates = { + [VXLANHDR_FLAGS] = HDR_BITFIELD("flags", &bitmask_type, 0, 8), + [VXLANHDR_VNI] = HDR_BITFIELD("vni", &integer_type, (4 * BITS_PER_BYTE), 24), + }, + .protocols = { + PROTO_LINK(__constant_htons(ETH_P_IP), &proto_ip), + PROTO_LINK(__constant_htons(ETH_P_ARP), &proto_arp), + PROTO_LINK(__constant_htons(ETH_P_IPV6), &proto_ip6), + PROTO_LINK(__constant_htons(ETH_P_8021Q), &proto_vlan), + }, + .inner = { + .hdrsize = sizeof(struct vxlanhdr), + .flags = NFT_INNER_HDRSIZE | NFT_INNER_LL | NFT_INNER_NH | NFT_INNER_TH, + .type = NFT_INNER_VXLAN, + }, +}; + /* * Dummy protocol for netdev tables. */ @@ -1171,6 +1222,7 @@ static const struct proto_desc *proto_definitions[PROTO_DESC_MAX + 1] = { [PROTO_DESC_ARP] = &proto_arp, [PROTO_DESC_VLAN] = &proto_vlan, [PROTO_DESC_ETHER] = &proto_eth, + [PROTO_DESC_VXLAN] = &proto_vxlan, }; const struct proto_desc *proto_find_desc(enum proto_desc_id desc_id) diff --git a/src/rule.c b/src/rule.c index d1ee6c2ee067..d993fc6a1b06 100644 --- a/src/rule.c +++ b/src/rule.c @@ -2892,7 +2892,8 @@ static void stmt_reduce(const struct rule *rule) switch (stmt->expr->op) { case OP_EQ: case OP_IMPLICIT: - if (stmt->expr->left->meta.key == NFT_META_PROTOCOL) { + if (stmt->expr->left->meta.key == NFT_META_PROTOCOL && + !stmt->expr->left->meta.inner_desc) { uint16_t protocol; protocol = mpz_get_uint16(stmt->expr->right->value); diff --git a/src/scanner.l b/src/scanner.l index 1371cd044b65..289b4d078855 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -620,6 +620,9 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) "dport" { return DPORT; } } +"vxlan" { return VXLAN; } +"vni" { return VNI; } + "tcp" { scanner_push_start_cond(yyscanner, SCANSTATE_TCP); return TCP; } "dccp" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_DCCP); return DCCP; } From patchwork Mon Oct 17 11:03:56 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pablo Neira Ayuso X-Patchwork-Id: 1690841 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=2620:137:e000::1:20; helo=out1.vger.email; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Received: from out1.vger.email (out1.vger.email [IPv6:2620:137:e000::1:20]) by legolas.ozlabs.org (Postfix) with ESMTP id 4MrYzB6W2Yz23jp for ; Mon, 17 Oct 2022 22:04:22 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230039AbiJQLEU (ORCPT ); Mon, 17 Oct 2022 07:04:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34288 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230096AbiJQLET (ORCPT ); Mon, 17 Oct 2022 07:04:19 -0400 Received: from mail.netfilter.org (mail.netfilter.org [217.70.188.207]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id C8E0E615B for ; Mon, 17 Oct 2022 04:04:17 -0700 (PDT) From: Pablo Neira Ayuso To: netfilter-devel@vger.kernel.org Subject: [PATCH nft,v2 04/16] tests: py: add vxlan tests Date: Mon, 17 Oct 2022 13:03:56 +0200 Message-Id: <20221017110408.742223-5-pablo@netfilter.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221017110408.742223-1-pablo@netfilter.org> References: <20221017110408.742223-1-pablo@netfilter.org> MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Signed-off-by: Pablo Neira Ayuso --- tests/py/inet/vxlan.t | 23 +++++++ tests/py/inet/vxlan.t.payload | 114 ++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 tests/py/inet/vxlan.t create mode 100644 tests/py/inet/vxlan.t.payload diff --git a/tests/py/inet/vxlan.t b/tests/py/inet/vxlan.t new file mode 100644 index 000000000000..10cdb7a44082 --- /dev/null +++ b/tests/py/inet/vxlan.t @@ -0,0 +1,23 @@ +:input;type filter hook input priority 0 +:ingress;type filter hook ingress device lo priority 0 +:egress;type filter hook egress device lo priority 0 + +*ip;test-ip4;input +*ip6;test-ip6;input +*inet;test-inet;input +*netdev;test-netdev;ingress,egress + +vxlan vni 10;fail +udp dport 4789 vxlan vni 10;ok +udp dport 4789 vxlan ip saddr 10.141.11.2;ok +udp dport 4789 vxlan ip saddr 10.141.11.0/24;ok +udp dport 4789 vxlan ip protocol 1;ok +udp dport 4789 vxlan udp sport 8888;ok +udp dport 4789 vxlan icmp type echo-reply;ok +udp dport 4789 vxlan ether saddr 62:87:4d:d6:19:05;ok +udp dport 4789 vxlan vlan id 10;ok +udp dport 4789 vxlan ip dscp 0x02;ok +udp dport 4789 vxlan ip dscp 0x02;ok +udp dport 4789 vxlan ip saddr . vxlan ip daddr { 1.2.3.4 . 4.3.2.1 };ok + +udp dport 4789 vxlan ip saddr set 1.2.3.4;fail diff --git a/tests/py/inet/vxlan.t.payload b/tests/py/inet/vxlan.t.payload new file mode 100644 index 000000000000..cde8e56f8b4b --- /dev/null +++ b/tests/py/inet/vxlan.t.payload @@ -0,0 +1,114 @@ +# udp dport 4789 vxlan vni 10 +netdev test-netdev ingress + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000011 ] + [ payload load 2b @ transport header + 2 => reg 1 ] + [ cmp eq reg 1 0x0000b512 ] + [ inner type 1 hdrsize 8 flags f [ payload load 3b @ unknown header + 4 => reg 1 ] ] + [ cmp eq reg 1 0x000a0000 ] + +# udp dport 4789 vxlan ip saddr 10.141.11.2 +netdev test-netdev ingress + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000011 ] + [ payload load 2b @ transport header + 2 => reg 1 ] + [ cmp eq reg 1 0x0000b512 ] + [ inner type 1 hdrsize 8 flags f [ meta load protocol => reg 1 ] ] + [ cmp eq reg 1 0x00000008 ] + [ inner type 1 hdrsize 8 flags f [ payload load 4b @ network header + 12 => reg 1 ] ] + [ cmp eq reg 1 0x020b8d0a ] + +# udp dport 4789 vxlan ip saddr 10.141.11.0/24 +netdev test-netdev ingress + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000011 ] + [ payload load 2b @ transport header + 2 => reg 1 ] + [ cmp eq reg 1 0x0000b512 ] + [ inner type 1 hdrsize 8 flags f [ meta load protocol => reg 1 ] ] + [ cmp eq reg 1 0x00000008 ] + [ inner type 1 hdrsize 8 flags f [ payload load 3b @ network header + 12 => reg 1 ] ] + [ cmp eq reg 1 0x000b8d0a ] + +# udp dport 4789 vxlan ip protocol 1 +netdev test-netdev ingress + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000011 ] + [ payload load 2b @ transport header + 2 => reg 1 ] + [ cmp eq reg 1 0x0000b512 ] + [ inner type 1 hdrsize 8 flags f [ meta load protocol => reg 1 ] ] + [ cmp eq reg 1 0x00000008 ] + [ inner type 1 hdrsize 8 flags f [ payload load 1b @ network header + 9 => reg 1 ] ] + [ cmp eq reg 1 0x00000001 ] + +# udp dport 4789 vxlan udp sport 8888 +netdev test-netdev ingress + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000011 ] + [ payload load 2b @ transport header + 2 => reg 1 ] + [ cmp eq reg 1 0x0000b512 ] + [ inner type 1 hdrsize 8 flags f [ meta load l4proto => reg 1 ] ] + [ cmp eq reg 1 0x00000011 ] + [ inner type 1 hdrsize 8 flags f [ payload load 2b @ transport header + 0 => reg 1 ] ] + [ cmp eq reg 1 0x0000b822 ] + +# udp dport 4789 vxlan icmp type echo-reply +netdev test-netdev ingress + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000011 ] + [ payload load 2b @ transport header + 2 => reg 1 ] + [ cmp eq reg 1 0x0000b512 ] + [ inner type 1 hdrsize 8 flags f [ payload load 2b @ link header + 12 => reg 1 ] ] + [ cmp eq reg 1 0x00000008 ] + [ inner type 1 hdrsize 8 flags f [ meta load l4proto => reg 1 ] ] + [ cmp eq reg 1 0x00000001 ] + [ inner type 1 hdrsize 8 flags f [ payload load 1b @ transport header + 0 => reg 1 ] ] + [ cmp eq reg 1 0x00000000 ] + +# udp dport 4789 vxlan ether saddr 62:87:4d:d6:19:05 +netdev test-netdev ingress + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000011 ] + [ payload load 2b @ transport header + 2 => reg 1 ] + [ cmp eq reg 1 0x0000b512 ] + [ inner type 1 hdrsize 8 flags f [ payload load 6b @ link header + 6 => reg 1 ] ] + [ cmp eq reg 1 0xd64d8762 0x00000519 ] + +# udp dport 4789 vxlan vlan id 10 +netdev test-netdev ingress + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000011 ] + [ payload load 2b @ transport header + 2 => reg 1 ] + [ cmp eq reg 1 0x0000b512 ] + [ inner type 1 hdrsize 8 flags f [ payload load 2b @ link header + 12 => reg 1 ] ] + [ cmp eq reg 1 0x00000081 ] + [ inner type 1 hdrsize 8 flags f [ payload load 2b @ link header + 14 => reg 1 ] ] + [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ] + [ cmp eq reg 1 0x00000a00 ] + +# udp dport 4789 vxlan ip dscp 0x02 +netdev test-netdev ingress + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000011 ] + [ payload load 2b @ transport header + 2 => reg 1 ] + [ cmp eq reg 1 0x0000b512 ] + [ inner type 1 hdrsize 8 flags f [ meta load protocol => reg 1 ] ] + [ cmp eq reg 1 0x00000008 ] + [ inner type 1 hdrsize 8 flags f [ payload load 1b @ network header + 1 => reg 1 ] ] + [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ] + [ cmp eq reg 1 0x00000008 ] + +# udp dport 4789 vxlan ip saddr . vxlan ip daddr { 1.2.3.4 . 4.3.2.1 } +__set%d test-netdev 3 size 1 +__set%d test-netdev 0 + element 04030201 01020304 : 0 [end] +netdev test-netdev ingress + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000011 ] + [ payload load 2b @ transport header + 2 => reg 1 ] + [ cmp eq reg 1 0x0000b512 ] + [ inner type 1 hdrsize 8 flags f [ meta load protocol => reg 1 ] ] + [ cmp eq reg 1 0x00000008 ] + [ inner type 1 hdrsize 8 flags f [ payload load 4b @ network header + 12 => reg 1 ] ] + [ inner type 1 hdrsize 8 flags f [ payload load 4b @ network header + 16 => reg 9 ] ] + [ lookup reg 1 set __set%d ] + From patchwork Mon Oct 17 11:03:57 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pablo Neira Ayuso X-Patchwork-Id: 1690840 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=2620:137:e000::1:20; helo=out1.vger.email; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Received: from out1.vger.email (out1.vger.email [IPv6:2620:137:e000::1:20]) by legolas.ozlabs.org (Postfix) with ESMTP id 4MrYz92g8cz23jp for ; Mon, 17 Oct 2022 22:04:21 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229815AbiJQLEU (ORCPT ); Mon, 17 Oct 2022 07:04:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34290 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230039AbiJQLET (ORCPT ); Mon, 17 Oct 2022 07:04:19 -0400 Received: from mail.netfilter.org (mail.netfilter.org [217.70.188.207]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 472256178 for ; Mon, 17 Oct 2022 04:04:18 -0700 (PDT) From: Pablo Neira Ayuso To: netfilter-devel@vger.kernel.org Subject: [PATCH nft,v2 05/16] tests: shell: add vxlan set tests Date: Mon, 17 Oct 2022 13:03:57 +0200 Message-Id: <20221017110408.742223-6-pablo@netfilter.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221017110408.742223-1-pablo@netfilter.org> References: <20221017110408.742223-1-pablo@netfilter.org> MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Signed-off-by: Pablo Neira Ayuso --- tests/shell/testcases/sets/dumps/inner_0.nft | 18 ++++++++++++++ tests/shell/testcases/sets/inner_0 | 25 ++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 tests/shell/testcases/sets/dumps/inner_0.nft create mode 100755 tests/shell/testcases/sets/inner_0 diff --git a/tests/shell/testcases/sets/dumps/inner_0.nft b/tests/shell/testcases/sets/dumps/inner_0.nft new file mode 100644 index 000000000000..925ca777ccd4 --- /dev/null +++ b/tests/shell/testcases/sets/dumps/inner_0.nft @@ -0,0 +1,18 @@ +table netdev x { + set x { + typeof vxlan ip saddr . vxlan ip daddr + elements = { 3.3.3.3 . 4.4.4.4 } + } + + set y { + typeof vxlan ip saddr + size 65535 + flags dynamic + } + + chain y { + udp dport 4789 vxlan ip saddr . vxlan ip daddr { 1.1.1.1 . 2.2.2.2 } counter packets 0 bytes 0 + udp dport 4789 vxlan ip saddr . vxlan ip daddr @x counter packets 0 bytes 0 + udp dport 4789 update @y { vxlan ip saddr } + } +} diff --git a/tests/shell/testcases/sets/inner_0 b/tests/shell/testcases/sets/inner_0 new file mode 100755 index 000000000000..0eb172a8cf06 --- /dev/null +++ b/tests/shell/testcases/sets/inner_0 @@ -0,0 +1,25 @@ +#!/bin/bash + +set -e + +RULESET="table netdev x { + set x { + typeof vxlan ip saddr . vxlan ip daddr + elements = { + 3.3.3.3 . 4.4.4.4, + } + } + + set y { + typeof vxlan ip saddr + flags dynamic + } + + chain y { + udp dport 4789 vxlan ip saddr . vxlan ip daddr { 1.1.1.1 . 2.2.2.2 } counter + udp dport 4789 vxlan ip saddr . vxlan ip daddr @x counter + udp dport 4789 update @y { vxlan ip saddr } + } +}" + +$NFT -f - <<< $RULESET From patchwork Mon Oct 17 11:03:58 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pablo Neira Ayuso X-Patchwork-Id: 1690842 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=2620:137:e000::1:20; helo=out1.vger.email; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Received: from out1.vger.email (out1.vger.email [IPv6:2620:137:e000::1:20]) by legolas.ozlabs.org (Postfix) with ESMTP id 4MrYzG2dJ9z23jp for ; Mon, 17 Oct 2022 22:04:26 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230231AbiJQLEW (ORCPT ); Mon, 17 Oct 2022 07:04:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34436 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230173AbiJQLEU (ORCPT ); Mon, 17 Oct 2022 07:04:20 -0400 Received: from mail.netfilter.org (mail.netfilter.org [217.70.188.207]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 0F6002AC1 for ; Mon, 17 Oct 2022 04:04:19 -0700 (PDT) From: Pablo Neira Ayuso To: netfilter-devel@vger.kernel.org Subject: [PATCH nft,v2 06/16] doc: add vxlan matching expression Date: Mon, 17 Oct 2022 13:03:58 +0200 Message-Id: <20221017110408.742223-7-pablo@netfilter.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221017110408.742223-1-pablo@netfilter.org> References: <20221017110408.742223-1-pablo@netfilter.org> MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Document new vxlan matching expression. This includes support for matching the encapsulated ethernet frame layer 2, 3 and 4 headers. Signed-off-by: Pablo Neira Ayuso --- doc/payload-expression.txt | 71 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) diff --git a/doc/payload-expression.txt b/doc/payload-expression.txt index 113f5bfc597c..c80198878c1a 100644 --- a/doc/payload-expression.txt +++ b/doc/payload-expression.txt @@ -532,6 +532,77 @@ compression Parameter Index | integer (16 bit) |============================ +VXLAN HEADER EXPRESSION +~~~~~~~~~~~~~~~~~~~~~~~ +[verse] +*vxlan* {*vni* | *flags*} +*vxlan* *ether* {*daddr* | *saddr* | *type*} +*vxlan* *vlan* {*id* | *dei* | *pcp* | *type*} +*vxlan* *ip* {*version* | *hdrlength* | *dscp* | *ecn* | *length* | *id* | *frag-off* | *ttl* | *protocol* | *checksum* | *saddr* | *daddr* } +*vxlan* *ip6* {*version* | *dscp* | *ecn* | *flowlabel* | *length* | *nexthdr* | *hoplimit* | *saddr* | *daddr*} +*vxlan* *tcp* {*sport* | *dport* | *sequence* | *ackseq* | *doff* | *reserved* | *flags* | *window* | *checksum* | *urgptr*} +*vxlan* *udp* {*sport* | *dport* | *length* | *checksum*} + +The vxlan expression is used to match on the vxlan header fields. The vxlan +header encapsulates a ethernet frame within a *udp* packet. This expression +requires that you restrict the matching to *udp* packets (usually at +port 4789 according to IANA-assigned ports). + +.VXLAN header expression +[options="header"] +|================== +|Keyword| Description| Type +|flags| +vxlan flags| +integer (8 bit) +|vni| +Virtual Network ID (VNI)| +integer (24 bit) +|================== + +.Matching inner TCP destination port encapsulated in vxlan +---------------------------------------------------------- +netdev filter ingress udp dport 4789 vxlan tcp dport 80 counter +---------------------------------------------------------- + +ARP HEADER EXPRESSION +~~~~~~~~~~~~~~~~~~~~~ +[verse] +*arp* {*htype* | *ptype* | *hlen* | *plen* | *operation* | *saddr* { *ip* | *ether* } | *daddr* { *ip* | *ether* } + +.ARP header expression +[options="header"] +|================== +|Keyword| Description| Type +|htype| +ARP hardware type| +integer (16 bit) +|ptype| +EtherType| +ether_type +|hlen| +Hardware address len| +integer (8 bit) +|plen| +Protocol address len | +integer (8 bit) +|operation| +Operation | +arp_op +|saddr ether| +Ethernet sender address| +ether_addr +|daddr ether| +Ethernet target address| +ether_addr +|saddr ip| +IPv4 sender address| +ipv4_addr +|daddr ip| +IPv4 target address| +ipv4_addr +|====================== + RAW PAYLOAD EXPRESSION ~~~~~~~~~~~~~~~~~~~~~~ [verse] From patchwork Mon Oct 17 11:03:59 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pablo Neira Ayuso X-Patchwork-Id: 1690843 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=2620:137:e000::1:20; helo=out1.vger.email; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Received: from out1.vger.email (out1.vger.email [IPv6:2620:137:e000::1:20]) by legolas.ozlabs.org (Postfix) with ESMTP id 4MrYzH2PtHz23kV for ; Mon, 17 Oct 2022 22:04:27 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230317AbiJQLEZ (ORCPT ); Mon, 17 Oct 2022 07:04:25 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34438 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230147AbiJQLEU (ORCPT ); Mon, 17 Oct 2022 07:04:20 -0400 Received: from mail.netfilter.org (mail.netfilter.org [217.70.188.207]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 3EFDD309 for ; Mon, 17 Oct 2022 04:04:19 -0700 (PDT) From: Pablo Neira Ayuso To: netfilter-devel@vger.kernel.org Subject: [PATCH nft,v2 07/16] src: display (inner) tag in --debug=proto-ctx Date: Mon, 17 Oct 2022 13:03:59 +0200 Message-Id: <20221017110408.742223-8-pablo@netfilter.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221017110408.742223-1-pablo@netfilter.org> References: <20221017110408.742223-1-pablo@netfilter.org> MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org For easier debugging, add decoration on protocol context: # nft --debug=proto-ctx add rule netdev x y udp dport 4789 vxlan ip protocol icmp counter update link layer protocol context (inner): link layer : netdev <- network layer : none transport layer : none payload data : none update network layer protocol context (inner): link layer : netdev network layer : ip <- transport layer : none payload data : none update network layer protocol context (inner): link layer : netdev network layer : ip <- transport layer : none payload data : none update transport layer protocol context (inner): link layer : netdev network layer : ip transport layer : icmp <- payload data : none Signed-off-by: Pablo Neira Ayuso --- include/proto.h | 3 ++- src/evaluate.c | 4 ++-- src/netlink.c | 2 +- src/netlink_delinearize.c | 4 ++-- src/proto.c | 7 +++++-- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/include/proto.h b/include/proto.h index 5bb7562db94b..32e0744854a5 100644 --- a/include/proto.h +++ b/include/proto.h @@ -190,6 +190,7 @@ extern const struct proto_desc *proto_dev_desc(uint16_t type); struct proto_ctx { unsigned int debug_mask; uint8_t family; + bool inner; union { struct { uint8_t type; @@ -209,7 +210,7 @@ struct proto_ctx { }; extern void proto_ctx_init(struct proto_ctx *ctx, unsigned int family, - unsigned int debug_mask); + unsigned int debug_mask, bool inner); extern void proto_ctx_update(struct proto_ctx *ctx, enum proto_bases base, const struct location *loc, const struct proto_desc *desc); diff --git a/src/evaluate.c b/src/evaluate.c index 6e3b6f187c83..19a232abf431 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -4590,9 +4590,9 @@ static int rule_evaluate(struct eval_ctx *ctx, struct rule *rule, struct stmt *stmt, *tstmt = NULL; struct error_record *erec; - proto_ctx_init(&ctx->_pctx[0], rule->handle.family, ctx->nft->debug_mask); + proto_ctx_init(&ctx->_pctx[0], rule->handle.family, ctx->nft->debug_mask, false); /* use NFPROTO_BRIDGE to set up proto_eth as base protocol. */ - proto_ctx_init(&ctx->_pctx[1], NFPROTO_BRIDGE, ctx->nft->debug_mask); + proto_ctx_init(&ctx->_pctx[1], NFPROTO_BRIDGE, ctx->nft->debug_mask, true); memset(&ctx->ectx, 0, sizeof(ctx->ectx)); ctx->rule = rule; diff --git a/src/netlink.c b/src/netlink.c index 799cf9b8ebef..e38bacf3ac3f 100644 --- a/src/netlink.c +++ b/src/netlink.c @@ -1995,7 +1995,7 @@ static void trace_print_packet(const struct nftnl_trace *nlt, meta_expr_alloc(&netlink_location, NFT_META_OIF), octx); - proto_ctx_init(&ctx, nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY), 0); + proto_ctx_init(&ctx, nftnl_trace_get_u32(nlt, NFTNL_TRACE_FAMILY), 0, false); ll_desc = ctx.protocol[PROTO_BASE_LL_HDR].desc; if ((ll_desc == &proto_inet || ll_desc == &proto_netdev) && nftnl_trace_is_set(nlt, NFTNL_TRACE_NFPROTO)) { diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index 897ff776f62f..54f140c48a13 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -3203,9 +3203,9 @@ static void rule_parse_postprocess(struct netlink_parse_ctx *ctx, struct rule *r struct expr *expr; memset(&rctx, 0, sizeof(rctx)); - proto_ctx_init(&rctx._dl[0].pctx, rule->handle.family, ctx->debug_mask); + proto_ctx_init(&rctx._dl[0].pctx, rule->handle.family, ctx->debug_mask, false); /* use NFPROTO_BRIDGE to set up proto_eth as base protocol. */ - proto_ctx_init(&rctx._dl[1].pctx, NFPROTO_BRIDGE, ctx->debug_mask); + proto_ctx_init(&rctx._dl[1].pctx, NFPROTO_BRIDGE, ctx->debug_mask, true); list_for_each_entry_safe(stmt, next, &rule->stmts, list) { enum stmt_types type = stmt->ops->type; diff --git a/src/proto.c b/src/proto.c index 1e0476bacffe..e6c1100bb448 100644 --- a/src/proto.c +++ b/src/proto.c @@ -181,7 +181,9 @@ static void proto_ctx_debug(const struct proto_ctx *ctx, enum proto_bases base, pr_debug(" %s", ctx->stacked_ll[i]->name); } - pr_debug("update %s protocol context:\n", proto_base_names[base]); + pr_debug("update %s protocol context%s:\n", + proto_base_names[base], ctx->inner ? " (inner)" : ""); + for (i = PROTO_BASE_LL_HDR; i <= PROTO_BASE_MAX; i++) { pr_debug(" %-20s: %s", proto_base_names[i], @@ -202,7 +204,7 @@ static void proto_ctx_debug(const struct proto_ctx *ctx, enum proto_bases base, * @debug_mask: display debugging information */ void proto_ctx_init(struct proto_ctx *ctx, unsigned int family, - unsigned int debug_mask) + unsigned int debug_mask, bool inner) { const struct hook_proto_desc *h = &hook_proto_desc[family]; @@ -210,6 +212,7 @@ void proto_ctx_init(struct proto_ctx *ctx, unsigned int family, ctx->family = family; ctx->protocol[h->base].desc = h->desc; ctx->debug_mask = debug_mask; + ctx->inner = inner; proto_ctx_debug(ctx, h->base, debug_mask); } From patchwork Mon Oct 17 11:04:00 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pablo Neira Ayuso X-Patchwork-Id: 1690847 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=2620:137:e000::1:20; helo=out1.vger.email; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Received: from out1.vger.email (out1.vger.email [IPv6:2620:137:e000::1:20]) by legolas.ozlabs.org (Postfix) with ESMTP id 4MrYzL0wMJz23kW for ; Mon, 17 Oct 2022 22:04:30 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230193AbiJQLE2 (ORCPT ); Mon, 17 Oct 2022 07:04:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34470 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230096AbiJQLEW (ORCPT ); Mon, 17 Oct 2022 07:04:22 -0400 Received: from mail.netfilter.org (mail.netfilter.org [217.70.188.207]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id B653BE9 for ; Mon, 17 Oct 2022 04:04:19 -0700 (PDT) From: Pablo Neira Ayuso To: netfilter-devel@vger.kernel.org Subject: [PATCH nft,v2 08/16] src: add gre support Date: Mon, 17 Oct 2022 13:04:00 +0200 Message-Id: <20221017110408.742223-9-pablo@netfilter.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221017110408.742223-1-pablo@netfilter.org> References: <20221017110408.742223-1-pablo@netfilter.org> MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org GRE has a number of fields that are conditional based on flags, which requires custom dependency code similar to icmp and icmpv6. Matching on optional fields is not supported at this stage. Since this is a layer 3 tunnel protocol, an implicit dependency on NFT_META_L4PROTO for IPPROTO_GRE is generated. To achieve this, this patch adds new infrastructure to remove an outer dependency based on the inner protocol from delinearize path. Signed-off-by: Pablo Neira Ayuso --- include/parser.h | 1 + include/payload.h | 2 ++ include/proto.h | 14 ++++++++++++ src/evaluate.c | 43 +++++++++++++++++++++++++---------- src/netlink_delinearize.c | 48 +++++++++++++++++++++++++++++++++++++++ src/parser_bison.y | 33 ++++++++++++++++++++++++--- src/payload.c | 47 ++++++++++++++++++++++++++++++++++++++ src/proto.c | 27 ++++++++++++++++++++++ src/scanner.l | 7 ++++-- 9 files changed, 205 insertions(+), 17 deletions(-) diff --git a/include/parser.h b/include/parser.h index f55da0fd47bf..5c62e1b17d30 100644 --- a/include/parser.h +++ b/include/parser.h @@ -37,6 +37,7 @@ enum startcond_type { PARSER_SC_CT, PARSER_SC_COUNTER, PARSER_SC_ETH, + PARSER_SC_GRE, PARSER_SC_ICMP, PARSER_SC_IGMP, PARSER_SC_IP, diff --git a/include/payload.h b/include/payload.h index aac553ee6b89..08e45f7f79e2 100644 --- a/include/payload.h +++ b/include/payload.h @@ -15,6 +15,8 @@ struct eval_ctx; struct stmt; extern int payload_gen_dependency(struct eval_ctx *ctx, const struct expr *expr, struct stmt **res); +int payload_gen_inner_dependency(struct eval_ctx *ctx, const struct expr *expr, + struct stmt **res); extern int payload_gen_icmp_dependency(struct eval_ctx *ctx, const struct expr *expr, struct stmt **res); diff --git a/include/proto.h b/include/proto.h index 32e0744854a5..4b0c71467638 100644 --- a/include/proto.h +++ b/include/proto.h @@ -97,6 +97,7 @@ enum proto_desc_id { PROTO_DESC_VLAN, PROTO_DESC_ETHER, PROTO_DESC_VXLAN, + PROTO_DESC_GRE, __PROTO_DESC_MAX }; #define PROTO_DESC_MAX (__PROTO_DESC_MAX - 1) @@ -396,7 +397,20 @@ enum vxlan_hdr_fields { VXLANHDR_FLAGS, }; +struct grehdr { + uint16_t flags; + uint16_t protocol; +}; + +enum gre_hdr_fields { + GREHDR_INVALID, + GREHDR_VERSION, + GREHDR_FLAGS, + GREHDR_PROTOCOL, +}; + extern const struct proto_desc proto_vxlan; +extern const struct proto_desc proto_gre; extern const struct proto_desc proto_icmp; extern const struct proto_desc proto_igmp; diff --git a/src/evaluate.c b/src/evaluate.c index 19a232abf431..173de6b67700 100644 --- a/src/evaluate.c +++ b/src/evaluate.c @@ -860,24 +860,43 @@ static int expr_evaluate_payload(struct eval_ctx *ctx, struct expr **exprp) static int expr_evaluate_inner(struct eval_ctx *ctx, struct expr **exprp) { struct proto_ctx *pctx = eval_proto_ctx(ctx); - const struct proto_desc *desc; + const struct proto_desc *desc = NULL; struct expr *expr = *exprp; int ret; - desc = pctx->protocol[expr->payload.inner_desc->base - 1].desc; - if (!desc) { - return expr_error(ctx->msgs, expr, - "no transport protocol specified"); - } + assert(expr->etype == EXPR_PAYLOAD); - if (proto_find_num(desc, expr->payload.inner_desc) < 0) { - return expr_error(ctx->msgs, expr, - "unexpected transport protocol %s", - desc->name); + pctx = eval_proto_ctx(ctx); + desc = pctx->protocol[PROTO_BASE_TRANSPORT_HDR].desc; + + if (desc == NULL && + expr->payload.inner_desc->base < PROTO_BASE_INNER_HDR) { + struct stmt *nstmt; + + if (payload_gen_inner_dependency(ctx, expr, &nstmt) < 0) + return -1; + + rule_stmt_insert_at(ctx->rule, nstmt, ctx->stmt); + + proto_ctx_update(pctx, PROTO_BASE_TRANSPORT_HDR, &expr->location, expr->payload.inner_desc); } - proto_ctx_update(pctx, PROTO_BASE_INNER_HDR, &expr->location, - expr->payload.inner_desc); + if (expr->payload.inner_desc->base == PROTO_BASE_INNER_HDR) { + desc = pctx->protocol[expr->payload.inner_desc->base - 1].desc; + if (!desc) { + return expr_error(ctx->msgs, expr, + "no transport protocol specified"); + } + + if (proto_find_num(desc, expr->payload.inner_desc) < 0) { + return expr_error(ctx->msgs, expr, + "unexpected transport protocol %s", + desc->name); + } + + proto_ctx_update(pctx, expr->payload.inner_desc->base, &expr->location, + expr->payload.inner_desc); + } if (expr->payload.base != PROTO_BASE_INNER_HDR) ctx->inner_desc = expr->payload.inner_desc; diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index 54f140c48a13..fbabb7d2203d 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -35,6 +35,11 @@ struct dl_proto_ctx *dl_proto_ctx(struct rule_pp_ctx *ctx) return ctx->dl; } +static struct dl_proto_ctx *dl_proto_ctx_outer(struct rule_pp_ctx *ctx) +{ + return &ctx->_dl[0]; +} + static int netlink_parse_expr(const struct nftnl_expr *nle, struct netlink_parse_ctx *ctx); @@ -1952,6 +1957,36 @@ struct stmt *netlink_parse_set_expr(const struct set *set, return pctx->stmt; } +static bool meta_outer_may_dependency_kill(struct rule_pp_ctx *ctx, + const struct expr *expr) +{ + struct dl_proto_ctx *dl_outer = dl_proto_ctx_outer(ctx); + struct stmt *stmt = dl_outer->pdctx.pdeps[expr->payload.inner_desc->base]; + struct expr *dep; + uint8_t l4proto; + + if (!stmt) + return false; + + dep = stmt->expr; + + if (dep->left->meta.key != NFT_META_L4PROTO) + return false; + + l4proto = mpz_get_uint8(dep->right->value); + + switch (l4proto) { + case IPPROTO_GRE: + if (expr->payload.inner_desc == &proto_gre) + return true; + break; + default: + break; + } + + return false; +} + static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp); static void payload_match_expand(struct rule_pp_ctx *ctx, @@ -1995,6 +2030,12 @@ static void payload_match_expand(struct rule_pp_ctx *ctx, nexpr->left->payload.tmpl = expr->left->payload.tmpl; } nexpr->left->payload.inner_desc = expr->left->payload.inner_desc; + + if (meta_outer_may_dependency_kill(ctx, expr->left)) { + struct dl_proto_ctx *dl_outer = dl_proto_ctx_outer(ctx); + + payload_dependency_release(&dl_outer->pdctx, expr->left->payload.inner_desc->base); + } } if (payload_is_stacked(dl->pctx.protocol[base].desc, nexpr)) @@ -2739,6 +2780,13 @@ static void expr_postprocess(struct rule_pp_ctx *ctx, struct expr **exprp) break; case EXPR_PAYLOAD: payload_expr_complete(expr, &dl->pctx); + if (expr->payload.inner_desc) { + if (meta_outer_may_dependency_kill(ctx, expr)) { + struct dl_proto_ctx *dl_outer = dl_proto_ctx_outer(ctx); + + payload_dependency_release(&dl_outer->pdctx, expr->payload.inner_desc->base); + } + } payload_dependency_kill(&dl->pdctx, expr, dl->pctx.family); break; case EXPR_VALUE: diff --git a/src/parser_bison.y b/src/parser_bison.y index 213254ecc5f0..9273a09a3727 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -442,6 +442,8 @@ int nft_lex(void *, void *, void *); %token VXLAN "vxlan" %token VNI "vni" +%token GRE "gre" + %token SCTP "sctp" %token CHUNK "chunk" %token DATA "data" @@ -900,9 +902,9 @@ int nft_lex(void *, void *, void *); %type tcpopt_field_maxseg tcpopt_field_mptcp tcpopt_field_sack tcpopt_field_tsopt tcpopt_field_window %type tcp_hdr_option_kind_and_field -%type inner_eth_expr inner_inet_expr inner_expr vxlan_hdr_expr -%destructor { expr_free($$); } inner_eth_expr inner_inet_expr inner_expr vxlan_hdr_expr -%type vxlan_hdr_field +%type inner_eth_expr inner_inet_expr inner_expr vxlan_hdr_expr gre_hdr_expr +%destructor { expr_free($$); } inner_eth_expr inner_inet_expr inner_expr vxlan_hdr_expr gre_hdr_expr +%type vxlan_hdr_field gre_hdr_field %type optstrip_stmt %destructor { stmt_free($$); } optstrip_stmt @@ -962,6 +964,7 @@ close_scope_export : { scanner_pop_start_cond(nft->scanner, PARSER_SC_CMD_EXPORT close_scope_fib : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_FIB); }; close_scope_frag : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_FRAG); }; close_scope_fwd : { scanner_pop_start_cond(nft->scanner, PARSER_SC_STMT_FWD); }; +close_scope_gre : { scanner_pop_start_cond(nft->scanner, PARSER_SC_GRE); }; close_scope_hash : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_HASH); }; close_scope_hbh : { scanner_pop_start_cond(nft->scanner, PARSER_SC_EXPR_HBH); }; close_scope_ip : { scanner_pop_start_cond(nft->scanner, PARSER_SC_IP); }; @@ -4863,6 +4866,13 @@ primary_rhs_expr : symbol_expr { $$ = $1; } BYTEORDER_HOST_ENDIAN, sizeof(data) * BITS_PER_BYTE, &data); } + | GRE close_scope_gre + { + uint8_t data = IPPROTO_GRE; + $$ = constant_expr_alloc(&@$, &inet_protocol_type, + BYTEORDER_HOST_ENDIAN, + sizeof(data) * BITS_PER_BYTE, &data); + } | COMP close_scope_comp { uint8_t data = IPPROTO_COMP; @@ -5319,6 +5329,7 @@ payload_expr : payload_raw_expr | sctp_hdr_expr | th_hdr_expr | vxlan_hdr_expr + | gre_hdr_expr ; payload_raw_expr : AT payload_base_spec COMMA NUM COMMA NUM close_scope_at @@ -5615,6 +5626,22 @@ vxlan_hdr_field : VNI { $$ = VXLANHDR_VNI; } | FLAGS { $$ = VXLANHDR_FLAGS; } ; +gre_hdr_expr : GRE gre_hdr_field close_scope_gre + { + $$ = payload_expr_alloc(&@$, &proto_gre, $2); + } + | GRE close_scope_gre inner_inet_expr + { + $$ = $3; + $$->payload.inner_desc = &proto_gre; + } + ; + +gre_hdr_field : HDRVERSION { $$ = GREHDR_VERSION; } + | FLAGS { $$ = GREHDR_FLAGS; } + | PROTOCOL { $$ = GREHDR_PROTOCOL; } + ; + optstrip_stmt : RESET TCP OPTION tcp_hdr_option_type close_scope_tcp { $$ = optstrip_stmt_alloc(&@$, tcpopt_expr_alloc(&@$, diff --git a/src/payload.c b/src/payload.c index 7abb5f5cbf51..32061278574a 100644 --- a/src/payload.c +++ b/src/payload.c @@ -487,6 +487,14 @@ payload_gen_special_dependency(struct eval_ctx *ctx, const struct expr *expr) break; } + /* this tunnel protocol does not encapsulate an inner + * link layer, use proto_netdev which relies on + * NFT_META_PROTOCOL for dependencies. + */ + if (expr->payload.inner_desc && + !(expr->payload.inner_desc->inner.flags & NFT_INNER_LL)) + desc = &proto_netdev; + desc_upper = &proto_ip6; if (expr->payload.desc == &proto_icmp || expr->payload.desc == &proto_igmp) @@ -1355,3 +1363,42 @@ bad_proto: return expr_error(ctx->msgs, expr, "incompatible icmp match: rule has %d, need %u", pctx->th_dep.icmp.type, type); } + +int payload_gen_inner_dependency(struct eval_ctx *ctx, const struct expr *expr, + struct stmt **res) +{ + struct proto_ctx *pctx = eval_proto_ctx(ctx); + const struct proto_hdr_template *tmpl; + const struct proto_desc *desc, *inner_desc; + struct expr *left, *right, *dep; + struct stmt *stmt = NULL; + int protocol; + + assert(expr->etype == EXPR_PAYLOAD); + + inner_desc = expr->payload.inner_desc; + desc = pctx->protocol[inner_desc->base - 1].desc; + if (desc == NULL) + desc = &proto_ip; + + tmpl = &inner_desc->templates[0]; + assert(tmpl); + + protocol = proto_find_num(desc, inner_desc); + if (protocol < 0) + return expr_error(ctx->msgs, expr, + "conflicting protocols specified: %s vs. %s", + desc->name, inner_desc->name); + + left = meta_expr_alloc(&expr->location, tmpl->meta_key); + + right = constant_expr_alloc(&expr->location, tmpl->dtype, + tmpl->dtype->byteorder, tmpl->len, + constant_data_ptr(protocol, tmpl->len)); + + dep = relational_expr_alloc(&expr->location, OP_EQ, left, right); + stmt = expr_stmt_alloc(&dep->location, dep); + + *res = stmt; + return 0; +} diff --git a/src/proto.c b/src/proto.c index e6c1100bb448..3bb4ae74a439 100644 --- a/src/proto.c +++ b/src/proto.c @@ -90,6 +90,7 @@ int proto_find_num(const struct proto_desc *base, static const struct proto_desc *inner_protocols[] = { &proto_vxlan, + &proto_gre, }; const struct proto_desc *proto_find_inner(uint32_t type, uint32_t hdrsize, @@ -771,6 +772,28 @@ const struct datatype ecn_type = { .sym_tbl = &ecn_type_tbl, }; +#define GREHDR_TEMPLATE(__name, __dtype, __member) \ + HDR_TEMPLATE(__name, __dtype, struct grehdr, __member) +#define GREHDR_TYPE(__name, __member) \ + GREHDR_TEMPLATE(__name, ðertype_type, __member) + +const struct proto_desc proto_gre = { + .name = "gre", + .id = PROTO_DESC_GRE, + .base = PROTO_BASE_TRANSPORT_HDR, + .templates = { + [0] = PROTO_META_TEMPLATE("l4proto", &inet_protocol_type, NFT_META_L4PROTO, 8), + [GREHDR_FLAGS] = HDR_BITFIELD("flags", &integer_type, 0, 5), + [GREHDR_VERSION] = HDR_BITFIELD("version", &integer_type, 13, 3), + [GREHDR_PROTOCOL] = HDR_BITFIELD("protocol", ðertype_type, 16, 16), + }, + .inner = { + .hdrsize = sizeof(struct grehdr), + .flags = NFT_INNER_NH | NFT_INNER_TH, + .type = NFT_INNER_GENEVE + 1, + }, +}; + #define IPHDR_FIELD(__name, __member) \ HDR_FIELD(__name, struct iphdr, __member) #define IPHDR_ADDR(__name, __member) \ @@ -794,6 +817,7 @@ const struct proto_desc proto_ip = { PROTO_LINK(IPPROTO_TCP, &proto_tcp), PROTO_LINK(IPPROTO_DCCP, &proto_dccp), PROTO_LINK(IPPROTO_SCTP, &proto_sctp), + PROTO_LINK(IPPROTO_GRE, &proto_gre), }, .templates = { [0] = PROTO_META_TEMPLATE("l4proto", &inet_protocol_type, NFT_META_L4PROTO, 8), @@ -920,6 +944,7 @@ const struct proto_desc proto_ip6 = { PROTO_LINK(IPPROTO_ICMP, &proto_icmp), PROTO_LINK(IPPROTO_IGMP, &proto_igmp), PROTO_LINK(IPPROTO_ICMPV6, &proto_icmp6), + PROTO_LINK(IPPROTO_GRE, &proto_gre), }, .templates = { [0] = PROTO_META_TEMPLATE("l4proto", &inet_protocol_type, NFT_META_L4PROTO, 8), @@ -985,6 +1010,7 @@ const struct proto_desc proto_inet_service = { PROTO_LINK(IPPROTO_ICMP, &proto_icmp), PROTO_LINK(IPPROTO_IGMP, &proto_igmp), PROTO_LINK(IPPROTO_ICMPV6, &proto_icmp6), + PROTO_LINK(IPPROTO_GRE, &proto_gre), }, .templates = { [0] = PROTO_META_TEMPLATE("l4proto", &inet_protocol_type, NFT_META_L4PROTO, 8), @@ -1226,6 +1252,7 @@ static const struct proto_desc *proto_definitions[PROTO_DESC_MAX + 1] = { [PROTO_DESC_VLAN] = &proto_vlan, [PROTO_DESC_ETHER] = &proto_eth, [PROTO_DESC_VXLAN] = &proto_vxlan, + [PROTO_DESC_GRE] = &proto_gre, }; const struct proto_desc *proto_find_desc(enum proto_desc_id desc_id) diff --git a/src/scanner.l b/src/scanner.l index 289b4d078855..06ca4059f266 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -201,6 +201,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) %s SCANSTATE_CT %s SCANSTATE_COUNTER %s SCANSTATE_ETH +%s SCANSTATE_GRE %s SCANSTATE_ICMP %s SCANSTATE_IGMP %s SCANSTATE_IP @@ -491,7 +492,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) } "ip" { scanner_push_start_cond(yyscanner, SCANSTATE_IP); return IP; } -{ +{ "version" { return HDRVERSION; } } { @@ -508,7 +509,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) { "ttl" { return TTL; } } -"protocol" { return PROTOCOL; } +"protocol" { return PROTOCOL; } { "checksum" { return CHECKSUM; } } @@ -623,6 +624,8 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) "vxlan" { return VXLAN; } "vni" { return VNI; } +"gre" { scanner_push_start_cond(yyscanner, SCANSTATE_GRE); return GRE; } + "tcp" { scanner_push_start_cond(yyscanner, SCANSTATE_TCP); return TCP; } "dccp" { scanner_push_start_cond(yyscanner, SCANSTATE_EXPR_DCCP); return DCCP; } From patchwork Mon Oct 17 11:04:01 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pablo Neira Ayuso X-Patchwork-Id: 1690849 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=2620:137:e000::1:20; helo=out1.vger.email; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Received: from out1.vger.email (out1.vger.email [IPv6:2620:137:e000::1:20]) by legolas.ozlabs.org (Postfix) with ESMTP id 4MrYzM1XyLz23kV for ; Mon, 17 Oct 2022 22:04:31 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230174AbiJQLE3 (ORCPT ); Mon, 17 Oct 2022 07:04:29 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34610 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230188AbiJQLEW (ORCPT ); Mon, 17 Oct 2022 07:04:22 -0400 Received: from mail.netfilter.org (mail.netfilter.org [217.70.188.207]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 393562DA for ; Mon, 17 Oct 2022 04:04:20 -0700 (PDT) From: Pablo Neira Ayuso To: netfilter-devel@vger.kernel.org Subject: [PATCH nft,v2 09/16] tests: py: add gre tests Date: Mon, 17 Oct 2022 13:04:01 +0200 Message-Id: <20221017110408.742223-10-pablo@netfilter.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221017110408.742223-1-pablo@netfilter.org> References: <20221017110408.742223-1-pablo@netfilter.org> MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Signed-off-by: Pablo Neira Ayuso --- tests/py/inet/gre.t | 22 +++++++++++ tests/py/inet/gre.t.payload | 78 +++++++++++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 tests/py/inet/gre.t create mode 100644 tests/py/inet/gre.t.payload diff --git a/tests/py/inet/gre.t b/tests/py/inet/gre.t new file mode 100644 index 000000000000..a3e046a1aea5 --- /dev/null +++ b/tests/py/inet/gre.t @@ -0,0 +1,22 @@ +:input;type filter hook input priority 0 +:ingress;type filter hook ingress device lo priority 0 +:egress;type filter hook egress device lo priority 0 + +*ip;test-ip4;input +*ip6;test-ip6;input +*inet;test-inet;input +*netdev;test-netdev;ingress,egress + +gre version 0;ok +gre ip saddr 10.141.11.2;ok +gre ip saddr 10.141.11.0/24;ok +gre ip protocol 1;ok +gre udp sport 8888;ok +gre icmp type echo-reply;ok +gre ether saddr 62:87:4d:d6:19:05;fail +gre vlan id 10;fail +gre ip dscp 0x02;ok +gre ip dscp 0x02;ok +gre ip saddr . gre ip daddr { 1.2.3.4 . 4.3.2.1 };ok + +gre ip saddr set 1.2.3.4;fail diff --git a/tests/py/inet/gre.t.payload b/tests/py/inet/gre.t.payload new file mode 100644 index 000000000000..333133ede415 --- /dev/null +++ b/tests/py/inet/gre.t.payload @@ -0,0 +1,78 @@ +# gre version 0 +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x0000002f ] + [ payload load 1b @ transport header + 1 => reg 1 ] + [ bitwise reg 1 = ( reg 1 & 0x00000007 ) ^ 0x00000000 ] + [ cmp eq reg 1 0x00000000 ] + +# gre ip saddr 10.141.11.2 +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x0000002f ] + [ inner type 3 hdrsize 4 flags c [ meta load protocol => reg 1 ] ] + [ cmp eq reg 1 0x00000008 ] + [ inner type 3 hdrsize 4 flags c [ payload load 4b @ network header + 12 => reg 1 ] ] + [ cmp eq reg 1 0x020b8d0a ] + +# gre ip saddr 10.141.11.0/24 +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x0000002f ] + [ inner type 3 hdrsize 4 flags c [ meta load protocol => reg 1 ] ] + [ cmp eq reg 1 0x00000008 ] + [ inner type 3 hdrsize 4 flags c [ payload load 3b @ network header + 12 => reg 1 ] ] + [ cmp eq reg 1 0x000b8d0a ] + +# gre ip protocol 1 +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x0000002f ] + [ inner type 3 hdrsize 4 flags c [ meta load protocol => reg 1 ] ] + [ cmp eq reg 1 0x00000008 ] + [ inner type 3 hdrsize 4 flags c [ payload load 1b @ network header + 9 => reg 1 ] ] + [ cmp eq reg 1 0x00000001 ] + +# gre udp sport 8888 +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x0000002f ] + [ inner type 3 hdrsize 4 flags c [ meta load l4proto => reg 1 ] ] + [ cmp eq reg 1 0x00000011 ] + [ inner type 3 hdrsize 4 flags c [ payload load 2b @ transport header + 0 => reg 1 ] ] + [ cmp eq reg 1 0x0000b822 ] + +# gre icmp type echo-reply +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x0000002f ] + [ inner type 3 hdrsize 4 flags c [ meta load protocol => reg 1 ] ] + [ cmp eq reg 1 0x00000008 ] + [ inner type 3 hdrsize 4 flags c [ meta load l4proto => reg 1 ] ] + [ cmp eq reg 1 0x00000001 ] + [ inner type 3 hdrsize 4 flags c [ payload load 1b @ transport header + 0 => reg 1 ] ] + [ cmp eq reg 1 0x00000000 ] + +# gre ip dscp 0x02 +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x0000002f ] + [ inner type 3 hdrsize 4 flags c [ meta load protocol => reg 1 ] ] + [ cmp eq reg 1 0x00000008 ] + [ inner type 3 hdrsize 4 flags c [ payload load 1b @ network header + 1 => reg 1 ] ] + [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ] + [ cmp eq reg 1 0x00000008 ] + +# gre ip saddr . gre ip daddr { 1.2.3.4 . 4.3.2.1 } +__set%d test-ip4 3 size 1 +__set%d test-ip4 0 + element 04030201 01020304 : 0 [end] +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x0000002f ] + [ inner type 3 hdrsize 4 flags c [ meta load protocol => reg 1 ] ] + [ cmp eq reg 1 0x00000008 ] + [ inner type 3 hdrsize 4 flags c [ payload load 4b @ network header + 12 => reg 1 ] ] + [ inner type 3 hdrsize 4 flags c [ payload load 4b @ network header + 16 => reg 9 ] ] + [ lookup reg 1 set __set%d ] + From patchwork Mon Oct 17 11:04:02 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pablo Neira Ayuso X-Patchwork-Id: 1690846 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=2620:137:e000::1:20; helo=out1.vger.email; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Received: from out1.vger.email (out1.vger.email [IPv6:2620:137:e000::1:20]) by legolas.ozlabs.org (Postfix) with ESMTP id 4MrYzK1mMZz23kV for ; Mon, 17 Oct 2022 22:04:29 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230186AbiJQLE2 (ORCPT ); Mon, 17 Oct 2022 07:04:28 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34620 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230193AbiJQLEW (ORCPT ); Mon, 17 Oct 2022 07:04:22 -0400 Received: from mail.netfilter.org (mail.netfilter.org [217.70.188.207]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id A9E86CF1 for ; Mon, 17 Oct 2022 04:04:20 -0700 (PDT) From: Pablo Neira Ayuso To: netfilter-devel@vger.kernel.org Subject: [PATCH nft,v2 10/16] doc: add gre matching expression Date: Mon, 17 Oct 2022 13:04:02 +0200 Message-Id: <20221017110408.742223-11-pablo@netfilter.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221017110408.742223-1-pablo@netfilter.org> References: <20221017110408.742223-1-pablo@netfilter.org> MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Document new vxlan matching expression. This includes support for matching the encapsulated ethernet frame layer 3 and 4 headers. Signed-off-by: Pablo Neira Ayuso --- doc/payload-expression.txt | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/doc/payload-expression.txt b/doc/payload-expression.txt index c80198878c1a..86e364713953 100644 --- a/doc/payload-expression.txt +++ b/doc/payload-expression.txt @@ -532,6 +532,36 @@ compression Parameter Index | integer (16 bit) |============================ +GRE HEADER EXPRESSION +~~~~~~~~~~~~~~~~~~~~~~~ +[verse] +*gre* {*flags* | *version* | *protocol*} +*gre* *ip* {*version* | *hdrlength* | *dscp* | *ecn* | *length* | *id* | *frag-off* | *ttl* | *protocol* | *checksum* | *saddr* | *daddr* } +*gre* *ip6* {*version* | *dscp* | *ecn* | *flowlabel* | *length* | *nexthdr* | *hoplimit* | *saddr* | *daddr*} + +The gre expression is used to match on the gre header fields. This expression +also allows to match on the IPv4 or IPv6 packet within the gre header. + +.GRE header expression +[options="header"] +|================== +|Keyword| Description| Type +|flags| +checksum, routing, key, sequence and strict source route flags| +integer (5 bit) +|version| +gre version field, 0 for GRE and 1 for PPTP| +integer (3 bit) +|protocol| +EtherType of encapsulated packet| +integer (16 bit) +|================== + +.Matching inner IPv4 destination address encapsulated in gre +------------------------------------------------------------ +netdev filter ingress gre ip daddr 9.9.9.9 counter +------------------------------------------------------------ + VXLAN HEADER EXPRESSION ~~~~~~~~~~~~~~~~~~~~~~~ [verse] From patchwork Mon Oct 17 11:04:03 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pablo Neira Ayuso X-Patchwork-Id: 1690848 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=2620:137:e000::1:20; helo=out1.vger.email; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Received: from out1.vger.email (out1.vger.email [IPv6:2620:137:e000::1:20]) by legolas.ozlabs.org (Postfix) with ESMTP id 4MrYzL5YLnz23jp for ; Mon, 17 Oct 2022 22:04:30 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230096AbiJQLE3 (ORCPT ); Mon, 17 Oct 2022 07:04:29 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34624 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230224AbiJQLEW (ORCPT ); Mon, 17 Oct 2022 07:04:22 -0400 Received: from mail.netfilter.org (mail.netfilter.org [217.70.188.207]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 0B66CE44 for ; Mon, 17 Oct 2022 04:04:21 -0700 (PDT) From: Pablo Neira Ayuso To: netfilter-devel@vger.kernel.org Subject: [PATCH nft,v2 11/16] src: add geneve matching support Date: Mon, 17 Oct 2022 13:04:03 +0200 Message-Id: <20221017110408.742223-12-pablo@netfilter.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221017110408.742223-1-pablo@netfilter.org> References: <20221017110408.742223-1-pablo@netfilter.org> MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Add support for GENEVE vni and (ether) type header field. Signed-off-by: Pablo Neira Ayuso --- include/proto.h | 13 +++++++++++++ src/parser_bison.y | 32 +++++++++++++++++++++++++++++--- src/proto.c | 28 ++++++++++++++++++++++++++++ src/scanner.l | 2 ++ 4 files changed, 72 insertions(+), 3 deletions(-) diff --git a/include/proto.h b/include/proto.h index 4b0c71467638..c2c973f383cf 100644 --- a/include/proto.h +++ b/include/proto.h @@ -97,6 +97,7 @@ enum proto_desc_id { PROTO_DESC_VLAN, PROTO_DESC_ETHER, PROTO_DESC_VXLAN, + PROTO_DESC_GENEVE, PROTO_DESC_GRE, __PROTO_DESC_MAX }; @@ -397,6 +398,17 @@ enum vxlan_hdr_fields { VXLANHDR_FLAGS, }; +struct gnvhdr { + uint16_t flags; + uint16_t type; + uint32_t vni; +}; +enum geneve_hdr_fields { + GNVHDR_INVALID, + GNVHDR_VNI, + GNVHDR_TYPE, +}; + struct grehdr { uint16_t flags; uint16_t protocol; @@ -410,6 +422,7 @@ enum gre_hdr_fields { }; extern const struct proto_desc proto_vxlan; +extern const struct proto_desc proto_geneve; extern const struct proto_desc proto_gre; extern const struct proto_desc proto_icmp; diff --git a/src/parser_bison.y b/src/parser_bison.y index 9273a09a3727..99bb17e7fb07 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -444,6 +444,8 @@ int nft_lex(void *, void *, void *); %token GRE "gre" +%token GENEVE "geneve" + %token SCTP "sctp" %token CHUNK "chunk" %token DATA "data" @@ -902,9 +904,12 @@ int nft_lex(void *, void *, void *); %type tcpopt_field_maxseg tcpopt_field_mptcp tcpopt_field_sack tcpopt_field_tsopt tcpopt_field_window %type tcp_hdr_option_kind_and_field -%type inner_eth_expr inner_inet_expr inner_expr vxlan_hdr_expr gre_hdr_expr -%destructor { expr_free($$); } inner_eth_expr inner_inet_expr inner_expr vxlan_hdr_expr gre_hdr_expr -%type vxlan_hdr_field gre_hdr_field +%type inner_eth_expr inner_inet_expr inner_expr +%destructor { expr_free($$); } inner_eth_expr inner_inet_expr inner_expr + +%type vxlan_hdr_expr geneve_hdr_expr gre_hdr_expr +%destructor { expr_free($$); } vxlan_hdr_expr geneve_hdr_expr gre_hdr_expr +%type vxlan_hdr_field geneve_hdr_field gre_hdr_field %type optstrip_stmt %destructor { stmt_free($$); } optstrip_stmt @@ -5329,6 +5334,7 @@ payload_expr : payload_raw_expr | sctp_hdr_expr | th_hdr_expr | vxlan_hdr_expr + | geneve_hdr_expr | gre_hdr_expr ; @@ -5626,6 +5632,26 @@ vxlan_hdr_field : VNI { $$ = VXLANHDR_VNI; } | FLAGS { $$ = VXLANHDR_FLAGS; } ; +geneve_hdr_expr : GENEVE geneve_hdr_field + { + struct expr *expr; + + expr = payload_expr_alloc(&@$, &proto_geneve, $2); + expr->payload.inner_desc = &proto_geneve; + $$ = expr; + } + | GENEVE inner_expr + { + $$ = $2; + $$->location = @$; + $$->payload.inner_desc = &proto_geneve; + } + ; + +geneve_hdr_field : VNI { $$ = GNVHDR_VNI; } + | TYPE { $$ = GNVHDR_TYPE; } + ; + gre_hdr_expr : GRE gre_hdr_field close_scope_gre { $$ = payload_expr_alloc(&@$, &proto_gre, $2); diff --git a/src/proto.c b/src/proto.c index 3bb4ae74a439..0986a3800000 100644 --- a/src/proto.c +++ b/src/proto.c @@ -90,6 +90,7 @@ int proto_find_num(const struct proto_desc *base, static const struct proto_desc *inner_protocols[] = { &proto_vxlan, + &proto_geneve, &proto_gre, }; @@ -542,6 +543,7 @@ const struct proto_desc proto_udp = { }, .protocols = { PROTO_LINK(0, &proto_vxlan), + PROTO_LINK(0, &proto_geneve), }, }; @@ -1215,6 +1217,32 @@ const struct proto_desc proto_vxlan = { }, }; +/* + * GENEVE + */ + +const struct proto_desc proto_geneve = { + .name = "geneve", + .id = PROTO_DESC_GENEVE, + .base = PROTO_BASE_INNER_HDR, + .templates = { + [GNVHDR_TYPE] = HDR_TYPE("type", ðertype_type, struct gnvhdr, type), + [GNVHDR_VNI] = HDR_BITFIELD("vni", &integer_type, (4 * BITS_PER_BYTE), 24), + }, + .protocols = { + PROTO_LINK(__constant_htons(ETH_P_IP), &proto_ip), + PROTO_LINK(__constant_htons(ETH_P_ARP), &proto_arp), + PROTO_LINK(__constant_htons(ETH_P_IPV6), &proto_ip6), + PROTO_LINK(__constant_htons(ETH_P_8021Q), &proto_vlan), + }, + .inner = { + .hdrsize = sizeof(struct gnvhdr), + .flags = NFT_INNER_HDRSIZE | NFT_INNER_LL | NFT_INNER_NH | NFT_INNER_TH, + .type = NFT_INNER_GENEVE, + }, +}; + + /* * Dummy protocol for netdev tables. */ diff --git a/src/scanner.l b/src/scanner.l index 06ca4059f266..cc5b9c43233f 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -624,6 +624,8 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) "vxlan" { return VXLAN; } "vni" { return VNI; } +"geneve" { return GENEVE; } + "gre" { scanner_push_start_cond(yyscanner, SCANSTATE_GRE); return GRE; } "tcp" { scanner_push_start_cond(yyscanner, SCANSTATE_TCP); return TCP; } From patchwork Mon Oct 17 11:04:04 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pablo Neira Ayuso X-Patchwork-Id: 1690845 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=2620:137:e000::1:20; helo=out1.vger.email; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Received: from out1.vger.email (out1.vger.email [IPv6:2620:137:e000::1:20]) by legolas.ozlabs.org (Postfix) with ESMTP id 4MrYzJ4Ltvz23jp for ; Mon, 17 Oct 2022 22:04:28 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230145AbiJQLE1 (ORCPT ); Mon, 17 Oct 2022 07:04:27 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34628 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230208AbiJQLEW (ORCPT ); Mon, 17 Oct 2022 07:04:22 -0400 Received: from mail.netfilter.org (mail.netfilter.org [217.70.188.207]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 72E9CF3C for ; Mon, 17 Oct 2022 04:04:21 -0700 (PDT) From: Pablo Neira Ayuso To: netfilter-devel@vger.kernel.org Subject: [PATCH nft,v2 12/16] tests: py: add geneve tests Date: Mon, 17 Oct 2022 13:04:04 +0200 Message-Id: <20221017110408.742223-13-pablo@netfilter.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221017110408.742223-1-pablo@netfilter.org> References: <20221017110408.742223-1-pablo@netfilter.org> MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Signed-off-by: Pablo Neira Ayuso --- tests/py/inet/geneve.t | 23 +++++++ tests/py/inet/geneve.t.payload | 114 +++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 tests/py/inet/geneve.t create mode 100644 tests/py/inet/geneve.t.payload diff --git a/tests/py/inet/geneve.t b/tests/py/inet/geneve.t new file mode 100644 index 000000000000..101f6dfcdb7e --- /dev/null +++ b/tests/py/inet/geneve.t @@ -0,0 +1,23 @@ +:input;type filter hook input priority 0 +:ingress;type filter hook ingress device lo priority 0 +:egress;type filter hook egress device lo priority 0 + +*ip;test-ip4;input +*ip6;test-ip6;input +*inet;test-inet;input +*netdev;test-netdev;ingress,egress + +geneve vni 10;fail +udp dport 6081 geneve vni 10;ok +udp dport 6081 geneve ip saddr 10.141.11.2;ok +udp dport 6081 geneve ip saddr 10.141.11.0/24;ok +udp dport 6081 geneve ip protocol 1;ok +udp dport 6081 geneve udp sport 8888;ok +udp dport 6081 geneve icmp type echo-reply;ok +udp dport 6081 geneve ether saddr 62:87:4d:d6:19:05;ok +udp dport 6081 geneve vlan id 10;ok +udp dport 6081 geneve ip dscp 0x02;ok +udp dport 6081 geneve ip dscp 0x02;ok +udp dport 6081 geneve ip saddr . geneve ip daddr { 1.2.3.4 . 4.3.2.1 };ok + +udp dport 6081 geneve ip saddr set 1.2.3.4;fail diff --git a/tests/py/inet/geneve.t.payload b/tests/py/inet/geneve.t.payload new file mode 100644 index 000000000000..1ce54de6cd3a --- /dev/null +++ b/tests/py/inet/geneve.t.payload @@ -0,0 +1,114 @@ +# udp dport 6081 geneve vni 10 +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000011 ] + [ payload load 2b @ transport header + 2 => reg 1 ] + [ cmp eq reg 1 0x0000c117 ] + [ inner type 2 hdrsize 8 flags f [ payload load 3b @ unknown header + 4 => reg 1 ] ] + [ cmp eq reg 1 0x000a0000 ] + +# udp dport 6081 geneve ip saddr 10.141.11.2 +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000011 ] + [ payload load 2b @ transport header + 2 => reg 1 ] + [ cmp eq reg 1 0x0000c117 ] + [ inner type 2 hdrsize 8 flags f [ meta load protocol => reg 1 ] ] + [ cmp eq reg 1 0x00000008 ] + [ inner type 2 hdrsize 8 flags f [ payload load 4b @ network header + 12 => reg 1 ] ] + [ cmp eq reg 1 0x020b8d0a ] + +# udp dport 6081 geneve ip saddr 10.141.11.0/24 +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000011 ] + [ payload load 2b @ transport header + 2 => reg 1 ] + [ cmp eq reg 1 0x0000c117 ] + [ inner type 2 hdrsize 8 flags f [ meta load protocol => reg 1 ] ] + [ cmp eq reg 1 0x00000008 ] + [ inner type 2 hdrsize 8 flags f [ payload load 3b @ network header + 12 => reg 1 ] ] + [ cmp eq reg 1 0x000b8d0a ] + +# udp dport 6081 geneve ip protocol 1 +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000011 ] + [ payload load 2b @ transport header + 2 => reg 1 ] + [ cmp eq reg 1 0x0000c117 ] + [ inner type 2 hdrsize 8 flags f [ meta load protocol => reg 1 ] ] + [ cmp eq reg 1 0x00000008 ] + [ inner type 2 hdrsize 8 flags f [ payload load 1b @ network header + 9 => reg 1 ] ] + [ cmp eq reg 1 0x00000001 ] + +# udp dport 6081 geneve udp sport 8888 +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000011 ] + [ payload load 2b @ transport header + 2 => reg 1 ] + [ cmp eq reg 1 0x0000c117 ] + [ inner type 2 hdrsize 8 flags f [ meta load l4proto => reg 1 ] ] + [ cmp eq reg 1 0x00000011 ] + [ inner type 2 hdrsize 8 flags f [ payload load 2b @ transport header + 0 => reg 1 ] ] + [ cmp eq reg 1 0x0000b822 ] + +# udp dport 6081 geneve icmp type echo-reply +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000011 ] + [ payload load 2b @ transport header + 2 => reg 1 ] + [ cmp eq reg 1 0x0000c117 ] + [ inner type 2 hdrsize 8 flags f [ payload load 2b @ link header + 12 => reg 1 ] ] + [ cmp eq reg 1 0x00000008 ] + [ inner type 2 hdrsize 8 flags f [ meta load l4proto => reg 1 ] ] + [ cmp eq reg 1 0x00000001 ] + [ inner type 2 hdrsize 8 flags f [ payload load 1b @ transport header + 0 => reg 1 ] ] + [ cmp eq reg 1 0x00000000 ] + +# udp dport 6081 geneve ether saddr 62:87:4d:d6:19:05 +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000011 ] + [ payload load 2b @ transport header + 2 => reg 1 ] + [ cmp eq reg 1 0x0000c117 ] + [ inner type 2 hdrsize 8 flags f [ payload load 6b @ link header + 6 => reg 1 ] ] + [ cmp eq reg 1 0xd64d8762 0x00000519 ] + +# udp dport 6081 geneve vlan id 10 +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000011 ] + [ payload load 2b @ transport header + 2 => reg 1 ] + [ cmp eq reg 1 0x0000c117 ] + [ inner type 2 hdrsize 8 flags f [ payload load 2b @ link header + 12 => reg 1 ] ] + [ cmp eq reg 1 0x00000081 ] + [ inner type 2 hdrsize 8 flags f [ payload load 2b @ link header + 14 => reg 1 ] ] + [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ] + [ cmp eq reg 1 0x00000a00 ] + +# udp dport 6081 geneve ip dscp 0x02 +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000011 ] + [ payload load 2b @ transport header + 2 => reg 1 ] + [ cmp eq reg 1 0x0000c117 ] + [ inner type 2 hdrsize 8 flags f [ meta load protocol => reg 1 ] ] + [ cmp eq reg 1 0x00000008 ] + [ inner type 2 hdrsize 8 flags f [ payload load 1b @ network header + 1 => reg 1 ] ] + [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ] + [ cmp eq reg 1 0x00000008 ] + +# udp dport 6081 geneve ip saddr . geneve ip daddr { 1.2.3.4 . 4.3.2.1 } +__set%d test-ip4 3 size 1 +__set%d test-ip4 0 + element 04030201 01020304 : 0 [end] +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x00000011 ] + [ payload load 2b @ transport header + 2 => reg 1 ] + [ cmp eq reg 1 0x0000c117 ] + [ inner type 2 hdrsize 8 flags f [ meta load protocol => reg 1 ] ] + [ cmp eq reg 1 0x00000008 ] + [ inner type 2 hdrsize 8 flags f [ payload load 4b @ network header + 12 => reg 1 ] ] + [ inner type 2 hdrsize 8 flags f [ payload load 4b @ network header + 16 => reg 9 ] ] + [ lookup reg 1 set __set%d ] + From patchwork Mon Oct 17 11:04:05 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pablo Neira Ayuso X-Patchwork-Id: 1690850 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=2620:137:e000::1:20; helo=out1.vger.email; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Received: from out1.vger.email (out1.vger.email [IPv6:2620:137:e000::1:20]) by legolas.ozlabs.org (Postfix) with ESMTP id 4MrYzM4dnpz23jp for ; Mon, 17 Oct 2022 22:04:31 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230188AbiJQLEa (ORCPT ); Mon, 17 Oct 2022 07:04:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34716 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230263AbiJQLEX (ORCPT ); Mon, 17 Oct 2022 07:04:23 -0400 Received: from mail.netfilter.org (mail.netfilter.org [217.70.188.207]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 40ED755BE for ; Mon, 17 Oct 2022 04:04:22 -0700 (PDT) From: Pablo Neira Ayuso To: netfilter-devel@vger.kernel.org Subject: [PATCH nft,v2 13/16] doc: add geneve matching expression Date: Mon, 17 Oct 2022 13:04:05 +0200 Message-Id: <20221017110408.742223-14-pablo@netfilter.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221017110408.742223-1-pablo@netfilter.org> References: <20221017110408.742223-1-pablo@netfilter.org> MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Document new geneve matching expression. This includes support for matching the encapsulated ethernet frame layer 2, 3 and 4 headers. --- doc/payload-expression.txt | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/doc/payload-expression.txt b/doc/payload-expression.txt index 86e364713953..e75cb1fae4cc 100644 --- a/doc/payload-expression.txt +++ b/doc/payload-expression.txt @@ -562,6 +562,39 @@ integer (16 bit) netdev filter ingress gre ip daddr 9.9.9.9 counter ------------------------------------------------------------ +GENEVE HEADER EXPRESSION +~~~~~~~~~~~~~~~~~~~~~~~~ +[verse] +*geneve* {*vni* | *flags*} +*geneve* *ether* {*daddr* | *saddr* | *type*} +*geneve* *vlan* {*id* | *dei* | *pcp* | *type*} +*geneve* *ip* {*version* | *hdrlength* | *dscp* | *ecn* | *length* | *id* | *frag-off* | *ttl* | *protocol* | *checksum* | *saddr* | *daddr* } +*geneve* *ip6* {*version* | *dscp* | *ecn* | *flowlabel* | *length* | *nexthdr* | *hoplimit* | *saddr* | *daddr*} +*geneve* *tcp* {*sport* | *dport* | *sequence* | *ackseq* | *doff* | *reserved* | *flags* | *window* | *checksum* | *urgptr*} +*geneve* *udp* {*sport* | *dport* | *length* | *checksum*} + +The geneve expression is used to match on the geneve header fields. The geneve +header encapsulates a ethernet frame within a *udp* packet. This expression +requires that you restrict the matching to *udp* packets (usually at +port 6081 according to IANA-assigned ports). + +.GENEVE header expression +[options="header"] +|================== +|Keyword| Description| Type +|protocol| +EtherType of encapsulated packet| +integer (16 bit) +|vni| +Virtual Network ID (VNI)| +integer (24 bit) +|================== + +.Matching inner TCP destination port encapsulated in geneve +---------------------------------------------------------- +netdev filter ingress udp dport 4789 geneve tcp dport 80 counter +---------------------------------------------------------- + VXLAN HEADER EXPRESSION ~~~~~~~~~~~~~~~~~~~~~~~ [verse] From patchwork Mon Oct 17 11:04:06 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pablo Neira Ayuso X-Patchwork-Id: 1690851 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=2620:137:e000::1:20; helo=out1.vger.email; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Received: from out1.vger.email (out1.vger.email [IPv6:2620:137:e000::1:20]) by legolas.ozlabs.org (Postfix) with ESMTP id 4MrYzN0Rlsz23kV for ; Mon, 17 Oct 2022 22:04:32 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230208AbiJQLEa (ORCPT ); Mon, 17 Oct 2022 07:04:30 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34724 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230273AbiJQLEX (ORCPT ); Mon, 17 Oct 2022 07:04:23 -0400 Received: from mail.netfilter.org (mail.netfilter.org [217.70.188.207]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 94AC460E1 for ; Mon, 17 Oct 2022 04:04:22 -0700 (PDT) From: Pablo Neira Ayuso To: netfilter-devel@vger.kernel.org Subject: [PATCH nft,v2 14/16] src: add gretap support Date: Mon, 17 Oct 2022 13:04:06 +0200 Message-Id: <20221017110408.742223-15-pablo@netfilter.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221017110408.742223-1-pablo@netfilter.org> References: <20221017110408.742223-1-pablo@netfilter.org> MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Signed-off-by: Pablo Neira Ayuso --- include/proto.h | 2 ++ src/netlink_delinearize.c | 3 ++- src/parser_bison.y | 13 +++++++++++-- src/proto.c | 19 +++++++++++++++++++ src/scanner.l | 1 + 5 files changed, 35 insertions(+), 3 deletions(-) diff --git a/include/proto.h b/include/proto.h index c2c973f383cf..3a20ff8c4071 100644 --- a/include/proto.h +++ b/include/proto.h @@ -99,6 +99,7 @@ enum proto_desc_id { PROTO_DESC_VXLAN, PROTO_DESC_GENEVE, PROTO_DESC_GRE, + PROTO_DESC_GRETAP, __PROTO_DESC_MAX }; #define PROTO_DESC_MAX (__PROTO_DESC_MAX - 1) @@ -424,6 +425,7 @@ enum gre_hdr_fields { extern const struct proto_desc proto_vxlan; extern const struct proto_desc proto_geneve; extern const struct proto_desc proto_gre; +extern const struct proto_desc proto_gretap; extern const struct proto_desc proto_icmp; extern const struct proto_desc proto_igmp; diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c index fbabb7d2203d..7ce693472641 100644 --- a/src/netlink_delinearize.c +++ b/src/netlink_delinearize.c @@ -1977,7 +1977,8 @@ static bool meta_outer_may_dependency_kill(struct rule_pp_ctx *ctx, switch (l4proto) { case IPPROTO_GRE: - if (expr->payload.inner_desc == &proto_gre) + if (expr->payload.inner_desc == &proto_gre || + expr->payload.inner_desc == &proto_gretap) return true; break; default: diff --git a/src/parser_bison.y b/src/parser_bison.y index 99bb17e7fb07..5a66b43cb205 100644 --- a/src/parser_bison.y +++ b/src/parser_bison.y @@ -443,6 +443,7 @@ int nft_lex(void *, void *, void *); %token VNI "vni" %token GRE "gre" +%token GRETAP "gretap" %token GENEVE "geneve" @@ -907,8 +908,8 @@ int nft_lex(void *, void *, void *); %type inner_eth_expr inner_inet_expr inner_expr %destructor { expr_free($$); } inner_eth_expr inner_inet_expr inner_expr -%type vxlan_hdr_expr geneve_hdr_expr gre_hdr_expr -%destructor { expr_free($$); } vxlan_hdr_expr geneve_hdr_expr gre_hdr_expr +%type vxlan_hdr_expr geneve_hdr_expr gre_hdr_expr gretap_hdr_expr +%destructor { expr_free($$); } vxlan_hdr_expr geneve_hdr_expr gre_hdr_expr gretap_hdr_expr %type vxlan_hdr_field geneve_hdr_field gre_hdr_field %type optstrip_stmt @@ -5336,6 +5337,7 @@ payload_expr : payload_raw_expr | vxlan_hdr_expr | geneve_hdr_expr | gre_hdr_expr + | gretap_hdr_expr ; payload_raw_expr : AT payload_base_spec COMMA NUM COMMA NUM close_scope_at @@ -5668,6 +5670,13 @@ gre_hdr_field : HDRVERSION { $$ = GREHDR_VERSION; } | PROTOCOL { $$ = GREHDR_PROTOCOL; } ; +gretap_hdr_expr : GRETAP close_scope_gre inner_expr + { + $$ = $3; + $$->payload.inner_desc = &proto_gretap; + } + ; + optstrip_stmt : RESET TCP OPTION tcp_hdr_option_type close_scope_tcp { $$ = optstrip_stmt_alloc(&@$, tcpopt_expr_alloc(&@$, diff --git a/src/proto.c b/src/proto.c index 0986a3800000..edf99e840c0c 100644 --- a/src/proto.c +++ b/src/proto.c @@ -92,6 +92,7 @@ static const struct proto_desc *inner_protocols[] = { &proto_vxlan, &proto_geneve, &proto_gre, + &proto_gretap, }; const struct proto_desc *proto_find_inner(uint32_t type, uint32_t hdrsize, @@ -796,6 +797,20 @@ const struct proto_desc proto_gre = { }, }; +const struct proto_desc proto_gretap = { + .name = "gretap", + .id = PROTO_DESC_GRETAP, + .base = PROTO_BASE_TRANSPORT_HDR, + .templates = { + [0] = PROTO_META_TEMPLATE("l4proto", &inet_protocol_type, NFT_META_L4PROTO, 8), + }, + .inner = { + .hdrsize = sizeof(struct grehdr), + .flags = NFT_INNER_LL | NFT_INNER_NH | NFT_INNER_TH, + .type = NFT_INNER_GENEVE + 2, + }, +}; + #define IPHDR_FIELD(__name, __member) \ HDR_FIELD(__name, struct iphdr, __member) #define IPHDR_ADDR(__name, __member) \ @@ -820,6 +835,7 @@ const struct proto_desc proto_ip = { PROTO_LINK(IPPROTO_DCCP, &proto_dccp), PROTO_LINK(IPPROTO_SCTP, &proto_sctp), PROTO_LINK(IPPROTO_GRE, &proto_gre), + PROTO_LINK(IPPROTO_GRE, &proto_gretap), }, .templates = { [0] = PROTO_META_TEMPLATE("l4proto", &inet_protocol_type, NFT_META_L4PROTO, 8), @@ -947,6 +963,7 @@ const struct proto_desc proto_ip6 = { PROTO_LINK(IPPROTO_IGMP, &proto_igmp), PROTO_LINK(IPPROTO_ICMPV6, &proto_icmp6), PROTO_LINK(IPPROTO_GRE, &proto_gre), + PROTO_LINK(IPPROTO_GRE, &proto_gretap), }, .templates = { [0] = PROTO_META_TEMPLATE("l4proto", &inet_protocol_type, NFT_META_L4PROTO, 8), @@ -1013,6 +1030,7 @@ const struct proto_desc proto_inet_service = { PROTO_LINK(IPPROTO_IGMP, &proto_igmp), PROTO_LINK(IPPROTO_ICMPV6, &proto_icmp6), PROTO_LINK(IPPROTO_GRE, &proto_gre), + PROTO_LINK(IPPROTO_GRE, &proto_gretap), }, .templates = { [0] = PROTO_META_TEMPLATE("l4proto", &inet_protocol_type, NFT_META_L4PROTO, 8), @@ -1281,6 +1299,7 @@ static const struct proto_desc *proto_definitions[PROTO_DESC_MAX + 1] = { [PROTO_DESC_ETHER] = &proto_eth, [PROTO_DESC_VXLAN] = &proto_vxlan, [PROTO_DESC_GRE] = &proto_gre, + [PROTO_DESC_GRETAP] = &proto_gretap, }; const struct proto_desc *proto_find_desc(enum proto_desc_id desc_id) diff --git a/src/scanner.l b/src/scanner.l index cc5b9c43233f..0ef9a1a5c9fd 100644 --- a/src/scanner.l +++ b/src/scanner.l @@ -627,6 +627,7 @@ addrstring ({macaddr}|{ip4addr}|{ip6addr}) "geneve" { return GENEVE; } "gre" { scanner_push_start_cond(yyscanner, SCANSTATE_GRE); return GRE; } +"gretap" { scanner_push_start_cond(yyscanner, SCANSTATE_GRE); return GRETAP; } "tcp" { scanner_push_start_cond(yyscanner, SCANSTATE_TCP); return TCP; } From patchwork Mon Oct 17 11:04:07 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pablo Neira Ayuso X-Patchwork-Id: 1690852 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=2620:137:e000::1:20; helo=out1.vger.email; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Received: from out1.vger.email (out1.vger.email [IPv6:2620:137:e000::1:20]) by legolas.ozlabs.org (Postfix) with ESMTP id 4MrYzN3dfQz23jp for ; Mon, 17 Oct 2022 22:04:32 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230224AbiJQLEb (ORCPT ); Mon, 17 Oct 2022 07:04:31 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34742 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230311AbiJQLEX (ORCPT ); Mon, 17 Oct 2022 07:04:23 -0400 Received: from mail.netfilter.org (mail.netfilter.org [217.70.188.207]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id A35F9309 for ; Mon, 17 Oct 2022 04:04:22 -0700 (PDT) From: Pablo Neira Ayuso To: netfilter-devel@vger.kernel.org Subject: [PATCH nft,v2 15/16] tests: py: add gretap tests Date: Mon, 17 Oct 2022 13:04:07 +0200 Message-Id: <20221017110408.742223-16-pablo@netfilter.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221017110408.742223-1-pablo@netfilter.org> References: <20221017110408.742223-1-pablo@netfilter.org> MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Signed-off-by: Pablo Neira Ayuso --- tests/py/inet/gretap.t | 21 ++++++++ tests/py/inet/gretap.t.payload | 87 ++++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 tests/py/inet/gretap.t create mode 100644 tests/py/inet/gretap.t.payload diff --git a/tests/py/inet/gretap.t b/tests/py/inet/gretap.t new file mode 100644 index 000000000000..cd7ee2158ede --- /dev/null +++ b/tests/py/inet/gretap.t @@ -0,0 +1,21 @@ +:input;type filter hook input priority 0 +:ingress;type filter hook ingress device lo priority 0 +:egress;type filter hook egress device lo priority 0 + +*ip;test-ip4;input +*ip6;test-ip6;input +*inet;test-inet;input +*netdev;test-netdev;ingress,egress + +gretap ip saddr 10.141.11.2;ok +gretap ip saddr 10.141.11.0/24;ok +gretap ip protocol 1;ok +gretap udp sport 8888;ok +gretap icmp type echo-reply;ok +gretap ether saddr 62:87:4d:d6:19:05;ok +gretap vlan id 10;ok +gretap ip dscp 0x02;ok +gretap ip dscp 0x02;ok +gretap ip saddr . gretap ip daddr { 1.2.3.4 . 4.3.2.1 };ok + +gretap ip saddr set 1.2.3.4;fail diff --git a/tests/py/inet/gretap.t.payload b/tests/py/inet/gretap.t.payload new file mode 100644 index 000000000000..654c71e4541a --- /dev/null +++ b/tests/py/inet/gretap.t.payload @@ -0,0 +1,87 @@ +# gretap ip saddr 10.141.11.2 +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x0000002f ] + [ inner type 4 hdrsize 4 flags e [ meta load protocol => reg 1 ] ] + [ cmp eq reg 1 0x00000008 ] + [ inner type 4 hdrsize 4 flags e [ payload load 4b @ network header + 12 => reg 1 ] ] + [ cmp eq reg 1 0x020b8d0a ] + +# gretap ip saddr 10.141.11.0/24 +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x0000002f ] + [ inner type 4 hdrsize 4 flags e [ meta load protocol => reg 1 ] ] + [ cmp eq reg 1 0x00000008 ] + [ inner type 4 hdrsize 4 flags e [ payload load 3b @ network header + 12 => reg 1 ] ] + [ cmp eq reg 1 0x000b8d0a ] + +# gretap ip protocol 1 +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x0000002f ] + [ inner type 4 hdrsize 4 flags e [ meta load protocol => reg 1 ] ] + [ cmp eq reg 1 0x00000008 ] + [ inner type 4 hdrsize 4 flags e [ payload load 1b @ network header + 9 => reg 1 ] ] + [ cmp eq reg 1 0x00000001 ] + +# gretap udp sport 8888 +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x0000002f ] + [ inner type 4 hdrsize 4 flags e [ meta load l4proto => reg 1 ] ] + [ cmp eq reg 1 0x00000011 ] + [ inner type 4 hdrsize 4 flags e [ payload load 2b @ transport header + 0 => reg 1 ] ] + [ cmp eq reg 1 0x0000b822 ] + +# gretap icmp type echo-reply +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x0000002f ] + [ inner type 4 hdrsize 4 flags e [ payload load 2b @ link header + 12 => reg 1 ] ] + [ cmp eq reg 1 0x00000008 ] + [ inner type 4 hdrsize 4 flags e [ meta load l4proto => reg 1 ] ] + [ cmp eq reg 1 0x00000001 ] + [ inner type 4 hdrsize 4 flags e [ payload load 1b @ transport header + 0 => reg 1 ] ] + [ cmp eq reg 1 0x00000000 ] + +# gretap ether saddr 62:87:4d:d6:19:05 +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x0000002f ] + [ inner type 4 hdrsize 4 flags e [ payload load 6b @ link header + 6 => reg 1 ] ] + [ cmp eq reg 1 0xd64d8762 0x00000519 ] + +# gretap vlan id 10 +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x0000002f ] + [ inner type 4 hdrsize 4 flags e [ payload load 2b @ link header + 12 => reg 1 ] ] + [ cmp eq reg 1 0x00000081 ] + [ inner type 4 hdrsize 4 flags e [ payload load 2b @ link header + 14 => reg 1 ] ] + [ bitwise reg 1 = ( reg 1 & 0x0000ff0f ) ^ 0x00000000 ] + [ cmp eq reg 1 0x00000a00 ] + +# gretap ip dscp 0x02 +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x0000002f ] + [ inner type 4 hdrsize 4 flags e [ meta load protocol => reg 1 ] ] + [ cmp eq reg 1 0x00000008 ] + [ inner type 4 hdrsize 4 flags e [ payload load 1b @ network header + 1 => reg 1 ] ] + [ bitwise reg 1 = ( reg 1 & 0x000000fc ) ^ 0x00000000 ] + [ cmp eq reg 1 0x00000008 ] + +# gretap ip saddr . gretap ip daddr { 1.2.3.4 . 4.3.2.1 } +__set%d test-ip4 3 size 1 +__set%d test-ip4 0 + element 04030201 01020304 : 0 [end] +ip test-ip4 input + [ meta load l4proto => reg 1 ] + [ cmp eq reg 1 0x0000002f ] + [ inner type 4 hdrsize 4 flags e [ meta load protocol => reg 1 ] ] + [ cmp eq reg 1 0x00000008 ] + [ inner type 4 hdrsize 4 flags e [ payload load 4b @ network header + 12 => reg 1 ] ] + [ inner type 4 hdrsize 4 flags e [ payload load 4b @ network header + 16 => reg 9 ] ] + [ lookup reg 1 set __set%d ] + From patchwork Mon Oct 17 11:04:08 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Pablo Neira Ayuso X-Patchwork-Id: 1690853 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org (client-ip=2620:137:e000::1:20; helo=out1.vger.email; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Received: from out1.vger.email (out1.vger.email [IPv6:2620:137:e000::1:20]) by legolas.ozlabs.org (Postfix) with ESMTP id 4MrYzN6kWRz23kV for ; Mon, 17 Oct 2022 22:04:32 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230235AbiJQLEb (ORCPT ); Mon, 17 Oct 2022 07:04:31 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34628 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230090AbiJQLEZ (ORCPT ); Mon, 17 Oct 2022 07:04:25 -0400 Received: from mail.netfilter.org (mail.netfilter.org [217.70.188.207]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 7C29D631A for ; Mon, 17 Oct 2022 04:04:23 -0700 (PDT) From: Pablo Neira Ayuso To: netfilter-devel@vger.kernel.org Subject: [PATCH nft,v2 16/16] doc: add gretap matching expression Date: Mon, 17 Oct 2022 13:04:08 +0200 Message-Id: <20221017110408.742223-17-pablo@netfilter.org> X-Mailer: git-send-email 2.30.2 In-Reply-To: <20221017110408.742223-1-pablo@netfilter.org> References: <20221017110408.742223-1-pablo@netfilter.org> MIME-Version: 1.0 X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,SPF_HELO_NONE, SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org Document new gretap matching expression. This includes support for matching the encapsulated ethernet frame layer 2, 3 and 4 headers within the gre header. Signed-off-by: Pablo Neira Ayuso --- doc/payload-expression.txt | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/doc/payload-expression.txt b/doc/payload-expression.txt index e75cb1fae4cc..9a49439b2252 100644 --- a/doc/payload-expression.txt +++ b/doc/payload-expression.txt @@ -595,6 +595,26 @@ integer (24 bit) netdev filter ingress udp dport 4789 geneve tcp dport 80 counter ---------------------------------------------------------- +GRETAP HEADER EXPRESSION +~~~~~~~~~~~~~~~~~~~~~~~~ +[verse] +*gretap* {*vni* | *flags*} +*gretap* *ether* {*daddr* | *saddr* | *type*} +*gretap* *vlan* {*id* | *dei* | *pcp* | *type*} +*gretap* *ip* {*version* | *hdrlength* | *dscp* | *ecn* | *length* | *id* | *frag-off* | *ttl* | *protocol* | *checksum* | *saddr* | *daddr* } +*gretap* *ip6* {*version* | *dscp* | *ecn* | *flowlabel* | *length* | *nexthdr* | *hoplimit* | *saddr* | *daddr*} +*gretap* *tcp* {*sport* | *dport* | *sequence* | *ackseq* | *doff* | *reserved* | *flags* | *window* | *checksum* | *urgptr*} +*gretap* *udp* {*sport* | *dport* | *length* | *checksum*} + +The gretap expression is used to match on the encapsulated ethernet frame +within the gre header. Use the *gre* expression to match on the *gre* header +fields. + +.Matching inner TCP destination port encapsulated in gretap +---------------------------------------------------------- +netdev filter ingress gretap tcp dport 80 counter +---------------------------------------------------------- + VXLAN HEADER EXPRESSION ~~~~~~~~~~~~~~~~~~~~~~~ [verse]