From patchwork Fri Aug 30 04:17:15 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: wenxu X-Patchwork-Id: 1155705 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=ucloud.cn Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 46KR5s3xBhz9sN6 for ; Fri, 30 Aug 2019 14:17:37 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726849AbfH3ERh (ORCPT ); Fri, 30 Aug 2019 00:17:37 -0400 Received: from m9784.mail.qiye.163.com ([220.181.97.84]:42659 "EHLO m9784.mail.qiye.163.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726219AbfH3ERh (ORCPT ); Fri, 30 Aug 2019 00:17:37 -0400 Received: from localhost.localdomain (unknown [123.59.132.129]) by m9784.mail.qiye.163.com (Hmail) with ESMTPA id A43344171B; Fri, 30 Aug 2019 12:17:22 +0800 (CST) From: wenxu@ucloud.cn To: pablo@netfilter.org, fw@strlen.de Cc: netfilter-devel@vger.kernel.org Subject: [PATCH nf-next v7 1/8] netfilter:nf_flow_table: Refactor flow_offload_tuple to destination Date: Fri, 30 Aug 2019 12:17:15 +0800 Message-Id: <1567138642-11446-2-git-send-email-wenxu@ucloud.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1567138642-11446-1-git-send-email-wenxu@ucloud.cn> References: <1567138642-11446-1-git-send-email-wenxu@ucloud.cn> X-HM-Spam-Status: e1kfGhgUHx5ZQUtXWQgYFAkeWUFZVkpVS05MS0tLS09KS0tDWVdZKFlBSU I3V1ktWUFJV1kJDhceCFlBWTU0KTY6NyQpLjc#WQY+ X-HM-Sender-Digest: e1kMHhlZQR0aFwgeV1kSHx4VD1lBWUc6PBA6EAw4Szg0DzJWFC0NLzYC IzUKFC9VSlVKTk1MSkhDTU9JTExPVTMWGhIXVQweFQMOOw4YFxQOH1UYFUVZV1kSC1lBWUpJSFVO QlVKSElVSklCWVdZCAFZQUxMQ003Bg++ X-HM-Tid: 0a6ce0bdfafc2086kuqya43344171b Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org From: wenxu Add struct flow_offload_dst to support more offload method to replace dst_cache which only work for route offload. Signed-off-by: wenxu --- 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: From patchwork Fri Aug 30 04:17:16 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: wenxu X-Patchwork-Id: 1155699 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=ucloud.cn Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 46KR5h6tz9z9sN6 for ; Fri, 30 Aug 2019 14:17:28 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726492AbfH3ER2 (ORCPT ); Fri, 30 Aug 2019 00:17:28 -0400 Received: from m9784.mail.qiye.163.com ([220.181.97.84]:42669 "EHLO m9784.mail.qiye.163.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725819AbfH3ER2 (ORCPT ); Fri, 30 Aug 2019 00:17:28 -0400 Received: from localhost.localdomain (unknown [123.59.132.129]) by m9784.mail.qiye.163.com (Hmail) with ESMTPA id C25FD4166E; Fri, 30 Aug 2019 12:17:22 +0800 (CST) From: wenxu@ucloud.cn To: pablo@netfilter.org, fw@strlen.de Cc: netfilter-devel@vger.kernel.org Subject: [PATCH nf-next v7 2/8] netfilter:nf_flow_table_core: Separate inet operation to single function Date: Fri, 30 Aug 2019 12:17:16 +0800 Message-Id: <1567138642-11446-3-git-send-email-wenxu@ucloud.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1567138642-11446-1-git-send-email-wenxu@ucloud.cn> References: <1567138642-11446-1-git-send-email-wenxu@ucloud.cn> X-HM-Spam-Status: e1kfGhgUHx5ZQUtXWQgYFAkeWUFZVklVSk9IS0tLSklOQ0NOS0pZV1koWU FJQjdXWS1ZQUlXWQkOFx4IWUFZNTQpNjo3JCkuNz5ZBg++ X-HM-Sender-Digest: e1kMHhlZQR0aFwgeV1kSHx4VD1lBWUc6OhQ6Kio4PTg5HzIRMiwZLzYO Ik4aCx5VSlVKTk1MSkhDTU9JQkxIVTMWGhIXVQweFQMOOw4YFxQOH1UYFUVZV1kSC1lBWUpJSFVO QlVKSElVSklCWVdZCAFZQU9OSE03Bg++ X-HM-Tid: 0a6ce0bdfb772086kuqyc25fd4166e Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org From: wenxu 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 --- 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); From patchwork Fri Aug 30 04:17:17 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: wenxu X-Patchwork-Id: 1155703 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=ucloud.cn Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 46KR5m5FJxz9sNC for ; Fri, 30 Aug 2019 14:17:32 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726834AbfH3ERc (ORCPT ); Fri, 30 Aug 2019 00:17:32 -0400 Received: from m9784.mail.qiye.163.com ([220.181.97.84]:42697 "EHLO m9784.mail.qiye.163.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726200AbfH3ERb (ORCPT ); Fri, 30 Aug 2019 00:17:31 -0400 Received: from localhost.localdomain (unknown [123.59.132.129]) by m9784.mail.qiye.163.com (Hmail) with ESMTPA id 0337341766; Fri, 30 Aug 2019 12:17:23 +0800 (CST) From: wenxu@ucloud.cn To: pablo@netfilter.org, fw@strlen.de Cc: netfilter-devel@vger.kernel.org Subject: [PATCH nf-next v7 3/8] netfilter:nf_flow_table_ip: Separate inet operation to single function Date: Fri, 30 Aug 2019 12:17:17 +0800 Message-Id: <1567138642-11446-4-git-send-email-wenxu@ucloud.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1567138642-11446-1-git-send-email-wenxu@ucloud.cn> References: <1567138642-11446-1-git-send-email-wenxu@ucloud.cn> X-HM-Spam-Status: e1kfGhgUHx5ZQUtXWQgYFAkeWUFZVkpVS0NNQkJCTExIQkxCSkJZV1koWU FJQjdXWS1ZQUlXWQkOFx4IWUFZNTQpNjo3JCkuNz5ZBg++ X-HM-Sender-Digest: e1kMHhlZQR0aFwgeV1kSHx4VD1lBWUc6K006DDo5VjgrSDIfFC4sLz1P IUsaC0lVSlVKTk1MSkhDTU9ISk9LVTMWGhIXVQweFQMOOw4YFxQOH1UYFUVZV1kSC1lBWUpJSFVO QlVKSElVSklCWVdZCAFZQUxNSEg3Bg++ X-HM-Tid: 0a6ce0bdfc562086kuqy0337341766 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org From: wenxu 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 --- 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); From patchwork Fri Aug 30 04:17:18 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: wenxu X-Patchwork-Id: 1155698 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=ucloud.cn Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 46KR5g5dbjz9sNC for ; Fri, 30 Aug 2019 14:17:27 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726358AbfH3ER1 (ORCPT ); Fri, 30 Aug 2019 00:17:27 -0400 Received: from m9784.mail.qiye.163.com ([220.181.97.84]:42701 "EHLO m9784.mail.qiye.163.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726236AbfH3ER1 (ORCPT ); Fri, 30 Aug 2019 00:17:27 -0400 Received: from localhost.localdomain (unknown [123.59.132.129]) by m9784.mail.qiye.163.com (Hmail) with ESMTPA id 28D10416B8; Fri, 30 Aug 2019 12:17:23 +0800 (CST) From: wenxu@ucloud.cn To: pablo@netfilter.org, fw@strlen.de Cc: netfilter-devel@vger.kernel.org Subject: [PATCH nf-next v7 4/8] bridge: add br_vlan_get_info_rcu() Date: Fri, 30 Aug 2019 12:17:18 +0800 Message-Id: <1567138642-11446-5-git-send-email-wenxu@ucloud.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1567138642-11446-1-git-send-email-wenxu@ucloud.cn> References: <1567138642-11446-1-git-send-email-wenxu@ucloud.cn> X-HM-Spam-Status: e1kfGhgUHx5ZQUtXWQgYFAkeWUFZVkpVSUlDS0tLS09PQ0lJTUJZV1koWU FJQjdXWS1ZQUlXWQkOFx4IWUFZNTQpNjo3JCkuNz5ZBg++ X-HM-Sender-Digest: e1kMHhlZQR0aFwgeV1kSHx4VD1lBWUc6OCo6GCo6ITgzMTISFCMsLzQe GiNPCQpVSlVKTk1MSkhDTU9ISUpCVTMWGhIXVQweFQMOOw4YFxQOH1UYFUVZV1kSC1lBWUpJSFVO QlVKSElVSklCWVdZCAFZQUhLTkM3Bg++ X-HM-Tid: 0a6ce0bdfceb2086kuqy28d10416b8 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org From: wenxu This new function allows you to fetch vlan info from packet path. Signed-off-by: wenxu Acked-by: Nikolay Aleksandrov --- 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) && From patchwork Fri Aug 30 04:17:19 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: wenxu X-Patchwork-Id: 1155700 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=ucloud.cn Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 46KR5k2wrNz9sN6 for ; Fri, 30 Aug 2019 14:17:30 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726495AbfH3ERa (ORCPT ); Fri, 30 Aug 2019 00:17:30 -0400 Received: from m9784.mail.qiye.163.com ([220.181.97.84]:42791 "EHLO m9784.mail.qiye.163.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726236AbfH3ER3 (ORCPT ); Fri, 30 Aug 2019 00:17:29 -0400 Received: from localhost.localdomain (unknown [123.59.132.129]) by m9784.mail.qiye.163.com (Hmail) with ESMTPA id 3B32D417B6; Fri, 30 Aug 2019 12:17:23 +0800 (CST) From: wenxu@ucloud.cn To: pablo@netfilter.org, fw@strlen.de Cc: netfilter-devel@vger.kernel.org Subject: [PATCH nf-next v7 5/8] netfilter:nf_flow_table_core: Support bridge family flow offload Date: Fri, 30 Aug 2019 12:17:19 +0800 Message-Id: <1567138642-11446-6-git-send-email-wenxu@ucloud.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1567138642-11446-1-git-send-email-wenxu@ucloud.cn> References: <1567138642-11446-1-git-send-email-wenxu@ucloud.cn> X-HM-Spam-Status: e1kfGhgUHx5ZQUtXWQgYFAkeWUFZVkpVSENJS0tLS0NDTUJKTEpZV1koWU FJQjdXWS1ZQUlXWQkOFx4IWUFZNTQpNjo3JCkuNz5ZBg++ X-HM-Sender-Digest: e1kMHhlZQR0aFwgeV1kSHx4VD1lBWUc6NT46CRw6HjgyVjIBMiwCLzNL HjcwCyJVSlVKTk1MSkhDTU9ISE5MVTMWGhIXVQweFQMOOw4YFxQOH1UYFUVZV1kSC1lBWUpJSFVO QlVKSElVSklCWVdZCAFZQU1PS043Bg++ X-HM-Tid: 0a6ce0bdfd3c2086kuqy3b32d417b6 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org From: wenxu 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 --- 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) From patchwork Fri Aug 30 04:17:20 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: wenxu X-Patchwork-Id: 1155701 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=ucloud.cn Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 46KR5l03WPz9sNC for ; Fri, 30 Aug 2019 14:17:31 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726528AbfH3ERa (ORCPT ); Fri, 30 Aug 2019 00:17:30 -0400 Received: from m9784.mail.qiye.163.com ([220.181.97.84]:42793 "EHLO m9784.mail.qiye.163.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1725774AbfH3ER3 (ORCPT ); Fri, 30 Aug 2019 00:17:29 -0400 Received: from localhost.localdomain (unknown [123.59.132.129]) by m9784.mail.qiye.163.com (Hmail) with ESMTPA id 5C703416C6; Fri, 30 Aug 2019 12:17:23 +0800 (CST) From: wenxu@ucloud.cn To: pablo@netfilter.org, fw@strlen.de Cc: netfilter-devel@vger.kernel.org Subject: [PATCH nf-next v7 6/8] netfilter:nf_flow_table_ip: Support bridge family flow offload Date: Fri, 30 Aug 2019 12:17:20 +0800 Message-Id: <1567138642-11446-7-git-send-email-wenxu@ucloud.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1567138642-11446-1-git-send-email-wenxu@ucloud.cn> References: <1567138642-11446-1-git-send-email-wenxu@ucloud.cn> X-HM-Spam-Status: e1kfGhgUHx5ZQUtXWQgYFAkeWUFZVkpVSENJS0tLS0NDTUJKTEpZV1koWU FJQjdXWS1ZQUlXWQkOFx4IWUFZNTQpNjo3JCkuNz5ZBg++ X-HM-Sender-Digest: e1kMHhlZQR0aFwgeV1kSHx4VD1lBWUc6OC46Pjo*MDg*OTIBMi4fLzkw HAIwCzFVSlVKTk1MSkhDTU9IT0xOVTMWGhIXVQweFQMOOw4YFxQOH1UYFUVZV1kSC1lBWUpJSFVO QlVKSElVSklCWVdZCAFZQU9CTk03Bg++ X-HM-Tid: 0a6ce0bdfdbe2086kuqy5c703416c6 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org From: wenxu 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 --- 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); From patchwork Fri Aug 30 04:17:21 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: wenxu X-Patchwork-Id: 1155702 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=ucloud.cn Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 46KR5m0zsjz9sN6 for ; Fri, 30 Aug 2019 14:17:32 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726831AbfH3ERb (ORCPT ); Fri, 30 Aug 2019 00:17:31 -0400 Received: from m9784.mail.qiye.163.com ([220.181.97.84]:42815 "EHLO m9784.mail.qiye.163.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726480AbfH3ERb (ORCPT ); Fri, 30 Aug 2019 00:17:31 -0400 Received: from localhost.localdomain (unknown [123.59.132.129]) by m9784.mail.qiye.163.com (Hmail) with ESMTPA id 7A9B5417C2; Fri, 30 Aug 2019 12:17:23 +0800 (CST) From: wenxu@ucloud.cn To: pablo@netfilter.org, fw@strlen.de Cc: netfilter-devel@vger.kernel.org Subject: [PATCH nf-next v7 7/8] netfilter:nft_flow_offload: Support bridge family flow offload Date: Fri, 30 Aug 2019 12:17:21 +0800 Message-Id: <1567138642-11446-8-git-send-email-wenxu@ucloud.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1567138642-11446-1-git-send-email-wenxu@ucloud.cn> References: <1567138642-11446-1-git-send-email-wenxu@ucloud.cn> X-HM-Spam-Status: e1kfGhgUHx5ZQUtXWQgYFAkeWUFZVkpVSU9KS0tLS05NSU1NTENZV1koWU FJQjdXWS1ZQUlXWQkOFx4IWUFZNTQpNjo3JCkuNz5ZBg++ X-HM-Sender-Digest: e1kMHhlZQR0aFwgeV1kSHx4VD1lBWUc6MzY6Kio*EDg4KTI3Mi01Lz0e E1YwCihVSlVKTk1MSkhDTU9ITkxCVTMWGhIXVQweFQMOOw4YFxQOH1UYFUVZV1kSC1lBWUpJSFVO QlVKSElVSklCWVdZCAFZQU1MSU83Bg++ X-HM-Tid: 0a6ce0bdfe3c2086kuqy7a9b5417c2 Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org From: wenxu 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 --- 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 #include #include +#include #include #include /* for ipv4 options. */ #include @@ -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; From patchwork Fri Aug 30 04:17:22 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: wenxu X-Patchwork-Id: 1155704 X-Patchwork-Delegate: pablo@netfilter.org Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=netfilter-devel-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=ucloud.cn Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 46KR5n6fX5z9sN6 for ; Fri, 30 Aug 2019 14:17:33 +1000 (AEST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1726200AbfH3ERd (ORCPT ); Fri, 30 Aug 2019 00:17:33 -0400 Received: from m9784.mail.qiye.163.com ([220.181.97.84]:42817 "EHLO m9784.mail.qiye.163.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1726090AbfH3ERd (ORCPT ); Fri, 30 Aug 2019 00:17:33 -0400 Received: from localhost.localdomain (unknown [123.59.132.129]) by m9784.mail.qiye.163.com (Hmail) with ESMTPA id 95BEA417DC; Fri, 30 Aug 2019 12:17:23 +0800 (CST) From: wenxu@ucloud.cn To: pablo@netfilter.org, fw@strlen.de Cc: netfilter-devel@vger.kernel.org Subject: [PATCH nf-next v7 8/8] netfilter: Support the bridge family in flow table Date: Fri, 30 Aug 2019 12:17:22 +0800 Message-Id: <1567138642-11446-9-git-send-email-wenxu@ucloud.cn> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1567138642-11446-1-git-send-email-wenxu@ucloud.cn> References: <1567138642-11446-1-git-send-email-wenxu@ucloud.cn> X-HM-Spam-Status: e1kfGhgUHx5ZQUtXWQgYFAkeWUFZVkpVSENJS0tLS0NDTUJKTEpZV1koWU FJQjdXWS1ZQUlXWQkOFx4IWUFZNTQpNjo3JCkuNz5ZBg++ X-HM-Sender-Digest: e1kMHhlZQR0aFwgeV1kSHx4VD1lBWUc6MAg6LSo6TDg#EzIzMi1PLzEe EgJPCklVSlVKTk1MSkhDTU9ITUxNVTMWGhIXVQweFQMOOw4YFxQOH1UYFUVZV1kSC1lBWUpJSFVO QlVKSElVSklCWVdZCAFZQU9LSEM3Bg++ X-HM-Tid: 0a6ce0bdfead2086kuqy95bea417dc Sender: netfilter-devel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: netfilter-devel@vger.kernel.org From: wenxu 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 --- 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 +#include +#include +#include +#include +#include + +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 "); +MODULE_ALIAS_NF_FLOWTABLE(7); /* NFPROTO_BRIDGE */