From patchwork Sat May 19 00:49:47 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Rose X-Patchwork-Id: 916723 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=openvswitch.org (client-ip=140.211.169.12; helo=mail.linuxfoundation.org; envelope-from=ovs-dev-bounces@openvswitch.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="JLcrFLo7"; dkim-atps=neutral Received: from mail.linuxfoundation.org (mail.linuxfoundation.org [140.211.169.12]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 40nn5Z3Qxjz9s4w for ; Sat, 19 May 2018 11:10:09 +1000 (AEST) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id A2932ED3; Sat, 19 May 2018 00:51:09 +0000 (UTC) X-Original-To: dev@openvswitch.org Delivered-To: ovs-dev@mail.linuxfoundation.org Received: from smtp1.linuxfoundation.org (smtp1.linux-foundation.org [172.17.192.35]) by mail.linuxfoundation.org (Postfix) with ESMTPS id E56DADD9 for ; Sat, 19 May 2018 00:50:32 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pf0-f194.google.com (mail-pf0-f194.google.com [209.85.192.194]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 4A3EB473 for ; Sat, 19 May 2018 00:50:32 +0000 (UTC) Received: by mail-pf0-f194.google.com with SMTP id f189-v6so4500456pfa.7 for ; Fri, 18 May 2018 17:50:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=ialQS4bWXLbkKIzfK2jAH9gDaWxY8I6EZlbVhIAhz5E=; b=JLcrFLo737HahJUfzIgC3P51NB/7ZUuMkJnWCyhxe6il2kGDuM0bbM8ou4QT6do9Cq vHTB0eQViBL969SAcGgba1M8N/VkmyjrocJdMYBK/9ookfSvMAF1L876tNkhpNISj5gN GkC1CTMaX2z1JF9nbCKKOv+57Ga0ihYiQtSSt18INwi2v0uuFhANOLvhWTJJOglz0iSk ZOgh4HYdgW9rI6aFyzoTezO0CxFe6JFal7jWiALrAVz5SciM2OhwPwysQ7KSa6kw2VF9 ctuQBe84hc85jXfOo8+09hU7uay+k+HbzTOP+tvX2cqBbojQWx6Jc0y0PTy5HudwBJbd 7hog== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=ialQS4bWXLbkKIzfK2jAH9gDaWxY8I6EZlbVhIAhz5E=; b=DVcKgBBqzNRIbNq2CpyXm3yS7ZKgBqevPEehkNHu3LDMptVn4S5cFnYOdB8Iap0GH/ SB/y6HI9HN5JA6Y2XNxucUL7reEvdIy/tlA7bnNT954a0B+wNyw2Xo8WK9atQ3owQYID gA9/fdQ/gJXDBk6LAuyfngeTcdAXSXrsaVOXYQlAncUv/ZFbAMYLnpUyxWrqkKZ5twUB Z9o/FOOmTtEt673H2zgl+U2ORbPRgdIotg94em+Qqkj9NpAAcb7HBXpsbSeB0e6ALeF3 +3wqVrmgMv6H7HaPy9Lbj5v/txVcjYVNlq9VuG/Nvz9awV3p1mwWc1qIgILmISlalsJi ZLAQ== X-Gm-Message-State: ALKqPwfVWZs9rB5CytuFItDeF/Fu53UX2pA4v43nGLWQ6aeRvLQTs2db jMIY3tmdLLohnuvjrTUooL7szA== X-Google-Smtp-Source: AB8JxZpvozR+AcHaQMlHK0dxlr16z95byfIXQ0KIsneRITKBGnBm1WV0fD9bJ1rwMDvuHnilIOldGQ== X-Received: by 2002:a62:859a:: with SMTP id m26-v6mr11299307pfk.247.1526691031550; Fri, 18 May 2018 17:50:31 -0700 (PDT) Received: from gizo.domain (97-115-125-157.ptld.qwest.net. [97.115.125.157]) by smtp.gmail.com with ESMTPSA id 131-v6sm13536685pfa.128.2018.05.18.17.50.30 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 18 May 2018 17:50:31 -0700 (PDT) From: Greg Rose To: dev@openvswitch.org Date: Fri, 18 May 2018 17:49:47 -0700 Message-Id: <1526690988-29912-40-git-send-email-gvrose8192@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1526690988-29912-1-git-send-email-gvrose8192@gmail.com> References: <1526690988-29912-1-git-send-email-gvrose8192@gmail.com> X-Spam-Status: No, score=-1.7 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM, RCVD_IN_DNSWL_NONE autolearn=no version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on smtp1.linux-foundation.org Subject: [ovs-dev] [PATCH V3 39/40] gre: Resolve gre receive issues X-BeenThere: ovs-dev@openvswitch.org X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: ovs-dev-bounces@openvswitch.org Errors-To: ovs-dev-bounces@openvswitch.org On newer Linux kernels or on older kernels such as Red Hat that backport from newer upstream Linux kernel releases the built-in gre kernel module will interfere with OVS gre code in the receive path. Fix this up by placing the gre kernel code within the openvswitch driver so it will not have to depend on the built-in gre kernel module. Signed-off-by: Greg Rose --- datapath/linux/compat/gre.c | 113 +++++++++++++++++++++++++++++--- datapath/linux/compat/include/net/gre.h | 18 +++++ datapath/linux/compat/ip_gre.c | 38 +++++++++-- datapath/vport.c | 13 ++-- 4 files changed, 164 insertions(+), 18 deletions(-) diff --git a/datapath/linux/compat/gre.c b/datapath/linux/compat/gre.c index 7d16aee..b45f8b4 100644 --- a/datapath/linux/compat/gre.c +++ b/datapath/linux/compat/gre.c @@ -41,6 +41,104 @@ #ifndef USE_UPSTREAM_TUNNEL #if IS_ENABLED(CONFIG_NET_IPGRE_DEMUX) +static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly; + +int rpl_gre_add_protocol(const struct gre_protocol *proto, u8 version) +{ + if (version >= GREPROTO_MAX) + return -EINVAL; + + return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ? + 0 : -EBUSY; +} +EXPORT_SYMBOL_GPL(rpl_gre_add_protocol); + +int rpl_gre_del_protocol(const struct gre_protocol *proto, u8 version) +{ + int ret; + + if (version >= GREPROTO_MAX) + return -EINVAL; + + ret = (cmpxchg((const struct gre_protocol **)&gre_proto[version], proto, NULL) == proto) ? + 0 : -EBUSY; + + if (ret) + return ret; + + synchronize_rcu(); + return 0; +} +EXPORT_SYMBOL_GPL(rpl_gre_del_protocol); + +static int gre_rcv(struct sk_buff *skb) +{ + const struct gre_protocol *proto; + u8 ver; + int ret; + + if (!pskb_may_pull(skb, 12)) + goto drop; + + ver = skb->data[1]&0x7f; + if (ver >= GREPROTO_MAX) + goto drop; + + rcu_read_lock(); + proto = rcu_dereference(gre_proto[ver]); + if (!proto || !proto->handler) + goto drop_unlock; + ret = proto->handler(skb); + rcu_read_unlock(); + return ret; + +drop_unlock: + rcu_read_unlock(); +drop: + kfree_skb(skb); + return NET_RX_DROP; +} + +static void gre_err(struct sk_buff *skb, u32 info) +{ + const struct gre_protocol *proto; + const struct iphdr *iph = (const struct iphdr *)skb->data; + u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f; + + if (ver >= GREPROTO_MAX) + return; + + rcu_read_lock(); + proto = rcu_dereference(gre_proto[ver]); + if (proto && proto->err_handler) + proto->err_handler(skb, info); + rcu_read_unlock(); +} + +static const struct net_protocol net_gre_protocol = { + .handler = gre_rcv, + .err_handler = gre_err, + .netns_ok = 1, +}; + +int rpl_gre_init(void) +{ + pr_info("GRE over IPv4 demultiplexor driver\n"); + + if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) { + pr_err("can't add protocol\n"); + return -EAGAIN; + } + return 0; +} +EXPORT_SYMBOL_GPL(rpl_gre_init); + +void rpl_gre_exit(void) +{ + inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); +} +EXPORT_SYMBOL_GPL(rpl_gre_exit); + #define ip_gre_calc_hlen rpl_ip_gre_calc_hlen #define gre_calc_hlen rpl_ip_gre_calc_hlen static int rpl_ip_gre_calc_hlen(__be16 o_flags) @@ -142,25 +240,20 @@ static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, return iptunnel_pull_header(skb, hdr_len, tpi->proto, false); } -#endif /* HAVE_DEMUX_PARSE_GRE_HEADER */ - static struct gre_cisco_protocol __rcu *gre_cisco_proto; static int gre_cisco_rcv(struct sk_buff *skb) { - struct tnl_ptk_info tpi; struct gre_cisco_protocol *proto; + struct tnl_ptk_info tpi; + bool csum_err = false; rcu_read_lock(); proto = rcu_dereference(gre_cisco_proto); if (!proto) goto drop; -#ifdef HAVE_DEMUX_PARSE_GRE_HEADER - { - bool csum_err = false; - if (parse_gre_header(skb, &tpi, &csum_err) < 0) + + if (parse_gre_header(skb, &tpi, &csum_err) < 0) goto drop; - } -#endif proto->handler(skb, &tpi); rcu_read_unlock(); return 0; @@ -194,7 +287,6 @@ EXPORT_SYMBOL_GPL(rpl_gre_cisco_register); int rpl_gre_cisco_unregister(struct gre_cisco_protocol *proto) { int ret; - ret = (cmpxchg((struct gre_cisco_protocol **)&gre_cisco_proto, proto, NULL) == proto) ? 0 : -EINVAL; @@ -207,6 +299,7 @@ int rpl_gre_cisco_unregister(struct gre_cisco_protocol *proto) } EXPORT_SYMBOL_GPL(rpl_gre_cisco_unregister); +#endif /* HAVE_DEMUX_PARSE_GRE_HEADER */ #endif /* !HAVE_GRE_CISCO_REGISTER */ #endif diff --git a/datapath/linux/compat/include/net/gre.h b/datapath/linux/compat/include/net/gre.h index 11a95a5..141ed2d 100644 --- a/datapath/linux/compat/include/net/gre.h +++ b/datapath/linux/compat/include/net/gre.h @@ -32,6 +32,15 @@ static inline void rpl_ip6_tunnel_cleanup(void) { } +static inline int rpl_gre_init(void) +{ + return 0; +} + +static inline void rpl_gre_exit(void) +{ +} + #define gre_fb_xmit dev_queue_xmit #ifdef CONFIG_INET @@ -153,6 +162,8 @@ int rpl_ip6gre_init(void); void rpl_ip6gre_fini(void); int rpl_ip6_tunnel_init(void); void rpl_ip6_tunnel_cleanup(void); +int rpl_gre_init(void); +void rpl_gre_exit(void); #define gretap_fb_dev_create rpl_gretap_fb_dev_create struct net_device *rpl_gretap_fb_dev_create(struct net *net, const char *name, @@ -164,6 +175,11 @@ int rpl_gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, #define gre_fb_xmit rpl_gre_fb_xmit netdev_tx_t rpl_gre_fb_xmit(struct sk_buff *skb); + +#define gre_add_protocol rpl_gre_add_protocol +int rpl_gre_add_protocol(const struct gre_protocol *proto, u8 version); +#define gre_del_protocol rpl_gre_del_protocol +int rpl_gre_del_protocol(const struct gre_protocol *proto, u8 version); #endif /* USE_UPSTREAM_TUNNEL */ #define ipgre_init rpl_ipgre_init @@ -172,6 +188,8 @@ netdev_tx_t rpl_gre_fb_xmit(struct sk_buff *skb); #define ip6gre_fini rpl_ip6gre_fini #define ip6_tunnel_init rpl_ip6_tunnel_init #define ip6_tunnel_cleanup rpl_ip6_tunnel_cleanup +#define gre_init rpl_gre_init +#define gre_exit rpl_gre_exit #define gre_fill_metadata_dst ovs_gre_fill_metadata_dst int ovs_gre_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb); diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index eecd41a..9240ab2 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -96,13 +96,14 @@ static __be32 tunnel_id_to_key(__be64 x) #endif } +#ifdef HAVE_DEMUX_PARSE_GRE_HEADER /* Called with rcu_read_lock and BH disabled. */ static int gre_err(struct sk_buff *skb, u32 info, const struct tnl_ptk_info *tpi) { return PACKET_REJECT; } - +#endif static struct dst_ops md_dst_ops = { .family = AF_UNSPEC, }; @@ -746,11 +747,28 @@ static void __gre_tunnel_init(struct net_device *dev) } } -static struct gre_cisco_protocol ipgre_protocol = { +#ifdef HAVE_DEMUX_PARSE_GRE_HEADER +static struct gre_cisco_protocol ipgre_cisco_protocol = { .handler = gre_rcv, .err_handler = gre_err, .priority = 1, }; +#endif + +static int __gre_rcv(struct sk_buff *skb) +{ + return gre_rcv(skb, NULL); +} + +void __gre_err(struct sk_buff *skb, u32 info) +{ + pr_warn("%s: GRE receive error\n", __func__); +} + +static const struct gre_protocol ipgre_protocol = { + .handler = __gre_rcv, + .err_handler = __gre_err, +}; static int __net_init ipgre_init_net(struct net *net) { @@ -1631,11 +1649,19 @@ int rpl_ipgre_init(void) if (err < 0) goto pnet_ipgre_failed; - err = gre_cisco_register(&ipgre_protocol); +#ifdef HAVE_DEMUX_PARSE_GRE_HEADER + err = gre_cisco_register(&ipgre_cisco_protocol); if (err < 0) { pr_info("%s: can't add protocol\n", __func__); goto add_proto_failed; } +#else + err = gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO); + if (err < 0) { + pr_info("%s: can't add protocol\n", __func__); + goto add_proto_failed; + } +#endif pr_info("GRE over IPv4 tunneling driver\n"); @@ -1658,7 +1684,11 @@ void rpl_ipgre_fini(void) { ovs_vport_ops_unregister(&ovs_erspan_vport_ops); ovs_vport_ops_unregister(&ovs_ipgre_vport_ops); - gre_cisco_unregister(&ipgre_protocol); +#ifdef HAVE_DEMUX_PARSE_GRE_HEADER + gre_cisco_unregister(&ipgre_cisco_protocol); +#else + gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO); +#endif unregister_pernet_device(&ipgre_net_ops); unregister_pernet_device(&erspan_net_ops); unregister_pernet_device(&ipgre_tap_net_ops); diff --git a/datapath/vport.c b/datapath/vport.c index 184c859..73dd778 100644 --- a/datapath/vport.c +++ b/datapath/vport.c @@ -66,7 +66,7 @@ int ovs_vport_init(void) goto err_lisp; err = ipgre_init(); if (err) - goto err_gre; + goto err_ipgre; err = ip6gre_init(); if (err) goto err_ip6gre; @@ -76,15 +76,19 @@ int ovs_vport_init(void) err = geneve_init_module(); if (err) goto err_geneve; - err = vxlan_init_module(); if (err) goto err_vxlan; err = ovs_stt_init_module(); if (err) goto err_stt; - return 0; + err = gre_init(); + if (err) + goto err_gre; + return 0; +err_gre: + ovs_stt_cleanup_module(); err_stt: vxlan_cleanup_module(); err_vxlan: @@ -95,7 +99,7 @@ err_ip6_tunnel: ip6gre_fini(); err_ip6gre: ipgre_fini(); -err_gre: +err_ipgre: lisp_cleanup_module(); err_lisp: kfree(dev_table); @@ -109,6 +113,7 @@ err_lisp: */ void ovs_vport_exit(void) { + gre_exit(); ovs_stt_cleanup_module(); vxlan_cleanup_module(); geneve_cleanup_module();