diff mbox series

[nft] payload: add offload flag to the statements

Message ID 20230503125654.41126-1-boris.sukholitko@broadcom.com
State Changes Requested
Delegated to: Pablo Neira
Headers show
Series [nft] payload: add offload flag to the statements | expand

Commit Message

Boris Sukholitko May 3, 2023, 12:56 p.m. UTC
Payload modification statements such as:

ip dscp set cs3

are not being executed by the flowtable fast path code the kernel.

This commit adds ability to mark such statements for offload to fix
this problem. For example the following configuration becomes correct
(notice offload in the ip dscp clause):

table inet filter {
        flowtable f1 {
                hook ingress priority filter
                devices = { veth0, veth1 }
        }

        chain forward {
                type filter hook forward priority filter; policy accept;
                ip dscp set cs3 offload
                ip protocol { tcp, udp, gre } flow add @f1
                ct state established,related accept
        }
}

Signed-off-by: Boris Sukholitko <boris.sukholitko@broadcom.com>
---
 include/linux/netfilter/nf_tables.h | 1 +
 include/statement.h                 | 3 ++-
 src/json.c                          | 9 ++++++++-
 src/netlink_delinearize.c           | 5 +++--
 src/netlink_linearize.c             | 8 ++++++--
 src/parser_bison.y                  | 9 ++++++---
 src/parser_json.c                   | 2 +-
 src/payload.c                       | 5 ++++-
 8 files changed, 31 insertions(+), 11 deletions(-)
diff mbox series

Patch

