netfilter-devel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH nf-next v7 0/8]  netfilter: Support the bridge family in flow table
@ 2019-08-30  4:17 wenxu
  2019-08-30  4:17 ` [PATCH nf-next v7 1/8] netfilter:nf_flow_table: Refactor flow_offload_tuple to destination wenxu
                   ` (7 more replies)
  0 siblings, 8 replies; 11+ messages in thread
From: wenxu @ 2019-08-30  4:17 UTC (permalink / raw)
  To: pablo, fw; +Cc: netfilter-devel

From: wenxu <wenxu@ucloud.cn>

This series add the bridge flow table type. Implement the datapath
flow table to forward both IPV4 and IPV6 traffic through bridge.

This version just rebase with upstream fix

wenxu (8):
  netfilter:nf_flow_table: Refactor flow_offload_tuple to destination
  netfilter:nf_flow_table_core: Separate inet operation to single
    function
  netfilter:nf_flow_table_ip: Separate inet operation to single function
  bridge: add br_vlan_get_info_rcu()
  netfilter:nf_flow_table_core: Support bridge family flow offload
  netfilter:nf_flow_table_ip: Support bridge family flow offload
  netfilter:nft_flow_offload: Support bridge family flow offload
  netfilter: Support the bridge family in flow table

 include/linux/if_bridge.h                   |   7 ++
 include/net/netfilter/nf_flow_table.h       |  39 +++++-
 net/bridge/br_vlan.c                        |  25 ++++
 net/bridge/netfilter/Kconfig                |   8 ++
 net/bridge/netfilter/Makefile               |   1 +
 net/bridge/netfilter/nf_flow_table_bridge.c |  48 ++++++++
 net/netfilter/nf_flow_table_core.c          | 102 ++++++++++++---
 net/netfilter/nf_flow_table_ip.c            | 184 ++++++++++++++++++++--------
 net/netfilter/nft_flow_offload.c            | 144 ++++++++++++++++++++--
 9 files changed, 475 insertions(+), 83 deletions(-)
 create mode 100644 net/bridge/netfilter/nf_flow_table_bridge.c

-- 
1.8.3.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH nf-next v7 1/8] netfilter:nf_flow_table: Refactor flow_offload_tuple to destination
  2019-08-30  4:17 [PATCH nf-next v7 0/8] netfilter: Support the bridge family in flow table wenxu
@ 2019-08-30  4:17 ` wenxu
  2019-08-30  4:17 ` [PATCH nf-next v7 2/8] netfilter:nf_flow_table_core: Separate inet operation to single function wenxu
                   ` (6 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: wenxu @ 2019-08-30  4:17 UTC (permalink / raw)
  To: pablo, fw; +Cc: netfilter-devel

From: wenxu <wenxu@ucloud.cn>

Add struct flow_offload_dst to support more offload method to replace
dst_cache which only work for route offload.

Signed-off-by: wenxu <wenxu@ucloud.cn>
---
v7: rebase with upstream fix

 include/net/netfilter/nf_flow_table.h | 12 ++++++++++--
 net/netfilter/nf_flow_table_core.c    | 24 ++++++++++++------------
 net/netfilter/nf_flow_table_ip.c      |  4 ++--
 net/netfilter/nft_flow_offload.c      | 10 +++++-----
 4 files changed, 29 insertions(+), 21 deletions(-)

diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
index 609df33..f58e09c 100644
--- a/include/net/netfilter/nf_flow_table.h
+++ b/include/net/netfilter/nf_flow_table.h
@@ -36,6 +36,10 @@ enum flow_offload_tuple_dir {
 	FLOW_OFFLOAD_DIR_MAX = IP_CT_DIR_MAX
 };
 
+struct flow_offload_dst {
+	struct dst_entry		*dst_cache;
+};
+
 struct flow_offload_tuple {
 	union {
 		struct in_addr		src_v4;
@@ -58,7 +62,7 @@ struct flow_offload_tuple {
 
 	u16				mtu;
 
-	struct dst_entry		*dst_cache;
+	struct flow_offload_dst		dst;
 };
 
 struct flow_offload_tuple_rhash {
@@ -88,8 +92,12 @@ struct nf_flow_route {
 	} tuple[FLOW_OFFLOAD_DIR_MAX];
 };
 
+struct nf_flow_dst {
+	struct nf_flow_route route;
+};
+
 struct flow_offload *flow_offload_alloc(struct nf_conn *ct,
-					struct nf_flow_route *route);
+					struct nf_flow_dst *flow_dst);
 void flow_offload_free(struct flow_offload *flow);
 
 int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow);
diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c
index 80a8f9ae..e9bc756 100644
--- a/net/netfilter/nf_flow_table_core.c
+++ b/net/netfilter/nf_flow_table_core.c
@@ -24,13 +24,13 @@ struct flow_offload_entry {
 
 static void
 flow_offload_fill_dir(struct flow_offload *flow, struct nf_conn *ct,
-		      struct nf_flow_route *route,
+		      struct nf_flow_dst *flow_dst,
 		      enum flow_offload_tuple_dir dir)
 {
 	struct flow_offload_tuple *ft = &flow->tuplehash[dir].tuple;
 	struct nf_conntrack_tuple *ctt = &ct->tuplehash[dir].tuple;
-	struct dst_entry *other_dst = route->tuple[!dir].dst;
-	struct dst_entry *dst = route->tuple[dir].dst;
+	struct dst_entry *other_dst = flow_dst->route.tuple[!dir].dst;
+	struct dst_entry *dst = flow_dst->route.tuple[dir].dst;
 
 	ft->dir = dir;
 
@@ -53,11 +53,11 @@ struct flow_offload_entry {
 	ft->dst_port = ctt->dst.u.tcp.port;
 
 	ft->iifidx = other_dst->dev->ifindex;
-	ft->dst_cache = dst;
+	ft->dst.dst_cache = dst;
 }
 
 struct flow_offload *
-flow_offload_alloc(struct nf_conn *ct, struct nf_flow_route *route)
+flow_offload_alloc(struct nf_conn *ct, struct nf_flow_dst *flow_dst)
 {
 	struct flow_offload_entry *entry;
 	struct flow_offload *flow;
@@ -72,16 +72,16 @@ struct flow_offload *
 
 	flow = &entry->flow;
 
-	if (!dst_hold_safe(route->tuple[FLOW_OFFLOAD_DIR_ORIGINAL].dst))
+	if (!dst_hold_safe(flow_dst->route.tuple[FLOW_OFFLOAD_DIR_ORIGINAL].dst))
 		goto err_dst_cache_original;
 
-	if (!dst_hold_safe(route->tuple[FLOW_OFFLOAD_DIR_REPLY].dst))
+	if (!dst_hold_safe(flow_dst->route.tuple[FLOW_OFFLOAD_DIR_REPLY].dst))
 		goto err_dst_cache_reply;
 
 	entry->ct = ct;
 
-	flow_offload_fill_dir(flow, ct, route, FLOW_OFFLOAD_DIR_ORIGINAL);
-	flow_offload_fill_dir(flow, ct, route, FLOW_OFFLOAD_DIR_REPLY);
+	flow_offload_fill_dir(flow, ct, flow_dst, FLOW_OFFLOAD_DIR_ORIGINAL);
+	flow_offload_fill_dir(flow, ct, flow_dst, FLOW_OFFLOAD_DIR_REPLY);
 
 	if (ct->status & IPS_SRC_NAT)
 		flow->flags |= FLOW_OFFLOAD_SNAT;
@@ -91,7 +91,7 @@ struct flow_offload *
 	return flow;
 
 err_dst_cache_reply:
-	dst_release(route->tuple[FLOW_OFFLOAD_DIR_ORIGINAL].dst);
+	dst_release(flow_dst->route.tuple[FLOW_OFFLOAD_DIR_ORIGINAL].dst);
 err_dst_cache_original:
 	kfree(entry);
 err_ct_refcnt:
@@ -153,8 +153,8 @@ void flow_offload_free(struct flow_offload *flow)
 {
 	struct flow_offload_entry *e;
 
-	dst_release(flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst_cache);
-	dst_release(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst_cache);
+	dst_release(flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst.dst_cache);
+	dst_release(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst.dst_cache);
 	e = container_of(flow, struct flow_offload_entry, flow);
 	if (flow->flags & FLOW_OFFLOAD_DYING)
 		nf_ct_delete(e->ct, 0, 0);
diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
index d68c801..3ff7b04 100644
--- a/net/netfilter/nf_flow_table_ip.c
+++ b/net/netfilter/nf_flow_table_ip.c
@@ -260,7 +260,7 @@ static unsigned int nf_flow_xmit_xfrm(struct sk_buff *skb,
 
 	dir = tuplehash->tuple.dir;
 	flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
-	rt = (struct rtable *)flow->tuplehash[dir].tuple.dst_cache;
+	rt = (struct rtable *)flow->tuplehash[dir].tuple.dst.dst_cache;
 	outdev = rt->dst.dev;
 
 	if (unlikely(nf_flow_exceeds_mtu(skb, flow->tuplehash[dir].tuple.mtu)))
@@ -488,7 +488,7 @@ static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev,
 
 	dir = tuplehash->tuple.dir;
 	flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
-	rt = (struct rt6_info *)flow->tuplehash[dir].tuple.dst_cache;
+	rt = (struct rt6_info *)flow->tuplehash[dir].tuple.dst.dst_cache;
 	outdev = rt->dst.dev;
 
 	if (unlikely(nf_flow_exceeds_mtu(skb, flow->tuplehash[dir].tuple.mtu)))
diff --git a/net/netfilter/nft_flow_offload.c b/net/netfilter/nft_flow_offload.c
index 060a4ed..2dd0d3e 100644
--- a/net/netfilter/nft_flow_offload.c
+++ b/net/netfilter/nft_flow_offload.c
@@ -74,7 +74,7 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
 	struct nf_flowtable *flowtable = &priv->flowtable->data;
 	struct tcphdr _tcph, *tcph = NULL;
 	enum ip_conntrack_info ctinfo;
-	struct nf_flow_route route;
+	struct nf_flow_dst flow_dst;
 	struct flow_offload *flow;
 	enum ip_conntrack_dir dir;
 	struct nf_conn *ct;
@@ -111,10 +111,10 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
 		goto out;
 
 	dir = CTINFO2DIR(ctinfo);
-	if (nft_flow_route(pkt, ct, &route, dir) < 0)
+	if (nft_flow_route(pkt, ct, &flow_dst.route, dir) < 0)
 		goto err_flow_route;
 
-	flow = flow_offload_alloc(ct, &route);
+	flow = flow_offload_alloc(ct, &flow_dst);
 	if (!flow)
 		goto err_flow_alloc;
 
@@ -127,13 +127,13 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
 	if (ret < 0)
 		goto err_flow_add;
 
-	dst_release(route.tuple[!dir].dst);
+	dst_release(flow_dst.route.tuple[!dir].dst);
 	return;
 
 err_flow_add:
 	flow_offload_free(flow);
 err_flow_alloc:
-	dst_release(route.tuple[!dir].dst);
+	dst_release(flow_dst.route.tuple[!dir].dst);
 err_flow_route:
 	clear_bit(IPS_OFFLOAD_BIT, &ct->status);
 out:
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH nf-next v7 2/8] netfilter:nf_flow_table_core: Separate inet operation to single function
  2019-08-30  4:17 [PATCH nf-next v7 0/8] netfilter: Support the bridge family in flow table wenxu
  2019-08-30  4:17 ` [PATCH nf-next v7 1/8] netfilter:nf_flow_table: Refactor flow_offload_tuple to destination wenxu
