diff mbox series

[net-next,3/3] filter: nf_tables_offload: set priority field for rules

Message ID 20190802132846.3067-4-pablo@netfilter.org
State Superseded
Delegated to: David Miller
Headers show
Series flow_offload hardware priority fixes | expand

Commit Message

Pablo Neira Ayuso Aug. 2, 2019, 1:28 p.m. UTC
This patch allocates the priority per rule starting from priority 1
since some drivers assume priority 0 never happens.

This patch is restricting the rule priority range to 8-bit integer since
the nft_rule object has 7-bit spare bits plus one that is scratched from
the handle. It should be possible to extend this later on by placing the
priority after the userdata area to turn this into 32-bits priority
field, to put this data away from the packet path cachelines.

Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
---
v1: formerly "netfilter: nf_tables: map basechain priority to hardware priority"
    address mapping to hardware based on comments from Jakub.

 include/net/netfilter/nf_tables.h         |  8 ++++++--
 include/net/netfilter/nf_tables_offload.h |  1 +
 net/netfilter/nf_tables_offload.c         | 27 ++++++++++++++++++++++-----
 3 files changed, 29 insertions(+), 7 deletions(-)
diff mbox series

Patch

diff --git a/include/net/netfilter/nf_tables.h b/include/net/netfilter/nf_tables.h
index 87dbe62c0f27..a6308fcf5bf0 100644
--- a/include/net/netfilter/nf_tables.h
+++ b/include/net/netfilter/nf_tables.h
@@ -9,6 +9,7 @@ 
 #include <linux/netfilter/nf_tables.h>
 #include <linux/u64_stats_sync.h>
 #include <linux/rhashtable.h>
+#include <linux/idr.h>
 #include <net/netfilter/nf_flow_table.h>
 #include <net/netlink.h>
 #include <net/flow_offload.h>
@@ -824,14 +825,16 @@  int nft_expr_dump(struct sk_buff *skb, unsigned int attr,
  *	@genmask: generation mask
  *	@dlen: length of expression data
  *	@udata: user data is appended to the rule
+ *	@prio: priority (for hardware offload)
  *	@data: expression data
  */
 struct nft_rule {
 	struct list_head		list;
-	u64				handle:42,
+	u64				handle:41,
 					genmask:2,
 					dlen:12,
-					udata:1;
+					udata:1,
+					prio:8;
 	unsigned char			data[]
 		__attribute__((aligned(__alignof__(struct nft_expr))));
 };
@@ -964,6 +967,7 @@  struct nft_base_chain {
 	char 				dev_name[IFNAMSIZ];
 	struct {
 		struct flow_block	flow_block;
+		struct idr		prio_idr;
 	} offload;
 };
 
diff --git a/include/net/netfilter/nf_tables_offload.h b/include/net/netfilter/nf_tables_offload.h
index fb3db391ade8..70f226568fe7 100644
--- a/include/net/netfilter/nf_tables_offload.h
+++ b/include/net/netfilter/nf_tables_offload.h
@@ -76,6 +76,7 @@  int nft_flow_rule_offload_commit(struct net *net);
 static inline void nft_basechain_offload_init(struct nft_base_chain *basechain)
 {
 	flow_block_init(&basechain->offload.flow_block);
+	idr_init(&basechain->offload.prio_idr);
 }
 
 #endif
diff --git a/net/netfilter/nf_tables_offload.c b/net/netfilter/nf_tables_offload.c
index 84615381b06f..21144938482a 100644
--- a/net/netfilter/nf_tables_offload.c
+++ b/net/netfilter/nf_tables_offload.c
@@ -103,10 +103,11 @@  void nft_offload_update_dependency(struct nft_offload_ctx *ctx,
 }
 
 static void nft_flow_offload_common_init(struct flow_cls_common_offload *common,
-					 __be16 proto,
-					struct netlink_ext_ack *extack)
+					 __be16 proto, u32 priority,
+					 struct netlink_ext_ack *extack)
 {
 	common->protocol = proto;
+	common->prio = priority;
 	common->extack = extack;
 }
 
@@ -125,6 +126,8 @@  static int nft_setup_cb_call(struct nft_base_chain *basechain,
 	return 0;
 }
 
+#define NFT_OFFLOAD_PRIO_MAX	U8_MAX
+
 static int nft_flow_offload_rule(struct nft_trans *trans,
 				 enum flow_cls_command command)
 {
@@ -134,22 +137,36 @@  static int nft_flow_offload_rule(struct nft_trans *trans,
 	struct nft_base_chain *basechain;
 	struct netlink_ext_ack extack;
 	__be16 proto = ETH_P_ALL;
+	u32 prio = 1;
+	int err;
 
 	if (!nft_is_base_chain(trans->ctx.chain))
 		return -EOPNOTSUPP;
 
 	basechain = nft_base_chain(trans->ctx.chain);
 
-	if (flow)
+	if (flow) {
+		if (idr_alloc_u32(&basechain->offload.prio_idr, NULL, &prio,
+				  NFT_OFFLOAD_PRIO_MAX, GFP_KERNEL) < 0)
+			return -E2BIG;
+
+		rule->prio = prio;
 		proto = flow->proto;
+	}
 
-	nft_flow_offload_common_init(&cls_flow.common, proto, &extack);
+	nft_flow_offload_common_init(&cls_flow.common, proto, rule->prio,
+				     &extack);
 	cls_flow.command = command;
 	cls_flow.cookie = (unsigned long) rule;
 	if (flow)
 		cls_flow.rule = flow->rule;
 
-	return nft_setup_cb_call(basechain, TC_SETUP_CLSFLOWER, &cls_flow);
+	err = nft_setup_cb_call(basechain, TC_SETUP_CLSFLOWER, &cls_flow);
+	if ((err < 0 && command == FLOW_CLS_REPLACE) ||
+	    (err == 0 && command == FLOW_CLS_DESTROY))
+		idr_remove(&basechain->offload.prio_idr, rule->prio);
+
+	return err;
 }
 
 static int nft_flow_offload_bind(struct flow_block_offload *bo,