diff --git a/include/linux/netfilter/nf_tables.h b/include/linux/netfilter/nf_tables.h
index e4b739d5..ee12a884 100644
--- a/include/linux/netfilter/nf_tables.h
+++ b/include/linux/netfilter/nf_tables.h
@@ -778,6 +778,7 @@  enum nft_payload_csum_types {
 
 enum nft_payload_csum_flags {
 	NFT_PAYLOAD_L4CSUM_PSEUDOHDR = (1 << 0),
+	NFT_PAYLOAD_CAN_OFFLOAD = (1 << 1),
 };
 
 enum nft_inner_type {
diff --git a/include/statement.h b/include/statement.h
index e648fb13..fa1a048c 100644
--- a/include/statement.h
+++ b/include/statement.h
@@ -58,10 +58,11 @@  extern struct stmt *exthdr_stmt_alloc(const struct location *loc,
 struct payload_stmt {
 	struct expr			*expr;
 	struct expr			*val;
+	bool				can_offload;
 };
 
 extern struct stmt *payload_stmt_alloc(const struct location *loc,
-				       struct expr *payload, struct expr *expr);
+				       struct expr *payload, struct expr *expr, bool off);
 
 #include <meta.h>
 struct meta_stmt {
diff --git a/src/json.c b/src/json.c
index f57f2f77..df50962c 100644
--- a/src/json.c
+++ b/src/json.c
@@ -1163,9 +1163,16 @@  json_t *flow_offload_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
 
 json_t *payload_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
 {
-	return json_pack("{s: {s:o, s:o}}", "mangle",
+	json_t *root;
+
+	root = json_pack("{s: {s:o, s:o}}", "mangle",
 			 "key", expr_print_json(stmt->payload.expr, octx),
 			 "value", expr_print_json(stmt->payload.val, octx));
+
+	if (stmt->payload.can_offload)
+		json_object_set_new(root, "offload", json_true());
+
+	return root;
 }
 
 json_t *exthdr_stmt_json(const struct stmt *stmt, struct output_ctx *octx)
diff --git a/src/netlink_delinearize.c b/src/netlink_delinearize.c
index 4cd6cc3a..48e2a520 100644
--- a/src/netlink_delinearize.c
+++ b/src/netlink_delinearize.c
@@ -713,13 +713,14 @@  static void netlink_parse_payload_stmt(struct netlink_parse_ctx *ctx,
 				       const struct nftnl_expr *nle)
 {
 	enum nft_registers sreg;
-	uint32_t base, offset, len;
+	uint32_t base, offset, len, flags;
 	struct expr *expr, *val;
 	struct stmt *stmt;
 
 	base   = nftnl_expr_get_u32(nle, NFTNL_EXPR_PAYLOAD_BASE) + 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;
+	flags    = nftnl_expr_get_u32(nle, NFTNL_EXPR_PAYLOAD_FLAGS);
 
 	sreg = netlink_parse_register(nle, NFTNL_EXPR_PAYLOAD_SREG);
 	val  = netlink_get_register(ctx, loc, sreg);
@@ -730,7 +731,7 @@  static void netlink_parse_payload_stmt(struct netlink_parse_ctx *ctx,
 	expr = payload_expr_alloc(loc, NULL, 0);
 	payload_init_raw(expr, base, offset, len);
 
-	stmt = payload_stmt_alloc(loc, expr, val);
+	stmt = payload_stmt_alloc(loc, expr, val, flags & NFT_PAYLOAD_CAN_OFFLOAD);
 	rule_stmt_append(ctx->rule, stmt);
 }
 
diff --git a/src/netlink_linearize.c b/src/netlink_linearize.c
index 3da72f50..82c89b8c 100644
--- a/src/netlink_linearize.c
+++ b/src/netlink_linearize.c
@@ -1070,12 +1070,15 @@  static void netlink_gen_payload_stmt(struct netlink_linearize_ctx *ctx,
 	const struct expr *expr;
 	enum nft_registers sreg;
 	unsigned int csum_off;
+	uint32_t flags = 0;
 
 	sreg = get_register(ctx, stmt->payload.val);
 	netlink_gen_expr(ctx, stmt->payload.val, sreg);
 	release_register(ctx, stmt->payload.val);
 
 	expr = stmt->payload.expr;
+	if (stmt->payload.can_offload)
+		flags |= NFT_PAYLOAD_CAN_OFFLOAD;
 
 	csum_off = 0;
 	desc = expr->payload.desc;
@@ -1099,9 +1102,10 @@  static void netlink_gen_payload_stmt(struct netlink_linearize_ctx *ctx,
 	if ((expr->payload.base == PROTO_BASE_NETWORK_HDR && desc &&
 	     payload_needs_l4csum_update_pseudohdr(expr, desc)) ||
 	    expr->payload.base == PROTO_BASE_INNER_HDR)
-		nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_FLAGS,
-				   NFT_PAYLOAD_L4CSUM_PSEUDOHDR);
+		flags |= NFT_PAYLOAD_L4CSUM_PSEUDOHDR;
 
+	if (flags)
+		nftnl_expr_set_u32(nle, NFTNL_EXPR_PAYLOAD_FLAGS, flags);
 	nft_rule_add_expr(ctx, nle, &expr->location);
 }
 
diff --git a/src/parser_bison.y b/src/parser_bison.y
index ccf07a30..8954eb4c 100644
--- a/src/parser_bison.y
+++ b/src/parser_bison.y
@@ -726,7 +726,7 @@  int nft_lex(void *, void *, void *);
 %destructor { stmt_free($$); }	reject_stmt reject_stmt_alloc
 %type <stmt>			nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc redir_stmt redir_stmt_alloc
 %destructor { stmt_free($$); }	nat_stmt nat_stmt_alloc masq_stmt masq_stmt_alloc redir_stmt redir_stmt_alloc
-%type <val>			nf_nat_flags nf_nat_flag offset_opt
+%type <val>			nf_nat_flags nf_nat_flag offset_opt set_offload
 %type <stmt>			tproxy_stmt
 %destructor { stmt_free($$); }	tproxy_stmt
 %type <stmt>			synproxy_stmt synproxy_stmt_alloc
@@ -5325,15 +5325,18 @@  ct_stmt			:	CT	ct_key		SET	stmt_expr	close_scope_ct
 			}
 			;
 
-payload_stmt		:	payload_expr		SET	stmt_expr
+payload_stmt		:	payload_expr		SET	stmt_expr set_offload
 			{
 				if ($1->etype == EXPR_EXTHDR)
 					$$ = exthdr_stmt_alloc(&@$, $1, $3);
 				else
-					$$ = payload_stmt_alloc(&@$, $1, $3);
+					$$ = payload_stmt_alloc(&@$, $1, $3, $4);
 			}
 			;
 
+set_offload		:	OFFLOAD 	{ $$ = true; }
+			|	/* empty */	{ $$ = false; }
+
 payload_expr		:	payload_raw_expr
 			|	eth_hdr_expr
 			|	vlan_hdr_expr
diff --git a/src/parser_json.c b/src/parser_json.c
index ae683314..270dddeb 100644
--- a/src/parser_json.c
+++ b/src/parser_json.c
@@ -1753,7 +1753,7 @@  static struct stmt *json_parse_mangle_stmt(struct json_ctx *ctx,
 	case EXPR_EXTHDR:
 		return exthdr_stmt_alloc(int_loc, key, value);
 	case EXPR_PAYLOAD:
-		return payload_stmt_alloc(int_loc, key, value);
+		return payload_stmt_alloc(int_loc, key, value, false);
 	case EXPR_META:
 		stmt = meta_stmt_alloc(int_loc, key->meta.key, value);
 		expr_free(key);
diff --git a/src/payload.c b/src/payload.c
index ed76623c..77390e02 100644
--- a/src/payload.c
+++ b/src/payload.c
@@ -373,6 +373,8 @@  static void payload_stmt_print(const struct stmt *stmt, struct output_ctx *octx)
 	expr_print(stmt->payload.expr, octx);
 	nft_print(octx, " set ");
 	expr_print(stmt->payload.val, octx);
+	if (stmt->payload.can_offload)
+		nft_print(octx, " offload");
 }
 
 static void payload_stmt_destroy(struct stmt *stmt)
@@ -390,13 +392,14 @@  static const struct stmt_ops payload_stmt_ops = {
 };
 
 struct stmt *payload_stmt_alloc(const struct location *loc,
-				struct expr *expr, struct expr *val)
+				struct expr *expr, struct expr *val, bool off)
 {
 	struct stmt *stmt;
 
 	stmt = stmt_alloc(loc, &payload_stmt_ops);
 	stmt->payload.expr = expr;
 	stmt->payload.val  = val;
+	stmt->payload.can_offload  = off;
 	return stmt;
 }