@ 2019-08-30  4:17 ` wenxu
  2019-08-30  4:17 ` [PATCH nf-next v7 3/8] netfilter:nf_flow_table_ip: " wenxu
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: wenxu @ 2019-08-30  4:17 UTC (permalink / raw)
  To: pablo, fw; +Cc: netfilter-devel

From: wenxu <wenxu@ucloud.cn>

This patch separate the inet family operation in nf_flow_table_core to
single function. Prepare for support the bridge family.

Signed-off-by: wenxu <wenxu@ucloud.cn>
---
v7: rebase with upstream fix

 net/netfilter/nf_flow_table_core.c | 52 ++++++++++++++++++++++++++++----------
 1 file changed, 38 insertions(+), 14 deletions(-)

diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c
index e9bc756..9492c97 100644
--- a/net/netfilter/nf_flow_table_core.c
+++ b/net/netfilter/nf_flow_table_core.c
@@ -22,6 +22,20 @@ struct flow_offload_entry {
 static DEFINE_MUTEX(flowtable_lock);
 static LIST_HEAD(flowtables);
 
+static struct dst_entry *
+flow_offload_fill_inet_dst(struct flow_offload_tuple *ft,
+			   struct nf_flow_route *route,
+			   enum flow_offload_tuple_dir dir)
+{
+	struct dst_entry *other_dst = route->tuple[!dir].dst;
+	struct dst_entry *dst = route->tuple[dir].dst;
+
+	ft->iifidx = other_dst->dev->ifindex;
+	ft->dst.dst_cache = dst;
+
+	return dst;
+}
+
 static void
 flow_offload_fill_dir(struct flow_offload *flow, struct nf_conn *ct,
 		      struct nf_flow_dst *flow_dst,
@@ -29,9 +43,9 @@ struct flow_offload_entry {
 {
 	struct flow_offload_tuple *ft = &flow->tuplehash[dir].tuple;
 	struct nf_conntrack_tuple *ctt = &ct->tuplehash[dir].tuple;
-	struct dst_entry *other_dst = flow_dst->route.tuple[!dir].dst;
-	struct dst_entry *dst = flow_dst->route.tuple[dir].dst;
+	struct dst_entry *dst;
 
+	dst = flow_offload_fill_inet_dst(ft, &flow_dst->route, dir);
 	ft->dir = dir;
 
 	switch (ctt->src.l3num) {
@@ -51,9 +65,19 @@ struct flow_offload_entry {
 	ft->l4proto = ctt->dst.protonum;
 	ft->src_port = ctt->src.u.tcp.port;
 	ft->dst_port = ctt->dst.u.tcp.port;
+}
 
-	ft->iifidx = other_dst->dev->ifindex;
-	ft->dst.dst_cache = dst;
+static int flow_offload_dst_hold(struct nf_flow_dst *flow_dst)
+{
+	if (!dst_hold_safe(flow_dst->route.tuple[FLOW_OFFLOAD_DIR_ORIGINAL].dst))
+		return -1;
+
+	if (!dst_hold_safe(flow_dst->route.tuple[FLOW_OFFLOAD_DIR_REPLY].dst)) {
+		dst_release(flow_dst->route.tuple[FLOW_OFFLOAD_DIR_ORIGINAL].dst);
+		return -1;
+	}
+
+	return 0;
 }
 
 struct flow_offload *
@@ -72,11 +96,8 @@ struct flow_offload *
 
 	flow = &entry->flow;
 
-	if (!dst_hold_safe(flow_dst->route.tuple[FLOW_OFFLOAD_DIR_ORIGINAL].dst))
-		goto err_dst_cache_original;
-
-	if (!dst_hold_safe(flow_dst->route.tuple[FLOW_OFFLOAD_DIR_REPLY].dst))
-		goto err_dst_cache_reply;
+	if (flow_offload_dst_hold(flow_dst))
+		goto err_dst_cache;
 
 	entry->ct = ct;
 
@@ -90,9 +111,7 @@ struct flow_offload *
 
 	return flow;
 
-err_dst_cache_reply:
-	dst_release(flow_dst->route.tuple[FLOW_OFFLOAD_DIR_ORIGINAL].dst);
-err_dst_cache_original:
+err_dst_cache:
 	kfree(entry);
 err_ct_refcnt:
 	nf_ct_put(ct);
@@ -149,12 +168,17 @@ static void flow_offload_fixup_ct(struct nf_conn *ct)
 	flow_offload_fixup_ct_timeout(ct);
 }
 
+static void flow_offload_dst_release(struct flow_offload *flow)
+{
+	dst_release(flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst.dst_cache);
+	dst_release(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst.dst_cache);
+}
+
 void flow_offload_free(struct flow_offload *flow)
 {
 	struct flow_offload_entry *e;
 
-	dst_release(flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst.dst_cache);
-	dst_release(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst.dst_cache);
+	flow_offload_dst_release(flow);
 	e = container_of(flow, struct flow_offload_entry, flow);
 	if (flow->flags & FLOW_OFFLOAD_DYING)
 		nf_ct_delete(e->ct, 0, 0);
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH nf-next v7 3/8] netfilter:nf_flow_table_ip: Separate inet operation to single function
  2019-08-30  4:17 [PATCH nf-next v7 0/8] netfilter: Support the bridge family in flow table wenxu
  2019-08-30  4:17 ` [PATCH nf-next v7 1/8] netfilter:nf_flow_table: Refactor flow_offload_tuple to destination wenxu
  2019-08-30  4:17 ` [PATCH nf-next v7 2/8] netfilter:nf_flow_table_core: Separate inet operation to single function wenxu
@ 2019-08-30  4:17 ` wenxu
  2019-08-30  4:17 ` [PATCH nf-next v7 4/8] bridge: add br_vlan_get_info_rcu() wenxu
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: wenxu @ 2019-08-30  4:17 UTC (permalink / raw)
  To: pablo, fw; +Cc: netfilter-devel

From: wenxu <wenxu@ucloud.cn>

This patch separate the inet family operation in nf_flow_table_ip to single
function. Prepare for support the bridge family.

Signed-off-by: wenxu <wenxu@ucloud.cn>
---
v7: rebase with upstream fix

 net/netfilter/nf_flow_table_ip.c | 128 ++++++++++++++++++++++-----------------
 1 file changed, 73 insertions(+), 55 deletions(-)

diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
index 3ff7b04..1c598af 100644
--- a/net/netfilter/nf_flow_table_ip.c
+++ b/net/netfilter/nf_flow_table_ip.c
@@ -233,6 +233,40 @@ static unsigned int nf_flow_xmit_xfrm(struct sk_buff *skb,
 	return NF_STOLEN;
 }
 
+static int nf_flow_ipv4_xmit(struct flow_offload *flow, struct sk_buff *skb,
+			     const struct nf_hook_state *state,
+			     enum flow_offload_tuple_dir dir)
+{
+	struct net_device *outdev;
+	struct rtable *rt;
+	struct iphdr *iph;
+	__be32 nexthop;
+
+	rt = (struct rtable *)flow->tuplehash[dir].tuple.dst.dst_cache;
+	if (nf_flow_offload_dst_check(&rt->dst)) {
+		flow_offload_teardown(flow);
+		return NF_ACCEPT;
+	}
+
+	outdev = rt->dst.dev;
+	iph = ip_hdr(skb);
+	ip_decrease_ttl(iph);
+
+	if (unlikely(dst_xfrm(&rt->dst))) {
+		memset(skb->cb, 0, sizeof(struct inet_skb_parm));
+		IPCB(skb)->iif = skb->dev->ifindex;
+		IPCB(skb)->flags = IPSKB_FORWARDED;
+		return nf_flow_xmit_xfrm(skb, state, &rt->dst);
+	}
+
+	skb->dev = outdev;
+	nexthop = rt_nexthop(rt, flow->tuplehash[!dir].tuple.src_v4.s_addr);
+	skb_dst_set_noref(skb, &rt->dst);
+	neigh_xmit(NEIGH_ARP_TABLE, outdev, &nexthop, skb);
+
+	return NF_STOLEN;
+}
+
 unsigned int
 nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
 			const struct nf_hook_state *state)
@@ -242,11 +276,7 @@ static unsigned int nf_flow_xmit_xfrm(struct sk_buff *skb,
 	struct flow_offload_tuple tuple = {};
 	enum flow_offload_tuple_dir dir;
 	struct flow_offload *flow;
-	struct net_device *outdev;
-	struct rtable *rt;
 	unsigned int thoff;
-	struct iphdr *iph;
-	__be32 nexthop;
 
 	if (skb->protocol != htons(ETH_P_IP))
 		return NF_ACCEPT;
@@ -260,44 +290,23 @@ static unsigned int nf_flow_xmit_xfrm(struct sk_buff *skb,
 
 	dir = tuplehash->tuple.dir;
 	flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
-	rt = (struct rtable *)flow->tuplehash[dir].tuple.dst.dst_cache;
-	outdev = rt->dst.dev;
 
 	if (unlikely(nf_flow_exceeds_mtu(skb, flow->tuplehash[dir].tuple.mtu)))
 		return NF_ACCEPT;
 
-	if (skb_try_make_writable(skb, sizeof(*iph)))
+	if (skb_try_make_writable(skb, sizeof(struct iphdr)))
 		return NF_DROP;
 
 	thoff = ip_hdr(skb)->ihl * 4;
 	if (nf_flow_state_check(flow, ip_hdr(skb)->protocol, skb, thoff))
 		return NF_ACCEPT;
 
-	if (nf_flow_offload_dst_check(&rt->dst)) {
-		flow_offload_teardown(flow);
-		return NF_ACCEPT;
-	}
-
 	if (nf_flow_nat_ip(flow, skb, thoff, dir) < 0)
 		return NF_DROP;
 
 	flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT;
-	iph = ip_hdr(skb);
-	ip_decrease_ttl(iph);
-
-	if (unlikely(dst_xfrm(&rt->dst))) {
-		memset(skb->cb, 0, sizeof(struct inet_skb_parm));
-		IPCB(skb)->iif = skb->dev->ifindex;
-		IPCB(skb)->flags = IPSKB_FORWARDED;
-		return nf_flow_xmit_xfrm(skb, state, &rt->dst);
-	}
 
-	skb->dev = outdev;
-	nexthop = rt_nexthop(rt, flow->tuplehash[!dir].tuple.src_v4.s_addr);
-	skb_dst_set_noref(skb, &rt->dst);
-	neigh_xmit(NEIGH_ARP_TABLE, outdev, &nexthop, skb);
-
-	return NF_STOLEN;
+	return nf_flow_ipv4_xmit(flow, skb, state, dir);
 }
 EXPORT_SYMBOL_GPL(nf_flow_offload_ip_hook);
 
@@ -462,6 +471,40 @@ static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev,
 	return 0;
 }
 
+static int nf_flow_ipv6_xmit(struct flow_offload *flow, struct sk_buff *skb,
+			     const struct nf_hook_state *state,
+			     enum flow_offload_tuple_dir dir)
+{
+	const struct in6_addr *nexthop;
+	struct net_device *outdev;
+	struct ipv6hdr *ip6h;
+	struct rt6_info *rt;
+
+	rt = (struct rt6_info *)flow->tuplehash[dir].tuple.dst.dst_cache;
+	if (nf_flow_offload_dst_check(&rt->dst)) {
+		flow_offload_teardown(flow);
+		return NF_ACCEPT;
+	}
+
+	outdev = rt->dst.dev;
+	ip6h = ipv6_hdr(skb);
+	ip6h->hop_limit--;
+
+	if (unlikely(dst_xfrm(&rt->dst))) {
+		memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
+		IP6CB(skb)->iif = skb->dev->ifindex;
+		IP6CB(skb)->flags = IP6SKB_FORWARDED;
+		return nf_flow_xmit_xfrm(skb, state, &rt->dst);
+	}
+
+	skb->dev = outdev;
+	nexthop = rt6_nexthop(rt, &flow->tuplehash[!dir].tuple.src_v6);
+	skb_dst_set_noref(skb, &rt->dst);
+	neigh_xmit(NEIGH_ND_TABLE, outdev, nexthop, skb);
+
+	return NF_STOLEN;
+}
+
 unsigned int
 nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
 			  const struct nf_hook_state *state)
@@ -470,11 +513,7 @@ static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev,
 	struct nf_flowtable *flow_table = priv;
 	struct flow_offload_tuple tuple = {};
 	enum flow_offload_tuple_dir dir;
-	const struct in6_addr *nexthop;
 	struct flow_offload *flow;
-	struct net_device *outdev;
-	struct ipv6hdr *ip6h;
-	struct rt6_info *rt;
 
 	if (skb->protocol != htons(ETH_P_IPV6))
 		return NF_ACCEPT;
@@ -488,43 +527,22 @@ static int nf_flow_tuple_ipv6(struct sk_buff *skb, const struct net_device *dev,
 
 	dir = tuplehash->tuple.dir;
 	flow = container_of(tuplehash, struct flow_offload, tuplehash[dir]);
-	rt = (struct rt6_info *)flow->tuplehash[dir].tuple.dst.dst_cache;
-	outdev = rt->dst.dev;
 
 	if (unlikely(nf_flow_exceeds_mtu(skb, flow->tuplehash[dir].tuple.mtu)))
 		return NF_ACCEPT;
 
 	if (nf_flow_state_check(flow, ipv6_hdr(skb)->nexthdr, skb,
-				sizeof(*ip6h)))
+				sizeof(struct ipv6hdr)))
 		return NF_ACCEPT;
 
-	if (nf_flow_offload_dst_check(&rt->dst)) {
-		flow_offload_teardown(flow);
-		return NF_ACCEPT;
-	}
-
-	if (skb_try_make_writable(skb, sizeof(*ip6h)))
+	if (skb_try_make_writable(skb, sizeof(struct ipv6hdr)))
 		return NF_DROP;
 
 	if (nf_flow_nat_ipv6(flow, skb, dir) < 0)
 		return NF_DROP;
 
 	flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT;
-	ip6h = ipv6_hdr(skb);
-	ip6h->hop_limit--;
-
-	if (unlikely(dst_xfrm(&rt->dst))) {
-		memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
-		IP6CB(skb)->iif = skb->dev->ifindex;
-		IP6CB(skb)->flags = IP6SKB_FORWARDED;
-		return nf_flow_xmit_xfrm(skb, state, &rt->dst);
-	}
 
-	skb->dev = outdev;
-	nexthop = rt6_nexthop(rt, &flow->tuplehash[!dir].tuple.src_v6);
-	skb_dst_set_noref(skb, &rt->dst);
-	neigh_xmit(NEIGH_ND_TABLE, outdev, nexthop, skb);
-
-	return NF_STOLEN;
+	return nf_flow_ipv6_xmit(flow, skb, state, dir);
 }
 EXPORT_SYMBOL_GPL(nf_flow_offload_ipv6_hook);
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH nf-next v7 4/8] bridge: add br_vlan_get_info_rcu()
  2019-08-30  4:17 [PATCH nf-next v7 0/8] netfilter: Support the bridge family in flow table wenxu
                   ` (2 preceding siblings ...)
  2019-08-30  4:17 ` [PATCH nf-next v7 3/8] netfilter:nf_flow_table_ip: " wenxu
