From patchwork Wed Feb 17 00:41:30 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jay Vosburgh X-Patchwork-Id: 583782 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) by ozlabs.org (Postfix) with ESMTP id B0F6A1402C4; Wed, 17 Feb 2016 11:42:09 +1100 (AEDT) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.76) (envelope-from ) id 1aVqBy-0005OS-Fo; Wed, 17 Feb 2016 00:42:06 +0000 Received: from youngberry.canonical.com ([91.189.89.112]) by huckleberry.canonical.com with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.76) (envelope-from ) id 1aVqBq-0005Nl-6I for kernel-team@lists.ubuntu.com; Wed, 17 Feb 2016 00:41:58 +0000 Received: from c-67-183-59-65.hsd1.wa.comcast.net ([67.183.59.65] helo=famine.localdomain) by youngberry.canonical.com with esmtpsa (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.76) (envelope-from ) id 1aVqBp-00029l-Jx for kernel-team@lists.ubuntu.com; Wed, 17 Feb 2016 00:41:57 +0000 From: Jay Vosburgh To: kernel-team@lists.ubuntu.com Subject: [SRU][Trusty][PATCH v2 1/4] netfilter: bridge: don't use nf_bridge_info data to store mac header Date: Tue, 16 Feb 2016 16:41:30 -0800 Message-Id: <1455669693-19975-2-git-send-email-jay.vosburgh@canonical.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1455669693-19975-1-git-send-email-jay.vosburgh@canonical.com> References: <1455669693-19975-1-git-send-email-jay.vosburgh@canonical.com> X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.14 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: kernel-team-bounces@lists.ubuntu.com From: Florian Westphal BugLink: https://bugs.launchpad.net/nova/+bug/1463911 br_netfilter maintains an extra state, nf_bridge_info, which is attached to skb via skb->nf_bridge pointer. Amongst other things we use skb->nf_bridge->data to store the original mac header for every processed skb. This is required for ip refragmentation when using conntrack on top of bridge, because ip_fragment doesn't copy it from original skb. However there is no need anymore to do this unconditionally. Move this to the one place where its needed -- when br_netfilter calls ip_fragment(). Also switch to percpu storage for this so we can handle fragmenting without accessing nf_bridge meta data. Only user left is neigh resolution when DNAT is detected, to hold the original source mac address (neigh resolution builds new mac header using bridge mac), so rename ->data and reduce its size to whats needed. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso (backported from commit e70deecbf8e1562cac0b19f23848919e2f5d65aa) Signed-off-by: Jay Vosburgh --- net/bridge/br_netfilter.c | 49 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 80cad2cf02a7..6143a6f37c0e 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -171,6 +171,19 @@ void br_netfilter_rtable_init(struct net_bridge *br) rt->dst.ops = &fake_dst_ops; } +/* largest possible L2 header, see br_nf_dev_queue_xmit() */ +#define NF_BRIDGE_MAX_MAC_HEADER_LENGTH (PPPOE_SES_HLEN + ETH_HLEN) + +#if IS_ENABLED(CONFIG_NF_DEFRAG_IPV4) +struct brnf_frag_data { + char mac[NF_BRIDGE_MAX_MAC_HEADER_LENGTH]; + u8 encap_size; + u8 size; +}; + +static DEFINE_PER_CPU(struct brnf_frag_data, brnf_frag_data_storage); +#endif + static inline struct rtable *bridge_parent_rtable(const struct net_device *dev) { struct net_bridge_port *port; @@ -860,6 +873,25 @@ static unsigned int br_nf_forward_arp(const struct nf_hook_ops *ops, } #if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV4) +static int br_nf_push_frag_xmit(struct sk_buff *skb) +{ + struct brnf_frag_data *data; + int err; + + data = this_cpu_ptr(&brnf_frag_data_storage); + err = skb_cow_head(skb, data->size); + + if (err) { + kfree_skb(skb); + return 0; + } + + skb_copy_to_linear_data_offset(skb, -data->size, data->mac, data->size); + __skb_push(skb, data->encap_size); + + return br_dev_queue_push_xmit(skb); +} + static int br_nf_dev_queue_xmit(struct sk_buff *skb) { int ret; @@ -867,12 +899,25 @@ static int br_nf_dev_queue_xmit(struct sk_buff *skb) if (skb->nfct != NULL && skb->protocol == htons(ETH_P_IP) && skb->len + nf_bridge_mtu_reduction(skb) > skb->dev->mtu && !skb_is_gso(skb)) { + struct brnf_frag_data *data; + if (br_parse_ip_options(skb)) /* Drop invalid packet */ return NF_DROP; - ret = ip_fragment(skb, br_dev_queue_push_xmit); - } else + + nf_bridge_update_protocol(skb); + + data = this_cpu_ptr(&brnf_frag_data_storage); + data->encap_size = nf_bridge_encap_header_len(skb); + data->size = ETH_HLEN + data->encap_size; + + skb_copy_from_linear_data_offset(skb, -data->size, data->mac, + data->size); + + ret = ip_fragment(skb, br_nf_push_frag_xmit); + } else { ret = br_dev_queue_push_xmit(skb); + } return ret; }