@ 2019-08-30  4:17 ` wenxu
  2019-08-30  4:17 ` [PATCH nf-next v7 5/8] netfilter:nf_flow_table_core: Support bridge family flow offload wenxu
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 11+ messages in thread
From: wenxu @ 2019-08-30  4:17 UTC (permalink / raw)
  To: pablo, fw; +Cc: netfilter-devel

From: wenxu <wenxu@ucloud.cn>

This new function allows you to fetch vlan info from packet path.

Signed-off-by: wenxu <wenxu@ucloud.cn>
Acked-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
---
v7: no change

 include/linux/if_bridge.h |  7 +++++++
 net/bridge/br_vlan.c      | 25 +++++++++++++++++++++++++
 2 files changed, 32 insertions(+)

diff --git a/include/linux/if_bridge.h b/include/linux/if_bridge.h
index 9e57c44..5c85608 100644
--- a/include/linux/if_bridge.h
+++ b/include/linux/if_bridge.h
@@ -92,6 +92,8 @@ static inline bool br_multicast_router(const struct net_device *dev)
 int br_vlan_get_proto(const struct net_device *dev, u16 *p_proto);
 int br_vlan_get_info(const struct net_device *dev, u16 vid,
 		     struct bridge_vlan_info *p_vinfo);
+int br_vlan_get_info_rcu(const struct net_device *dev, u16 vid,
+			 struct bridge_vlan_info *p_vinfo);
 #else
 static inline bool br_vlan_enabled(const struct net_device *dev)
 {
@@ -118,6 +120,11 @@ static inline int br_vlan_get_info(const struct net_device *dev, u16 vid,
 {
 	return -EINVAL;
 }
+static inline int br_vlan_get_info_rcu(const struct net_device *dev, u16 vid,
+				       struct bridge_vlan_info *p_vinfo)
+{
+	return -EINVAL;
+}
 #endif
 
 #if IS_ENABLED(CONFIG_BRIDGE)
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index f5b2aee..dfcf098 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -1285,6 +1285,31 @@ int br_vlan_get_info(const struct net_device *dev, u16 vid,
 }
 EXPORT_SYMBOL_GPL(br_vlan_get_info);
 
+int br_vlan_get_info_rcu(const struct net_device *dev, u16 vid,
+			 struct bridge_vlan_info *p_vinfo)
+{
+	struct net_bridge_vlan_group *vg;
+	struct net_bridge_vlan *v;
+	struct net_bridge_port *p;
+
+	p = br_port_get_check_rcu(dev);
+	if (p)
+		vg = nbp_vlan_group_rcu(p);
+	else if (netif_is_bridge_master(dev))
+		vg = br_vlan_group_rcu(netdev_priv(dev));
+	else
+		return -EINVAL;
+
+	v = br_vlan_find(vg, vid);
+	if (!v)
+		return -ENOENT;
+
+	p_vinfo->vid = vid;
+	p_vinfo->flags = v->flags;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(br_vlan_get_info_rcu);
+
 static int br_vlan_is_bind_vlan_dev(const struct net_device *dev)
 {
 	return is_vlan_dev(dev) &&
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH nf-next v7 5/8] netfilter:nf_flow_table_core: Support bridge family flow offload
  2019-08-30  4:17 [PATCH nf-next v7 0/8] netfilter: Support the bridge family in flow table wenxu
                   ` (3 preceding siblings ...)
  2019-08-30  4:17 ` [PATCH nf-next v7 4/8] bridge: add br_vlan_get_info_rcu() wenxu
@ 2019-08-30  4:17 ` wenxu
  2019-08-30 12:12   ` kbuild test robot
  2019-08-30  4:17 ` [PATCH nf-next v7 6/8] netfilter:nf_flow_table_ip: " wenxu
                   ` (2 subsequent siblings)
  7 siblings, 1 reply; 11+ messages in thread
From: wenxu @ 2019-08-30  4:17 UTC (permalink / raw)
  To: pablo, fw; +Cc: netfilter-devel

From: wenxu <wenxu@ucloud.cn>

With nf_conntrack_bridge function. The bridge family can do
conntrack it self. The flow offload function based on the
conntrack. This patch add bridge family operation in
nf_flow_table_core

Signed-off-by: wenxu <wenxu@ucloud.cn>
---
v7: no change

 include/net/netfilter/nf_flow_table.h | 31 +++++++++++++++++--
 net/netfilter/nf_flow_table_core.c    | 58 +++++++++++++++++++++++++++++------
 2 files changed, 78 insertions(+), 11 deletions(-)

diff --git a/include/net/netfilter/nf_flow_table.h b/include/net/netfilter/nf_flow_table.h
index f58e09c..8820d17 100644
--- a/include/net/netfilter/nf_flow_table.h
+++ b/include/net/netfilter/nf_flow_table.h
@@ -36,8 +36,23 @@ enum flow_offload_tuple_dir {
 	FLOW_OFFLOAD_DIR_MAX = IP_CT_DIR_MAX
 };
 
+enum flow_offload_tuple_type {
+	FLOW_OFFLOAD_TYPE_INET,
+	FLOW_OFFLOAD_TYPE_BRIDGE,
+};
+
+struct dst_br_port {
+	struct net_device *dev;
+	u16	dst_vlan_tag;
+	u16	vlan_proto;
+};
+
 struct flow_offload_dst {
-	struct dst_entry		*dst_cache;
+	enum flow_offload_tuple_type type;
+	union {
+		struct dst_entry		*dst_cache;
+		struct dst_br_port		dst_port;
+	};
 };
 
 struct flow_offload_tuple {
@@ -55,6 +70,7 @@ struct flow_offload_tuple {
 	};
 
 	int				iifidx;
+	u16				vlan_tag;
 
 	u8				l3proto;
 	u8				l4proto;
@@ -92,8 +108,19 @@ struct nf_flow_route {
 	} tuple[FLOW_OFFLOAD_DIR_MAX];
 };
 
+struct nf_flow_forward {
+	struct {
+		struct dst_br_port	dst_port;
+		u16 vlan_tag;
+	} tuple[FLOW_OFFLOAD_DIR_MAX];
+};
+
 struct nf_flow_dst {
-	struct nf_flow_route route;
+	enum flow_offload_tuple_type type;
+	union {
+		struct nf_flow_route route;
+		struct nf_flow_forward forward;
+	};
 };
 
 struct flow_offload *flow_offload_alloc(struct nf_conn *ct,
diff --git a/net/netfilter/nf_flow_table_core.c b/net/netfilter/nf_flow_table_core.c
index 9492c97..9948ab0c 100644
--- a/net/netfilter/nf_flow_table_core.c
+++ b/net/netfilter/nf_flow_table_core.c
@@ -36,6 +36,21 @@ struct flow_offload_entry {
 	return dst;
 }
 
+static struct dst_br_port *
+flow_offload_fill_bridge_dst(struct flow_offload_tuple *ft,
+			     struct nf_flow_forward *forward,
+			     enum flow_offload_tuple_dir dir)
+{
+	struct dst_br_port other_dst_port = forward->tuple[!dir].dst_port;
+	struct dst_br_port dst_port = forward->tuple[dir].dst_port;
+
+	ft->iifidx = other_dst_port.dev->ifindex;
+	ft->dst.dst_port = dst_port;
+	ft->vlan_tag = forward->tuple[dir].vlan_tag;
+
+	return &ft->dst.dst_port;
+}
+
 static void
 flow_offload_fill_dir(struct flow_offload *flow, struct nf_conn *ct,
 		      struct nf_flow_dst *flow_dst,
@@ -43,16 +58,29 @@ struct flow_offload_entry {
 {
 	struct flow_offload_tuple *ft = &flow->tuplehash[dir].tuple;
 	struct nf_conntrack_tuple *ctt = &ct->tuplehash[dir].tuple;
+	struct dst_br_port *dst_port;
 	struct dst_entry *dst;
 
-	dst = flow_offload_fill_inet_dst(ft, &flow_dst->route, dir);
+	switch (flow_dst->type) {
+	case FLOW_OFFLOAD_TYPE_INET:
+		dst = flow_offload_fill_inet_dst(ft, &flow_dst->route, dir);
+		break;
+	case FLOW_OFFLOAD_TYPE_BRIDGE:
+		dst_port = flow_offload_fill_bridge_dst(ft, &flow_dst->forward, dir);
+		break;
+	}
+
+	ft->dst.type = flow_dst->type;
 	ft->dir = dir;
 
 	switch (ctt->src.l3num) {
 	case NFPROTO_IPV4:
 		ft->src_v4 = ctt->src.u3.in;
 		ft->dst_v4 = ctt->dst.u3.in;
-		ft->mtu = ip_dst_mtu_maybe_forward(dst, true);
+		if (flow_dst->type == FLOW_OFFLOAD_TYPE_INET)
+			ft->mtu = ip_dst_mtu_maybe_forward(dst, true);
+		else
+			ft->mtu = dst_port->dev->mtu;
 		break;
 	case NFPROTO_IPV6:
 		ft->src_v6 = ctt->src.u3.in6;
@@ -67,13 +95,13 @@ struct flow_offload_entry {
 	ft->dst_port = ctt->dst.u.tcp.port;
 }
 
-static int flow_offload_dst_hold(struct nf_flow_dst *flow_dst)
+static int flow_offload_dst_hold(struct nf_flow_route *route)
 {
-	if (!dst_hold_safe(flow_dst->route.tuple[FLOW_OFFLOAD_DIR_ORIGINAL].dst))
+	if (!dst_hold_safe(route->tuple[FLOW_OFFLOAD_DIR_ORIGINAL].dst))
 		return -1;
 
-	if (!dst_hold_safe(flow_dst->route.tuple[FLOW_OFFLOAD_DIR_REPLY].dst)) {
-		dst_release(flow_dst->route.tuple[FLOW_OFFLOAD_DIR_ORIGINAL].dst);
+	if (!dst_hold_safe(route->tuple[FLOW_OFFLOAD_DIR_REPLY].dst)) {
+		dst_release(route->tuple[FLOW_OFFLOAD_DIR_ORIGINAL].dst);
 		return -1;
 	}
 
@@ -96,7 +124,8 @@ struct flow_offload *
 
 	flow = &entry->flow;
 
-	if (flow_offload_dst_hold(flow_dst))
+	if (flow_dst->type == FLOW_OFFLOAD_TYPE_INET &&
+	    flow_offload_dst_hold(&flow_dst->route))
 		goto err_dst_cache;
 
 	entry->ct = ct;
@@ -170,8 +199,19 @@ static void flow_offload_fixup_ct(struct nf_conn *ct)
 
 static void flow_offload_dst_release(struct flow_offload *flow)
 {
-	dst_release(flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst.dst_cache);
-	dst_release(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst.dst_cache);
+	enum flow_offload_tuple_type type = flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst.type;
+
+	switch (type) {
+	case FLOW_OFFLOAD_TYPE_INET:
+		dst_release(flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst.dst_cache);
+		dst_release(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst.dst_cache);
+		break;
+
+	case FLOW_OFFLOAD_TYPE_BRIDGE:
+		dev_put(flow->tuplehash[FLOW_OFFLOAD_DIR_ORIGINAL].tuple.dst.dst_port.dev);
+		dev_put(flow->tuplehash[FLOW_OFFLOAD_DIR_REPLY].tuple.dst.dst_port.dev);
+		break;
+	}
 }
 
 void flow_offload_free(struct flow_offload *flow)
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH nf-next v7 6/8] netfilter:nf_flow_table_ip: Support bridge family flow offload
  2019-08-30  4:17 [PATCH nf-next v7 0/8] netfilter: Support the bridge family in flow table wenxu
                   ` (4 preceding siblings ...)
  2019-08-30  4:17 ` [PATCH nf-next v7 5/8] netfilter:nf_flow_table_core: Support bridge family flow offload wenxu
@ 2019-08-30  4:17 ` wenxu
  2019-08-30 13:30   ` kbuild test robot
  2019-08-30  4:17 ` [PATCH nf-next v7 7/8] netfilter:nft_flow_offload: " wenxu
  2019-08-30  4:17 ` [PATCH nf-next v7 8/8] netfilter: Support the bridge family in flow table wenxu
  7 siblings, 1 reply; 11+ messages in thread
From: wenxu @ 2019-08-30  4:17 UTC (permalink / raw)
  To: pablo, fw; +Cc: netfilter-devel

From: wenxu <wenxu@ucloud.cn>

With nf_conntrack_bridge function. The bridge family can do
conntrack it self. The flow offload function based on the
conntrack. This patch a bridge family operation in
nf_flow_table_ip.

Signed-off-by: wenxu <wenxu@ucloud.cn>
---
v7: rebase with upstream fix

 net/netfilter/nf_flow_table_ip.c | 64 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 62 insertions(+), 2 deletions(-)

diff --git a/net/netfilter/nf_flow_table_ip.c b/net/netfilter/nf_flow_table_ip.c
index 1c598af..6336f32 100644
--- a/net/netfilter/nf_flow_table_ip.c
+++ b/net/netfilter/nf_flow_table_ip.c
@@ -267,23 +267,59 @@ static int nf_flow_ipv4_xmit(struct flow_offload *flow, struct sk_buff *skb,
 	return NF_STOLEN;
 }
 
+static int  nf_flow_bridge_xmit(struct flow_offload *flow, struct sk_buff *skb,
+				enum flow_offload_tuple_dir dir)
+{
+	struct net_device *outdev;
+	u16 vlan_tag, vlan_proto;
+
+	vlan_tag = flow->tuplehash[dir].tuple.dst.dst_port.dst_vlan_tag;
+	vlan_proto = flow->tuplehash[dir].tuple.dst.dst_port.vlan_proto;
+	outdev = flow->tuplehash[dir].tuple.dst.dst_port.dev;
+	skb->dev = outdev;
+
+	if (vlan_tag)
+		__vlan_hwaccel_put_tag(skb, htons(vlan_proto), vlan_tag);
+	else
+		__vlan_hwaccel_clear_tag(skb);
+
+	skb_push(skb, ETH_HLEN);
+	if (!is_skb_forwardable(skb->dev, skb))
+		goto drop;
+
+	dev_queue_xmit(skb);
+	return NF_STOLEN;
+
+drop:
+	kfree_skb(skb);
+	return NF_STOLEN;
+}
+
 unsigned int
 nf_flow_offload_ip_hook(void *priv, struct sk_buff *skb,
 			const struct nf_hook_state *state)
 {
 	struct flow_offload_tuple_rhash *tuplehash;
 	struct nf_flowtable *flow_table = priv;
+	int family = flow_table->type->family;
 	struct flow_offload_tuple tuple = {};
 	enum flow_offload_tuple_dir dir;
 	struct flow_offload *flow;
 	unsigned int thoff;
+	int ret;
 
 	if (skb->protocol != htons(ETH_P_IP))
 		return NF_ACCEPT;
 
+	if (family != NFPROTO_BRIDGE && family != NFPROTO_IPV4)
+		return NF_ACCEPT;
+
 	if (nf_flow_tuple_ip(skb, state->in, &tuple) < 0)
 		return NF_ACCEPT;
 
+	if (family == NFPROTO_BRIDGE && skb_vlan_tag_present(skb))
+		tuple.vlan_tag = skb_vlan_tag_get_id(skb);
+
 	tuplehash = flow_offload_lookup(flow_table, &tuple);
 	if (tuplehash == NULL)
 		return NF_ACCEPT;
@@ -305,8 +341,16 @@ static int nf_flow_ipv4_xmit(struct flow_offload *flow, struct sk_buff *skb,
 		return NF_DROP;
 
 	flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT;
+	switch (family) {
+	case NFPROTO_IPV4:
+		ret = nf_flow_ipv4_xmit(flow, skb, state, dir);
+		break;
+	case NFPROTO_BRIDGE:
+		ret = nf_flow_bridge_xmit(flow, skb, dir);
+		break;
+	}
 
-	return nf_flow_ipv4_xmit(flow, skb, state, dir);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(nf_flow_offload_ip_hook);
 
@@ -511,16 +555,24 @@ static int nf_flow_ipv6_xmit(struct flow_offload *flow, struct sk_buff *skb,
 {
 	struct flow_offload_tuple_rhash *tuplehash;
 	struct nf_flowtable *flow_table = priv;
+	int family = flow_table->type->family;
 	struct flow_offload_tuple tuple = {};
 	enum flow_offload_tuple_dir dir;
 	struct flow_offload *flow;
+	int ret;
 
 	if (skb->protocol != htons(ETH_P_IPV6))
 		return NF_ACCEPT;
 
+	if (family != NFPROTO_BRIDGE && family != NFPROTO_IPV6)
+		return NF_ACCEPT;
+
 	if (nf_flow_tuple_ipv6(skb, state->in, &tuple) < 0)
 		return NF_ACCEPT;
 
+	if (family == NFPROTO_BRIDGE && skb_vlan_tag_present(skb))
+		tuple.vlan_tag = skb_vlan_tag_get_id(skb);
+
 	tuplehash = flow_offload_lookup(flow_table, &tuple);
 	if (tuplehash == NULL)
 		return NF_ACCEPT;
@@ -542,7 +594,15 @@ static int nf_flow_ipv6_xmit(struct flow_offload *flow, struct sk_buff *skb,
 		return NF_DROP;
 
 	flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT;
+	switch (family) {
+	case NFPROTO_IPV6:
+		ret = nf_flow_ipv6_xmit(flow, skb, state, dir);
+		break;
+	case NFPROTO_BRIDGE:
+		ret = nf_flow_bridge_xmit(flow, skb, dir);
+		break;
+	}
 
-	return nf_flow_ipv6_xmit(flow, skb, state, dir);
+	return ret;
 }
 EXPORT_SYMBOL_GPL(nf_flow_offload_ipv6_hook);
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH nf-next v7 7/8] netfilter:nft_flow_offload: Support bridge family flow offload
  2019-08-30  4:17 [PATCH nf-next v7 0/8] netfilter: Support the bridge family in flow table wenxu
                   ` (5 preceding siblings ...)
  2019-08-30  4:17 ` [PATCH nf-next v7 6/8] netfilter:nf_flow_table_ip: " wenxu
@ 2019-08-30  4:17 ` wenxu
  2019-08-30  4:17 ` [PATCH nf-next v7 8/8] netfilter: Support the bridge family in flow table wenxu
  7 siblings, 0 replies; 11+ messages in thread
From: wenxu @ 2019-08-30  4:17 UTC (permalink / raw)
  To: pablo, fw; +Cc: netfilter-devel

From: wenxu <wenxu@ucloud.cn>

With nf_conntrack_bridge function. The bridge family can do
conntrack it self. The flow offload function based on the conntrack.
This patch add bridge family operation in nf_flow_offload

Signed-off-by: wenxu <wenxu@ucloud.cn>
---
v7: no change

 net/netfilter/nft_flow_offload.c | 140 +++++++++++++++++++++++++++++++++++++--
 1 file changed, 133 insertions(+), 7 deletions(-)

diff --git a/net/netfilter/nft_flow_offload.c b/net/netfilter/nft_flow_offload.c
index 2dd0d3e..c54392f 100644
--- a/net/netfilter/nft_flow_offload.c
+++ b/net/netfilter/nft_flow_offload.c
@@ -6,6 +6,7 @@
 #include <linux/netfilter.h>
 #include <linux/workqueue.h>
 #include <linux/spinlock.h>
+#include <linux/if_bridge.h>
 #include <linux/netfilter/nf_tables.h>
 #include <net/ip.h> /* for ipv4 options. */
 #include <net/netfilter/nf_tables.h>
@@ -49,23 +50,144 @@ static int nft_flow_route(const struct nft_pktinfo *pkt,
 	return 0;
 }
 
+#if IS_ENABLED(CONFIG_NF_TABLES_BRIDGE)
+static const struct net_device *
+nft_get_bridge(const struct net_device *dev)
+{
+	if (dev && netif_is_bridge_port(dev))
+		return netdev_master_upper_dev_get_rcu((struct net_device *)dev);
+
+	return NULL;
+}
+#endif
+
+static int nft_flow_forward(const struct nft_pktinfo *pkt,
+			    const struct nf_conn *ct,
+			    struct nf_flow_forward *forward,
+			    enum ip_conntrack_dir dir)
+{
+#if IS_ENABLED(CONFIG_NF_TABLES_BRIDGE)
+	const struct net_device *br_dev;
+	u16 vlan_proto = 0;
+	u16 vid = 0;
+
+	if (skb_vlan_tag_present(pkt->skb)) {
+		vid = skb_vlan_tag_get_id(pkt->skb);
+		vlan_proto = ntohs(pkt->skb->vlan_proto);
+	}
+
+	forward->tuple[dir].dst_port.dst_vlan_tag = vid;
+	forward->tuple[dir].dst_port.vlan_proto = vlan_proto;
+	forward->tuple[!dir].vlan_tag = vid;
+	forward->tuple[dir].dst_port.dev = dev_get_by_index(dev_net(nft_out(pkt)),
+							    nft_out(pkt)->ifindex);
+	forward->tuple[!dir].dst_port.dev = dev_get_by_index(dev_net(nft_in(pkt)),
+							     nft_in(pkt)->ifindex);
+
+	br_dev = nft_get_bridge(nft_out(pkt));
+	if (!br_dev)
+		goto err;
+
+	if (!br_vlan_enabled(br_dev))
+		goto out;
+
+	if (!vid)
+		br_vlan_get_pvid_rcu(nft_out(pkt), &vid);
+
+	if (vid) {
+		struct bridge_vlan_info vinfo;
+		int ret;
+
+		ret = br_vlan_get_proto(br_dev, &vlan_proto);
+		if (ret < 0)
+			goto err;
+
+		ret = br_vlan_get_info_rcu(nft_in(pkt), vid, &vinfo);
+		if (ret < 0)
+			goto err;
+
+		if (vinfo.flags & BRIDGE_VLAN_INFO_UNTAGGED) {
+			vid = 0;
+			vlan_proto = 0;
+		}
+	}
+
+out:
+	forward->tuple[!dir].dst_port.vlan_proto = vlan_proto;
+	forward->tuple[!dir].dst_port.dst_vlan_tag = vid;
+	forward->tuple[dir].vlan_tag = vid;
+
+	return 0;
+
+err:
+	dev_put(forward->tuple[dir].dst_port.dev);
+	dev_put(forward->tuple[!dir].dst_port.dev);
+#endif
+	return -ENOENT;
+}
+
 static bool nft_flow_offload_skip(struct sk_buff *skb, int family)
 {
 	if (skb_sec_path(skb))
 		return true;
 
-	if (family == NFPROTO_IPV4) {
+	switch (family) {
+	case NFPROTO_IPV4: {
 		const struct ip_options *opt;
 
 		opt = &(IPCB(skb)->opt);
 
 		if (unlikely(opt->optlen))
 			return true;
+		break;
+	}
+	case NFPROTO_BRIDGE: {
+		if (skb->protocol != htons(ETH_P_IPV6) &&
+		    skb->protocol != htons(ETH_P_IP))
+			return true;
+
+		if (skb->protocol == htons(ETH_P_IP)) {
+			const struct iphdr *iph;
+
+			iph = ip_hdr(skb);
+			if (iph->ihl > 5)
+				return true;
+		}
+		break;
+	}
 	}
 
 	return false;
 }
 
+static void flow_offload_release_dst(struct nf_flow_dst *flow_dst,
+				     enum ip_conntrack_dir dir)
+{
+	if (flow_dst->type == FLOW_OFFLOAD_TYPE_BRIDGE) {
+		dev_put(flow_dst->forward.tuple[dir].dst_port.dev);
+		dev_put(flow_dst->forward.tuple[!dir].dst_port.dev);
+	} else {
+		dst_release(flow_dst->route.tuple[!dir].dst);
+	}
+}
+
+static int flow_offload_get_dst(const struct nft_pktinfo *pkt, struct nf_conn *ct,
+				enum ip_conntrack_dir dir, int family,
+				struct nf_flow_dst *flow_dst)
+{
+	if (family == NFPROTO_BRIDGE) {
+		flow_dst->type = FLOW_OFFLOAD_TYPE_BRIDGE;
+		if (nft_flow_forward(pkt, ct, &flow_dst->forward, dir) < 0)
+			return -1;
+	} else {
+		flow_dst->type = FLOW_OFFLOAD_TYPE_INET;
+		if (nft_flow_route(pkt, ct, &flow_dst->route, dir) < 0)
+			return -1;
+	}
+
+	return 0;
+}
+
 static void nft_flow_offload_eval(const struct nft_expr *expr,
 				  struct nft_regs *regs,
 				  const struct nft_pktinfo *pkt)
@@ -77,10 +199,11 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
 	struct nf_flow_dst flow_dst;
 	struct flow_offload *flow;
 	enum ip_conntrack_dir dir;
+	int family = nft_pf(pkt);
 	struct nf_conn *ct;
 	int ret;
 
-	if (nft_flow_offload_skip(pkt->skb, nft_pf(pkt)))
+	if (nft_flow_offload_skip(pkt->skb, family))
 		goto out;
 
 	ct = nf_ct_get(pkt->skb, &ctinfo);
@@ -111,8 +234,9 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
 		goto out;
 
 	dir = CTINFO2DIR(ctinfo);
-	if (nft_flow_route(pkt, ct, &flow_dst.route, dir) < 0)
-		goto err_flow_route;
+
+	if (flow_offload_get_dst(pkt, ct, dir, family, &flow_dst) < 0)
+		goto err_flow_dst;
 
 	flow = flow_offload_alloc(ct, &flow_dst);
 	if (!flow)
@@ -127,14 +251,16 @@ static void nft_flow_offload_eval(const struct nft_expr *expr,
 	if (ret < 0)
 		goto err_flow_add;
 
-	dst_release(flow_dst.route.tuple[!dir].dst);
+	if (family != NFPROTO_BRIDGE)
+		dst_release(flow_dst.route.tuple[!dir].dst);
+
 	return;
 
 err_flow_add:
 	flow_offload_free(flow);
 err_flow_alloc:
-	dst_release(flow_dst.route.tuple[!dir].dst);
-err_flow_route:
+	flow_offload_release_dst(&flow_dst, dir);
+err_flow_dst:
 	clear_bit(IPS_OFFLOAD_BIT, &ct->status);
 out:
 	regs->verdict.code = NFT_BREAK;
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH nf-next v7 8/8] netfilter: Support the bridge family in flow table
  2019-08-30  4:17 [PATCH nf-next v7 0/8] netfilter: Support the bridge family in flow table wenxu
                   ` (6 preceding siblings ...)
  2019-08-30  4:17 ` [PATCH nf-next v7 7/8] netfilter:nft_flow_offload: " wenxu
@ 2019-08-30  4:17 ` wenxu
  7 siblings, 0 replies; 11+ messages in thread
From: wenxu @ 2019-08-30  4:17 UTC (permalink / raw)
  To: pablo, fw; +Cc: netfilter-devel

From: wenxu <wenxu@ucloud.cn>

This patch add the bridge flow table type. Implement the datapath
flow table to forward both IPV4 and IPV6 traffic through bridge.

Signed-off-by: wenxu <wenxu@ucloud.cn>
---
v7: no change

 net/bridge/netfilter/Kconfig                |  8 +++++
 net/bridge/netfilter/Makefile               |  1 +
 net/bridge/netfilter/nf_flow_table_bridge.c | 48 +++++++++++++++++++++++++++++
 3 files changed, 57 insertions(+)
 create mode 100644 net/bridge/netfilter/nf_flow_table_bridge.c

diff --git a/net/bridge/netfilter/Kconfig b/net/bridge/netfilter/Kconfig
index 5040fe4..ad100cb 100644
--- a/net/bridge/netfilter/Kconfig
+++ b/net/bridge/netfilter/Kconfig
@@ -41,6 +41,14 @@ config NF_CONNTRACK_BRIDGE
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+config NF_FLOW_TABLE_BRIDGE
+	tristate "Netfilter flow table bridge module"
+	depends on NF_FLOW_TABLE && NF_CONNTRACK_BRIDGE
+	help
+          This option adds the flow table bridge support.
+
+	  To compile it as a module, choose M here.
+
 menuconfig BRIDGE_NF_EBTABLES
 	tristate "Ethernet Bridge tables (ebtables) support"
 	depends on BRIDGE && NETFILTER && NETFILTER_XTABLES
diff --git a/net/bridge/netfilter/Makefile b/net/bridge/netfilter/Makefile
index 8e2c575..627b269 100644
--- a/net/bridge/netfilter/Makefile
+++ b/net/bridge/netfilter/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_NFT_BRIDGE_REJECT)  += nft_reject_bridge.o
 
 # connection tracking
 obj-$(CONFIG_NF_CONNTRACK_BRIDGE) += nf_conntrack_bridge.o
+obj-$(CONFIG_NF_FLOW_TABLE_BRIDGE) += nf_flow_table_bridge.o
 
 # packet logging
 obj-$(CONFIG_NF_LOG_BRIDGE) += nf_log_bridge.o
diff --git a/net/bridge/netfilter/nf_flow_table_bridge.c b/net/bridge/netfilter/nf_flow_table_bridge.c
new file mode 100644
index 0000000..c4fdd4a
--- /dev/null
+++ b/net/bridge/netfilter/nf_flow_table_bridge.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0-only
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/netfilter.h>
+#include <net/netfilter/nf_flow_table.h>
+#include <net/netfilter/nf_tables.h>
+
+static unsigned int
+nf_flow_offload_bridge_hook(void *priv, struct sk_buff *skb,
+			    const struct nf_hook_state *state)
+{
+	switch (skb->protocol) {
+	case htons(ETH_P_IP):
+		return nf_flow_offload_ip_hook(priv, skb, state);
+	case htons(ETH_P_IPV6):
+		return nf_flow_offload_ipv6_hook(priv, skb, state);
+	}
+
+	return NF_ACCEPT;
+}
+
+static struct nf_flowtable_type flowtable_bridge = {
+	.family		= NFPROTO_BRIDGE,
+	.init		= nf_flow_table_init,
+	.free		= nf_flow_table_free,
+	.hook		= nf_flow_offload_bridge_hook,
+	.owner		= THIS_MODULE,
+};
+
+static int __init nf_flow_bridge_module_init(void)
+{
+	nft_register_flowtable_type(&flowtable_bridge);
+
+	return 0;
+}
+
+static void __exit nf_flow_bridge_module_exit(void)
+{
+	nft_unregister_flowtable_type(&flowtable_bridge);
+}
+
+module_init(nf_flow_bridge_module_init);
+module_exit(nf_flow_bridge_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("wenxu <wenxu@ucloud.cn>");
+MODULE_ALIAS_NF_FLOWTABLE(7); /* NFPROTO_BRIDGE */
-- 
1.8.3.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH nf-next v7 5/8] netfilter:nf_flow_table_core: Support bridge family flow offload
  2019-08-30  4:17 ` [PATCH nf-next v7 5/8] netfilter:nf_flow_table_core: Support bridge family flow offload wenxu
@ 2019-08-30 12:12   ` kbuild test robot
  0 siblings, 0 replies; 11+ messages in thread
From: kbuild test robot @ 2019-08-30 12:12 UTC (permalink / raw)
  To: wenxu; +Cc: kbuild-all, pablo, fw, netfilter-devel

[-- Attachment #1: Type: text/plain, Size: 5328 bytes --]

Hi,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on nf-next/master]

url:    https://github.com/0day-ci/linux/commits/wenxu-ucloud-cn/netfilter-Support-the-bridge-family-in-flow-table/20190830-172019
base:   https://kernel.googlesource.com/pub/scm/linux/kernel/git/pablo/nf-next.git master
config: x86_64-allmodconfig (attached as .config)
compiler: gcc-7 (Debian 7.4.0-11) 7.4.0
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

Note: it may well be a FALSE warning. FWIW you are at least aware of it now.
http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings

All warnings (new ones prefixed by >>):

   In file included from net//netfilter/nf_flow_table_core.c:9:0:
   net//netfilter/nf_flow_table_core.c: In function 'flow_offload_fill_dir':
>> include/net/ip6_route.h:322:26: warning: 'dst' may be used uninitialized in this function [-Wmaybe-uninitialized]
     idev = __in6_dev_get(dst->dev);
                          ~~~^~~~~
   net//netfilter/nf_flow_table_core.c:62:20: note: 'dst' was declared here
     struct dst_entry *dst;
                       ^~~
>> net//netfilter/nf_flow_table_core.c:83:22: warning: 'dst_port' may be used uninitialized in this function [-Wmaybe-uninitialized]
       ft->mtu = dst_port->dev->mtu;
                 ~~~~~~~~^~~~~
--
   In file included from net/netfilter/nf_flow_table_core.c:9:0:
   net/netfilter/nf_flow_table_core.c: In function 'flow_offload_fill_dir':
>> include/net/ip6_route.h:322:26: warning: 'dst' may be used uninitialized in this function [-Wmaybe-uninitialized]
     idev = __in6_dev_get(dst->dev);
                          ~~~^~~~~
   net/netfilter/nf_flow_table_core.c:62:20: note: 'dst' was declared here
     struct dst_entry *dst;
                       ^~~
   net/netfilter/nf_flow_table_core.c:83:22: warning: 'dst_port' may be used uninitialized in this function [-Wmaybe-uninitialized]
       ft->mtu = dst_port->dev->mtu;
                 ~~~~~~~~^~~~~

vim +/dst_port +83 net//netfilter/nf_flow_table_core.c

   > 9	#include <net/ip6_route.h>
    10	#include <net/netfilter/nf_tables.h>
    11	#include <net/netfilter/nf_flow_table.h>
    12	#include <net/netfilter/nf_conntrack.h>
    13	#include <net/netfilter/nf_conntrack_core.h>
    14	#include <net/netfilter/nf_conntrack_tuple.h>
    15	
    16	struct flow_offload_entry {
    17		struct flow_offload	flow;
    18		struct nf_conn		*ct;
    19		struct rcu_head		rcu_head;
    20	};
    21	
    22	static DEFINE_MUTEX(flowtable_lock);
    23	static LIST_HEAD(flowtables);
    24	
    25	static struct dst_entry *
    26	flow_offload_fill_inet_dst(struct flow_offload_tuple *ft,
    27				   struct nf_flow_route *route,
    28				   enum flow_offload_tuple_dir dir)
    29	{
    30		struct dst_entry *other_dst = route->tuple[!dir].dst;
    31		struct dst_entry *dst = route->tuple[dir].dst;
    32	
    33		ft->iifidx = other_dst->dev->ifindex;
    34		ft->dst.dst_cache = dst;
    35	
    36		return dst;
    37	}
    38	
    39	static struct dst_br_port *
    40	flow_offload_fill_bridge_dst(struct flow_offload_tuple *ft,
    41				     struct nf_flow_forward *forward,
    42				     enum flow_offload_tuple_dir dir)
    43	{
    44		struct dst_br_port other_dst_port = forward->tuple[!dir].dst_port;
    45		struct dst_br_port dst_port = forward->tuple[dir].dst_port;
    46	
    47		ft->iifidx = other_dst_port.dev->ifindex;
    48		ft->dst.dst_port = dst_port;
    49		ft->vlan_tag = forward->tuple[dir].vlan_tag;
    50	
    51		return &ft->dst.dst_port;
    52	}
    53	
    54	static void
    55	flow_offload_fill_dir(struct flow_offload *flow, struct nf_conn *ct,
    56			      struct nf_flow_dst *flow_dst,
    57			      enum flow_offload_tuple_dir dir)
    58	{
    59		struct flow_offload_tuple *ft = &flow->tuplehash[dir].tuple;
    60		struct nf_conntrack_tuple *ctt = &ct->tuplehash[dir].tuple;
    61		struct dst_br_port *dst_port;
    62		struct dst_entry *dst;
    63	
    64		switch (flow_dst->type) {
    65		case FLOW_OFFLOAD_TYPE_INET:
    66			dst = flow_offload_fill_inet_dst(ft, &flow_dst->route, dir);
    67			break;
    68		case FLOW_OFFLOAD_TYPE_BRIDGE:
    69			dst_port = flow_offload_fill_bridge_dst(ft, &flow_dst->forward, dir);
    70			break;
    71		}
    72	
    73		ft->dst.type = flow_dst->type;
    74		ft->dir = dir;
    75	
    76		switch (ctt->src.l3num) {
    77		case NFPROTO_IPV4:
    78			ft->src_v4 = ctt->src.u3.in;
    79			ft->dst_v4 = ctt->dst.u3.in;
    80			if (flow_dst->type == FLOW_OFFLOAD_TYPE_INET)
    81				ft->mtu = ip_dst_mtu_maybe_forward(dst, true);
    82			else
  > 83				ft->mtu = dst_port->dev->mtu;
    84			break;
    85		case NFPROTO_IPV6:
    86			ft->src_v6 = ctt->src.u3.in6;
    87			ft->dst_v6 = ctt->dst.u3.in6;
    88			ft->mtu = ip6_dst_mtu_forward(dst);
    89			break;
    90		}
    91	
    92		ft->l3proto = ctt->src.l3num;
    93		ft->l4proto = ctt->dst.protonum;
    94		ft->src_port = ctt->src.u.tcp.port;
    95		ft->dst_port = ctt->dst.u.tcp.port;
    96	}
    97	

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 70228 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH nf-next v7 6/8] netfilter:nf_flow_table_ip: Support bridge family flow offload
  2019-08-30  4:17 ` [PATCH nf-next v7 6/8] netfilter:nf_flow_table_ip: " wenxu
@ 2019-08-30 13:30   ` kbuild test robot
  0 siblings, 0 replies; 11+ messages in thread
From: kbuild test robot @ 2019-08-30 13:30 UTC (permalink / raw)
  To: wenxu; +Cc: kbuild-all, pablo, fw, netfilter-devel

[-- Attachment #1: Type: text/plain, Size: 1884 bytes --]

Hi,

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on nf-next/master]

url:    https://github.com/0day-ci/linux/commits/wenxu-ucloud-cn/netfilter-Support-the-bridge-family-in-flow-table/20190830-172019
base:   https://kernel.googlesource.com/pub/scm/linux/kernel/git/pablo/nf-next.git master
config: x86_64-allmodconfig (attached as .config)
compiler: gcc-7 (Debian 7.4.0-11) 7.4.0
reproduce:
        # save the attached .config to linux build tree
        make ARCH=x86_64 

If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>

Note: it may well be a FALSE warning. FWIW you are at least aware of it now.
http://gcc.gnu.org/wiki/Better_Uninitialized_Warnings

All warnings (new ones prefixed by >>):

   net/netfilter/nf_flow_table_ip.c: In function 'nf_flow_offload_ipv6_hook':
>> net/netfilter/nf_flow_table_ip.c:562:6: warning: 'ret' may be used uninitialized in this function [-Wmaybe-uninitialized]
     int ret;
         ^~~
   net/netfilter/nf_flow_table_ip.c: In function 'nf_flow_offload_ip_hook':
   net/netfilter/nf_flow_table_ip.c:309:6: warning: 'ret' may be used uninitialized in this function [-Wmaybe-uninitialized]
     int ret;
         ^~~

vim +/ret +562 net/netfilter/nf_flow_table_ip.c

   551	
   552	unsigned int
   553	nf_flow_offload_ipv6_hook(void *priv, struct sk_buff *skb,
   554				  const struct nf_hook_state *state)
   555	{
   556		struct flow_offload_tuple_rhash *tuplehash;
   557		struct nf_flowtable *flow_table = priv;
   558		int family = flow_table->type->family;
   559		struct flow_offload_tuple tuple = {};
   560		enum flow_offload_tuple_dir dir;
   561		struct flow_offload *flow;
 > 562		int ret;

---
0-DAY kernel test infrastructure                Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all                   Intel Corporation

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 70228 bytes --]

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2019-08-30 13:30 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-30  4:17 [PATCH nf-next v7 0/8] netfilter: Support the bridge family in flow table wenxu
2019-08-30  4:17 ` [PATCH nf-next v7 1/8] netfilter:nf_flow_table: Refactor flow_offload_tuple to destination wenxu
2019-08-30  4:17 ` [PATCH nf-next v7 2/8] netfilter:nf_flow_table_core: Separate inet operation to single function wenxu
2019-08-30  4:17 ` [PATCH nf-next v7 3/8] netfilter:nf_flow_table_ip: " wenxu
2019-08-30  4:17 ` [PATCH nf-next v7 4/8] bridge: add br_vlan_get_info_rcu() wenxu
2019-08-30  4:17 ` [PATCH nf-next v7 5/8] netfilter:nf_flow_table_core: Support bridge family flow offload wenxu
2019-08-30 12:12   ` kbuild test robot
2019-08-30  4:17 ` [PATCH nf-next v7 6/8] netfilter:nf_flow_table_ip: " wenxu
2019-08-30 13:30   ` kbuild test robot
2019-08-30  4:17 ` [PATCH nf-next v7 7/8] netfilter:nft_flow_offload: " wenxu
2019-08-30  4:17 ` [PATCH nf-next v7 8/8] netfilter: Support the bridge family in flow table wenxu

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).