From patchwork Thu Mar 22 22:07:17 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Rose X-Patchwork-Id: 889672 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="NVVNfGCr"; 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 406gnW4sGKz9s0y for ; Fri, 23 Mar 2018 09:09:35 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 60A7EED4; Thu, 22 Mar 2018 22:07:56 +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 96E21E32 for ; Thu, 22 Mar 2018 22:07:54 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pf0-f175.google.com (mail-pf0-f175.google.com [209.85.192.175]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id E9223360 for ; Thu, 22 Mar 2018 22:07:49 +0000 (UTC) Received: by mail-pf0-f175.google.com with SMTP id a11so571694pff.8 for ; Thu, 22 Mar 2018 15:07:49 -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=2391jni3Q1DNbTHETX4OGzIo7TSEJL2MwZ6BCIO9WGY=; b=NVVNfGCrr2WUmnBkjZZpQnOeXl1ycPjfayL2mPwWIx22qj7UQlGvT5/vl51LDe26Gd /0ZRIBFNdB1nQME3BHUoX8yOcJuBcULmnEULzRIWNkgnsUbcXrtaCprJP1n46+ydY1Jq 2ymOVrK/zM355baDUBoJG8kxrUJgjd4JJDZP3DmlfbOur5IDIzqmHmycBE6qrw6pZQPH lM90kZkm0mR7gX2T5u8fITjwFMwRdnvYzFQiwZHxJvPGT43irRJrybRaXZVgJ+z+dW5q iri77GrHp401xJMcPack/TbY7otO8TOzM95QR59tGEcN0LVXY/VOXMkb8FqvpDYGDBD0 60gw== 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=2391jni3Q1DNbTHETX4OGzIo7TSEJL2MwZ6BCIO9WGY=; b=Eeh7AdUrhVScqku5AX/q5bPk1Y6v0EimMMZ+S9jXK9ebZcmTirijmqP7jLFm/9zhwv H1nrXRd9VeBGJYFqi4ZHAOecALCcj3cnYL0mN6rBpWZSDM530jW/mNsBQ9o5C5dlkLvC AHLnTCM6tT4llgfSJVN0Sz+lAN+xsVJHP+OAXH4dJWr/ERoCpMUVbN/fzqf5Mek73fG5 UXa5IojKDU0Qj/f3vf13219ITfMRCm5aYz4B7C3eBYMtXzQx0qmYck7hs9AqTgIisKyz i8z2LO9sQ3cRkZ7T0WT3iLB7O4+zzfsBO8Z0Jfxr6H6ObWu+afGmWSSM+6EaIpX4ld7g shGA== X-Gm-Message-State: AElRT7H0Q3boyuzSbTA3RtNUuwGoIdXZgm+BWy5l21bbSXnRPE29383E QGQBhgMYHDPPdwjSLFqcnTvDOA== X-Google-Smtp-Source: AG47ELu152MYuNoAYQSgBX92+RmiSfPKOIhfUIZ8Rb5Cuq/UyoCmfOArg0WwyOr8n2ZC9In76jo3bQ== X-Received: by 10.99.117.86 with SMTP id f22mr18680738pgn.180.1521756467983; Thu, 22 Mar 2018 15:07:47 -0700 (PDT) Received: from gizo.domain (184-100-240-187.ptld.qwest.net. [184.100.240.187]) by smtp.gmail.com with ESMTPSA id 4sm2280775pfn.32.2018.03.22.15.07.46 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Mar 2018 15:07:46 -0700 (PDT) From: Greg Rose To: dev@openvswitch.org Date: Thu, 22 Mar 2018 15:07:17 -0700 Message-Id: <1521756461-3870-2-git-send-email-gvrose8192@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1521756461-3870-1-git-send-email-gvrose8192@gmail.com> References: <1521756461-3870-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] [ERSPAN RFC 01/25] gre: introduce native tunnel support for ERSPAN 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 From: William Tu Upstream commit: commit 84e54fe0a5eaed696dee4019c396f8396f5a908b Author: William Tu Date: Tue Aug 22 09:40:28 2017 -0700 gre: introduce native tunnel support for ERSPAN The patch adds ERSPAN type II tunnel support. The implementation is based on the draft at [1]. One of the purposes is for Linux box to be able to receive ERSPAN monitoring traffic sent from the Cisco switch, by creating a ERSPAN tunnel device. In addition, the patch also adds ERSPAN TX, so Linux virtual switch can redirect monitored traffic to the ERSPAN tunnel device. The traffic will be encapsulated into ERSPAN and sent out. The implementation reuses tunnel key as ERSPAN session ID, and field 'erspan' as ERSPAN Index fields: ./ip link add dev ers11 type erspan seq key 100 erspan 123 \ local 172.16.1.200 remote 172.16.1.100 To use the above device as ERSPAN receiver, configure Nexus 5000 switch as below: monitor session 100 type erspan-source erspan-id 123 vrf default destination ip 172.16.1.200 source interface Ethernet1/11 both source interface Ethernet1/12 both no shut monitor erspan origin ip-address 172.16.1.100 global [1] https://tools.ietf.org/html/draft-foschiano-erspan-01 [2] iproute2 patch: http://marc.info/?l=linux-netdev&m=150306086924951&w=2 [3] test script: http://marc.info/?l=linux-netdev&m=150231021807304&w=2 Signed-off-by: William Tu Signed-off-by: Meenakshi Vohra Cc: Alexey Kuznetsov Cc: Hideaki YOSHIFUJI Signed-off-by: David S. Miller This commit also backports heavily from upstream gre, ip_gre and ip_tunnel modules to support the necessary erspan ip gre infrastructure as well as implementing a variety of compatability layer changes for same support. Cc: William Tu Signed-off-by: Greg Rose --- acinclude.m4 | 10 +- datapath/linux/Modules.mk | 3 +- datapath/linux/compat/gre.c | 202 ++++++------ datapath/linux/compat/include/linux/if_ether.h | 4 + datapath/linux/compat/include/linux/skbuff.h | 29 ++ datapath/linux/compat/include/net/erspan.h | 65 ++++ datapath/linux/compat/include/net/gre.h | 13 +- datapath/linux/compat/include/net/ip_tunnels.h | 159 ++++++++- datapath/linux/compat/ip_gre.c | 339 ++++++++++++++++++- datapath/linux/compat/ip_tunnel.c | 439 ++++++++++++++++++++++++- datapath/linux/compat/ip_tunnels_core.c | 41 +++ 11 files changed, 1173 insertions(+), 131 deletions(-) create mode 100644 datapath/linux/compat/include/net/erspan.h diff --git a/acinclude.m4 b/acinclude.m4 index d61e37a..6ef244d 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -814,7 +814,15 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [ OVS_GREP_IFELSE([$KSRC/include/net/inet_frag.h], frag_percpu_counter_batch[], [OVS_DEFINE([HAVE_FRAG_PERCPU_COUNTER_BATCH])]) - + OVS_FIND_FIELD_IFELSE([$KSRC/include/net/ip_tunnels.h], [tnl_ptk_info], + [hdr_len], + [OVS_DEFINE([HAVE_TNL_PTK_INFO_HDR_LEN])]) + OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], + [null_compute_pseudo], + [OVS_DEFINE([HAVE_NULL_COMPUTE_PSEUDO])]) + OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], + [__skb_checksum_convert], + [OVS_DEFINE([HAVE_SKB_CHECKSUM_CONVERT])]) if cmp -s datapath/linux/kcompat.h.new \ datapath/linux/kcompat.h >/dev/null 2>&1; then diff --git a/datapath/linux/Modules.mk b/datapath/linux/Modules.mk index 0dbc1ed..e0a90c3 100644 --- a/datapath/linux/Modules.mk +++ b/datapath/linux/Modules.mk @@ -104,5 +104,6 @@ openvswitch_headers += \ linux/compat/include/net/netfilter/nf_conntrack_zones.h \ linux/compat/include/net/netfilter/nf_nat.h \ linux/compat/include/net/netfilter/ipv6/nf_defrag_ipv6.h \ - linux/compat/include/net/sctp/checksum.h + linux/compat/include/net/sctp/checksum.h \ + linux/compat/include/net/erspan.h EXTRA_DIST += linux/compat/build-aux/export-check-whitelist diff --git a/datapath/linux/compat/gre.c b/datapath/linux/compat/gre.c index a341fa3..98924c9 100644 --- a/datapath/linux/compat/gre.c +++ b/datapath/linux/compat/gre.c @@ -41,90 +41,24 @@ #ifndef USE_UPSTREAM_TUNNEL #if IS_ENABLED(CONFIG_NET_IPGRE_DEMUX) -#ifndef HAVE_GRE_HANDLE_OFFLOADS - -#ifndef HAVE_GRE_CISCO_REGISTER - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) - -#define GREPROTO_CISCO 0 -#define GREPROTO_MAX 1 - -struct gre_protocol { - int (*handler)(struct sk_buff *skb); -}; -static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly; - -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 const struct net_protocol net_gre_protocol = { - .handler = gre_rcv, - .netns_ok = 1, -}; - -static int gre_add_protocol(const struct gre_protocol *proto, u8 version) +#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) { - if (version >= GREPROTO_MAX) - return -EINVAL; - - if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) { - pr_err("%s: cannot register gre protocol handler\n", __func__); - return -EAGAIN; - } + int addend = 4; - return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ? - 0 : -EBUSY; + if (o_flags & TUNNEL_CSUM) + addend += 4; + if (o_flags & TUNNEL_KEY) + addend += 4; + if (o_flags & TUNNEL_SEQ) + addend += 4; + return addend; } -static int 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_net(); - - ret = inet_del_protocol(&net_gre_protocol, IPPROTO_GRE); - if (ret) - return ret; - - return 0; -} +#ifndef HAVE_GRE_HANDLE_OFFLOADS -#endif +#ifndef HAVE_GRE_CISCO_REGISTER static __sum16 check_checksum(struct sk_buff *skb) { @@ -148,20 +82,6 @@ static __sum16 check_checksum(struct sk_buff *skb) return csum; } -#define ip_gre_calc_hlen rpl_ip_gre_calc_hlen -static int ip_gre_calc_hlen(__be16 o_flags) -{ - int addend = 4; - - if (o_flags & TUNNEL_CSUM) - addend += 4; - if (o_flags & TUNNEL_KEY) - addend += 4; - if (o_flags & TUNNEL_SEQ) - addend += 4; - return addend; -} - #define gre_flags_to_tnl_flags rpl_gre_flags_to_tnl_flags static __be16 gre_flags_to_tnl_flags(__be16 flags) { @@ -309,5 +229,101 @@ EXPORT_SYMBOL_GPL(rpl_gre_cisco_unregister); #endif /* !HAVE_GRE_CISCO_REGISTER */ #endif +void rpl_gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi, + int hdr_len) +{ + struct gre_base_hdr *greh; + + skb_push(skb, hdr_len); + + skb_reset_transport_header(skb); + greh = (struct gre_base_hdr *)skb->data; + greh->flags = tnl_flags_to_gre_flags(tpi->flags); + greh->protocol = tpi->proto; + + if (tpi->flags&(TUNNEL_KEY|TUNNEL_CSUM|TUNNEL_SEQ)) { + __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4); + + if (tpi->flags&TUNNEL_SEQ) { + *ptr = tpi->seq; + ptr--; + } + if (tpi->flags&TUNNEL_KEY) { + *ptr = tpi->key; + ptr--; + } + if (tpi->flags&TUNNEL_CSUM && + !(skb_shinfo(skb)->gso_type & + (SKB_GSO_GRE|SKB_GSO_GRE_CSUM))) { + *ptr = 0; + *(__sum16 *)ptr = csum_fold(skb_checksum(skb, 0, + skb->len, 0)); + } + } +} +EXPORT_SYMBOL_GPL(rpl_gre_build_header); + +/* Fills in tpi and returns header length to be pulled. */ +int rpl_gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, + bool *csum_err, __be16 proto, int nhs) +{ + const struct gre_base_hdr *greh; + __be32 *options; + int hdr_len; + + if (unlikely(!pskb_may_pull(skb, nhs + sizeof(struct gre_base_hdr)))) + return -EINVAL; + + greh = (struct gre_base_hdr *)(skb->data + nhs); + if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING))) + return -EINVAL; + + tpi->flags = gre_flags_to_tnl_flags(greh->flags); + hdr_len = gre_calc_hlen(tpi->flags); + + if (!pskb_may_pull(skb, nhs + hdr_len)) + return -EINVAL; + + greh = (struct gre_base_hdr *)(skb->data + nhs); + tpi->proto = greh->protocol; + + options = (__be32 *)(greh + 1); + if (greh->flags & GRE_CSUM) { + if (skb_checksum_simple_validate(skb)) { + *csum_err = true; + return -EINVAL; + } + + skb_checksum_try_convert(skb, IPPROTO_GRE, 0, + null_compute_pseudo); + options++; + } + + if (greh->flags & GRE_KEY) { + tpi->key = *options; + options++; + } else { + tpi->key = 0; + } + if (unlikely(greh->flags & GRE_SEQ)) { + tpi->seq = *options; + options++; + } else { + tpi->seq = 0; + } + /* WCCP version 1 and 2 protocol decoding. + * * - Change protocol to IPv4/IPv6 + * * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header + * */ + if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) { + tpi->proto = proto; + if ((*(u8 *)options & 0xF0) != 0x40) + hdr_len += 4; + } + tpi->hdr_len = hdr_len; + return hdr_len; +} +EXPORT_SYMBOL(rpl_gre_parse_header); + #endif /* CONFIG_NET_IPGRE_DEMUX */ #endif /* USE_UPSTREAM_TUNNEL */ diff --git a/datapath/linux/compat/include/linux/if_ether.h b/datapath/linux/compat/include/linux/if_ether.h index c989c6e..aaa88db 100644 --- a/datapath/linux/compat/include/linux/if_ether.h +++ b/datapath/linux/compat/include/linux/if_ether.h @@ -23,6 +23,10 @@ #define ETH_P_NSH 0x894F /* Network Service Header */ #endif +#ifndef ETH_P_ERSPAN +#define ETH_P_ERSPAN 0x88BE /* ERSPAN TYPE II */ +#endif + #define inner_eth_hdr rpl_inner_eth_hdr static inline struct ethhdr *inner_eth_hdr(const struct sk_buff *skb) { diff --git a/datapath/linux/compat/include/linux/skbuff.h b/datapath/linux/compat/include/linux/skbuff.h index 2910f3f..f0665ed 100644 --- a/datapath/linux/compat/include/linux/skbuff.h +++ b/datapath/linux/compat/include/linux/skbuff.h @@ -21,6 +21,35 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, #define ignore_df local_df #endif + +#ifndef HAVE_NULL_COMPUTE_PSEUDO +static inline __wsum null_compute_pseudo(struct sk_buff *skb, int proto) +{ + return 0; +} +#endif + +#ifndef HAVE_SKB_CHECKSUM_CONVERT +static inline bool __skb_checksum_convert_check(struct sk_buff *skb) +{ + return (skb->ip_summed == CHECKSUM_NONE && skb->csum_valid); +} + +static inline void __skb_checksum_convert(struct sk_buff *skb, + __sum16 check, __wsum pseudo) +{ + skb->csum = ~pseudo; + skb->ip_summed = CHECKSUM_COMPLETE; +} + +#define skb_checksum_try_convert(skb, proto, check, compute_pseudo) \ +do { \ + if (__skb_checksum_convert_check(skb)) \ + __skb_checksum_convert(skb, check, \ + compute_pseudo(skb, proto)); \ +} while (0) + +#endif #ifndef HAVE_SKB_COPY_FROM_LINEAR_DATA_OFFSET static inline void skb_copy_from_linear_data_offset(const struct sk_buff *skb, const int offset, void *to, diff --git a/datapath/linux/compat/include/net/erspan.h b/datapath/linux/compat/include/net/erspan.h new file mode 100644 index 0000000..6c5d3a7 --- /dev/null +++ b/datapath/linux/compat/include/net/erspan.h @@ -0,0 +1,65 @@ +#ifndef USE_UPSTREAM_TUNNEL +#ifndef __LINUX_ERSPAN_H +#define __LINUX_ERSPAN_H + +/* + * GRE header for ERSPAN encapsulation (8 octets [34:41]) -- 8 bytes + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |0|0|0|1|0|00000|000000000|00000| Protocol Type for ERSPAN | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Sequence Number (increments per packet per session) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Note that in the above GRE header [RFC1701] out of the C, R, K, S, + * s, Recur, Flags, Version fields only S (bit 03) is set to 1. The + * other fields are set to zero, so only a sequence number follows. + * + * ERSPAN Type II header (8 octets [42:49]) + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Ver | VLAN | COS | En|T| Session ID | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Reserved | Index | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * GRE proto ERSPAN type II = 0x88BE, type III = 0x22EB + */ + +#define ERSPAN_VERSION 0x1 + +#define VER_MASK 0xf000 +#define VLAN_MASK 0x0fff +#define COS_MASK 0xe000 +#define EN_MASK 0x1800 +#define T_MASK 0x0400 +#define ID_MASK 0x03ff +#define INDEX_MASK 0xfffff + +enum erspan_encap_type { + ERSPAN_ENCAP_NOVLAN = 0x0, /* originally without VLAN tag */ + ERSPAN_ENCAP_ISL = 0x1, /* originally ISL encapsulated */ + ERSPAN_ENCAP_8021Q = 0x2, /* originally 802.1Q encapsulated */ + ERSPAN_ENCAP_INFRAME = 0x3, /* VLAN tag perserved in frame */ +}; + +struct erspan_metadata { + __be32 index; /* type II */ +}; + +struct erspanhdr { + __be16 ver_vlan; +#define VER_OFFSET 12 + __be16 session_id; +#define COS_OFFSET 13 +#define EN_OFFSET 11 +#define T_OFFSET 10 + struct erspan_metadata md; +}; + +#endif +#else +#include_next +#endif diff --git a/datapath/linux/compat/include/net/gre.h b/datapath/linux/compat/include/net/gre.h index 764b9f1..ead86f6 100644 --- a/datapath/linux/compat/include/net/gre.h +++ b/datapath/linux/compat/include/net/gre.h @@ -28,11 +28,7 @@ static inline struct net_device *rpl_gretap_fb_dev_create( #endif #else - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37) || \ - defined(HAVE_GRE_CISCO_REGISTER) #include_next -#endif #ifndef HAVE_GRE_CISCO_REGISTER @@ -62,6 +58,10 @@ struct gre_base_hdr { #endif /* HAVE_GRE_CISCO_REGISTER */ +#define gre_build_header rpl_gre_build_header +void rpl_gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi, + int hdr_len); + int rpl_ipgre_init(void); void rpl_ipgre_fini(void); @@ -69,6 +69,10 @@ void rpl_ipgre_fini(void); struct net_device *rpl_gretap_fb_dev_create(struct net *net, const char *name, u8 name_assign_type); +#define gre_parse_header rpl_gre_parse_header +int rpl_gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, + bool *csum_err, __be16 proto, int nhs); + #define gre_fb_xmit rpl_gre_fb_xmit netdev_tx_t rpl_gre_fb_xmit(struct sk_buff *skb); #endif /* USE_UPSTREAM_TUNNEL */ @@ -79,4 +83,5 @@ netdev_tx_t rpl_gre_fb_xmit(struct sk_buff *skb); #define gre_fill_metadata_dst ovs_gre_fill_metadata_dst int ovs_gre_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb); + #endif diff --git a/datapath/linux/compat/include/net/ip_tunnels.h b/datapath/linux/compat/include/net/ip_tunnels.h index ae60f09..e3fb13b 100644 --- a/datapath/linux/compat/include/net/ip_tunnels.h +++ b/datapath/linux/compat/include/net/ip_tunnels.h @@ -8,6 +8,11 @@ * Only function that do not depend on ip_tunnel structure can * be used. Those needs to be explicitly defined in this header file. */ #include_next + +#ifndef TUNNEL_ERSPAN_OPT +#define TUNNEL_ERSPAN_OPT __cpu_to_be16(0x4000) +#endif +#define ovs_ip_tunnel_encap ip_tunnel_encap #else #include @@ -18,6 +23,21 @@ #include #include #include +#include + +#ifndef MAX_IPTUN_ENCAP_OPS +#define MAX_IPTUN_ENCAP_OPS 8 +#endif + +#ifndef HAVE_TUNNEL_ENCAP_TYPES +enum tunnel_encap_types { + TUNNEL_ENCAP_NONE, + TUNNEL_ENCAP_FOU, + TUNNEL_ENCAP_GUE, +}; + +#define HAVE_TUNNEL_ENCAP_TYPES 1 +#endif #define __iptunnel_pull_header rpl___iptunnel_pull_header int rpl___iptunnel_pull_header(struct sk_buff *skb, int hdr_len, @@ -41,13 +61,17 @@ int ovs_iptunnel_handle_offloads(struct sk_buff *skb, */ #define iptunnel_handle_offloads rpl_iptunnel_handle_offloads struct sk_buff *rpl_iptunnel_handle_offloads(struct sk_buff *skb, - bool csum_help, - int gso_type_mask); + bool csum_help, + int gso_type_mask); #define iptunnel_xmit rpl_iptunnel_xmit void rpl_iptunnel_xmit(struct sock *sk, struct rtable *rt, struct sk_buff *skb, __be32 src, __be32 dst, __u8 proto, __u8 tos, __u8 ttl, __be16 df, bool xnet); +#define ip_tunnel_xmit rpl_ip_tunnel_xmit +void rpl_ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, + const struct iphdr *tnl_params, const u8 protocol); + #ifndef TUNNEL_CSUM #define TUNNEL_CSUM __cpu_to_be16(0x01) @@ -64,12 +88,18 @@ struct tnl_ptk_info { __be16 proto; __be32 key; __be32 seq; +#ifndef HAVE_TNL_PTK_INFO_HDR_LEN + int hdr_len; +#endif }; #define PACKET_RCVD 0 #define PACKET_REJECT 1 #endif +#define IP_TNL_HASH_BITS 7 +#define IP_TNL_HASH_SIZE (1 << IP_TNL_HASH_BITS) + #ifndef TUNNEL_DONT_FRAGMENT #define TUNNEL_DONT_FRAGMENT __cpu_to_be16(0x0100) #endif @@ -91,6 +121,9 @@ struct tnl_ptk_info { #undef TUNNEL_OPTIONS_PRESENT #define TUNNEL_OPTIONS_PRESENT (TUNNEL_GENEVE_OPT | TUNNEL_VXLAN_OPT) +/* Keep error state on tunnel for 30 sec */ +#define IPTUNNEL_ERR_TIMEO (30*HZ) + /* Used to memset ip_tunnel padding. */ #define IP_TUNNEL_KEY_SIZE offsetofend(struct ip_tunnel_key, tp_dst) @@ -131,6 +164,30 @@ struct ip_tunnel_info { u8 mode; }; +/* 6rd prefix/relay information */ +#ifdef CONFIG_IPV6_SIT_6RD +struct ip_tunnel_6rd_parm { + struct in6_addr prefix; + __be32 relay_prefix; + u16 prefixlen; + u16 relay_prefixlen; +}; +#endif + +struct ip_tunnel_encap { + u16 type; + u16 flags; + __be16 sport; + __be16 dport; +}; + +struct ip_tunnel_prl_entry { + struct ip_tunnel_prl_entry __rcu *next; + __be32 addr; + u16 flags; + struct rcu_head rcu_head; +}; + static inline unsigned short ip_tunnel_info_af(const struct ip_tunnel_info *tun_info) { return tun_info->mode & IP_TUNNEL_INFO_IPV6 ? AF_INET6 : AF_INET; @@ -203,39 +260,115 @@ ip_tunnel_dst_cache_usable(const struct sk_buff *skb, } #endif -#define ip_tunnel rpl_ip_tunnel +#define ip_tunnel_dst rpl_ip_tunnel_dst +struct rpl_ip_tunnel_dst { + struct dst_entry __rcu *dst; + __be32 saddr; +}; +#define ip_tunnel rpl_ip_tunnel struct ip_tunnel { + struct ip_tunnel __rcu *next; + struct hlist_node hash_node; struct net_device *dev; struct net *net; /* netns for packet i/o */ - int err_count; /* Number of arrived ICMP errors */ unsigned long err_time; /* Time when the last ICMP error - * arrived - */ + * arrived */ + int err_count; /* Number of arrived ICMP errors */ /* These four fields used only by GRE */ u32 i_seqno; /* The last seen seqno */ u32 o_seqno; /* The last output seqno */ int tun_hlen; /* Precalculated header length */ - int mlink; + + /* These four fields used only by ERSPAN */ + u32 index; /* ERSPAN type II index */ + u8 erspan_ver; /* ERSPAN version */ + u8 dir; /* ERSPAN direction */ + u16 hwid; /* ERSPAN hardware ID */ + + struct dst_cache dst_cache; struct ip_tunnel_parm parms; + int mlink; int encap_hlen; /* Encap header length (FOU,GUE) */ int hlen; /* tun_hlen + encap_hlen */ + struct ip_tunnel_encap encap; - int ip_tnl_net_id; - bool collect_md; + /* for SIT */ +#ifdef CONFIG_IPV6_SIT_6RD + struct ip_tunnel_6rd_parm ip6rd; +#endif + struct ip_tunnel_prl_entry __rcu *prl; /* potential router list */ + unsigned int prl_count; /* # of entries in PRL */ + unsigned int ip_tnl_net_id; + struct gro_cells gro_cells; + __u32 fwmark; + bool collect_md; + bool ignore_df; }; #define ip_tunnel_net rpl_ip_tunnel_net struct ip_tunnel_net { + struct net_device *fb_tunnel_dev; + struct hlist_head tunnels[IP_TNL_HASH_SIZE]; struct ip_tunnel __rcu *collect_md_tun; - struct rtnl_link_ops *rtnl_ops; }; +struct ip_tunnel_encap_ops { + size_t (*encap_hlen)(struct ip_tunnel_encap *e); + int (*build_header)(struct sk_buff *skb, struct ip_tunnel_encap *e, + const u8 *protocol, struct flowi4 *fl4); +}; + +extern const struct ip_tunnel_encap_ops __rcu * + rpl_iptun_encaps[MAX_IPTUN_ENCAP_OPS]; + +#define ip_encap_hlen rpl_ip_encap_hlen +static inline int rpl_ip_encap_hlen(struct ip_tunnel_encap *e) +{ + const struct ip_tunnel_encap_ops *ops; + int hlen = -EINVAL; + + if (e->type == TUNNEL_ENCAP_NONE) + return 0; + + if (e->type >= MAX_IPTUN_ENCAP_OPS) + return -EINVAL; + + rcu_read_lock(); + ops = rcu_dereference(rpl_iptun_encaps[e->type]); + if (likely(ops && ops->encap_hlen)) + hlen = ops->encap_hlen(e); + rcu_read_unlock(); + + return hlen; +} + +static inline int ovs_ip_tunnel_encap(struct sk_buff *skb, struct ip_tunnel *t, + const u8 *protocol, struct flowi4 *fl4) +{ + const struct ip_tunnel_encap_ops *ops; + int ret = -EINVAL; + + if (t->encap.type == TUNNEL_ENCAP_NONE) + return 0; + + if (t->encap.type >= MAX_IPTUN_ENCAP_OPS) + return -EINVAL; + + rcu_read_lock(); + ops = rcu_dereference(rpl_iptun_encaps[t->encap.type]); + if (likely(ops && ops->build_header)) + ret = ops->build_header(skb, &t->encap, protocol, fl4); + rcu_read_unlock(); + + return ret; +} + #ifndef HAVE_PCPU_SW_NETSTATS #define ip_tunnel_get_stats64 rpl_ip_tunnel_get_stats64 #else @@ -326,6 +459,12 @@ struct net *rpl_ip_tunnel_get_link_net(const struct net_device *dev); #define __ip_tunnel_change_mtu rpl___ip_tunnel_change_mtu int rpl___ip_tunnel_change_mtu(struct net_device *dev, int new_mtu, bool strict); +#define ip_tunnel_lookup rpl_ip_tunnel_lookup +struct ip_tunnel *rpl_ip_tunnel_lookup(struct ip_tunnel_net *itn, + int link, __be16 flags, + __be32 remote, __be32 local, + __be32 key); + static inline int iptunnel_pull_offloads(struct sk_buff *skb) { if (skb_is_gso(skb)) { diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index 4e32591..a82808a 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -52,6 +52,7 @@ #include #include #include +#include #if IS_ENABLED(CONFIG_IPV6) #include @@ -63,6 +64,7 @@ #include "vport-netdev.h" static int gre_tap_net_id __read_mostly; +static unsigned int erspan_net_id __read_mostly; #define ip_gre_calc_hlen rpl_ip_gre_calc_hlen static int ip_gre_calc_hlen(__be16 o_flags) @@ -120,6 +122,63 @@ static __be32 tunnel_id_to_key(__be64 x) #endif } +/* 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; +} + +static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, + int gre_hdr_len) +{ + struct net *net = dev_net(skb->dev); + struct metadata_dst *tun_dst = NULL; + struct ip_tunnel_net *itn; + struct ip_tunnel *tunnel; + struct erspanhdr *ershdr; + const struct iphdr *iph; + __be32 session_id; + __be32 index; + int len; + + itn = net_generic(net, erspan_net_id); + iph = ip_hdr(skb); + len = gre_hdr_len + sizeof(*ershdr); + + if (unlikely(!pskb_may_pull(skb, len))) + return -ENOMEM; + + iph = ip_hdr(skb); + ershdr = (struct erspanhdr *)(skb->data + gre_hdr_len); + + /* The original GRE header does not have key field, + * Use ERSPAN 10-bit session ID as key. + */ + session_id = cpu_to_be32(ntohs(ershdr->session_id)); + tpi->key = session_id; + index = ershdr->md.index; + tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, + tpi->flags | TUNNEL_KEY, + iph->saddr, iph->daddr, tpi->key); + + if (tunnel) { + if (__iptunnel_pull_header(skb, + gre_hdr_len + sizeof(*ershdr), + htons(ETH_P_TEB), + false, false) < 0) + goto drop; + + tunnel->index = ntohl(index); + skb_reset_mac_header(skb); + ovs_ip_tunnel_rcv(tunnel->dev, skb, tun_dst); + return PACKET_RCVD; + } +drop: + kfree_skb(skb); + return PACKET_RCVD; +} + static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi) { struct net *net = dev_net(skb->dev); @@ -164,11 +223,46 @@ static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi) return PACKET_REJECT; } -static int gre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi) +static void __gre_xmit(struct sk_buff *skb, struct net_device *dev, + const struct iphdr *tnl_params, + __be16 proto) +{ + struct ip_tunnel *tunnel = netdev_priv(dev); + struct tnl_ptk_info tpi; + + tpi.flags = tunnel->parms.o_flags; + tpi.proto = proto; + tpi.key = tunnel->parms.o_key; + if (tunnel->parms.o_flags & TUNNEL_SEQ) + tunnel->o_seqno++; + tpi.seq = htonl(tunnel->o_seqno); + + /* Push GRE header. */ + gre_build_header(skb, &tpi, tunnel->hlen); + + ip_tunnel_xmit(skb, dev, tnl_params, tnl_params->protocol); +} + +static int gre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *unused_tpi) { - if (ipgre_rcv(skb, tpi) == PACKET_RCVD) + struct tnl_ptk_info tpi; + bool csum_err = false; + int hdr_len; + + hdr_len = gre_parse_header(skb, &tpi, &csum_err, htons(ETH_P_IP), 0); + if (hdr_len < 0) + goto drop; + + if (unlikely(tpi.proto == htons(ETH_P_ERSPAN))) { + if (erspan_rcv(skb, &tpi, hdr_len) == PACKET_RCVD) + return 0; + } + + if (ipgre_rcv(skb, &tpi) == PACKET_RCVD) return 0; +drop: + kfree_skb(skb); return 0; } @@ -382,13 +476,6 @@ static void __gre_tunnel_init(struct net_device *dev) } } -/* 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; -} - static struct gre_cisco_protocol ipgre_protocol = { .handler = gre_rcv, .err_handler = gre_err, @@ -437,6 +524,61 @@ out: return ipgre_tunnel_validate(tb, data); } +enum { +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0) + IFLA_GRE_ENCAP_TYPE = IFLA_GRE_FLAGS + 1, + IFLA_GRE_ENCAP_FLAGS, + IFLA_GRE_ENCAP_SPORT, + IFLA_GRE_ENCAP_DPORT, +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,3,0) + IFLA_GRE_COLLECT_METADATA = IFLA_GRE_ENCAP_DPORT + 1, +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,8,0) + IFLA_GRE_IGNORE_DF = IFLA_GRE_COLLECT_METADATA + 1, +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,12,0) + IFLA_GRE_FWMARK = IFLA_GRE_IGNORE_DF + 1, +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0) + IFLA_GRE_ERSPAN_INDEX = IFLA_GRE_FWMARK + 1, +#endif +}; + +#define RPL_IFLA_GRE_MAX (IFLA_GRE_ERSPAN_INDEX + 1) + +static int erspan_validate(struct nlattr *tb[], struct nlattr *data[]) +{ + __be16 flags = 0; + int ret; + + if (!data) + return 0; + + ret = ipgre_tap_validate(tb, data); + if (ret) + return ret; + + /* ERSPAN should only have GRE sequence and key flag */ + flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]); + flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]); + if (flags != (GRE_SEQ | GRE_KEY)) + return -EINVAL; + + /* ERSPAN Session ID only has 10-bit. Since we reuse + * 32-bit key field as ID, check it's range. + */ + if (data[IFLA_GRE_IKEY] && + (ntohl(nla_get_be32(data[IFLA_GRE_IKEY])) & ~ID_MASK)) + return -EINVAL; + + if (data[IFLA_GRE_OKEY] && + (ntohl(nla_get_be32(data[IFLA_GRE_OKEY])) & ~ID_MASK)) + return -EINVAL; + + return 0; +} + static void ipgre_netlink_parms(struct net_device *dev, struct nlattr *data[], struct nlattr *tb[], @@ -466,6 +608,81 @@ static netdev_tx_t gre_dev_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } +static inline u8 tos_to_cos(u8 tos) +{ + u8 dscp, cos; + + dscp = tos >> 2; + cos = dscp >> 3; + return cos; +} + +static void erspan_build_header(struct sk_buff *skb, + __be32 id, u32 index, bool truncate) +{ + struct iphdr *iphdr = ip_hdr(skb); + struct ethhdr *eth = eth_hdr(skb); + enum erspan_encap_type enc_type; + struct erspanhdr *ershdr; + struct qtag_prefix { + __be16 eth_type; + __be16 tci; + } *qp; + u16 vlan_tci = 0; + + enc_type = ERSPAN_ENCAP_NOVLAN; + + /* If mirrored packet has vlan tag, extract tci and + * perserve vlan header in the mirrored frame. + */ + if (eth->h_proto == htons(ETH_P_8021Q)) { + qp = (struct qtag_prefix *)(skb->data + 2 * ETH_ALEN); + vlan_tci = ntohs(qp->tci); + enc_type = ERSPAN_ENCAP_INFRAME; + } + + skb_push(skb, sizeof(*ershdr)); + ershdr = (struct erspanhdr *)skb->data; + memset(ershdr, 0, sizeof(*ershdr)); + + ershdr->ver_vlan = htons((vlan_tci & VLAN_MASK) | + (ERSPAN_VERSION << VER_OFFSET)); + ershdr->session_id = htons((u16)(ntohl(id) & ID_MASK) | + ((tos_to_cos(iphdr->tos) << COS_OFFSET) & COS_MASK) | + (enc_type << EN_OFFSET & EN_MASK) | + ((truncate << T_OFFSET) & T_MASK)); + ershdr->md.index = htonl(index & INDEX_MASK); +} + +static netdev_tx_t erspan_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct ip_tunnel *tunnel = netdev_priv(dev); + bool truncate = false; + + if (gre_handle_offloads(skb, false)) + goto free_skb; + + if (skb_cow_head(skb, dev->needed_headroom)) + goto free_skb; + + if (skb->len > dev->mtu) { + pskb_trim(skb, dev->mtu); + truncate = true; + } + + /* Push ERSPAN header */ + erspan_build_header(skb, tunnel->parms.o_key, tunnel->index, truncate); + tunnel->parms.o_flags &= ~TUNNEL_KEY; + __gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_ERSPAN)); + return NETDEV_TX_OK; + +free_skb: + kfree_skb(skb); + dev->stats.tx_dropped++; + return NETDEV_TX_OK; +} + int ovs_gre_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb) { struct ip_tunnel_info *info = skb_tunnel_info(skb); @@ -503,6 +720,40 @@ static const struct net_device_ops gre_tap_netdev_ops = { #endif }; +static int erspan_tunnel_init(struct net_device *dev) +{ + struct ip_tunnel *tunnel = netdev_priv(dev); + int t_hlen; + + tunnel->tun_hlen = 8; + tunnel->parms.iph.protocol = IPPROTO_GRE; + t_hlen = tunnel->hlen + sizeof(struct iphdr) + sizeof(struct erspanhdr); + + dev->needed_headroom = LL_MAX_HEADER + t_hlen + 4; + dev->mtu = ETH_DATA_LEN - t_hlen - 4; + dev->features |= GRE_FEATURES; + dev->hw_features |= GRE_FEATURES; + dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; + + return ip_tunnel_init(dev); +} + +static const struct net_device_ops erspan_netdev_ops = { + .ndo_init = erspan_tunnel_init, + .ndo_uninit = rpl_ip_tunnel_uninit, + .ndo_start_xmit = erspan_xmit, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = ip_tunnel_change_mtu, + .ndo_get_stats64 = rpl_ip_tunnel_get_stats64, +#ifdef HAVE_NDO_GET_IFLINK + .ndo_get_iflink = rpl_ip_tunnel_get_iflink, +#endif +#ifdef HAVE_NDO_FILL_METADATA_DST + .ndo_fill_metadata_dst = gre_fill_metadata_dst, +#endif +}; + static void ipgre_tap_setup(struct net_device *dev) { ether_setup(dev); @@ -561,6 +812,8 @@ static size_t ipgre_get_size(const struct net_device *dev) nla_total_size(2) + /* IFLA_GRE_COLLECT_METADATA */ nla_total_size(0) + + /* IFLA_GRE_ERSPAN_INDEX */ + nla_total_size(4) + 0; } @@ -582,13 +835,26 @@ static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev) !!(p->iph.frag_off & htons(IP_DF)))) goto nla_put_failure; + if (t->index) + if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, t->index)) + goto nla_put_failure; + return 0; nla_put_failure: return -EMSGSIZE; } -static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = { +static void erspan_setup(struct net_device *dev) +{ + ether_setup(dev); + dev->netdev_ops = &erspan_netdev_ops; + dev->priv_flags &= ~IFF_TX_SKB_SHARING; + dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; + ip_tunnel_setup(dev, erspan_net_id); +} + +static const struct nla_policy ipgre_policy[RPL_IFLA_GRE_MAX + 1] = { [IFLA_GRE_LINK] = { .type = NLA_U32 }, [IFLA_GRE_IFLAGS] = { .type = NLA_U16 }, [IFLA_GRE_OFLAGS] = { .type = NLA_U16 }, @@ -599,11 +865,12 @@ static const struct nla_policy ipgre_policy[IFLA_GRE_MAX + 1] = { [IFLA_GRE_TTL] = { .type = NLA_U8 }, [IFLA_GRE_TOS] = { .type = NLA_U8 }, [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 }, + [IFLA_GRE_ERSPAN_INDEX] = { .type = NLA_U32 }, }; static struct rtnl_link_ops ipgre_tap_ops __read_mostly = { .kind = "ovs_gretap", - .maxtype = IFLA_GRE_MAX, + .maxtype = RPL_IFLA_GRE_MAX, .policy = ipgre_policy, .priv_size = sizeof(struct ip_tunnel), .setup = ipgre_tap_setup, @@ -617,6 +884,22 @@ static struct rtnl_link_ops ipgre_tap_ops __read_mostly = { #endif }; +static struct rtnl_link_ops erspan_link_ops __read_mostly = { + .kind = "erspan", + .maxtype = RPL_IFLA_GRE_MAX, + .policy = ipgre_policy, + .priv_size = sizeof(struct ip_tunnel), + .setup = erspan_setup, + .validate = erspan_validate, + .newlink = ipgre_newlink, + .dellink = ip_tunnel_dellink, + .get_size = ipgre_get_size, + .fill_info = ipgre_fill_info, +#ifdef HAVE_GET_LINK_NET + .get_link_net = ip_tunnel_get_link_net, +#endif +}; + struct net_device *rpl_gretap_fb_dev_create(struct net *net, const char *name, u8 name_assign_type) { @@ -657,6 +940,26 @@ out: } EXPORT_SYMBOL_GPL(rpl_gretap_fb_dev_create); +static int __net_init erspan_init_net(struct net *net) +{ + return ip_tunnel_init_net(net, erspan_net_id, + &erspan_link_ops, "erspan0"); +} + +static void __net_exit erspan_exit_net(struct net *net) +{ + struct ip_tunnel_net *itn = net_generic(net, erspan_net_id); + + ip_tunnel_delete_net(itn, &erspan_link_ops); +} + +static struct pernet_operations erspan_net_ops = { + .init = erspan_init_net, + .exit = erspan_exit_net, + .id = &erspan_net_id, + .size = sizeof(struct ip_tunnel_net), +}; + static int __net_init ipgre_tap_init_net(struct net *net) { return ip_tunnel_init_net(net, gre_tap_net_id, &ipgre_tap_ops, "gretap0"); @@ -684,6 +987,10 @@ int rpl_ipgre_init(void) if (err < 0) goto pnet_tap_faied; + err = register_pernet_device(&erspan_net_ops); + if (err < 0) + goto pnet_erspan_failed; + err = gre_cisco_register(&ipgre_protocol); if (err < 0) { pr_info("%s: can't add protocol\n", __func__); @@ -694,12 +1001,20 @@ int rpl_ipgre_init(void) if (err < 0) goto tap_ops_failed; + err = rtnl_link_register(&erspan_link_ops); + if (err < 0) + goto erspan_link_failed; + pr_info("GRE over IPv4 tunneling driver\n"); return 0; +erspan_link_failed: + rtnl_link_unregister(&ipgre_tap_ops); tap_ops_failed: gre_cisco_unregister(&ipgre_protocol); add_proto_failed: + unregister_pernet_device(&erspan_net_ops); +pnet_erspan_failed: unregister_pernet_device(&ipgre_tap_net_ops); pnet_tap_faied: pr_err("Error while initializing GRE %d\n", err); @@ -709,8 +1024,10 @@ pnet_tap_faied: void rpl_ipgre_fini(void) { rtnl_link_unregister(&ipgre_tap_ops); + rtnl_link_unregister(&erspan_link_ops); gre_cisco_unregister(&ipgre_protocol); unregister_pernet_device(&ipgre_tap_net_ops); + unregister_pernet_device(&erspan_net_ops); } #endif diff --git a/datapath/linux/compat/ip_tunnel.c b/datapath/linux/compat/ip_tunnel.c index be82b55..6e9fa95 100644 --- a/datapath/linux/compat/ip_tunnel.c +++ b/datapath/linux/compat/ip_tunnel.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Nicira, Inc. + * Copyright (c) 2013,2018 Nicira, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -52,7 +51,6 @@ #include #include #include -#include #if IS_ENABLED(CONFIG_IPV6) #include @@ -63,6 +61,9 @@ #include "compat.h" #ifndef USE_UPSTREAM_TUNNEL +const struct ip_tunnel_encap_ops __rcu * + rpl_iptun_encaps[MAX_IPTUN_ENCAP_OPS] __read_mostly; + static void ip_tunnel_add(struct ip_tunnel_net *itn, struct ip_tunnel *t) { if (t->collect_md) @@ -77,6 +78,52 @@ static void ip_tunnel_del(struct ip_tunnel_net *itn, struct ip_tunnel *t) rcu_assign_pointer(itn->collect_md_tun, NULL); } +static struct net_device *__ip_tunnel_create(struct net *net, + const struct rtnl_link_ops *ops, + struct ip_tunnel_parm *parms) +{ + int err; + struct ip_tunnel *tunnel; + struct net_device *dev; + char name[IFNAMSIZ]; + + if (parms->name[0]) + strlcpy(name, parms->name, IFNAMSIZ); + else { + if (strlen(ops->kind) > (IFNAMSIZ - 3)) { + err = -E2BIG; + goto failed; + } + strlcpy(name, ops->kind, IFNAMSIZ); + strncat(name, "%d", 2); + } + + ASSERT_RTNL(); + dev = alloc_netdev(ops->priv_size, name, NET_NAME_UNKNOWN, ops->setup); + if (!dev) { + err = -ENOMEM; + goto failed; + } + dev_net_set(dev, net); + + dev->rtnl_link_ops = ops; + + tunnel = netdev_priv(dev); + tunnel->parms = *parms; + tunnel->net = net; + + err = register_netdevice(dev); + if (err) + goto failed_free; + + return dev; + +failed_free: + free_netdev(dev); +failed: + return ERR_PTR(err); +} + static inline void init_tunnel_flow(struct flowi4 *fl4, int proto, __be32 daddr, __be32 saddr, @@ -162,6 +209,222 @@ int rpl_ip_tunnel_change_mtu(struct net_device *dev, int new_mtu) return rpl___ip_tunnel_change_mtu(dev, new_mtu, true); } +static int rpl_tnl_update_pmtu(struct net_device *dev, struct sk_buff *skb, + struct rtable *rt, __be16 df, + const struct iphdr *inner_iph) +{ + struct ip_tunnel *tunnel = netdev_priv(dev); + int pkt_size = skb->len - tunnel->hlen - dev->hard_header_len; + int mtu; + + if (df) + mtu = dst_mtu(&rt->dst) - dev->hard_header_len + - sizeof(struct iphdr) - tunnel->hlen; + else + mtu = skb_dst(skb) ? dst_mtu(skb_dst(skb)) : dev->mtu; + + if (skb_dst(skb)) + skb_dst(skb)->ops->update_pmtu(skb_dst(skb), NULL, skb, mtu); + + if (skb->protocol == htons(ETH_P_IP)) { + if (!skb_is_gso(skb) && + (inner_iph->frag_off & htons(IP_DF)) && + mtu < pkt_size) { + memset(IPCB(skb), 0, sizeof(*IPCB(skb))); + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); + return -E2BIG; + } + } +#if IS_ENABLED(CONFIG_IPV6) + else if (skb->protocol == htons(ETH_P_IPV6)) { + struct rt6_info *rt6 = (struct rt6_info *)skb_dst(skb); + + if (rt6 && mtu < dst_mtu(skb_dst(skb)) && + mtu >= IPV6_MIN_MTU) { + if ((tunnel->parms.iph.daddr && + !ipv4_is_multicast(tunnel->parms.iph.daddr)) || + rt6->rt6i_dst.plen == 128) { + rt6->rt6i_flags |= RTF_MODIFIED; + dst_metric_set(skb_dst(skb), RTAX_MTU, mtu); + } + } + + if (!skb_is_gso(skb) && mtu >= IPV6_MIN_MTU && + mtu < pkt_size) { + icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); + return -E2BIG; + } + } +#endif + return 0; +} + +void rpl_ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, + const struct iphdr *tnl_params, const u8 protocol) +{ + struct ip_tunnel *tunnel = netdev_priv(dev); + const struct iphdr *inner_iph; + struct flowi4 fl4; + u8 tos, ttl; + __be16 df; + struct rtable *rt; /* Route to the other host */ + unsigned int max_headroom; /* The extra header space needed */ + __be32 dst; + bool connected; + + inner_iph = (const struct iphdr *)skb_inner_network_header(skb); + connected = (tunnel->parms.iph.daddr != 0); + + dst = tnl_params->daddr; + if (dst == 0) { + /* NBMA tunnel */ + + if (skb_dst(skb) == NULL) { + dev->stats.tx_fifo_errors++; + goto tx_error; + } + + if (skb->protocol == htons(ETH_P_IP)) { + rt = skb_rtable(skb); + dst = rt_nexthop(rt, inner_iph->daddr); + } +#if IS_ENABLED(CONFIG_IPV6) + else if (skb->protocol == htons(ETH_P_IPV6)) { + const struct in6_addr *addr6; + struct neighbour *neigh; + bool do_tx_error_icmp; + int addr_type; + + neigh = dst_neigh_lookup(skb_dst(skb), + &ipv6_hdr(skb)->daddr); + if (neigh == NULL) + goto tx_error; + + addr6 = (const struct in6_addr *)&neigh->primary_key; + addr_type = ipv6_addr_type(addr6); + + if (addr_type == IPV6_ADDR_ANY) { + addr6 = &ipv6_hdr(skb)->daddr; + addr_type = ipv6_addr_type(addr6); + } + + if ((addr_type & IPV6_ADDR_COMPATv4) == 0) + do_tx_error_icmp = true; + else { + do_tx_error_icmp = false; + dst = addr6->s6_addr32[3]; + } + neigh_release(neigh); + if (do_tx_error_icmp) + goto tx_error_icmp; + } +#endif + else + goto tx_error; + + connected = false; + } + + tos = tnl_params->tos; + if (tos & 0x1) { + tos &= ~0x1; + if (skb->protocol == htons(ETH_P_IP)) { + tos = inner_iph->tos; + connected = false; + } else if (skb->protocol == htons(ETH_P_IPV6)) { + tos = ipv6_get_dsfield((const struct ipv6hdr *)inner_iph); + connected = false; + } + } + + init_tunnel_flow(&fl4, protocol, dst, tnl_params->saddr, + tunnel->parms.o_key, RT_TOS(tos), tunnel->parms.link); + + if (ovs_ip_tunnel_encap(skb, tunnel, &protocol, &fl4) < 0) + goto tx_error; + + rt = connected ? dst_cache_get_ip4(&tunnel->dst_cache, &fl4.saddr) : + NULL; + + if (!rt) { + rt = ip_route_output_key(tunnel->net, &fl4); + + if (IS_ERR(rt)) { + dev->stats.tx_carrier_errors++; + goto tx_error; + } + if (connected) + dst_cache_set_ip4(&tunnel->dst_cache, &rt->dst, + fl4.saddr); + } + + if (rt->dst.dev == dev) { + ip_rt_put(rt); + dev->stats.collisions++; + goto tx_error; + } + + if (rpl_tnl_update_pmtu(dev, skb, rt, + tnl_params->frag_off, inner_iph)) { + ip_rt_put(rt); + goto tx_error; + } + + if (tunnel->err_count > 0) { + if (time_before(jiffies, + tunnel->err_time + IPTUNNEL_ERR_TIMEO)) { + tunnel->err_count--; + + memset(IPCB(skb), 0, sizeof(*IPCB(skb))); + dst_link_failure(skb); + } else + tunnel->err_count = 0; + } + + tos = ip_tunnel_ecn_encap(tos, inner_iph, skb); + ttl = tnl_params->ttl; + if (ttl == 0) { + if (skb->protocol == htons(ETH_P_IP)) + ttl = inner_iph->ttl; +#if IS_ENABLED(CONFIG_IPV6) + else if (skb->protocol == htons(ETH_P_IPV6)) + ttl = ((const struct ipv6hdr *)inner_iph)->hop_limit; +#endif + else + ttl = ip4_dst_hoplimit(&rt->dst); + } + + df = tnl_params->frag_off; + if (skb->protocol == htons(ETH_P_IP)) + df |= (inner_iph->frag_off&htons(IP_DF)); + + max_headroom = LL_RESERVED_SPACE(rt->dst.dev) + sizeof(struct iphdr) + + rt->dst.header_len; + if (max_headroom > dev->needed_headroom) + dev->needed_headroom = max_headroom; + + if (skb_cow_head(skb, dev->needed_headroom)) { + ip_rt_put(rt); + dev->stats.tx_dropped++; + kfree_skb(skb); + return; + } + + iptunnel_xmit(skb->sk, rt, skb, fl4.saddr, fl4.daddr, protocol, + tos, ttl, df, !net_eq(tunnel->net, dev_net(dev))); + + return; + +#if IS_ENABLED(CONFIG_IPV6) +tx_error_icmp: + dst_link_failure(skb); +#endif +tx_error: + dev->stats.tx_errors++; + kfree_skb(skb); +} +EXPORT_SYMBOL_GPL(rpl_ip_tunnel_xmit); + static void ip_tunnel_dev_free(struct net_device *dev) { free_percpu(dev->tstats); @@ -181,7 +444,7 @@ void rpl_ip_tunnel_dellink(struct net_device *dev) ip_tunnel_del(itn, netdev_priv(dev)); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) - unregister_netdevice_queue(dev, head); + unregister_netdevice_queue(dev, head); #endif } @@ -189,10 +452,34 @@ int rpl_ip_tunnel_init_net(struct net *net, int ip_tnl_net_id, struct rtnl_link_ops *ops, char *devname) { struct ip_tunnel_net *itn = net_generic(net, ip_tnl_net_id); + struct ip_tunnel_parm parms; + unsigned int i; - itn->collect_md_tun = NULL; - itn->rtnl_ops = ops; - return 0; + for (i = 0; i < IP_TNL_HASH_SIZE; i++) + INIT_HLIST_HEAD(&itn->tunnels[i]); + + if (!ops) { + itn->fb_tunnel_dev = NULL; + return 0; + } + + memset(&parms, 0, sizeof(parms)); + if (devname) + strlcpy(parms.name, devname, IFNAMSIZ); + + rtnl_lock(); + itn->fb_tunnel_dev = __ip_tunnel_create(net, ops, &parms); + /* FB netdevice is special: we have one, and only one per netns. + * * Allowing to move it to another netns is clearly unsafe. + * */ + if (!IS_ERR(itn->fb_tunnel_dev)) { + itn->fb_tunnel_dev->features |= NETIF_F_NETNS_LOCAL; + itn->fb_tunnel_dev->mtu = ip_tunnel_bind_dev(itn->fb_tunnel_dev); + ip_tunnel_add(itn, netdev_priv(itn->fb_tunnel_dev)); + } + rtnl_unlock(); + + return PTR_ERR_OR_ZERO(itn->fb_tunnel_dev); } static void ip_tunnel_destroy(struct ip_tunnel_net *itn, struct list_head *head, @@ -257,20 +544,41 @@ int rpl_ip_tunnel_init(struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); struct iphdr *iph = &tunnel->parms.iph; + int err; - dev->destructor = ip_tunnel_dev_free; - dev->tstats = (typeof(dev->tstats)) netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); +#ifndef HAVE_NEEDS_FREE_NETDEV + dev->destructor = ip_tunnel_dev_free; +#else + dev->needs_free_netdev = true; + dev->priv_destructor = ip_tunnel_dev_free; +#endif + dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); if (!dev->tstats) return -ENOMEM; + + err = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL); + if (err) { + free_percpu(dev->tstats); + return err; + } + + err = gro_cells_init(&tunnel->gro_cells, dev); + if (err) { + dst_cache_destroy(&tunnel->dst_cache); + free_percpu(dev->tstats); + return err; + } + tunnel->dev = dev; tunnel->net = dev_net(dev); strcpy(tunnel->parms.name, dev->name); iph->version = 4; iph->ihl = 5; - if (tunnel->collect_md) + if (tunnel->collect_md) { dev->features |= NETIF_F_NETNS_LOCAL; - + netif_keep_dst(dev); + } return 0; } @@ -306,4 +614,113 @@ struct net *rpl_ip_tunnel_get_link_net(const struct net_device *dev) return tunnel->net; } +static unsigned int rpl_ip_tunnel_hash(__be32 key, __be32 remote) +{ + return hash_32((__force u32)key ^ (__force u32)remote, + IP_TNL_HASH_BITS); +} + +static bool rpl_ip_tunnel_key_match(const struct ip_tunnel_parm *p, + __be16 flags, __be32 key) +{ + if (p->i_flags & TUNNEL_KEY) { + if (flags & TUNNEL_KEY) + return key == p->i_key; + else + /* key expected, none present */ + return false; + } else + return !(flags & TUNNEL_KEY); +} + +struct ip_tunnel *rpl_ip_tunnel_lookup(struct ip_tunnel_net *itn, + int link, __be16 flags, + __be32 remote, __be32 local, + __be32 key) +{ + unsigned int hash; + struct ip_tunnel *t, *cand = NULL; + struct hlist_head *head; + + hash = rpl_ip_tunnel_hash(key, remote); + head = &itn->tunnels[hash]; + + hlist_for_each_entry_rcu(t, head, hash_node) { + if (local != t->parms.iph.saddr || + remote != t->parms.iph.daddr || + !(t->dev->flags & IFF_UP)) + continue; + + if (!rpl_ip_tunnel_key_match(&t->parms, flags, key)) + continue; + + if (t->parms.link == link) + return t; + else + cand = t; + } + + hlist_for_each_entry_rcu(t, head, hash_node) { + if (remote != t->parms.iph.daddr || + t->parms.iph.saddr != 0 || + !(t->dev->flags & IFF_UP)) + continue; + + if (!rpl_ip_tunnel_key_match(&t->parms, flags, key)) + continue; + + if (t->parms.link == link) + return t; + else if (!cand) + cand = t; + } + + hash = rpl_ip_tunnel_hash(key, 0); + head = &itn->tunnels[hash]; + + hlist_for_each_entry_rcu(t, head, hash_node) { + if ((local != t->parms.iph.saddr || t->parms.iph.daddr != 0) && + (local != t->parms.iph.daddr || !ipv4_is_multicast(local))) + continue; + + if (!(t->dev->flags & IFF_UP)) + continue; + + if (!rpl_ip_tunnel_key_match(&t->parms, flags, key)) + continue; + + if (t->parms.link == link) + return t; + else if (!cand) + cand = t; + } + + if (flags & TUNNEL_NO_KEY) + goto skip_key_lookup; + + hlist_for_each_entry_rcu(t, head, hash_node) { + if (t->parms.i_key != key || + t->parms.iph.saddr != 0 || + t->parms.iph.daddr != 0 || + !(t->dev->flags & IFF_UP)) + continue; + + if (t->parms.link == link) + return t; + else if (!cand) + cand = t; + } + +skip_key_lookup: + if (cand) + return cand; + + if (itn->fb_tunnel_dev && itn->fb_tunnel_dev->flags & IFF_UP) + return netdev_priv(itn->fb_tunnel_dev); + + + return NULL; +} +EXPORT_SYMBOL_GPL(rpl_ip_tunnel_lookup); + #endif diff --git a/datapath/linux/compat/ip_tunnels_core.c b/datapath/linux/compat/ip_tunnels_core.c index 7ade6c1..90e838a 100644 --- a/datapath/linux/compat/ip_tunnels_core.c +++ b/datapath/linux/compat/ip_tunnels_core.c @@ -129,6 +129,47 @@ error: } EXPORT_SYMBOL_GPL(ovs_iptunnel_handle_offloads); +struct sk_buff *rpl_iptunnel_handle_offloads(struct sk_buff *skb, + bool csum_help, + int gso_type_mask) +{ + int err; + + if (likely(!skb->encapsulation)) { + skb_reset_inner_headers(skb); + skb->encapsulation = 1; + } + + if (skb_is_gso(skb)) { + err = skb_unclone(skb, GFP_ATOMIC); + if (unlikely(err)) + goto error; + skb_shinfo(skb)->gso_type |= gso_type_mask; + return skb; + } + + /* If packet is not gso and we are resolving any partial checksum, + * clear encapsulation flag. This allows setting CHECKSUM_PARTIAL + * on the outer header without confusing devices that implement + * NETIF_F_IP_CSUM with encapsulation. + */ + if (csum_help) + skb->encapsulation = 0; + + if (skb->ip_summed == CHECKSUM_PARTIAL && csum_help) { + err = skb_checksum_help(skb); + if (unlikely(err)) + goto error; + } else if (skb->ip_summed != CHECKSUM_PARTIAL) + skb->ip_summed = CHECKSUM_NONE; + + return skb; +error: + kfree_skb(skb); + return ERR_PTR(err); +} +EXPORT_SYMBOL_GPL(rpl_iptunnel_handle_offloads); + int rpl___iptunnel_pull_header(struct sk_buff *skb, int hdr_len, __be16 inner_proto, bool raw_proto, bool xnet) { From patchwork Thu Mar 22 22:07:18 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Rose X-Patchwork-Id: 889669 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="sjL/Rbl+"; 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 406gm15CYkz9s0y for ; Fri, 23 Mar 2018 09:08:17 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 7D41FDE6; Thu, 22 Mar 2018 22:07:51 +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 8D2BCDE6 for ; Thu, 22 Mar 2018 22:07:50 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pl0-f65.google.com (mail-pl0-f65.google.com [209.85.160.65]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 37AEB5D3 for ; Thu, 22 Mar 2018 22:07:50 +0000 (UTC) Received: by mail-pl0-f65.google.com with SMTP id n15-v6so6198303plp.12 for ; Thu, 22 Mar 2018 15:07:50 -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=yzeR6IrkrSMn8U57rlaBVon/A4K9fKNh9aDRFdpAtJw=; b=sjL/Rbl+Q5fDF6ZjySzDwNCkODwhDe57/DxbTdUyfer4bCJQmPjjTsx4Yiu0XRHLFt pKsw4c9grEpAjTLs9kGRRe2Rlel/OSTf+voTi9azSmcgewzIdBvd/tOrMqjSLBhggAd+ EUnRIglMSivpBs1j9LSWGgsl3OlEUjxW9K7C1ye0tnwZg0rCU+rbNVLbInw4xto2bn2g FKe10ZbGSsgeUNB3teRJ6uLjBUsRB8Q+KzyhwEVfmMBCurTTzWzo4GtQRAVTbSKdva+2 8cl4DCtkLQi0WL8EfZ3aRtBJUYnqD9EMiTRcCepZYd3wMSwH+3Z6yKODOf+BBA64sB3S TugQ== 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=yzeR6IrkrSMn8U57rlaBVon/A4K9fKNh9aDRFdpAtJw=; b=OIUrEFraY4QuR3byDk7XL9+tSeghy7C4XZ/FHz8aCeXIcUBBuwfAuglSVVjCTe2eIQ w/kxXOXIrAEovD4M7OHgBJZKR6sS7a+6x66h4YXLYviQ6OffpKrMgB4Mwaw1c7u+5SuY M50I6YG76Q+uN5YmZGRh8iIgOSCM5EvoReW1VDgtpNCYydmV9VZFhNZeUTvZYD7hLmuJ xeBBa+VCKoaStq5mJ7WlOrM/5LLnrHsokyuj+zxGSlOqv1Htfh2qwtFKPAPt0aE6hVBS smloFcYdoWzNRaBOEuCS9gC5GkLK45D4JZDIC0xQnWlwwW7pRlqKHKfIP9j0ksSYcsDO V4ZQ== X-Gm-Message-State: AElRT7HvZKqbR2EBRihdqVsZ4V5GUzZ5HyQiqOE9tZbs5XE8+Ft5u/fW FGqqp70F04tMqTD3dwcHy8uekA== X-Google-Smtp-Source: AG47ELuDrWkFdnCoeh7ihFhlyEgvEsd949siGb+y42THnIpieKpo/C3IU0Q5Zs67OH/Zo5AVOVXzdg== X-Received: by 2002:a17:902:158b:: with SMTP id m11-v6mr26558830pla.300.1521756469374; Thu, 22 Mar 2018 15:07:49 -0700 (PDT) Received: from gizo.domain (184-100-240-187.ptld.qwest.net. [184.100.240.187]) by smtp.gmail.com with ESMTPSA id 4sm2280775pfn.32.2018.03.22.15.07.48 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Mar 2018 15:07:48 -0700 (PDT) From: Greg Rose To: dev@openvswitch.org Date: Thu, 22 Mar 2018 15:07:18 -0700 Message-Id: <1521756461-3870-3-git-send-email-gvrose8192@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1521756461-3870-1-git-send-email-gvrose8192@gmail.com> References: <1521756461-3870-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] [ERSPAN RFC 02/25] gre: fix goto statement typo 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 From: William Tu Upstream commit: commit e3d0328c76dde0b957f62f8c407b79f1d8fe3ef8 Author: William Tu Date: Tue Aug 22 17:04:05 2017 -0700 gre: fix goto statement typo Fix typo: pnet_tap_faied. Signed-off-by: William Tu Signed-off-by: David S. Miller Cc: William Tu Signed-off-by: Greg Rose --- datapath/linux/compat/ip_gre.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index a82808a..1bed8c5 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -985,7 +985,7 @@ int rpl_ipgre_init(void) err = register_pernet_device(&ipgre_tap_net_ops); if (err < 0) - goto pnet_tap_faied; + goto pnet_tap_failed; err = register_pernet_device(&erspan_net_ops); if (err < 0) @@ -1016,7 +1016,7 @@ add_proto_failed: unregister_pernet_device(&erspan_net_ops); pnet_erspan_failed: unregister_pernet_device(&ipgre_tap_net_ops); -pnet_tap_faied: +pnet_tap_failed: pr_err("Error while initializing GRE %d\n", err); return err; } From patchwork Thu Mar 22 22:07:19 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Rose X-Patchwork-Id: 889670 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="qF1h24TO"; 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 406gmS1TNVz9s0y for ; Fri, 23 Mar 2018 09:08:40 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 64001E31; Thu, 22 Mar 2018 22:07:52 +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 B761BE25 for ; Thu, 22 Mar 2018 22:07:51 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pl0-f68.google.com (mail-pl0-f68.google.com [209.85.160.68]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 74A665D4 for ; Thu, 22 Mar 2018 22:07:51 +0000 (UTC) Received: by mail-pl0-f68.google.com with SMTP id b7-v6so6207401plr.8 for ; Thu, 22 Mar 2018 15:07:51 -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=XsTf1GZufb3QqwlmkxIE38zlzSRURbr7db/f7V/4KSk=; b=qF1h24TOc8huRWxFDQOh+rXMCeUgBjTcTnkc2XP7cma19JYwc4opp6U80j6J/pWrJJ U6dDqmqL+edEYoIot7gJGPFqNXgT+ZFGZI2RV1PkZr4H6/KB4ou+mX4cLaAYIoUplnCL yzRNWfuju7bVKWpg/3fYMgLGoMNSfBsuLXfoqWbYuwcWUpHInLXUrz+APSj3QWN2McwN qPPcRx0dXCseM6YGAAiETpKksktV6+ne6G/T2BpRPKn28EOXy6MmlIABWSCQgGJ1ybsM BWrtSFnPo/rJzPS98vygL2wGAEweUcm35aY8ZxNvJf9uqnTQEgVXmrYOuP47XXTh0vnQ q1+g== 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=XsTf1GZufb3QqwlmkxIE38zlzSRURbr7db/f7V/4KSk=; b=NSP6/wlLGaAOa30pE/quU9xpr9EazwUskn5tlm/wcP6KDs6BkpoaddD+3Pz19Wgb5b 5vcygpfkGH6WHeZxvD78gUt1vDs/7T39919AjF3hrqqxEJ/zzBY6RSSX8QtkLaY/KEH7 hxmREnytYjKtxJzIFxAv6/q2/knYzcndwv6V3DtLDtriCsVMJfJ2K28rdgpPBGSX6KQe 0MpdvgaPCU+tLfqJE2HheMGMwUbIcjxKL4wD1WaF6+8078l5o9Hq8LHlt+aKzbiWLb6f V/iXJy58CG9fdrU9NjqVssZAd6UtNZ3anYhIAKDKm0QzwdvwdYg5DCeK9t532k3V01JF mVlg== X-Gm-Message-State: AElRT7EeW6NT4NaDmLE58hzDrInH8Wyho3JgD5uElOAIEnAQ5K/wCyCh Od+uCAlU3qe4ubVHLywufB0l2w== X-Google-Smtp-Source: AG47ELtrMankRAbFXj5Yl1h96XLA1JAfwDnXVvaEixCi7FDvcdC76RGpcDr9Strjf28sc7sydLcxtQ== X-Received: by 2002:a17:902:536c:: with SMTP id b99-v6mr18875353pli.399.1521756470737; Thu, 22 Mar 2018 15:07:50 -0700 (PDT) Received: from gizo.domain (184-100-240-187.ptld.qwest.net. [184.100.240.187]) by smtp.gmail.com with ESMTPSA id 4sm2280775pfn.32.2018.03.22.15.07.49 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Mar 2018 15:07:49 -0700 (PDT) From: Greg Rose To: dev@openvswitch.org Date: Thu, 22 Mar 2018 15:07:19 -0700 Message-Id: <1521756461-3870-4-git-send-email-gvrose8192@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1521756461-3870-1-git-send-email-gvrose8192@gmail.com> References: <1521756461-3870-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] [ERSPAN RFC 03/25] gre: refactor the gre_fb_xmit 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 From: William Tu Upstream commit: commit 862a03c35ed76c50a562f7406ad23315f7862642 Author: William Tu Date: Fri Aug 25 09:21:27 2017 -0700 gre: refactor the gre_fb_xmit The patch refactors the gre_fb_xmit function, by creating prepare_fb_xmit function for later ERSPAN collect_md mode patch. Signed-off-by: William Tu Signed-off-by: David S. Miller Only the prepare_fb_xmit() function is pulled in. Compatibility issues prevent the refactor of gre_fb_xmit() but we need the prepare_fb_xmit() function for the subsequent patch. Cc: William Tu Signed-off-by: Greg Rose --- datapath/linux/compat/ip_gre.c | 48 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index 1bed8c5..d25d2df 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -369,6 +369,54 @@ static struct rtable *gre_get_rt(struct sk_buff *skb, return ip_route_output_key(net, fl); } +static struct rtable *prepare_fb_xmit(struct sk_buff *skb, + struct net_device *dev, + struct flowi4 *fl, + int tunnel_hlen) +{ + struct ip_tunnel_info *tun_info; + const struct ip_tunnel_key *key; + struct rtable *rt = NULL; + int min_headroom; + bool use_cache; + int err; + + tun_info = skb_tunnel_info(skb); + key = &tun_info->key; + use_cache = ip_tunnel_dst_cache_usable(skb, tun_info); + + if (use_cache) + rt = dst_cache_get_ip4(&tun_info->dst_cache, &fl->saddr); + if (!rt) { + rt = gre_get_rt(skb, dev, fl, key); + if (IS_ERR(rt)) + goto err_free_skb; + if (use_cache) + dst_cache_set_ip4(&tun_info->dst_cache, &rt->dst, + fl->saddr); + } + + min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len + + tunnel_hlen + sizeof(struct iphdr); + if (skb_headroom(skb) < min_headroom || skb_header_cloned(skb)) { + int head_delta = SKB_DATA_ALIGN(min_headroom - + skb_headroom(skb) + + 16); + err = pskb_expand_head(skb, max_t(int, head_delta, 0), + 0, GFP_ATOMIC); + if (unlikely(err)) + goto err_free_rt; + } + return rt; + +err_free_rt: + ip_rt_put(rt); +err_free_skb: + kfree_skb(skb); + dev->stats.tx_dropped++; + return NULL; +} + netdev_tx_t rpl_gre_fb_xmit(struct sk_buff *skb) { struct net_device *dev = skb->dev; From patchwork Thu Mar 22 22:07:20 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Rose X-Patchwork-Id: 889671 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="pqeiMvwI"; 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 406gmz68H3z9s0y for ; Fri, 23 Mar 2018 09:09:07 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 5E3DCE6B; Thu, 22 Mar 2018 22:07:55 +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 0611CE38 for ; Thu, 22 Mar 2018 22:07:54 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pl0-f67.google.com (mail-pl0-f67.google.com [209.85.160.67]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 634945D3 for ; Thu, 22 Mar 2018 22:07:53 +0000 (UTC) Received: by mail-pl0-f67.google.com with SMTP id n15-v6so6198394plp.12 for ; Thu, 22 Mar 2018 15:07:53 -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=nIINX12vwgdg0QXc+QYvIXhucB+EkCvqi8TLqgUTNuU=; b=pqeiMvwIyz+W6s4C5aeXVUJ1f4TN58wuuH68sZq1xuOQ3C15nj8Mj6zrq//lrBY7BO c1mEsDGWQGlZ7IM3nqHeGKRuRDU1E7KVBXEFiOLbQdZ4rtMa8ateA3b3iRUqZ4ilmK7S AxW6vckx+oKZ3EuEjChT9o0AzHM5AQel0lVqNnC+e5mEhBmVmfLoqo52QRgwL5VzPDLh 5t5bRYtvRL1GQlTi01nUsTqG2V2mYK/dWOLO4cSkR0O5zt6mIJnL3Y/4dVQIcuYdW7ad iqgriBkpLb+omvCxY41OFGeZT2rDDTdgPfxf6Hl/hMxQ+G1XbyaO7ljGl1/D4gfzPDF6 XyZg== 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=nIINX12vwgdg0QXc+QYvIXhucB+EkCvqi8TLqgUTNuU=; b=j5GUqXqmZYbH2EmbuuSY+Y4O00QPXESzre8XCqotYuiBAtb0uQQgpDEXGwilrA7U4f ZmaXKoXntLARc2DgTtrkGN1bw++h6SDCVRWQ/R/OX+ijXCZm99b562CojfICYzI7vq1d nSIuQmd94udVOBd1dFe1AMvZ4hLwxTHPZ3eIZJqRZk8juMcf48RLgu75999gEWqZy7rB LM/+Up0rguNgUmjGSR1NEJG3+Pdh+1/AmgiLv4WtxRKEAegchnPbZes3t5L+YDaSl40H wQBnZ4F8I4xgWpCFLn/pprdgnWeMB+74AUIRaweiyBcXK0Qx+ThRlDqMkcT8E0/81U6o AmbQ== X-Gm-Message-State: AElRT7EvmsmECYXqf0sRaHkV7sMcorHaVQZHosU6nASTthMTlIu/LfzM eZzHEv4VGi79kbLfscRU+hH5eQ== X-Google-Smtp-Source: AG47ELtUS3ZT7sd+5j/Zq50YO4yHRbXaqXDBqHAagqOa+oe2V6wDBEcYdSdX9Q9NOVGU+lRrmPp6ag== X-Received: by 2002:a17:902:7290:: with SMTP id d16-v6mr26520681pll.31.1521756472556; Thu, 22 Mar 2018 15:07:52 -0700 (PDT) Received: from gizo.domain (184-100-240-187.ptld.qwest.net. [184.100.240.187]) by smtp.gmail.com with ESMTPSA id 4sm2280775pfn.32.2018.03.22.15.07.50 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Mar 2018 15:07:51 -0700 (PDT) From: Greg Rose To: dev@openvswitch.org Date: Thu, 22 Mar 2018 15:07:20 -0700 Message-Id: <1521756461-3870-5-git-send-email-gvrose8192@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1521756461-3870-1-git-send-email-gvrose8192@gmail.com> References: <1521756461-3870-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] [ERSPAN RFC 04/25] compat/gre: add collect_md mode 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 From: William Tu commit 1a66a836da630cd70f3639208da549b549ce576b Author: William Tu Date: Fri Aug 25 09:21:28 2017 -0700 gre: add collect_md mode to ERSPAN tunnel Similar to gre, vxlan, geneve, ipip tunnels, allow ERSPAN tunnels to operate in 'collect metadata' mode. bpf_skb_[gs]et_tunnel_key() helpers can make use of it right away. OVS can use it as well in the future. Signed-off-by: William Tu Signed-off-by: David S. Miller With some adjustments for compatibility layer. Cc: William Tu Signed-off-by: Greg Rose --- datapath/linux/compat/include/net/ip_tunnels.h | 68 ++++++++------ datapath/linux/compat/ip_gre.c | 117 ++++++++++++++++++++++--- 2 files changed, 146 insertions(+), 39 deletions(-) diff --git a/datapath/linux/compat/include/net/ip_tunnels.h b/datapath/linux/compat/include/net/ip_tunnels.h index e3fb13b..159eb48 100644 --- a/datapath/linux/compat/include/net/ip_tunnels.h +++ b/datapath/linux/compat/include/net/ip_tunnels.h @@ -74,14 +74,25 @@ void rpl_ip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev, #ifndef TUNNEL_CSUM -#define TUNNEL_CSUM __cpu_to_be16(0x01) -#define TUNNEL_ROUTING __cpu_to_be16(0x02) -#define TUNNEL_KEY __cpu_to_be16(0x04) -#define TUNNEL_SEQ __cpu_to_be16(0x08) -#define TUNNEL_STRICT __cpu_to_be16(0x10) -#define TUNNEL_REC __cpu_to_be16(0x20) -#define TUNNEL_VERSION __cpu_to_be16(0x40) -#define TUNNEL_NO_KEY __cpu_to_be16(0x80) +#define TUNNEL_CSUM __cpu_to_be16(0x01) +#define TUNNEL_ROUTING __cpu_to_be16(0x02) +#define TUNNEL_KEY __cpu_to_be16(0x04) +#define TUNNEL_SEQ __cpu_to_be16(0x08) +#define TUNNEL_STRICT __cpu_to_be16(0x10) +#define TUNNEL_REC __cpu_to_be16(0x20) +#define TUNNEL_VERSION __cpu_to_be16(0x40) +#define TUNNEL_NO_KEY __cpu_to_be16(0x80) +#define TUNNEL_DONT_FRAGMENT __cpu_to_be16(0x0100) +#define TUNNEL_OAM __cpu_to_be16(0x0200) +#define TUNNEL_CRIT_OPT __cpu_to_be16(0x0400) +#define TUNNEL_GENEVE_OPT __cpu_to_be16(0x0800) +#define TUNNEL_VXLAN_OPT __cpu_to_be16(0x1000) +#define TUNNEL_NOCACHE __cpu_to_be16(0x2000) +#define TUNNEL_ERSPAN_OPT __cpu_to_be16(0x4000) + +#undef TUNNEL_OPTIONS_PRESENT +#define TUNNEL_OPTIONS_PRESENT \ + (TUNNEL_GENEVE_OPT | TUNNEL_VXLAN_OPT | TUNNEL_ERSPAN_OPT) struct tnl_ptk_info { __be16 flags; @@ -100,27 +111,6 @@ struct tnl_ptk_info { #define IP_TNL_HASH_BITS 7 #define IP_TNL_HASH_SIZE (1 << IP_TNL_HASH_BITS) -#ifndef TUNNEL_DONT_FRAGMENT -#define TUNNEL_DONT_FRAGMENT __cpu_to_be16(0x0100) -#endif - -#ifndef TUNNEL_OAM -#define TUNNEL_OAM __cpu_to_be16(0x0200) -#define TUNNEL_CRIT_OPT __cpu_to_be16(0x0400) -#endif - -#ifndef TUNNEL_GENEVE_OPT -#define TUNNEL_GENEVE_OPT __cpu_to_be16(0x0800) -#endif - -#ifndef TUNNEL_VXLAN_OPT -#define TUNNEL_VXLAN_OPT __cpu_to_be16(0x1000) -#endif - -/* Older kernels defined TUNNEL_OPTIONS_PRESENT to GENEVE only */ -#undef TUNNEL_OPTIONS_PRESENT -#define TUNNEL_OPTIONS_PRESENT (TUNNEL_GENEVE_OPT | TUNNEL_VXLAN_OPT) - /* Keep error state on tunnel for 30 sec */ #define IPTUNNEL_ERR_TIMEO (30*HZ) @@ -243,6 +233,7 @@ static inline void ip_tunnel_key_init(struct ip_tunnel_key *key, #define ip_tunnel_collect_metadata() true #if LINUX_VERSION_CODE < KERNEL_VERSION(4,6,0) +#undef TUNNEL_NOCACHE #define TUNNEL_NOCACHE 0 static inline bool @@ -420,6 +411,25 @@ static inline void iptunnel_xmit_stats(struct net_device *dev, int pkt_len) } } +static inline __be64 key32_to_tunnel_id(__be32 key) +{ +#ifdef __BIG_ENDIAN + return (__force __be64)key; +#else + return (__force __be64)((__force u64)key << 32); +#endif +} + +/* Returns the least-significant 32 bits of a __be64. */ +static inline __be32 tunnel_id_to_key32(__be64 tun_id) +{ +#ifdef __BIG_ENDIAN + return (__force __be32)tun_id; +#else + return (__force __be32)((__force u64)tun_id >> 32); +#endif +} + #define ip_tunnel_init rpl_ip_tunnel_init int rpl_ip_tunnel_init(struct net_device *dev); diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index d25d2df..d0f112d 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -122,6 +122,9 @@ static __be32 tunnel_id_to_key(__be64 x) #endif } +static void erspan_build_header(struct sk_buff *skb, + __be32 id, u32 index, bool truncate); + /* Called with rcu_read_lock and BH disabled. */ static int gre_err(struct sk_buff *skb, u32 info, const struct tnl_ptk_info *tpi) @@ -133,7 +136,7 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, int gre_hdr_len) { struct net *net = dev_net(skb->dev); - struct metadata_dst *tun_dst = NULL; + struct metadata_dst tun_dst; struct ip_tunnel_net *itn; struct ip_tunnel *tunnel; struct erspanhdr *ershdr; @@ -169,9 +172,33 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, false, false) < 0) goto drop; - tunnel->index = ntohl(index); + if (tunnel->collect_md) { + struct ip_tunnel_info *info; + struct erspan_metadata *md; + __be64 tun_id; + __be16 flags; + + tpi->flags |= TUNNEL_KEY; + flags = tpi->flags; + tun_id = key32_to_tunnel_id(tpi->key); + + ovs_ip_tun_rx_dst(&tun_dst, skb, flags, + tun_id, sizeof(*md)); + + md = ip_tunnel_info_opts(&tun_dst.u.tun_info); + if (!md) + return PACKET_REJECT; + + md->index = index; + info = &tun_dst.u.tun_info; + info->key.tun_flags |= TUNNEL_ERSPAN_OPT; + info->options_len = sizeof(*md); + } else { + tunnel->index = ntohl(index); + } + skb_reset_mac_header(skb); - ovs_ip_tunnel_rcv(tunnel->dev, skb, tun_dst); + ovs_ip_tunnel_rcv(tunnel->dev, skb, &tun_dst); return PACKET_RCVD; } drop: @@ -484,6 +511,72 @@ err_free_skb: } EXPORT_SYMBOL(rpl_gre_fb_xmit); + + +static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev, + __be16 proto) +{ + struct ip_tunnel *tunnel = netdev_priv(dev); + struct ip_tunnel_info *tun_info; + const struct ip_tunnel_key *key; + struct erspan_metadata *md; + struct rtable *rt = NULL; + struct tnl_ptk_info tpi; + bool truncate = false; + struct flowi4 fl; + int tunnel_hlen; + __be16 df; + + tun_info = skb_tunnel_info(skb); + if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) || + ip_tunnel_info_af(tun_info) != AF_INET)) + goto err_free_skb; + + key = &tun_info->key; + + /* ERSPAN has fixed 8 byte GRE header */ + tunnel_hlen = 8 + sizeof(struct erspanhdr); + + rt = prepare_fb_xmit(skb, dev, &fl, tunnel_hlen); + if (!rt) + return; + + if (gre_handle_offloads(skb, false)) + goto err_free_rt; + + if (skb->len > dev->mtu) { + pskb_trim(skb, dev->mtu); + truncate = true; + } + + md = ip_tunnel_info_opts(tun_info); + if (!md) + goto err_free_rt; + + erspan_build_header(skb, tunnel_id_to_key32(key->tun_id), + ntohl(md->index), truncate); + + tpi.flags = (TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_SEQ); + tpi.proto = htons(ETH_P_ERSPAN); + tpi.key = tunnel_id_to_key32(key->tun_id); + tpi.seq = htonl(tunnel->o_seqno++); + tpi.hdr_len = 8; + + gre_build_header(skb, &tpi, 8); + + df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0; + + iptunnel_xmit(skb->sk, rt, skb, fl.saddr, key->u.ipv4.dst, IPPROTO_GRE, + key->tos, key->ttl, df, false); + return; + +err_free_rt: + ip_rt_put(rt); +err_free_skb: + kfree_skb(skb); + dev->stats.tx_dropped++; +} + #define GRE_FEATURES (NETIF_F_SG | \ NETIF_F_FRAGLIST | \ NETIF_F_HIGHDMA | \ @@ -608,18 +701,17 @@ static int erspan_validate(struct nlattr *tb[], struct nlattr *data[]) return ret; /* ERSPAN should only have GRE sequence and key flag */ - flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]); - flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]); - if (flags != (GRE_SEQ | GRE_KEY)) + if (data[IFLA_GRE_OFLAGS]) + flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]); + if (data[IFLA_GRE_IFLAGS]) + flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]); + if (!data[IFLA_GRE_COLLECT_METADATA] && + flags != (GRE_SEQ | GRE_KEY)) return -EINVAL; /* ERSPAN Session ID only has 10-bit. Since we reuse * 32-bit key field as ID, check it's range. */ - if (data[IFLA_GRE_IKEY] && - (ntohl(nla_get_be32(data[IFLA_GRE_IKEY])) & ~ID_MASK)) - return -EINVAL; - if (data[IFLA_GRE_OKEY] && (ntohl(nla_get_be32(data[IFLA_GRE_OKEY])) & ~ID_MASK)) return -EINVAL; @@ -708,6 +800,11 @@ static netdev_tx_t erspan_xmit(struct sk_buff *skb, struct ip_tunnel *tunnel = netdev_priv(dev); bool truncate = false; + if (tunnel->collect_md) { + erspan_fb_xmit(skb, dev, skb->protocol); + return NETDEV_TX_OK; + } + if (gre_handle_offloads(skb, false)) goto free_skb; From patchwork Thu Mar 22 22:07:21 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Rose X-Patchwork-Id: 889673 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="HoQfcy0a"; 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 406gp56rcvz9s1B for ; Fri, 23 Mar 2018 09:10:05 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 82F31EE3; Thu, 22 Mar 2018 22:07:58 +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 49493CE9 for ; Thu, 22 Mar 2018 22:07:55 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pg0-f68.google.com (mail-pg0-f68.google.com [74.125.83.68]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id CAE68360 for ; Thu, 22 Mar 2018 22:07:54 +0000 (UTC) Received: by mail-pg0-f68.google.com with SMTP id n11so3814613pgp.4 for ; Thu, 22 Mar 2018 15:07:54 -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=pYjwKAxO9Jg1J/Gva1g/HR31RHMFtzjka0IWpeCci9w=; b=HoQfcy0aISF6P/gdbsVdQVQVJgwywvfhNIW7RnGhl5QqV0gLiTvNs+mgp0lrfp8Uxb 16/DUzTwnNqETx+OGhR5tBSXyYy772+skJVb0GU09gAHLi7f4xgM0P3E7jhkYVR0/NXs BXINDl1Dhzi4s+AcVjqturCWMFDQncqAGZNWIOvefXQOG61EhhApBU3aLYr0Fxqy9Ycm lTDBh+GZzXM07pLrEyVifODKkLRGH9U4KpkBuxsaRfhc6wnS4kDS1hCiKEjjTWXku97c bnGp87/6Cz5r2U0vNBXANqoE4RcOR39lYlcHiPF66JmSAjI8jsb98cnbDg5MymLiknDD GoEg== 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=pYjwKAxO9Jg1J/Gva1g/HR31RHMFtzjka0IWpeCci9w=; b=boSjgzA4ULFBRqQU6eJrjPw3vMUEsQkNFuAfr6gn6FERKq266wczWaR9tLr0K3NIjg M1v+2Ap7ad75T4Sbi9lp2oSVtc7UnKACcnfZUunExUmBio1EalxFiD5Zc2ZenMdUw+pN AWvteuAAu627PbocT+aTAJNjf3c2sJGGY8V3k7E3k5Uq/qKFxacnPCNHRZa0exX0tISP ac36rigNRQD1LREMPtgvb4OK4LTruLlIVOhMXK+II2AvMXP0cXOVLM7kfqKAd9YUbxlp ARCDBjwvTb8WT/MAYT4cya1+QpEPLA59pL7X/B6nRrN5o2jfceS//GPSrJEHj8RZqGV0 rYyA== X-Gm-Message-State: AElRT7HZoZWht7fBT24DQX0aL1JrM5o1N7gGg2pvwJHDQLPabcQ2yY2B ChcGwPxLU/iZ7Kk+3AM9EsqEFA== X-Google-Smtp-Source: AG47ELvHSSRjaWBtHbbaqp6DQ1zhknpPLGAJ8cBfOnU81corZM89gswN9DrTjn/080oHjSOGGLevag== X-Received: by 10.98.16.131 with SMTP id 3mr21986176pfq.188.1521756474003; Thu, 22 Mar 2018 15:07:54 -0700 (PDT) Received: from gizo.domain (184-100-240-187.ptld.qwest.net. [184.100.240.187]) by smtp.gmail.com with ESMTPSA id 4sm2280775pfn.32.2018.03.22.15.07.52 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Mar 2018 15:07:53 -0700 (PDT) From: Greg Rose To: dev@openvswitch.org Date: Thu, 22 Mar 2018 15:07:21 -0700 Message-Id: <1521756461-3870-6-git-send-email-gvrose8192@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1521756461-3870-1-git-send-email-gvrose8192@gmail.com> References: <1521756461-3870-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] [ERSPAN RFC 05/25] ip_gre: check packet length and mtu correctly in erspan tx 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 From: William Tu Upstream commit: commit f192970de860d3ab90aa9e2a22853201a57bde78 Author: William Tu Date: Thu Oct 5 12:07:12 2017 -0700 ip_gre: check packet length and mtu correctly in erspan tx Similarly to early patch for erspan_xmit(), the ARPHDR_ETHER device is the length of the whole ether packet. So skb->len should subtract the dev->hard_header_len. Fixes: 1a66a836da63 ("gre: add collect_md mode to ERSPAN tunnel") Fixes: 84e54fe0a5ea ("gre: introduce native tunnel support for ERSPAN") Signed-off-by: William Tu Cc: Xin Long Cc: David Laight Reviewed-by: Xin Long Signed-off-by: David S. Miller Cc: William Tu Signed-off-by: Greg Rose --- datapath/linux/compat/ip_gre.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index d0f112d..af9fbb3 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -544,8 +544,8 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev, if (gre_handle_offloads(skb, false)) goto err_free_rt; - if (skb->len > dev->mtu) { - pskb_trim(skb, dev->mtu); + if (skb->len > dev->mtu + dev->hard_header_len) { + pskb_trim(skb, dev->mtu + dev->hard_header_len); truncate = true; } @@ -811,8 +811,8 @@ static netdev_tx_t erspan_xmit(struct sk_buff *skb, if (skb_cow_head(skb, dev->needed_headroom)) goto free_skb; - if (skb->len > dev->mtu) { - pskb_trim(skb, dev->mtu); + if (skb->len > dev->mtu + dev->hard_header_len) { + pskb_trim(skb, dev->mtu + dev->hard_header_len); truncate = true; } From patchwork Thu Mar 22 22:07:22 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Rose X-Patchwork-Id: 889674 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="oRfDP3Mx"; 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 406gpZ6nnwz9s0y for ; Fri, 23 Mar 2018 09:10:30 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 24031EEB; Thu, 22 Mar 2018 22:08:00 +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 B4243E50 for ; Thu, 22 Mar 2018 22:07:56 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pf0-f195.google.com (mail-pf0-f195.google.com [209.85.192.195]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 6C9455D4 for ; Thu, 22 Mar 2018 22:07:56 +0000 (UTC) Received: by mail-pf0-f195.google.com with SMTP id m68so3922353pfm.11 for ; Thu, 22 Mar 2018 15:07:56 -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=cq0K+eoCz4Ggq/Xc5ItB3PiYMEjk7H6N0JE92IiH4io=; b=oRfDP3MxDFbaITJj+5q+bjkqtnfazQE9jxwqooTfaUSmdK3duzNHF9omRNB9E2EjKA zepO6t8C3diXZo1/2q0aN532Tg1S4cslnjoKtWVYxYsnMYEEA6dANB6UJSovQp3zmx/u mU1IBu0Q6AXk/NDD54f0BpmPPVEgohvCTxdK+pdwIgy9tN2y2rmljCSq2JgtlmnsMKfU 0RciV9qBzjHkPzHNBJ+jaj8ikS7gJTIL6iMOUYnLpUNzXyeUlwS8RAK1E+nV0UBVwosZ h+gDaiww8KMZMKvwpGUWwmKw5XyMIwcVQOoDMNAkQQFPry84zXuUFJK+nc8AVlLO6MJm OldQ== 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=cq0K+eoCz4Ggq/Xc5ItB3PiYMEjk7H6N0JE92IiH4io=; b=pbVgLohKKa1W2XVsVP5YhZgRcXHBBrKWpkHqa+/tgCRyKrTLT6+abEZradcWSHLVCl hf3g/Xefsl6iUxmra5DJbJV2jOzKq0emd/KIlPcxy9qrDj6gpCAwH20kIUv6bAi1uPir POOX5Aus45Xb1H8EICcklZi+7siNL/roQc+e85OHh0aUBWK3BELRkmAewZs4Jc96xD+3 1kDlDYkaYxqE8YxPnvfz6gL5Tg/5mLtte6CduptI0bKZt1CWn1bPyMBy7GbZLQR595c0 QK1uevJzxvm7EwmdzbYoAHd/9K95o/Uk3XTLENq1Q9bBaS1SxUFkwC11oZnqG9oJkXkG Klqg== X-Gm-Message-State: AElRT7G6rTtOsrcmIJzbGkqZXYxxRhmjL/3sNGYWCoGoCLIOno8uIg+m eL6T0/6eYFnlbNAqy/8Y6lT6AA== X-Google-Smtp-Source: AG47ELsbcxizF62NFU3AU/+XesX3m6x4tQz7Nu+rvZIUvND+ISlZ4pPuyNfPbOKa8xVa1OHvm+iAKg== X-Received: by 10.99.182.73 with SMTP id v9mr18773035pgt.158.1521756475638; Thu, 22 Mar 2018 15:07:55 -0700 (PDT) Received: from gizo.domain (184-100-240-187.ptld.qwest.net. [184.100.240.187]) by smtp.gmail.com with ESMTPSA id 4sm2280775pfn.32.2018.03.22.15.07.54 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Mar 2018 15:07:54 -0700 (PDT) From: Greg Rose To: dev@openvswitch.org Date: Thu, 22 Mar 2018 15:07:22 -0700 Message-Id: <1521756461-3870-7-git-send-email-gvrose8192@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1521756461-3870-1-git-send-email-gvrose8192@gmail.com> References: <1521756461-3870-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 Cc: Xin Long Subject: [ovs-dev] [ERSPAN RFC 06/25] ip_gre: get key from session_id correctly in erspan_rcv 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 From: Xin Long Upstream commit: commit 935a9749a36828af0e8be224a5cd4bc758112c34 Author: Xin Long Date: Sun Oct 1 22:00:53 2017 +0800 ip_gre: get key from session_id correctly in erspan_rcv erspan only uses the first 10 bits of session_id as the key to look up the tunnel. But in erspan_rcv, it missed 'session_id & ID_MASK' when getting the key from session_id. If any other flag is also set in session_id in a packet, it would fail to find the tunnel due to incorrect key in erspan_rcv. This patch is to add 'session_id & ID_MASK' there and also remove the unnecessary variable session_id. Fixes: 84e54fe0a5ea ("gre: introduce native tunnel support for ERSPAN") Signed-off-by: Xin Long Signed-off-by: David S. Miller Cc: Xin Long Signed-off-by: Greg Rose --- datapath/linux/compat/ip_gre.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index af9fbb3..2fc4659 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -141,7 +141,6 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, struct ip_tunnel *tunnel; struct erspanhdr *ershdr; const struct iphdr *iph; - __be32 session_id; __be32 index; int len; @@ -158,8 +157,7 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, /* The original GRE header does not have key field, * Use ERSPAN 10-bit session ID as key. */ - session_id = cpu_to_be32(ntohs(ershdr->session_id)); - tpi->key = session_id; + tpi->key = cpu_to_be32(ntohs(ershdr->session_id) & ID_MASK); index = ershdr->md.index; tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags | TUNNEL_KEY, From patchwork Thu Mar 22 22:07:23 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Rose X-Patchwork-Id: 889675 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="LP6iENaJ"; 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 406gq42fkPz9s1B for ; Fri, 23 Mar 2018 09:10:56 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 725ADEEC; Thu, 22 Mar 2018 22:08:02 +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 6C814E69 for ; Thu, 22 Mar 2018 22:07:58 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pf0-f195.google.com (mail-pf0-f195.google.com [209.85.192.195]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id F2EE7360 for ; Thu, 22 Mar 2018 22:07:57 +0000 (UTC) Received: by mail-pf0-f195.google.com with SMTP id h11so3925947pfn.4 for ; Thu, 22 Mar 2018 15:07:57 -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=JgJrTtOsSsaIl6PuotSN67EVr2Wq2K7owqNasqNkrDk=; b=LP6iENaJtZXjq9JQuTjdUAXYuUk2QStIeSlnlGkOhXF2RMef0LWjIXXMOsJ0b7irUf 7GGxaJITlkPDVVTrl/tq8H+7ei5VZ5kAwXqFzfKW5hheJHKPKmDq5Ke4sEgDGyHCmvFw AP45rHYhv/o9zU0V8XFun5q0PuhrODvfGFIUbOlzo1gsVrunGe8uq5HpvGwtOfXYQ1Jb vO7CWkAozHimflxN3pzW6uOW3vEJhg1C+/Nf/fX2vIBFQekYwApx6UZV2TxNBkGCqNW7 2a2F7k4neEZNnkUBM5PjXb3fI6e8gtedthBnf68g5j+kElMG/0qVNexq7FOfjhsgPTqh uX6w== 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=JgJrTtOsSsaIl6PuotSN67EVr2Wq2K7owqNasqNkrDk=; b=Nn/NoKYARufEOqqQfgJFOP3IquRi/ojd1JNuuTnhNw+ybgDLaVeRYLvXvsc5h4Mh5k UouF6GDKtdTYgxhVG3Wir/ZOaaCjRrvOikyIYuDTr2uTzWWU8MYR9zQQ+w3U08bkVKNr XwSk2zepmWvQJtuPF/eUvPHGM7f0p9fOGCywc/3FYfkSrycOEOUJnubuWdRRziSLfqyi 4KygnMZ+RLXwzWakVVFoDEjAmjOCPSCEwYL7zyYxoSe0ucw3rJ/TmuSHr7q713aSwUKg w2HiA03nK0Cb5WvSspnqFdce15oQ4jyy3iM4RC7ujPWc3Vc57ZSYynfdE9qsISWcmf4D MpUg== X-Gm-Message-State: AElRT7ExWTKzJvkagP8G1Tk+u86jfc98CLOApj6O/+fPLGuMpbcJ8iMN PatJdB3ze04vaP+k3T5VkTc16Q== X-Google-Smtp-Source: AG47ELvkzzO76xmKQY5Jx5Mb47WTy4bH13IN7jacXnjwYVhfoK7etaQ/98B23I0TjaU4ZZhS5cFSYA== X-Received: by 10.101.65.10 with SMTP id w10mr1421656pgp.39.1521756477195; Thu, 22 Mar 2018 15:07:57 -0700 (PDT) Received: from gizo.domain (184-100-240-187.ptld.qwest.net. [184.100.240.187]) by smtp.gmail.com with ESMTPSA id 4sm2280775pfn.32.2018.03.22.15.07.55 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Mar 2018 15:07:56 -0700 (PDT) From: Greg Rose To: dev@openvswitch.org Date: Thu, 22 Mar 2018 15:07:23 -0700 Message-Id: <1521756461-3870-8-git-send-email-gvrose8192@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1521756461-3870-1-git-send-email-gvrose8192@gmail.com> References: <1521756461-3870-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 Cc: Xin Long Subject: [ovs-dev] [ERSPAN RFC 07/25] ip_gre: set tunnel hlen properly in erspan_tunnel_init 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 From: Xin Long Upstream commit: commit c122fda271717f4fc618e0a31e833941fd5f1efd Author: Xin Long Date: Sun Oct 1 22:00:55 2017 +0800 ip_gre: set tunnel hlen properly in erspan_tunnel_init According to __gre_tunnel_init, tunnel->hlen should be set as the headers' length between inner packet and outer iphdr. It would be used especially to calculate a proper mtu when updating mtu in tnl_update_pmtu. Now without setting it, a bigger mtu value than expected would be updated, which hurts performance a lot. This patch is to fix it by setting tunnel->hlen with: tunnel->tun_hlen + tunnel->encap_hlen + sizeof(struct erspanhdr) Fixes: 84e54fe0a5ea ("gre: introduce native tunnel support for ERSPAN") Signed-off-by: Xin Long Signed-off-by: David S. Miller Cc: Xin Long Signed-off-by: Greg Rose --- datapath/linux/compat/ip_gre.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index 2fc4659..dc58396 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -870,7 +870,9 @@ static int erspan_tunnel_init(struct net_device *dev) tunnel->tun_hlen = 8; tunnel->parms.iph.protocol = IPPROTO_GRE; - t_hlen = tunnel->hlen + sizeof(struct iphdr) + sizeof(struct erspanhdr); + tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen + + sizeof(struct erspanhdr); + t_hlen = tunnel->hlen + sizeof(struct iphdr); dev->needed_headroom = LL_MAX_HEADER + t_hlen + 4; dev->mtu = ETH_DATA_LEN - t_hlen - 4; From patchwork Thu Mar 22 22:07:24 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Rose X-Patchwork-Id: 889676 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="Wwco5/1V"; 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 406gqV11Vdz9s0y for ; Fri, 23 Mar 2018 09:11:18 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 9E1B3F0A; Thu, 22 Mar 2018 22:08:03 +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 75AC3EEB for ; Thu, 22 Mar 2018 22:07:59 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pg0-f66.google.com (mail-pg0-f66.google.com [74.125.83.66]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 3A4435D9 for ; Thu, 22 Mar 2018 22:07:59 +0000 (UTC) Received: by mail-pg0-f66.google.com with SMTP id m24so3809676pgv.8 for ; Thu, 22 Mar 2018 15:07:59 -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=inWo7VtA4n7QAlk8Qa7e7iDeFYw2M2zbiLUPFjcGTW4=; b=Wwco5/1VEJFeGfcYl4cOcHEChjWIUWcOan4imw+SWnEXfjmgdF/nShBlSp8CEELm4h PaU18eUJ5eq0K+KjU2y0OFcPM6lLvEZ4VytC5tZrjN1DG5KzoW1qjyfuwPyOGmvCrrr3 uPgGikRSg9zBJdZVSfHxPrubInIAYzr2ggWOUuAPn/5wo+DYn9HgxuzEF6hLiKNruk51 jKIgpHPP/0A9rmr5nn7KEH/mO74l0U1KUxoQVEbz81KVeGeVt+Z1ZYMlh6OE+IHzJtBB rYb5/NA02ccOb42hQwLyl6wB+YrRPnzdHYvdzHLF1o+9vZQEbLvnCYEhQArHbFMiSq4q HLpw== 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=inWo7VtA4n7QAlk8Qa7e7iDeFYw2M2zbiLUPFjcGTW4=; b=CfhyqCRR/7lAWI4w5DMR2JvYoQntJBlthriyELbye8I0DEJ0+WCQcdZP4vldIJe5fa cci1sGLidtubgvxxZgWTSBk+KN9X0RqdEd5w4QO3YMEh9YMnm10bXLJKj1WZZPG1mwBT 0n6xS7Y6GCff3RN2pMQMK5nZLtxEJwKMgO30c9097EJWG2rFpR9kyPH1NeG4P4vesgb1 YSTcP69LiPRVppgBmfrY16fWWM8Jrf/iEkjkpuX8MUAev+Ve9VFZhcf+fvS+/DIday6B J/1HnR3LhTJCogtLD8oytarEgVKYABmUYAC0Plt3nrOsM8l9lIZVl9vh4YSaOl0SPdt1 uzmw== X-Gm-Message-State: AElRT7E17UIQgAPE4i/+y7//D4u8jpkf0MbKV9RsWkapSTsPsf70c5w+ hmTsFuHoZhUbLQnFs24yk1xhKg== X-Google-Smtp-Source: AG47ELuhmQ/WF4I6sJNh+wgumggFifrxVWwGz/abyhFvoTPcJz8lMHrakQ8jc1BG0aEMJBrswkZY/g== X-Received: by 10.167.128.143 with SMTP id v15mr22034071pff.36.1521756478499; Thu, 22 Mar 2018 15:07:58 -0700 (PDT) Received: from gizo.domain (184-100-240-187.ptld.qwest.net. [184.100.240.187]) by smtp.gmail.com with ESMTPSA id 4sm2280775pfn.32.2018.03.22.15.07.57 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Mar 2018 15:07:57 -0700 (PDT) From: Greg Rose To: dev@openvswitch.org Date: Thu, 22 Mar 2018 15:07:24 -0700 Message-Id: <1521756461-3870-9-git-send-email-gvrose8192@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1521756461-3870-1-git-send-email-gvrose8192@gmail.com> References: <1521756461-3870-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 Cc: Xin Long Subject: [ovs-dev] [ERSPAN RFC 08/25] ip_gre: erspan device should keep dst 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 From: Xin Long Upstream commit: commit c84bed440e4e11a973e8c0254d0dfaccfca41fb0 Author: Xin Long Date: Sun Oct 1 22:00:56 2017 +0800 ip_gre: erspan device should keep dst The patch 'ip_gre: ipgre_tap device should keep dst' fixed the issue ipgre_tap dev mtu couldn't be updated in tx path. The same fix is needed for erspan as well. Fixes: 84e54fe0a5ea ("gre: introduce native tunnel support for ERSPAN") Signed-off-by: Xin Long Signed-off-by: David S. Miller Cc: Xin Long Signed-off-by: Greg Rose --- datapath/linux/compat/ip_gre.c | 1 + 1 file changed, 1 insertion(+) diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index dc58396..0199350 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -879,6 +879,7 @@ static int erspan_tunnel_init(struct net_device *dev) dev->features |= GRE_FEATURES; dev->hw_features |= GRE_FEATURES; dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; + netif_keep_dst(dev); return ip_tunnel_init(dev); } From patchwork Thu Mar 22 22:07:25 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Rose X-Patchwork-Id: 889677 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="Zs6JDJ5k"; 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 406gqv2yTyz9s0y for ; Fri, 23 Mar 2018 09:11:39 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id C612EF15; Thu, 22 Mar 2018 22:08:04 +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 79330EE1 for ; Thu, 22 Mar 2018 22:08:01 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pl0-f65.google.com (mail-pl0-f65.google.com [209.85.160.65]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id E038F5E7 for ; Thu, 22 Mar 2018 22:08:00 +0000 (UTC) Received: by mail-pl0-f65.google.com with SMTP id b7-v6so6207601plr.8 for ; Thu, 22 Mar 2018 15:08:00 -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=wFp2CkZZj/a5ZRsF+aIzmcFyAjCuuv/+m9vQ1HlQfHA=; b=Zs6JDJ5kCTXXAWSnLvgthmHn6aCyv1NLKAlHMfmPlpnYgv6CKvjt11MRiA74JJpTMY j2Mrc0VmhgmaT927zOjzcoPgmbwffLt1CDDJrsMhPcJows6Fp7MJI6+tkc1fdLvuP8x9 HcGJNuKAj3l1YPJkJwiZBDHe6NCkhJPNnF5wt56aW4kScMJwqQwybx7C2A9vfTucemjL a74BOsemcKmzm1lWGXHPWc6msG/OJGh2sasxaQflDaXmHDSEHCqRcid6ya1dygmvT53h ONVC6FmkhzqAIyXzxB1VZH0h0+PBGU6bpk02Q+Hta+VZCM8cP1FVCqDe4EfT8s+xIDNa Gbcg== 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=wFp2CkZZj/a5ZRsF+aIzmcFyAjCuuv/+m9vQ1HlQfHA=; b=sTOCYnQWXm2/phvGhelbmv2+NakYB3KLld3jncZtdpUGPDaYymeb4s1XvykqYmDgKj aqwZCMIjHPB0OZhUM8KYlByluw1VcuwbuY8EegnG1R6NGH3+TUHdqu9WP4USJ++cmUfl LZZuNjUUUxlU8KfYRwjhEfpBzQ3wv+aS5XWllyVSeHSXI5a+9o+VRjPa2zIP9zUGG+Q0 iyWS93xbABafwI87g3MNCW0ajphIKgF3lN8dpbgRZ7poFTc6xrMGkb7S0brUCJNOww0N qTnQHqaO+vIuwsCZ8ArB69yAL+HroaOz9SFWrbDsHacGWWL/u4SnV2El1YLKCZ9TtrH5 UtHw== X-Gm-Message-State: AElRT7FuK88YQ27LbrzrQm/UwixZfRPsWNKKL4PP48j5KyHKVvX5l+ev DlGf1BanPmdC3HI2Jm/C9mZ0EQ== X-Google-Smtp-Source: AG47ELvzCY2qT4zMaO2WQW4HBaoHDYRMUoAeybF47YPMMPJoMp21pMPkfJTxrs2rvgBewt9VMiBdhw== X-Received: by 2002:a17:902:28e3:: with SMTP id f90-v6mr18498292plb.250.1521756479943; Thu, 22 Mar 2018 15:07:59 -0700 (PDT) Received: from gizo.domain (184-100-240-187.ptld.qwest.net. [184.100.240.187]) by smtp.gmail.com with ESMTPSA id 4sm2280775pfn.32.2018.03.22.15.07.58 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Mar 2018 15:07:58 -0700 (PDT) From: Greg Rose To: dev@openvswitch.org Date: Thu, 22 Mar 2018 15:07:25 -0700 Message-Id: <1521756461-3870-10-git-send-email-gvrose8192@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1521756461-3870-1-git-send-email-gvrose8192@gmail.com> References: <1521756461-3870-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] [ERSPAN RFC 09/25] ip_gre: Refactor the erpsan tunnel code. 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 From: William Tu Upstream commit: commit a3222dc95ca751cdc5f6ac3c9b092b160b73ed9f Author: William Tu Date: Thu Nov 30 11:51:27 2017 -0800 ip_gre: Refector the erpsan tunnel code. Move two erspan functions to header file, erspan.h, so ipv6 erspan implementation can use it. Signed-off-by: William Tu Signed-off-by: David S. Miller Cc: William Tu Signed-off-by: Greg Rose --- datapath/linux/compat/include/net/erspan.h | 51 ++++++++++++++++++++++++++ datapath/linux/compat/ip_gre.c | 57 ++++-------------------------- 2 files changed, 57 insertions(+), 51 deletions(-) diff --git a/datapath/linux/compat/include/net/erspan.h b/datapath/linux/compat/include/net/erspan.h index 6c5d3a7..b4f13e6 100644 --- a/datapath/linux/compat/include/net/erspan.h +++ b/datapath/linux/compat/include/net/erspan.h @@ -59,6 +59,57 @@ struct erspanhdr { struct erspan_metadata md; }; +static inline u8 tos_to_cos(u8 tos) +{ + u8 dscp, cos; + + dscp = tos >> 2; + cos = dscp >> 3; + return cos; +} + +static inline void erspan_build_header(struct sk_buff *skb, + __be32 id, u32 index, + bool truncate, bool is_ipv4) +{ + struct ethhdr *eth = eth_hdr(skb); + enum erspan_encap_type enc_type; + struct erspanhdr *ershdr; + struct qtag_prefix { + __be16 eth_type; + __be16 tci; + } *qp; + u16 vlan_tci = 0; + u8 tos; + + tos = is_ipv4 ? ip_hdr(skb)->tos : + (ipv6_hdr(skb)->priority << 4) + + (ipv6_hdr(skb)->flow_lbl[0] >> 4); + + enc_type = ERSPAN_ENCAP_NOVLAN; + + /* If mirrored packet has vlan tag, extract tci and + * perserve vlan header in the mirrored frame. + */ + if (eth->h_proto == htons(ETH_P_8021Q)) { + qp = (struct qtag_prefix *)(skb->data + 2 * ETH_ALEN); + vlan_tci = ntohs(qp->tci); + enc_type = ERSPAN_ENCAP_INFRAME; + } + + skb_push(skb, sizeof(*ershdr)); + ershdr = (struct erspanhdr *)skb->data; + memset(ershdr, 0, sizeof(*ershdr)); + + ershdr->ver_vlan = htons((vlan_tci & VLAN_MASK) | + (ERSPAN_VERSION << VER_OFFSET)); + ershdr->session_id = htons((u16)(ntohl(id) & ID_MASK) | + ((tos_to_cos(tos) << COS_OFFSET) & COS_MASK) | + (enc_type << EN_OFFSET & EN_MASK) | + ((truncate << T_OFFSET) & T_MASK)); + ershdr->md.index = htonl(index & INDEX_MASK); +} + #endif #else #include_next diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index 0199350..c4abc6f 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -65,6 +65,9 @@ static int gre_tap_net_id __read_mostly; static unsigned int erspan_net_id __read_mostly; +static void erspan_build_header(struct sk_buff *skb, + __be32 id, u32 index, + bool truncate, bool is_ipv4); #define ip_gre_calc_hlen rpl_ip_gre_calc_hlen static int ip_gre_calc_hlen(__be16 o_flags) @@ -122,9 +125,6 @@ static __be32 tunnel_id_to_key(__be64 x) #endif } -static void erspan_build_header(struct sk_buff *skb, - __be32 id, u32 index, bool truncate); - /* Called with rcu_read_lock and BH disabled. */ static int gre_err(struct sk_buff *skb, u32 info, const struct tnl_ptk_info *tpi) @@ -552,7 +552,7 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev, goto err_free_rt; erspan_build_header(skb, tunnel_id_to_key32(key->tun_id), - ntohl(md->index), truncate); + ntohl(md->index), truncate, true); tpi.flags = (TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_SEQ); tpi.proto = htons(ETH_P_ERSPAN); @@ -746,52 +746,6 @@ static netdev_tx_t gre_dev_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } -static inline u8 tos_to_cos(u8 tos) -{ - u8 dscp, cos; - - dscp = tos >> 2; - cos = dscp >> 3; - return cos; -} - -static void erspan_build_header(struct sk_buff *skb, - __be32 id, u32 index, bool truncate) -{ - struct iphdr *iphdr = ip_hdr(skb); - struct ethhdr *eth = eth_hdr(skb); - enum erspan_encap_type enc_type; - struct erspanhdr *ershdr; - struct qtag_prefix { - __be16 eth_type; - __be16 tci; - } *qp; - u16 vlan_tci = 0; - - enc_type = ERSPAN_ENCAP_NOVLAN; - - /* If mirrored packet has vlan tag, extract tci and - * perserve vlan header in the mirrored frame. - */ - if (eth->h_proto == htons(ETH_P_8021Q)) { - qp = (struct qtag_prefix *)(skb->data + 2 * ETH_ALEN); - vlan_tci = ntohs(qp->tci); - enc_type = ERSPAN_ENCAP_INFRAME; - } - - skb_push(skb, sizeof(*ershdr)); - ershdr = (struct erspanhdr *)skb->data; - memset(ershdr, 0, sizeof(*ershdr)); - - ershdr->ver_vlan = htons((vlan_tci & VLAN_MASK) | - (ERSPAN_VERSION << VER_OFFSET)); - ershdr->session_id = htons((u16)(ntohl(id) & ID_MASK) | - ((tos_to_cos(iphdr->tos) << COS_OFFSET) & COS_MASK) | - (enc_type << EN_OFFSET & EN_MASK) | - ((truncate << T_OFFSET) & T_MASK)); - ershdr->md.index = htonl(index & INDEX_MASK); -} - static netdev_tx_t erspan_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -815,7 +769,8 @@ static netdev_tx_t erspan_xmit(struct sk_buff *skb, } /* Push ERSPAN header */ - erspan_build_header(skb, tunnel->parms.o_key, tunnel->index, truncate); + erspan_build_header(skb, tunnel->parms.o_key, tunnel->index, + truncate, true); tunnel->parms.o_flags &= ~TUNNEL_KEY; __gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_ERSPAN)); return NETDEV_TX_OK; From patchwork Thu Mar 22 22:07:26 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Rose X-Patchwork-Id: 889678 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="sZ+3m1rb"; 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 406grl5ZZVz9s0y for ; Fri, 23 Mar 2018 09:12:23 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 04333DCA; Thu, 22 Mar 2018 22:08: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 07A81EF9 for ; Thu, 22 Mar 2018 22:08:03 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pl0-f68.google.com (mail-pl0-f68.google.com [209.85.160.68]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 8021B5D9 for ; Thu, 22 Mar 2018 22:08:02 +0000 (UTC) Received: by mail-pl0-f68.google.com with SMTP id p9-v6so6212766pls.2 for ; Thu, 22 Mar 2018 15:08:02 -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=Sxq4F1fWCrRPu6JbxHWHJ56xUN1TiR0+LLP+L1o5vjQ=; b=sZ+3m1rbpqNdoSs6Chpym7zSwLa6wfiOEu+OTo9aUld0SR3cv+Mr0FMn43BvZV8+4p /I5WiQwOujJ+zv1cEr8qxkTZ6SWLNHnI+WIqioyKQAKeCEP6edQUmbNQg08Cp5QTWHWo H85f5OLgBPsgw5s0pqF710zyyTZLQHv5hLZg9lCxO3TOZT6EWxp+sutiYj3I1PPz1s/H GMuLVqJswW5GDM1n7zl0l9NWK/CgMWOCF71IihGn2fZKOe3ZPfYg/rm2tn6l2SU6w61S xaKW5yMou5l4WAs5PWkV7KhhBXIyceUQIiTidtwRf1OjTET5IVGZCeOaShKdQvZ8D2NE 9A1A== 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=Sxq4F1fWCrRPu6JbxHWHJ56xUN1TiR0+LLP+L1o5vjQ=; b=Yx4mQQtqOGy+RhV51kr8Zgu25TeEyXGZ+d/vvxSeqTjGuc+GC5OnrO26hLu6w0T9s6 DadO6bUijyGr+WlRSNOszceJ0HNYlftJnqaJM0q3dE293X4hQXRM/HQdfRrNgz2I/9EO /NWBoBLraNMaYw7W9sEzrxsyiy8disEdFDy7jxUIA26FRO/TFASXVVGtw8tT0rJxo838 Ts8cRNLpTPxRDKlU9/Eu6+K33kWQlKeQ1DqX2Z4x3/X3sK3U4GgNvsp4WZsG1/q8nQh5 SHGlU68dnuyzD65ptVx4xKjnSibsT1u6Quwk6GLQxWtZap6ynISybKZl9+EB69rJriXj X37w== X-Gm-Message-State: AElRT7EqaspItl+9+Lx457MV6JrG+z82JOfpJaT+1EpX3emsppYp6UTt 3k5xZ5x9uLrAQf7x35GopAhYHg== X-Google-Smtp-Source: AG47ELtyTZplBNGQiReHdMNIeke+p1+lsFPW5yZD3BIwp+lk6QMXdvOZX19zgpT7o78+OrqTo/5nhw== X-Received: by 2002:a17:902:5489:: with SMTP id e9-v6mr18846106pli.306.1521756481546; Thu, 22 Mar 2018 15:08:01 -0700 (PDT) Received: from gizo.domain (184-100-240-187.ptld.qwest.net. [184.100.240.187]) by smtp.gmail.com with ESMTPSA id 4sm2280775pfn.32.2018.03.22.15.07.59 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Mar 2018 15:08:00 -0700 (PDT) From: Greg Rose To: dev@openvswitch.org Date: Thu, 22 Mar 2018 15:07:26 -0700 Message-Id: <1521756461-3870-11-git-send-email-gvrose8192@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1521756461-3870-1-git-send-email-gvrose8192@gmail.com> References: <1521756461-3870-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] [ERSPAN RFC 10/25] compat/erspan: refactor existing erspan code 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 From: William Tu Upstream commit: commit 1d7e2ed22f8d9171fa8b629754022f22115b3f03 Author: William Tu Date: Wed Dec 13 16:38:55 2017 -0800 net: erspan: refactor existing erspan code The patch refactors the existing erspan implementation in order to support erspan version 2, which has additional metadata. So, in stead of having one 'struct erspanhdr' holding erspan version 1, breaks it into 'struct erspan_base_hdr' and 'struct erspan_metadata'. Signed-off-by: William Tu Signed-off-by: David S. Miller Partial of the upstream commit. While doing backports it is pretty much impossible to fully reconstitute all upstream commits but we're doing our best. Other parts of this commit are introduced in the upcoming monster patch for ip6 gre support. Cc: William Tu Signed-off-by: Greg Rose --- datapath/linux/compat/ip_gre.c | 29 ++++++++++++++++++----------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index c4abc6f..eeea4bb 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -136,36 +136,43 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, int gre_hdr_len) { struct net *net = dev_net(skb->dev); - struct metadata_dst tun_dst; + struct metadata_dst tun_dst = NULL; + struct erspan_base_hdr *ershdr; + struct erspan_metadata *pkt_md; struct ip_tunnel_net *itn; struct ip_tunnel *tunnel; - struct erspanhdr *ershdr; const struct iphdr *iph; - __be32 index; + int ver; int len; itn = net_generic(net, erspan_net_id); iph = ip_hdr(skb); len = gre_hdr_len + sizeof(*ershdr); + /* Check based hdr len */ if (unlikely(!pskb_may_pull(skb, len))) return -ENOMEM; iph = ip_hdr(skb); - ershdr = (struct erspanhdr *)(skb->data + gre_hdr_len); + ershdr = (struct erspan_base_hdr *)(skb->data + gre_hdr_len); + ver = (ntohs(ershdr->ver_vlan) & VER_MASK) >> VER_OFFSET; /* The original GRE header does not have key field, * Use ERSPAN 10-bit session ID as key. */ tpi->key = cpu_to_be32(ntohs(ershdr->session_id) & ID_MASK); - index = ershdr->md.index; + pkt_md = (struct erspan_metadata *)(ershdr + 1); tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags | TUNNEL_KEY, iph->saddr, iph->daddr, tpi->key); if (tunnel) { + len = gre_hdr_len + erspan_hdr_len(ver); + if (unlikely(!pskb_may_pull(skb, len))) + return -ENOMEM; + if (__iptunnel_pull_header(skb, - gre_hdr_len + sizeof(*ershdr), + len, htons(ETH_P_TEB), false, false) < 0) goto drop; @@ -187,12 +194,12 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, if (!md) return PACKET_REJECT; - md->index = index; + memcpy(md, pkt_md, sizeof(*md)); info = &tun_dst.u.tun_info; info->key.tun_flags |= TUNNEL_ERSPAN_OPT; info->options_len = sizeof(*md); } else { - tunnel->index = ntohl(index); + tunnel->index = ntohl(pkt_md->u.index); } skb_reset_mac_header(skb); @@ -533,7 +540,7 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev, key = &tun_info->key; /* ERSPAN has fixed 8 byte GRE header */ - tunnel_hlen = 8 + sizeof(struct erspanhdr); + tunnel_hlen = 8 + sizeof(struct erspan_base_hdr) + ERSPAN_V1_MDSIZE; rt = prepare_fb_xmit(skb, dev, &fl, tunnel_hlen); if (!rt) @@ -552,7 +559,7 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev, goto err_free_rt; erspan_build_header(skb, tunnel_id_to_key32(key->tun_id), - ntohl(md->index), truncate, true); + ntohl(md->u.index), truncate, true); tpi.flags = (TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_SEQ); tpi.proto = htons(ETH_P_ERSPAN); @@ -826,7 +833,7 @@ static int erspan_tunnel_init(struct net_device *dev) tunnel->tun_hlen = 8; tunnel->parms.iph.protocol = IPPROTO_GRE; tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen + - sizeof(struct erspanhdr); + sizeof(struct erspan_base_hdr) + ERSPAN_V1_MDSIZE; t_hlen = tunnel->hlen + sizeof(struct iphdr); dev->needed_headroom = LL_MAX_HEADER + t_hlen + 4; From patchwork Thu Mar 22 22:07:27 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Rose X-Patchwork-Id: 889679 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="Lyqj1Phl"; 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 406gsD3xlYz9s0y for ; Fri, 23 Mar 2018 09:12:48 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id F14F3E03; Thu, 22 Mar 2018 22:08: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 3E1E1F0F for ; Thu, 22 Mar 2018 22:08:04 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pl0-f68.google.com (mail-pl0-f68.google.com [209.85.160.68]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id C0F345D4 for ; Thu, 22 Mar 2018 22:08:03 +0000 (UTC) Received: by mail-pl0-f68.google.com with SMTP id f23-v6so6205176plr.10 for ; Thu, 22 Mar 2018 15:08:03 -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=zp+36qXeHCByrI4z8JydDC2gpyMELPKSbONVh1skRxg=; b=Lyqj1Phl3/2vl8pHpum7HjRTyYCmZASYIWpp7M4z2HEmFWTVqTfm06LGf90Uw/0Xhm OSffNETwMmtpd8P4q6fmaIKvGcdjAiZwVzerkSfOV31M01uh+vAiOuXR2dSuP2ZJYKBj cQx3LpJF1q2EsM2EcWsIqf3XUcZqxH48eQgLfpGVofA5Lpob0YLFWR6gmFZ7qo2KePAV NnJoMIjfk0GfwLQq0FN5hFqY5d7htr8eNUi+mm1RPkOSCKYg05Qa/DLZDq5onQu7gtx6 IBpT6MJu8UftDrkWFCPnHpKhU9Ke/Kk9zmhouOiHsv9AO+kSNZ8UXz7gy5JMjMyyGBmF zjgQ== 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=zp+36qXeHCByrI4z8JydDC2gpyMELPKSbONVh1skRxg=; b=WcP7gjHU/iDZx5mwG/Loj+kyGicXpHOEtQtBohZWWS727rA5iau2TBVrwJ3ez2Itw8 iQ1GMiDIOc7Q22daiS9wxgtkJwwW19qY02FJTGAhagjTW6/h5v8w37a1kuQKTts2DmfL ylGVA6B9ynJuTyn1XwB/IAcyl1zUZx6xBfW7prwr87ijRKb05TA6KLBxtlta4jENyY8B aL3SNuZWD9nIlFCKYtSX35NPZMCYJLsZRvIAZ1WsrCpvaYO7wcoO0Aqr6QR89XJ2XxnK 5fi1VBybHvwH5bU+yA5wbSCz97ZwLhKFk1H5HifX+DUS0z/KZ4DKvkgU2k94eOJk45HQ bhgg== X-Gm-Message-State: AElRT7EHtiIddFEfmYiga1W/kn6ZDA2wXZaUUdawgW+lL+WeWBGl/jsH /lHVoajqyxg5blUovugcaFYWxA== X-Google-Smtp-Source: AG47ELugWej1VJB4/fGCR1m9DJcrmpKDd26Qi8phz9SW/GezQpMHSm28tT4eXdjlTxkCo6zuZbLW6Q== X-Received: by 2002:a17:902:51ee:: with SMTP id y101-v6mr27281264plh.359.1521756483033; Thu, 22 Mar 2018 15:08:03 -0700 (PDT) Received: from gizo.domain (184-100-240-187.ptld.qwest.net. [184.100.240.187]) by smtp.gmail.com with ESMTPSA id 4sm2280775pfn.32.2018.03.22.15.08.01 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Mar 2018 15:08:02 -0700 (PDT) From: Greg Rose To: dev@openvswitch.org Date: Thu, 22 Mar 2018 15:07:27 -0700 Message-Id: <1521756461-3870-12-git-send-email-gvrose8192@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1521756461-3870-1-git-send-email-gvrose8192@gmail.com> References: <1521756461-3870-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 Cc: Haishuang Yan Subject: [ovs-dev] [ERSPAN RFC 11/25] ip_gre: fix wrong return value of erspan_rcv 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 From: Haishuang Yan Upstream commit: commit c05fad5713b81b049ec6ac4eb2d304030b1efdce Author: Haishuang Yan Date: Fri Dec 15 10:46:16 2017 +0800 ip_gre: fix wrong return value of erspan_rcv If pskb_may_pull return failed, return PACKET_REJECT instead of -ENOMEM. Fixes: 84e54fe0a5ea ("gre: introduce native tunnel support for ERSPAN") Cc: William Tu Signed-off-by: Haishuang Yan Acked-by: William Tu Signed-off-by: David S. Miller Cc: Haishuang Yan Signed-off-by: Greg Rose --- datapath/linux/compat/ip_gre.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index eeea4bb..183b451 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -169,7 +169,7 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, if (tunnel) { len = gre_hdr_len + erspan_hdr_len(ver); if (unlikely(!pskb_may_pull(skb, len))) - return -ENOMEM; + return PACKET_REJECT; if (__iptunnel_pull_header(skb, len, From patchwork Thu Mar 22 22:07:28 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Rose X-Patchwork-Id: 889680 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="DgKv0VXi"; 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 406gsg1yBpz9s0y for ; Fri, 23 Mar 2018 09:13:11 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 5A43FE38; Thu, 22 Mar 2018 22:08:11 +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 71BDAF00 for ; Thu, 22 Mar 2018 22:08:05 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pf0-f195.google.com (mail-pf0-f195.google.com [209.85.192.195]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 32CA5360 for ; Thu, 22 Mar 2018 22:08:05 +0000 (UTC) Received: by mail-pf0-f195.google.com with SMTP id a11so571959pff.8 for ; Thu, 22 Mar 2018 15:08:05 -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=o0IAZXxPezu02FAmKNTbHxCOjXC7LtR1gnmbEXgG4Xc=; b=DgKv0VXiTnV+grpA1PuLagOoGWcIz3455+rEcx6tNdxFIivy41gklfbL0Ds+56TmjY I6aKeM4jOCEFpec7WOCEsBfPFKbfY53HmaqffTC4q++A5qfBtzGV8IfoFOgqvi4ZTxYS oWhp5Mo44XOE0CNK6TZIxxdKpg1YuYhLTxcpIH+h0ywmyJ3XRQ8tCAbUr9N/1JGS5l7c /RVfPf9i9yzEQIaRABQOaNiJCH5srF8SYg4T6qXJLPYxilsu8FeO/3cKTpwp3Ykbx/EW gARvlNXw68ADra39e6MhR5Ntfp9207MBwY5HmLVDKurtGwwAuUV08GsqD5nxGE6auNYX 8PAQ== 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=o0IAZXxPezu02FAmKNTbHxCOjXC7LtR1gnmbEXgG4Xc=; b=sbVjyXvEltu/agyc8sirvLziqzabOZH1B68EehNmnplkEg1K3Hiu/YwubZUVGo6mnB Obur+Jwh5iUGlsTqzwBjaX0t2Pucj/IGL4FoFBeS1Yl9zLvAxezxHFsWMqKITmdE5JE1 KB8VPG1Wfpxh+bgyemtfrmJVYHuRwkt5jqkNfXy2xJ4AM3Q7o2thIWWYseP+FaUN+12V //SBKLKN8dNZQF9XERVtoj2Ohguf+y29OvfaHehTRJov2KIO+YA8BMxKFbgXFThryYA2 nWNv9JkqfXXUB/NGnNmWD+C1uT6zfy5znoG0v8JprpuPNhgivNfr3gcmPFaLJqiw8kAZ h6Pw== X-Gm-Message-State: AElRT7GqLlfRhuHVO8HXHElzf90hYvv6g9spSJi3/6gM/Q0IKS1AaDqh DWTvRAwt/+5l+Gp3oHXTSQe+nQ== X-Google-Smtp-Source: AG47ELs5BXJmw9ijlA9SRNl1GjxzojJI7QWeBbN/Qz6ubU0dLBjG50Yeg91Cu2hhd6QbmUNoTxAVbQ== X-Received: by 10.101.97.15 with SMTP id z15mr17179733pgu.393.1521756484367; Thu, 22 Mar 2018 15:08:04 -0700 (PDT) Received: from gizo.domain (184-100-240-187.ptld.qwest.net. [184.100.240.187]) by smtp.gmail.com with ESMTPSA id 4sm2280775pfn.32.2018.03.22.15.08.03 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Mar 2018 15:08:03 -0700 (PDT) From: Greg Rose To: dev@openvswitch.org Date: Thu, 22 Mar 2018 15:07:28 -0700 Message-Id: <1521756461-3870-13-git-send-email-gvrose8192@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1521756461-3870-1-git-send-email-gvrose8192@gmail.com> References: <1521756461-3870-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] [ERSPAN RFC 12/25] ip_gre: erspan: reload pointer after pskb_may_pull 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 From: William Tu Upstream commit: commit d91e8db5b629a3c8c81db4dc317a66c7b5591821 Author: William Tu Date: Fri Dec 15 14:27:44 2017 -0800 net: erspan: reload pointer after pskb_may_pull pskb_may_pull() can change skb->data, so we need to re-load pkt_md and ershdr at the right place. Fixes: 94d7d8f29287 ("ip6_gre: add erspan v2 support") Fixes: f551c91de262 ("net: erspan: introduce erspan v2 for ip_gre") Signed-off-by: William Tu Cc: Haishuang Yan Signed-off-by: David S. Miller Only the ip_gre portion of the upstream commit. The ipv6 portion is pulled in with later patch in series. Cc: William Tu Signed-off-by: Greg Rose --- datapath/linux/compat/ip_gre.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index 183b451..9863dd7 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -161,7 +161,6 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, * Use ERSPAN 10-bit session ID as key. */ tpi->key = cpu_to_be32(ntohs(ershdr->session_id) & ID_MASK); - pkt_md = (struct erspan_metadata *)(ershdr + 1); tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags | TUNNEL_KEY, iph->saddr, iph->daddr, tpi->key); @@ -171,6 +170,9 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, if (unlikely(!pskb_may_pull(skb, len))) return PACKET_REJECT; + ershdr = (struct erspan_base_hdr *)skb->data; + pkt_md = (struct erspan_metadata *)(ershdr + 1); + if (__iptunnel_pull_header(skb, len, htons(ETH_P_TEB), From patchwork Thu Mar 22 22:07:29 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Rose X-Patchwork-Id: 889681 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="doc1zjW2"; 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 406gt40ZNHz9s0y for ; Fri, 23 Mar 2018 09:13:32 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id E008CF32; Thu, 22 Mar 2018 22:08:12 +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 C8EECEF2 for ; Thu, 22 Mar 2018 22:08:06 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pg0-f66.google.com (mail-pg0-f66.google.com [74.125.83.66]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 870455E1 for ; Thu, 22 Mar 2018 22:08:06 +0000 (UTC) Received: by mail-pg0-f66.google.com with SMTP id f10so3651037pgs.9 for ; Thu, 22 Mar 2018 15:08:06 -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=AufApuBB0WfX3SAnyQuxVEEWcyC/M4Uw2H8Z210vWBY=; b=doc1zjW2xCGR4q738L3L5ccDs9ktl4KJU4k4FrwGHPRue8hLoxXWfOU6qSnzxOJmMG zVJ98WESMgqyyZNG+S9gDZVClTAiFF2DnAyF9uKCnFt90onFX63rc50SoMS7JM3TcaUv vAXKwyJF2s5T7qXUBHQweprEsGwuehyUp/+S9ChJ+k83M2w2A+6ITEUnVbnCiZoYYROk FfCntRSoEPFhM6o/+gfjzXQnKUXLo3hTQ5alaR/mWVjSYdS/ZShkGLghgWL5bbCH+Pxc pGSRyWV9tQYqeioZpeJ9xPhPSAwaa47eSG5kmsHpiFf4d1WUtB9Yt96lqW9sVYxdrnXY yvKg== 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=AufApuBB0WfX3SAnyQuxVEEWcyC/M4Uw2H8Z210vWBY=; b=qG6IaqP7XoCCvxQDvTgiYTYKf+p2MsAYGk1781z9i73VkfGBOYC8LGllgr8yVCUsBJ s/g8OsuqgISccNYMTleXHPOZT3ZeLvFxYhQsfFrmLl7QM4PQXaR6U37iK1eq04KxFCRP Nu+fnD30viwvV/x9pxBc9A6IRsNs/3zyKfuIoOUfz0+GYptI8/WYZ7E6/GhNnCouIxM8 LwkFtqxHpRrI7qXgCUkY7xF6n4EYVQMSA9ZGSCg0vUadytC1TTMF/Wm9LEh23tM8Ts/Q KeEsUsrP08gFbrl54BaZ1LNqjKniV2IpZWM9SAR7/xKnljA+qJYvAgCuoOWBh55cs5ea Fmsg== X-Gm-Message-State: AElRT7E+s3w7ATeutpkIHIQKuIJzoxF1Z2644erxPrY4s488qEv3oVZ8 nKkK9UTgpf3x44yZi65ULC33pA== X-Google-Smtp-Source: AG47ELsFUoBzpcpMb35fRvGPqk2MOUu8rEAkA9tSoACx3kIrXi/chOfDWss8bDDoh+n6c2w6lIq2Vw== X-Received: by 10.99.171.72 with SMTP id k8mr19510182pgp.355.1521756485719; Thu, 22 Mar 2018 15:08:05 -0700 (PDT) Received: from gizo.domain (184-100-240-187.ptld.qwest.net. [184.100.240.187]) by smtp.gmail.com with ESMTPSA id 4sm2280775pfn.32.2018.03.22.15.08.04 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Mar 2018 15:08:04 -0700 (PDT) From: Greg Rose To: dev@openvswitch.org Date: Thu, 22 Mar 2018 15:07:29 -0700 Message-Id: <1521756461-3870-14-git-send-email-gvrose8192@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1521756461-3870-1-git-send-email-gvrose8192@gmail.com> References: <1521756461-3870-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 Cc: Xin Long Subject: [ovs-dev] [ERSPAN RFC 13/25] ip_gre: remove the incorrect mtu limit for ipgre tap 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 From: Xin Long Upstream commit: commit cfddd4c33c254954927942599d299b3865743146 Author: Xin Long Date: Mon Dec 18 14:24:35 2017 +0800 ip_gre: remove the incorrect mtu limit for ipgre tap ipgre tap driver calls ether_setup(), after commit 61e84623ace3 ("net: centralize net_device min/max MTU checking"), the range of mtu is [min_mtu, max_mtu], which is [68, 1500] by default. It causes the dev mtu of the ipgre tap device to not be greater than 1500, this limit value is not correct for ipgre tap device. Besides, it's .change_mtu already does the right check. So this patch is just to set max_mtu as 0, and leave the check to it's .change_mtu. Fixes: 61e84623ace3 ("net: centralize net_device min/max MTU checking") Reported-by: Jianlin Shi Signed-off-by: Xin Long Signed-off-by: David S. Miller Cc: Xin Long Signed-off-by: Greg Rose --- datapath/linux/compat/ip_gre.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index 9863dd7..7cd35a3 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -290,11 +290,11 @@ static int gre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *unused_tpi) if (unlikely(tpi.proto == htons(ETH_P_ERSPAN))) { if (erspan_rcv(skb, &tpi, hdr_len) == PACKET_RCVD) return 0; + goto drop; } if (ipgre_rcv(skb, &tpi) == PACKET_RCVD) return 0; - drop: kfree_skb(skb); @@ -867,6 +867,7 @@ static const struct net_device_ops erspan_netdev_ops = { static void ipgre_tap_setup(struct net_device *dev) { ether_setup(dev); + dev->max_mtu = 0; dev->netdev_ops = &gre_tap_netdev_ops; dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; ip_tunnel_setup(dev, gre_tap_net_id); From patchwork Thu Mar 22 22:07:30 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Rose X-Patchwork-Id: 889682 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="A8WUgfeS"; 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 406gtT068Fz9s0y for ; Fri, 23 Mar 2018 09:13:53 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 28BD0F2E; Thu, 22 Mar 2018 22:08:14 +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 274A4ECE for ; Thu, 22 Mar 2018 22:08:08 +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 DB78F5D3 for ; Thu, 22 Mar 2018 22:08:07 +0000 (UTC) Received: by mail-pf0-f194.google.com with SMTP id m68so3922542pfm.11 for ; Thu, 22 Mar 2018 15:08:07 -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=1dbl3wRfWicWRcfXK7B3geAHkg2Ikc8bGDGLTod14Ao=; b=A8WUgfeSTuWEpzru5qAEXekh8+KrVmfGd2QLtSk1Im1kM+JuV0eyaO52poSXVTDk3Z v2McNS4KQJlTcJURgA/0zVwjLmv2gzOSG10gQKqibi6e5VNTF//i4nLE8moZlm7Eldiy wIaCL5gkyDltDyVhael+8SqZlZ1JNueJTbQGEAs2b5JYvdEN1KS6WNwsBoxpTCJ6lODp l8dOU5aaKaC/53f9diKsGm7EaC3GHTwUsbfVdXRc5OJXPhG9vLpWzOB2+MmPwDbcQtza FqYTGLSs7e8OpZFH27xVd5mBA4gw4a/knK9bys1U/2d+1dn3NfKi6IrTcNIWX2Ykqc5R quEw== 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=1dbl3wRfWicWRcfXK7B3geAHkg2Ikc8bGDGLTod14Ao=; b=gaATJvsbPc/MPvzzb0K2r3PYyBwjxPJ1jI+PwNncRj+K+RTjWVg9lOQnkAgqd9+pRa mkTDIJJuPsWcUDDKw2FKVA9Y68oytpUaVyDP0W2FtmFEMomJKkyl2CHBl+LYNgQuIMpP 1fQOltDjcIZ3WAELkdAYRlBuV6Z8TAKH51RDOH24kk4izGHN0AwTaiLvIb1K+dvDxXyv Yk4QyVx3M0AKUvhZyMv+Y3I62XSvg8eojQbTsK91ngm9Y9ojjXadjXHyDxH6tzHEG1Rw x+lqdxkgMOli/+9uH9t5b+1Tm72wgUz/jRzgMzHF5a8xKPhcPdkPakLGA/4hn2bgub0p UgTQ== X-Gm-Message-State: AElRT7EY5vX2v4Jg2oLgdTPxETS4J+4QXnTN7sU3SnO4RKAKS2y57W/m XWR/rxjLTxeTtMv04mtFSHwqIg== X-Google-Smtp-Source: AG47ELvT28cRgmQ885tVQkqxPBvNkkvD0yTt0M35eb/3RM3uD2JfDdgFlEOsaZxJ5zy85ljFd9J8RQ== X-Received: by 10.99.127.91 with SMTP id p27mr18996216pgn.28.1521756487152; Thu, 22 Mar 2018 15:08:07 -0700 (PDT) Received: from gizo.domain (184-100-240-187.ptld.qwest.net. [184.100.240.187]) by smtp.gmail.com with ESMTPSA id 4sm2280775pfn.32.2018.03.22.15.08.05 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Mar 2018 15:08:06 -0700 (PDT) From: Greg Rose To: dev@openvswitch.org Date: Thu, 22 Mar 2018 15:07:30 -0700 Message-Id: <1521756461-3870-15-git-send-email-gvrose8192@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1521756461-3870-1-git-send-email-gvrose8192@gmail.com> References: <1521756461-3870-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 Cc: Haishuang Yan Subject: [ovs-dev] [ERSPAN RFC 14/25] ip_gre: fix potential memory leak in erspan_rcv 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 From: Haishuang Yan Upstream commit: commit 50670b6ee9bc4ae8f9ce3112b437987adf273245 Author: Haishuang Yan Date: Wed Dec 20 10:07:00 2017 +0800 ip_gre: fix potential memory leak in erspan_rcv If md is NULL, tun_dst must be freed, otherwise it will cause memory leak. Fixes: 1a66a836da6 ("gre: add collect_md mode to ERSPAN tunnel") Cc: William Tu Signed-off-by: Haishuang Yan Signed-off-by: David S. Miller Cc: Haishuang Yan Signed-off-by: Greg Rose --- datapath/linux/compat/ip_gre.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index 7cd35a3..f315b16 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -193,8 +193,10 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, tun_id, sizeof(*md)); md = ip_tunnel_info_opts(&tun_dst.u.tun_info); - if (!md) + if (!md) { + dst_release((struct dst_entry *)tun_dst); return PACKET_REJECT; + } memcpy(md, pkt_md, sizeof(*md)); info = &tun_dst.u.tun_info; From patchwork Thu Mar 22 22:07:31 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Rose X-Patchwork-Id: 889684 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="J28VW+a3"; 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 406gvD68vZz9s0y for ; Fri, 23 Mar 2018 09:14:32 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 70837F48; Thu, 22 Mar 2018 22:08:17 +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 8D9A0F28 for ; Thu, 22 Mar 2018 22:08:11 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pg0-f66.google.com (mail-pg0-f66.google.com [74.125.83.66]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 21EF85D4 for ; Thu, 22 Mar 2018 22:08:10 +0000 (UTC) Received: by mail-pg0-f66.google.com with SMTP id a19so3811938pgw.6 for ; Thu, 22 Mar 2018 15:08:10 -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=C264RLHjNh7yHjVapZL6VdXYw63sW29sdtf5kpnuK7s=; b=J28VW+a3NUCBuQQf3tfPMDdDOMRuWO9dIs/XEbnVt/pYSFzR3cpVJpEF538txJgMR1 C/QlaVDTC02IH75H0cjpeiIOKfmoBDlx/8EXVR7SrSR4ssgiDBkbh72Ja+YW/eHyYzZU OL24DcaKM+UT/kvpKObg5a2vnrlmt9/bc6bz062ycGfqFjLUa6d5/J5buBfT1tbuNakU d0gDdMbHooMk6Nw3Eu8Q2kMCfll1Kiu0YhPoz3bo5bIV6VzRstGCVnO+k+N2h6d2R3gr yBT5lIakXCpTsZgmv038IokrpLxhBADcDhMhda/EZ7cTsg85rJbo4phgKxuM7C6UB12R FvJQ== 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=C264RLHjNh7yHjVapZL6VdXYw63sW29sdtf5kpnuK7s=; b=Ksbx8GreBLBM0mPfZHlbczSESGikuPqaqISG3iNSxzgyVxCsll08/DZaezCRMB40DB r/WuLNxHgR1vlBUS9o19yw7oBYtv9NEGzWbBOWBTulYmNBZtW4VytXTQKfhsgojbr4Ks ZNCmgvIQDtx5V/xsOZhOB/q1yhfLkRBF+bN2Xrc2m9jZxxDXjCKTtaZVuER7ZtMggbau BryOYeD81sAHIo5hQLEkD1qDbk6T0rg71TA4RsV5ZwQkH1OaitI8Q/l67TRuvezLA51v LkW03dQl/3qmVA7O8krBudyVkANysPviAykX7FejuX9x9LubZPo+cnrDaehOU/RfkGT+ NMCw== X-Gm-Message-State: AElRT7F3nsRR3MTfjjlECnB4TPJWqgUBjJ1n9gdlwPpvm7cMuLnYBXeT Y1JwFCjgFjHwY4u5JEQnev6mgg== X-Google-Smtp-Source: AG47ELv/EG/aP0ou8O93/0rzOoEAx4fLNQfjbRKNuR3AfnlHUBZzQ1hEEi2BFU53hFr7jtKvuRePdw== X-Received: by 10.101.99.149 with SMTP id h21mr16723596pgv.345.1521756488630; Thu, 22 Mar 2018 15:08:08 -0700 (PDT) Received: from gizo.domain (184-100-240-187.ptld.qwest.net. [184.100.240.187]) by smtp.gmail.com with ESMTPSA id 4sm2280775pfn.32.2018.03.22.15.08.07 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Mar 2018 15:08:07 -0700 (PDT) From: Greg Rose To: dev@openvswitch.org Date: Thu, 22 Mar 2018 15:07:31 -0700 Message-Id: <1521756461-3870-16-git-send-email-gvrose8192@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1521756461-3870-1-git-send-email-gvrose8192@gmail.com> References: <1521756461-3870-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] [ERSPAN RFC 15/25] compat: Remove unsupported kernel compat code 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 Anything less than 3.10 isn't supported since a couple of releases ago so remove the dead code. Signed-off-by: Greg Rose --- datapath/linux/compat/include/linux/etherdevice.h | 30 ------ datapath/linux/compat/include/linux/if_vlan.h | 11 --- datapath/linux/compat/include/linux/kconfig.h | 8 -- datapath/linux/compat/include/linux/kernel.h | 38 -------- .../linux/compat/include/linux/netdev_features.h | 19 ---- datapath/linux/compat/include/linux/netdevice.h | 5 - datapath/linux/compat/include/linux/skbuff.h | 7 -- datapath/linux/compat/include/linux/workqueue.h | 4 - datapath/linux/compat/include/net/checksum.h | 6 -- datapath/linux/compat/include/net/dst.h | 28 +----- datapath/linux/compat/include/net/genetlink.h | 11 --- datapath/linux/compat/include/net/ip6_route.h | 23 ----- datapath/linux/compat/include/net/ip_tunnels.h | 4 - datapath/linux/compat/include/net/ipv6.h | 15 --- .../include/net/netfilter/nf_conntrack_zones.h | 2 - datapath/linux/compat/include/net/netlink.h | 15 --- datapath/linux/compat/include/net/route.h | 105 --------------------- datapath/linux/compat/ip_gre.c | 11 --- datapath/linux/compat/ip_tunnel.c | 6 -- datapath/linux/compat/lisp.c | 2 - datapath/linux/compat/stt.c | 6 -- datapath/linux/compat/udp_tunnel.c | 2 - datapath/linux/compat/utils.c | 22 ----- 23 files changed, 1 insertion(+), 379 deletions(-) diff --git a/datapath/linux/compat/include/linux/etherdevice.h b/datapath/linux/compat/include/linux/etherdevice.h index 850b779..4b27074 100644 --- a/datapath/linux/compat/include/linux/etherdevice.h +++ b/datapath/linux/compat/include/linux/etherdevice.h @@ -4,36 +4,6 @@ #include #include_next -#ifndef HAVE_ETH_HW_ADDR_RANDOM -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) -static inline void eth_hw_addr_random(struct net_device *dev) -{ - random_ether_addr(dev->dev_addr); -} -#elif LINUX_VERSION_CODE < KERNEL_VERSION(3,4,0) -static inline void eth_hw_addr_random(struct net_device *dev) -{ - dev_hw_addr_random(dev, dev->dev_addr); -} -#endif -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0) -#define eth_mac_addr rpl_eth_mac_addr -static inline int eth_mac_addr(struct net_device *dev, void *p) -{ - struct sockaddr *addr = p; - - if (!is_valid_ether_addr(addr->sa_data)) - return -EADDRNOTAVAIL; -#ifdef NET_ADDR_RANDOM - dev->addr_assign_type &= ~NET_ADDR_RANDOM; -#endif - memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - return 0; -} -#endif - #ifndef HAVE_ETHER_ADDR_COPY static inline void ether_addr_copy(u8 *dst, const u8 *src) { diff --git a/datapath/linux/compat/include/linux/if_vlan.h b/datapath/linux/compat/include/linux/if_vlan.h index fc95b04..2cf18e5 100644 --- a/datapath/linux/compat/include/linux/if_vlan.h +++ b/datapath/linux/compat/include/linux/if_vlan.h @@ -90,17 +90,6 @@ static inline struct sk_buff *vlan_hwaccel_push_inside(struct sk_buff *skb) } #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) -static inline struct sk_buff *rpl___vlan_hwaccel_put_tag(struct sk_buff *skb, - __be16 vlan_proto, - u16 vlan_tci) -{ - return __vlan_hwaccel_put_tag(skb, vlan_tci); -} - -#define __vlan_hwaccel_put_tag rpl___vlan_hwaccel_put_tag -#endif - #ifndef HAVE_ETH_TYPE_VLAN /** * eth_type_vlan - check for valid vlan ether type. diff --git a/datapath/linux/compat/include/linux/kconfig.h b/datapath/linux/compat/include/linux/kconfig.h index 5717a26..d3fa57a 100644 --- a/datapath/linux/compat/include/linux/kconfig.h +++ b/datapath/linux/compat/include/linux/kconfig.h @@ -3,14 +3,6 @@ #include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) -#define CONFIG_NET_IPGRE_DEMUX 1 -#endif - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,1,0) -#include_next -#endif - #ifndef IS_ENABLED /* diff --git a/datapath/linux/compat/include/linux/kernel.h b/datapath/linux/compat/include/linux/kernel.h index 5c4269b..2e81abc 100644 --- a/datapath/linux/compat/include/linux/kernel.h +++ b/datapath/linux/compat/include/linux/kernel.h @@ -8,44 +8,6 @@ #include -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) -#define pr_warn pr_warning -#endif - -/* - * Print a one-time message (analogous to WARN_ONCE() et al): - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38) -#undef printk_once -#define printk_once(fmt, ...) \ -({ \ - static bool __print_once; \ - \ - if (!__print_once) { \ - __print_once = true; \ - printk(fmt, ##__VA_ARGS__); \ - } \ -}) - -#define pr_emerg_once(fmt, ...) \ - printk_once(KERN_EMERG pr_fmt(fmt), ##__VA_ARGS__) -#define pr_alert_once(fmt, ...) \ - printk_once(KERN_ALERT pr_fmt(fmt), ##__VA_ARGS__) -#define pr_crit_once(fmt, ...) \ - printk_once(KERN_CRIT pr_fmt(fmt), ##__VA_ARGS__) -#define pr_err_once(fmt, ...) \ - printk_once(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) -#define pr_warn_once(fmt, ...) \ - printk_once(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__) -#define pr_notice_once(fmt, ...) \ - printk_once(KERN_NOTICE pr_fmt(fmt), ##__VA_ARGS__) -#define pr_info_once(fmt, ...) \ - printk_once(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__) -#define pr_cont_once(fmt, ...) \ - printk_once(KERN_CONT pr_fmt(fmt), ##__VA_ARGS__) - -#endif - #ifndef USHRT_MAX #define USHRT_MAX ((u16)(~0U)) #define SHRT_MAX ((s16)(USHRT_MAX>>1)) diff --git a/datapath/linux/compat/include/linux/netdev_features.h b/datapath/linux/compat/include/linux/netdev_features.h index a39bd4a..411f294 100644 --- a/datapath/linux/compat/include/linux/netdev_features.h +++ b/datapath/linux/compat/include/linux/netdev_features.h @@ -1,18 +1,7 @@ #ifndef __LINUX_NETDEV_FEATURES_WRAPPER_H #define __LINUX_NETDEV_FEATURES_WRAPPER_H -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,3,0) #include_next -#endif - -#if RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(7,0) -/* On RHEL 6, netdev features are defined in netdevice.h header. */ -#include -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) -#define NETIF_F_HW_VLAN_CTAG_TX NETIF_F_HW_VLAN_TX -#endif #ifndef NETIF_F_GSO_GRE #define NETIF_F_GSO_GRE 0 @@ -81,14 +70,6 @@ NETIF_F_GSO_MPLS) #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0) -#define SKB_GSO_GRE 0 -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,10,0) -#define SKB_GSO_UDP_TUNNEL 0 -#endif - #ifndef HAVE_NETIF_F_GSO_GRE_CSUM #define SKB_GSO_GRE_CSUM 0 #endif diff --git a/datapath/linux/compat/include/linux/netdevice.h b/datapath/linux/compat/include/linux/netdevice.h index 9d3b249..29ef6c7 100644 --- a/datapath/linux/compat/include/linux/netdevice.h +++ b/datapath/linux/compat/include/linux/netdevice.h @@ -37,11 +37,6 @@ struct net; alloc_netdev_mq(sizeof_priv, name, setup, 1) #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,33) -#define unregister_netdevice_queue(dev, head) unregister_netdevice(dev) -#define unregister_netdevice_many(head) -#endif - #ifndef HAVE_DEV_DISABLE_LRO extern void dev_disable_lro(struct net_device *dev); #endif diff --git a/datapath/linux/compat/include/linux/skbuff.h b/datapath/linux/compat/include/linux/skbuff.h index f0665ed..45778bd 100644 --- a/datapath/linux/compat/include/linux/skbuff.h +++ b/datapath/linux/compat/include/linux/skbuff.h @@ -241,13 +241,6 @@ static inline int skb_orphan_frags(struct sk_buff *skb, gfp_t gfp_mask) #define skb_get_hash skb_get_rxhash #endif /* HAVE_SKB_GET_HASH */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0) -static inline void skb_tx_error(struct sk_buff *skb) -{ - return; -} -#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0) */ - #if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0) #define skb_zerocopy_headlen rpl_skb_zerocopy_headlen unsigned int rpl_skb_zerocopy_headlen(const struct sk_buff *from); diff --git a/datapath/linux/compat/include/linux/workqueue.h b/datapath/linux/compat/include/linux/workqueue.h index 461fefd..ed573c2 100644 --- a/datapath/linux/compat/include/linux/workqueue.h +++ b/datapath/linux/compat/include/linux/workqueue.h @@ -3,8 +3,4 @@ #include_next -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,36) -#define queue_work(wq, dw) schedule_work(dw); -#endif - #endif diff --git a/datapath/linux/compat/include/net/checksum.h b/datapath/linux/compat/include/net/checksum.h index 398df93..d1f1125 100644 --- a/datapath/linux/compat/include/net/checksum.h +++ b/datapath/linux/compat/include/net/checksum.h @@ -36,10 +36,4 @@ static inline void csum_replace2(__sum16 *sum, __be16 from, __be16 to) #define CSUM_MANGLED_0 ((__force __sum16)0xffff) #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) -#define inet_proto_csum_replace16 rpl_inet_proto_csum_replace16 -void rpl_inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb, - const __be32 *from, const __be32 *to, - int pseudohdr); -#endif #endif /* checksum.h */ diff --git a/datapath/linux/compat/include/net/dst.h b/datapath/linux/compat/include/net/dst.h index 5ec3d30..af78a6c 100644 --- a/datapath/linux/compat/include/net/dst.h +++ b/datapath/linux/compat/include/net/dst.h @@ -4,13 +4,6 @@ #include #include_next -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,3,0) && \ - LINUX_VERSION_CODE > KERNEL_VERSION(3,0,20) - -#define dst_get_neighbour_noref dst_get_neighbour - -#endif - #ifndef HAVE_SKB_DST_ACCESSOR_FUNCS static inline void skb_dst_drop(struct sk_buff *skb) @@ -30,19 +23,7 @@ static inline void skb_dst_drop(struct sk_buff *skb) #define DST_NOCOUNT 0 #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35) -static inline void __skb_dst_copy(struct sk_buff *nskb, unsigned long refdst) -{ - nskb->_skb_dst = refdst; - dst_clone(skb_dst(nskb)); -} - -static inline void refdst_drop(unsigned long refdst) { } -static inline void skb_dst_set_noref(struct sk_buff *skb, - struct dst_entry *dst) { } -static inline void dst_init_metrics(struct dst_entry *dst, const u32 *metrics, - bool read_only) { } -#elif !defined(HAVE___SKB_DST_COPY) +#if !defined(HAVE___SKB_DST_COPY) static inline void __skb_dst_copy(struct sk_buff *nskb, unsigned long refdst) { nskb->_skb_refdst = refdst; @@ -51,13 +32,6 @@ static inline void __skb_dst_copy(struct sk_buff *nskb, unsigned long refdst) } #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) -static inline void dst_entries_add(struct dst_ops *ops, int count) -{ - atomic_add(count, &ops->entries); -} -#endif - #if LINUX_VERSION_CODE < KERNEL_VERSION(4,3,0) static const u32 rpl_dst_default_metrics[RTAX_MAX + 1] = { /* This initializer is needed to force linker to place this variable diff --git a/datapath/linux/compat/include/net/genetlink.h b/datapath/linux/compat/include/net/genetlink.h index b05eae5..602ce38 100644 --- a/datapath/linux/compat/include/net/genetlink.h +++ b/datapath/linux/compat/include/net/genetlink.h @@ -6,17 +6,6 @@ #include #include_next -/* - * 15e473046cb6e5d18a4d0057e61d76315230382b renames pid to portid - * the affected structures are - * netlink_skb_parms::pid -> portid - * genl_info::snd_pid -> snd_portid - */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) -#define snd_portid snd_pid -#define portid pid -#endif - #ifndef HAVE_GENL_NOTIFY_TAKES_FAMILY struct rpl_genl_family { struct genl_family compat_family; diff --git a/datapath/linux/compat/include/net/ip6_route.h b/datapath/linux/compat/include/net/ip6_route.h index e49ca39..7c78fd5 100644 --- a/datapath/linux/compat/include/net/ip6_route.h +++ b/datapath/linux/compat/include/net/ip6_route.h @@ -7,29 +7,6 @@ #include_next -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39) - -static inline -struct dst_entry *rpl_ip6_route_output(struct net *net, const struct sock *sk, - struct flowi6 *fl6) -{ - struct flowi fl; - - memset(&fl, 0, sizeof(fl)); - fl.oif = fl6->flowi6_oif; - fl.fl6_dst = fl6->daddr; - fl.fl6_src = fl6->saddr; - fl.mark = fl6->flowi6_mark; - fl.proto = fl6->flowi6_proto; - - return ip6_route_output(net, (struct sock *) sk, &fl); -} -#define ip6_route_output rpl_ip6_route_output - -#define ip6_dst_hoplimit(dst) dst_metric(dst, RTAX_HOPLIMIT) - -#endif /* 2.6.39 */ - #ifndef HAVE_NF_IPV6_OPS_FRAGMENT int rpl_ip6_fragment(struct sock *sk, struct sk_buff *skb, int (*output)(OVS_VPORT_OUTPUT_PARAMS)); diff --git a/datapath/linux/compat/include/net/ip_tunnels.h b/datapath/linux/compat/include/net/ip_tunnels.h index 159eb48..4c1f0a1 100644 --- a/datapath/linux/compat/include/net/ip_tunnels.h +++ b/datapath/linux/compat/include/net/ip_tunnels.h @@ -444,11 +444,7 @@ int rpl_ip_tunnel_newlink(struct net_device *dev, struct nlattr *tb[], struct ip_tunnel_parm *p); #define ip_tunnel_dellink rpl_ip_tunnel_dellink -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) void rpl_ip_tunnel_dellink(struct net_device *dev, struct list_head *head); -#else -void rpl_ip_tunnel_dellink(struct net_device *dev); -#endif #define ip_tunnel_init_net rpl_ip_tunnel_init_net int rpl_ip_tunnel_init_net(struct net *net, int ip_tnl_net_id, diff --git a/datapath/linux/compat/include/net/ipv6.h b/datapath/linux/compat/include/net/ipv6.h index 48a307a..7fc0339 100644 --- a/datapath/linux/compat/include/net/ipv6.h +++ b/datapath/linux/compat/include/net/ipv6.h @@ -26,21 +26,6 @@ extern int rpl_ipv6_find_hdr(const struct sk_buff *skb, unsigned int *offset, int target, unsigned short *fragoff, int *fragflg); #endif -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,6,0) -static inline u32 ipv6_addr_hash(const struct in6_addr *a) -{ -#if defined(CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS) && BITS_PER_LONG == 64 - const unsigned long *ul = (const unsigned long *)a; - unsigned long x = ul[0] ^ ul[1]; - - return (u32)(x ^ (x >> 32)); -#else - return (__force u32)(a->s6_addr32[0] ^ a->s6_addr32[1] ^ - a->s6_addr32[2] ^ a->s6_addr32[3]); -#endif -} -#endif - #ifndef HAVE___IPV6_ADDR_JHASH static inline u32 __ipv6_addr_jhash(const struct in6_addr *a, const u32 unused) { diff --git a/datapath/linux/compat/include/net/netfilter/nf_conntrack_zones.h b/datapath/linux/compat/include/net/netfilter/nf_conntrack_zones.h index fb43acb..d46c098 100644 --- a/datapath/linux/compat/include/net/netfilter/nf_conntrack_zones.h +++ b/datapath/linux/compat/include/net/netfilter/nf_conntrack_zones.h @@ -3,9 +3,7 @@ #include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,34) #include_next -#endif #ifndef HAVE_NF_CT_ZONE_INIT diff --git a/datapath/linux/compat/include/net/netlink.h b/datapath/linux/compat/include/net/netlink.h index ba24a34..d42bf10 100644 --- a/datapath/linux/compat/include/net/netlink.h +++ b/datapath/linux/compat/include/net/netlink.h @@ -16,21 +16,6 @@ static inline __be16 nla_get_be16(const struct nlattr *nla) } #endif /* !HAVE_NLA_GET_BE16 */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,34) -/* This function was introduced in 2.6.31, but initially it performed an - * unaligned access, so we replace it up to 2.6.34 where it was fixed. */ -#define nla_get_be64 rpl_nla_get_be64 -static inline __be64 nla_get_be64(const struct nlattr *nla) -{ - __be64 tmp; - - /* The additional cast is necessary because */ - nla_memcpy(&tmp, (struct nlattr *) nla, sizeof(tmp)); - - return tmp; -} -#endif - #ifndef HAVE_NLA_PUT_BE16 static inline int nla_put_be16(struct sk_buff *skb, int attrtype, __be16 value) { diff --git a/datapath/linux/compat/include/net/route.h b/datapath/linux/compat/include/net/route.h index 8f336b6..9e4a1f1 100644 --- a/datapath/linux/compat/include/net/route.h +++ b/datapath/linux/compat/include/net/route.h @@ -3,109 +3,4 @@ #include_next -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,39) -struct flowi_common { - int flowic_oif; - __u32 flowic_mark; - __u8 flowic_tos; - __u8 flowic_proto; -}; - -union flowi_uli { - struct { - __be16 dport; - __be16 sport; - } ports; - - struct { - __u8 type; - __u8 code; - } icmpt; - - struct { - __le16 dport; - __le16 sport; - } dnports; - - __be32 spi; - __be32 gre_key; - - struct { - __u8 type; - } mht; -}; - -struct flowi4 { - struct flowi_common __fl_common; -#define flowi4_oif __fl_common.flowic_oif -#define flowi4_iif __fl_common.flowic_iif -#define flowi4_mark __fl_common.flowic_mark -#define flowi4_tos __fl_common.flowic_tos -#define flowi4_scope __fl_common.flowic_scope -#define flowi4_proto __fl_common.flowic_proto -#define flowi4_flags __fl_common.flowic_flags -#define flowi4_secid __fl_common.flowic_secid -#define flowi4_tun_key __fl_common.flowic_tun_key - - union flowi_uli uli; -#define fl4_gre_key uli.gre_key - - /* (saddr,daddr) must be grouped, same order as in IP header */ - __be32 saddr; - __be32 daddr; - -} __attribute__((__aligned__(BITS_PER_LONG/8))); - -struct flowi6 { - struct flowi_common __fl_common; -#define flowi6_oif __fl_common.flowic_oif -#define flowi6_iif __fl_common.flowic_iif -#define flowi6_mark __fl_common.flowic_mark -#define flowi6_tos __fl_common.flowic_tos -#define flowi6_scope __fl_common.flowic_scope -#define flowi6_proto __fl_common.flowic_proto -#define flowi6_flags __fl_common.flowic_flags -#define flowi6_secid __fl_common.flowic_secid -#define flowi6_tun_key __fl_common.flowic_tun_key - struct in6_addr daddr; - struct in6_addr saddr; - __be32 flowlabel; - union flowi_uli uli; -#define fl6_sport uli.ports.sport -#define fl6_dport uli.ports.dport -#define fl6_icmp_type uli.icmpt.type -#define fl6_icmp_code uli.icmpt.code -#define fl6_ipsec_spi uli.spi -#define fl6_mh_type uli.mht.type -#define fl6_gre_key uli.gre_key -} __attribute__((__aligned__(BITS_PER_LONG/8))); - -static inline struct rtable *rpl_ip_route_output_key(struct net *net, struct flowi4 *flp) -{ - struct rtable *rt; - /* Tunnel configuration keeps DSCP part of TOS bits, But Linux - * router expect RT_TOS bits only. - */ - - struct flowi fl = { .nl_u = { .ip4_u = { - .daddr = flp->daddr, - .saddr = flp->saddr, - .tos = RT_TOS(flp->flowi4_tos) } }, - .mark = flp->flowi4_mark, - .proto = flp->flowi4_proto }; - - if (unlikely(ip_route_output_key(net, &rt, &fl))) - return ERR_PTR(-EADDRNOTAVAIL); - flp->saddr = fl.nl_u.ip4_u.saddr; - return rt; -} -#define ip_route_output_key rpl_ip_route_output_key -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,38) -static inline int ip4_dst_hoplimit(const struct dst_entry *dst) -{ - return dst_metric(dst, RTAX_HOPLIMIT); -} -#endif #endif diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index f315b16..e684019 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -609,16 +609,12 @@ static void __gre_tunnel_init(struct net_device *dev) dev->mtu = ETH_DATA_LEN - t_hlen - 4; dev->features |= GRE_FEATURES; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) dev->hw_features |= GRE_FEATURES; -#endif if (!(tunnel->parms.o_flags & TUNNEL_SEQ)) { /* TCP offload with GRE SEQ is not supported. */ dev->features |= NETIF_F_GSO_SOFTWARE; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) dev->hw_features |= NETIF_F_GSO_SOFTWARE; -#endif /* Can use a lockless transmit, unless we generate * output sequences */ @@ -818,9 +814,7 @@ static const struct net_device_ops gre_tap_netdev_ops = { .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = ip_tunnel_change_mtu, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) .ndo_get_stats64 = ip_tunnel_get_stats64, -#endif #ifdef HAVE_NDO_GET_IFLINK .ndo_get_iflink = ip_tunnel_get_iflink, #endif @@ -875,13 +869,8 @@ static void ipgre_tap_setup(struct net_device *dev) ip_tunnel_setup(dev, gre_tap_net_id); } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) static int ipgre_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) -#else -static int ipgre_newlink(struct net_device *dev, - struct nlattr *tb[], struct nlattr *data[]) -#endif { struct ip_tunnel_parm p; int err; diff --git a/datapath/linux/compat/ip_tunnel.c b/datapath/linux/compat/ip_tunnel.c index 6e9fa95..d8cd798 100644 --- a/datapath/linux/compat/ip_tunnel.c +++ b/datapath/linux/compat/ip_tunnel.c @@ -431,11 +431,7 @@ static void ip_tunnel_dev_free(struct net_device *dev) free_netdev(dev); } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) void rpl_ip_tunnel_dellink(struct net_device *dev, struct list_head *head) -#else -void rpl_ip_tunnel_dellink(struct net_device *dev) -#endif { struct ip_tunnel *tunnel = netdev_priv(dev); struct ip_tunnel_net *itn; @@ -443,9 +439,7 @@ void rpl_ip_tunnel_dellink(struct net_device *dev) itn = net_generic(tunnel->net, tunnel->ip_tnl_net_id); ip_tunnel_del(itn, netdev_priv(dev)); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) unregister_netdevice_queue(dev, head); -#endif } int rpl_ip_tunnel_init_net(struct net *net, int ip_tnl_net_id, diff --git a/datapath/linux/compat/lisp.c b/datapath/linux/compat/lisp.c index 34f8232..f7e48ff 100644 --- a/datapath/linux/compat/lisp.c +++ b/datapath/linux/compat/lisp.c @@ -593,10 +593,8 @@ static void lisp_setup(struct net_device *dev) dev->features |= NETIF_F_RXCSUM; dev->features |= NETIF_F_GSO_SOFTWARE; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,39) dev->hw_features |= NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_RXCSUM; dev->hw_features |= NETIF_F_GSO_SOFTWARE; -#endif #ifdef USE_UPSTREAM_TUNNEL netif_keep_dst(dev); #endif diff --git a/datapath/linux/compat/stt.c b/datapath/linux/compat/stt.c index 2189476..405d0d7 100644 --- a/datapath/linux/compat/stt.c +++ b/datapath/linux/compat/stt.c @@ -239,9 +239,7 @@ static void copy_skb_metadata(struct sk_buff *to, struct sk_buff *from) to->priority = from->priority; to->mark = from->mark; to->vlan_tci = from->vlan_tci; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) to->vlan_proto = from->vlan_proto; -#endif skb_copy_secmark(to, from); } @@ -762,10 +760,8 @@ static int stt_can_offload(struct sk_buff *skb, __be16 l3_proto, u8 l4_proto) if (skb->len + STT_HEADER_LEN + sizeof(struct iphdr) > 65535) return 0; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) if (skb_vlan_tag_present(skb) && skb->vlan_proto != htons(ETH_P_8021Q)) return 0; -#endif return 1; } @@ -792,7 +788,6 @@ static struct sk_buff *handle_offloads(struct sk_buff *skb, int min_headroom) { int err; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,10,0) if (skb_vlan_tag_present(skb) && skb->vlan_proto != htons(ETH_P_8021Q)) { min_headroom += VLAN_HLEN; @@ -812,7 +807,6 @@ static struct sk_buff *handle_offloads(struct sk_buff *skb, int min_headroom) goto error; } } -#endif if (skb_is_gso(skb)) { struct sk_buff *nskb; diff --git a/datapath/linux/compat/udp_tunnel.c b/datapath/linux/compat/udp_tunnel.c index 23801bb..852069f 100644 --- a/datapath/linux/compat/udp_tunnel.c +++ b/datapath/linux/compat/udp_tunnel.c @@ -130,9 +130,7 @@ void rpl_setup_udp_tunnel_sock(struct net *net, struct socket *sock, udp_sk(sk)->encap_type = cfg->encap_type; udp_sk(sk)->encap_rcv = cfg->encap_rcv; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,9,0) udp_sk(sk)->encap_destroy = cfg->encap_destroy; -#endif #ifdef HAVE_UDP_TUNNEL_SOCK_CFG_GRO_RECEIVE udp_sk(sk)->gro_receive = cfg->gro_receive; udp_sk(sk)->gro_complete = cfg->gro_complete; diff --git a/datapath/linux/compat/utils.c b/datapath/linux/compat/utils.c index c9546ea..a4a98ba 100644 --- a/datapath/linux/compat/utils.c +++ b/datapath/linux/compat/utils.c @@ -18,28 +18,6 @@ #include #include -#if LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0) -void rpl_inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb, - const __be32 *from, const __be32 *to, - int pseudohdr) -{ - __be32 diff[] = { - ~from[0], ~from[1], ~from[2], ~from[3], - to[0], to[1], to[2], to[3], - }; - if (skb->ip_summed != CHECKSUM_PARTIAL) { - *sum = csum_fold(csum_partial(diff, sizeof(diff), - ~csum_unfold(*sum))); - if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr) - skb->csum = ~csum_partial(diff, sizeof(diff), - ~skb->csum); - } else if (pseudohdr) - *sum = ~csum_fold(csum_partial(diff, sizeof(diff), - csum_unfold(*sum))); -} -EXPORT_SYMBOL_GPL(rpl_inet_proto_csum_replace16); -#endif - #if LINUX_VERSION_CODE < KERNEL_VERSION(3,13,0) bool rpl___net_get_random_once(void *buf, int nbytes, bool *done, From patchwork Thu Mar 22 22:07:32 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Rose X-Patchwork-Id: 889683 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="QhUvl9o1"; 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 406gtr3YZLz9s0y for ; Fri, 23 Mar 2018 09:14:12 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 75948F46; Thu, 22 Mar 2018 22:08:16 +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 F2F07E58 for ; Thu, 22 Mar 2018 22:08:10 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pf0-f193.google.com (mail-pf0-f193.google.com [209.85.192.193]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id B3F975D3 for ; Thu, 22 Mar 2018 22:08:10 +0000 (UTC) Received: by mail-pf0-f193.google.com with SMTP id j2so3921029pff.10 for ; Thu, 22 Mar 2018 15:08:10 -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=D9pKhC+TXjLvjIiSR5KlmAGIy2Y1xwVUbIr1kSnV64k=; b=QhUvl9o174qhxoPzpBwjgYc5q2Pmmt4pkOi3K0OvbNLKEvo6wghmaJMb3pN64NfD3z Pm/UbXfjXAbl+VrJJGmy4N9LU1Uka3tINyo5YoiVSVNN8lY5g3dtGEcFVQhQ0G5y3rSS M5SmvTJ51srnM/07XXFtIzSCfBbDFVSby6F4hcPopLwR1OVuIttLy5LsMuWxc2oGFQ6l YFHdMaUdJTi4kdNWUISHuYMbnKYWo7v7TfEsholx1KrBADqUrXSMa29Bc0uhrA12rFhT sLa22JJlcFD1Q202HkMYlBV2ZayEkrv0GXaBgdoUM4ob5UPBBM2fyg5Ysilsfvir8JL2 Nq5Q== 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=D9pKhC+TXjLvjIiSR5KlmAGIy2Y1xwVUbIr1kSnV64k=; b=VhyamcP/Pa+6qKt6ZeHksyawZwGm/zx14LTpLyHgrgrs2u6HBOxKXbb1VOTRUzRehc uMPnom6C3lDAXvy2w2r1eAsFXGfMovqBnShKo4yTypV7UJFz4JZdWNOlKaR0w++xlW21 Mx3wy7YsKqf+x4yRsMQxFk8L+C4yIzsBTI13av/uOscr7uOu216edSMvePEda6xGyKvy DB49KxHC/S863UPr2IjugNk8XhkrbtaNGaSXQfjum/TkihMMjUE3FaxPDVkKgkuJhxn2 bePmZGg+2IJm8tyYCosa/Z3Y4voLsEJVXmJfYh3Cdl4z+v3S/p7fY4qa5Eb7ZnPMN6bq 1yXg== X-Gm-Message-State: AElRT7HieQGnhcrOV+geRVzp931OrW916oG7uA5e2l2yIufZmGQnxxee T+nsh70n5NSiKuovy7wXvtiQqA== X-Google-Smtp-Source: AG47ELtGzvGjb+JWKu7VKIJQExw5VxB4J3fq3RMlg5/l5g9ZIAl1cvSkoWpZTn4KhLX1YgP7auhcWw== X-Received: by 10.99.127.72 with SMTP id p8mr19516858pgn.52.1521756489866; Thu, 22 Mar 2018 15:08:09 -0700 (PDT) Received: from gizo.domain (184-100-240-187.ptld.qwest.net. [184.100.240.187]) by smtp.gmail.com with ESMTPSA id 4sm2280775pfn.32.2018.03.22.15.08.08 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Mar 2018 15:08:09 -0700 (PDT) From: Greg Rose To: dev@openvswitch.org Date: Thu, 22 Mar 2018 15:07:32 -0700 Message-Id: <1521756461-3870-17-git-send-email-gvrose8192@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1521756461-3870-1-git-send-email-gvrose8192@gmail.com> References: <1521756461-3870-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] [ERSPAN RFC 16/25] compat: Move function to header 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 tnl_flags_to_gre_flags is also needed in both ip_gre.c and gre.c on some kernels. Move it from ip_gre.c to the common header. Signed-off-by: Greg Rose --- datapath/linux/compat/include/net/gre.h | 23 +++++++++++++++++++++++ datapath/linux/compat/ip_gre.c | 23 ----------------------- 2 files changed, 23 insertions(+), 23 deletions(-) diff --git a/datapath/linux/compat/include/net/gre.h b/datapath/linux/compat/include/net/gre.h index ead86f6..e2473f2 100644 --- a/datapath/linux/compat/include/net/gre.h +++ b/datapath/linux/compat/include/net/gre.h @@ -30,6 +30,29 @@ static inline struct net_device *rpl_gretap_fb_dev_create( #else #include_next +#define tnl_flags_to_gre_flags rpl_tnl_flags_to_gre_flags +static inline __be16 tnl_flags_to_gre_flags(__be16 tflags) +{ + __be16 flags = 0; + + if (tflags & TUNNEL_CSUM) + flags |= GRE_CSUM; + if (tflags & TUNNEL_ROUTING) + flags |= GRE_ROUTING; + if (tflags & TUNNEL_KEY) + flags |= GRE_KEY; + if (tflags & TUNNEL_SEQ) + flags |= GRE_SEQ; + if (tflags & TUNNEL_STRICT) + flags |= GRE_STRICT; + if (tflags & TUNNEL_REC) + flags |= GRE_REC; + if (tflags & TUNNEL_VERSION) + flags |= GRE_VERSION; + + return flags; +} + #ifndef HAVE_GRE_CISCO_REGISTER /* GRE demux not available, implement our own demux. */ diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index e684019..9ed391d 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -83,29 +83,6 @@ static int ip_gre_calc_hlen(__be16 o_flags) return addend; } -#define tnl_flags_to_gre_flags rpl_tnl_flags_to_gre_flags -static __be16 tnl_flags_to_gre_flags(__be16 tflags) -{ - __be16 flags = 0; - - if (tflags & TUNNEL_CSUM) - flags |= GRE_CSUM; - if (tflags & TUNNEL_ROUTING) - flags |= GRE_ROUTING; - if (tflags & TUNNEL_KEY) - flags |= GRE_KEY; - if (tflags & TUNNEL_SEQ) - flags |= GRE_SEQ; - if (tflags & TUNNEL_STRICT) - flags |= GRE_STRICT; - if (tflags & TUNNEL_REC) - flags |= GRE_REC; - if (tflags & TUNNEL_VERSION) - flags |= GRE_VERSION; - - return flags; -} - static __be64 key_to_tunnel_id(__be32 key) { #ifdef __BIG_ENDIAN From patchwork Thu Mar 22 22:07:33 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Rose X-Patchwork-Id: 889685 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="BV9UIHrE"; 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 406gvf4G6jz9s0y for ; Fri, 23 Mar 2018 09:14:54 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 7288DF4A; Thu, 22 Mar 2018 22:08:18 +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 37FC1F14 for ; Thu, 22 Mar 2018 22:08:12 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pg0-f65.google.com (mail-pg0-f65.google.com [74.125.83.65]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id E86375D7 for ; Thu, 22 Mar 2018 22:08:11 +0000 (UTC) Received: by mail-pg0-f65.google.com with SMTP id m24so3809866pgv.8 for ; Thu, 22 Mar 2018 15:08:11 -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=lUJjOznZ2vaSBuacHJO8S8oyQGtdOc+1yPUidIjhagw=; b=BV9UIHrEJYqqNya9wL0b9loEvqQlGsYwtjn0ueNiolZWEqBI4/tw8QNWxWYSujMEee rd1pO5kQp/J4W7OTF6lebzhvUyYXxdG0cgwcNtQgiRZV2zZ96FdCHcuQIpM3uS/Nrew+ 0DdbXRIjKhQr8iAg3j23zx9ooi9Oq5wjtpRCOJv5lzNWqq/+dgt68EL7VKxw9UheMTxQ gkW8Yb6ckNxqx7dZZE79cHgPzlQTFGxouiZRTKeirPfrzPVuuCcyZ2Ftz29D8HksgHDK cE1w4VTdd0qWsboWrpJrTY2JJJ7E0oTKLYuReZF50xdan+wss0HTGHj33ZxgziU4EJ/q HrZQ== 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=lUJjOznZ2vaSBuacHJO8S8oyQGtdOc+1yPUidIjhagw=; b=Y2/wn3wKGExLsrSVQBzx6MvOX/5SdUKtHY0Jlz5EgK9ImWJuVmgx65rFkGiggHVd+7 2L2nrBC553gQJVOBEPG/Ue1VjWv7TULLiAdmPCfiOy9/he/KpULnk7MosIVVrhZpSBgE gmunG4mL3lOKDrhpKKQ2T3I9n+YMLfKMLpAj3p9NRSxyyV4coEg84E6PFvuzQB5beuHe TgPoEK45qxlo9WCPstlrI4hlS9ZJyrWRiatShsjsOTXei4U+mrZICY+lY0Aho1gLGIDB i7xkSz4RYRUZUv+AXFFUWiQj51ew7cnvRpBmo0pRM/ErYEVe+4L0gKg/aaXUxsOhFywi CnyA== X-Gm-Message-State: AElRT7EiHn5ho5STni0ipE92wOV6TzmKHcYfog6C0dNv2I81o3tAoflW dVUE0XlLTzHFyx/itVjTEvSN5g== X-Google-Smtp-Source: AG47ELvyZ4rcRi519XGgu1/InafncDmK9mRRoQVdDHEJP2zH+JHSq8B4+exWvm+6d3w6N/0dC2DwfQ== X-Received: by 10.101.82.10 with SMTP id o10mr349418pgp.271.1521756491233; Thu, 22 Mar 2018 15:08:11 -0700 (PDT) Received: from gizo.domain (184-100-240-187.ptld.qwest.net. [184.100.240.187]) by smtp.gmail.com with ESMTPSA id 4sm2280775pfn.32.2018.03.22.15.08.09 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Mar 2018 15:08:10 -0700 (PDT) From: Greg Rose To: dev@openvswitch.org Date: Thu, 22 Mar 2018 15:07:33 -0700 Message-Id: <1521756461-3870-18-git-send-email-gvrose8192@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1521756461-3870-1-git-send-email-gvrose8192@gmail.com> References: <1521756461-3870-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] [ERSPAN RFC 17/25] compat: Add #define for gre_handle_offloads 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 Fixes compile errors on some 4.x kernels. Signed-off-by: Greg Rose --- datapath/linux/compat/ip_gre.c | 1 + 1 file changed, 1 insertion(+) diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index 9ed391d..6e75094 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -303,6 +303,7 @@ static bool is_gre_gso(struct sk_buff *skb) return skb_is_gso(skb); } +#define gre_handle_offloads rpl_gre_handle_offloads static int rpl_gre_handle_offloads(struct sk_buff *skb, bool gre_csum) { int type = gre_csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE; From patchwork Thu Mar 22 22:07:34 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Rose X-Patchwork-Id: 889686 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="JQhSjCH1"; 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 406gw24HFhz9s0y for ; Fri, 23 Mar 2018 09:15:14 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 62EB6F5C; Thu, 22 Mar 2018 22:08:19 +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 63C72EE9 for ; Thu, 22 Mar 2018 22:08:14 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pg0-f66.google.com (mail-pg0-f66.google.com [74.125.83.66]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id E86F25D3 for ; Thu, 22 Mar 2018 22:08:13 +0000 (UTC) Received: by mail-pg0-f66.google.com with SMTP id t9so2438317pgo.3 for ; Thu, 22 Mar 2018 15:08:13 -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=o1Z04YKM/hSnZgIOldOVdwyXN/8WNdDn22lTRKK7FIE=; b=JQhSjCH1TYmSIpERwWvBSxlkADNrN7sqoRhT98a9dqQwk84c6L8INTsqRzBq1M4SvX JU24sjcfRbviwDLQQwrZJdb8N69RPMzPqKusU3iQn7g1g8y+NeR2uhwXHolgYCvVVZvk ZZp4wn3hPo0b6a4v7fEELmz1GTWztCDunoZByEnc2S2ud++QyGNDivMjKR5yW4WJAxB3 f5I0xvPIS6rVYanbFPHvw6lSoK58ptGtYkyh8UvGyshNltRod4TmcF3LVlE4JjIK8TRe KUzW/7Xt29NlCNX8uImLXU7cDof9X/o/cZd8D6tIUiI+4oNDUqOQ//W41FNGLZloxiSK GFaQ== 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=o1Z04YKM/hSnZgIOldOVdwyXN/8WNdDn22lTRKK7FIE=; b=AJD6HCBFNvtte6evh7Kxhw9nVshW8FrRrSSvZpmaqaBxlYjbL2jzUAOkMkhaXc5M1/ gcjKKbuAZ8mOAACjRZTeACOeb6dn0Jzf8FIfT719kp3S6Gnpdd97auBOo3Kvfnqf/F1F ZbB6SzclNjGQjMybnveqSvLWR0xTKp8gOxy+lmrKl6Kt+R7fJ9B9arteTyl8eVQCfkCc r40DCoqK09IQo3pXIZelJaz8twvhSh5U12f2f3LKxqhPsnNlmMEE5hXzL3OKpkRYZBAw mvEJJc8bcHPUr9qxZAYijBBNMNaWE7rSz+UbpbsqHRCZ/ARCyMdsK+mAatdCGrf3e7f1 YD6Q== X-Gm-Message-State: AElRT7FTgfOgmGJcKvD8VhINovLW0H73PlmAmgiCVU+YbsvKmg4JOuCC 23DLBqGcqoZPBaHWzlL6+CS5DQ== X-Google-Smtp-Source: AG47ELuFdz8ZB5JKwdX4mL6SM2P/Ew9oByw9EEy2GK2tq8LpcGRr2f2JtlLrv/KKL1AAtJ9X55BypQ== X-Received: by 10.101.88.76 with SMTP id s12mr19200930pgr.423.1521756492942; Thu, 22 Mar 2018 15:08:12 -0700 (PDT) Received: from gizo.domain (184-100-240-187.ptld.qwest.net. [184.100.240.187]) by smtp.gmail.com with ESMTPSA id 4sm2280775pfn.32.2018.03.22.15.08.11 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Mar 2018 15:08:11 -0700 (PDT) From: Greg Rose To: dev@openvswitch.org Date: Thu, 22 Mar 2018 15:07:34 -0700 Message-Id: <1521756461-3870-19-git-send-email-gvrose8192@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1521756461-3870-1-git-send-email-gvrose8192@gmail.com> References: <1521756461-3870-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] [ERSPAN RFC 18/25] compat: Fixups for some compile warnings and errors 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 A lot of code has been pulled in. Fix it up to make sure it compiles correctly. Signed-off-by: Greg Rose --- acinclude.m4 | 3 +++ datapath/linux/compat/gre.c | 23 ---------------- datapath/linux/compat/include/net/gre.h | 47 ++++++++++++++++++++++++++++++++- datapath/linux/compat/ip_gre.c | 19 ++++++------- 4 files changed, 59 insertions(+), 33 deletions(-) diff --git a/acinclude.m4 b/acinclude.m4 index 6ef244d..8ee6a44 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -823,6 +823,9 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [ OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], [__skb_checksum_convert], [OVS_DEFINE([HAVE_SKB_CHECKSUM_CONVERT])]) + OVS_FIND_FIELD_IFELSE([$KSRC/include/linux/netdevice.h], [net_device], + [max_mtu], + [OVS_DEFINE([HAVE_NET_DEVICE_MAX_MTU])]) if cmp -s datapath/linux/kcompat.h.new \ datapath/linux/kcompat.h >/dev/null 2>&1; then diff --git a/datapath/linux/compat/gre.c b/datapath/linux/compat/gre.c index 98924c9..6a6dc91 100644 --- a/datapath/linux/compat/gre.c +++ b/datapath/linux/compat/gre.c @@ -82,29 +82,6 @@ static __sum16 check_checksum(struct sk_buff *skb) return csum; } -#define gre_flags_to_tnl_flags rpl_gre_flags_to_tnl_flags -static __be16 gre_flags_to_tnl_flags(__be16 flags) -{ - __be16 tflags = 0; - - if (flags & GRE_CSUM) - tflags |= TUNNEL_CSUM; - if (flags & GRE_ROUTING) - tflags |= TUNNEL_ROUTING; - if (flags & GRE_KEY) - tflags |= TUNNEL_KEY; - if (flags & GRE_SEQ) - tflags |= TUNNEL_SEQ; - if (flags & GRE_STRICT) - tflags |= TUNNEL_STRICT; - if (flags & GRE_REC) - tflags |= TUNNEL_REC; - if (flags & GRE_VERSION) - tflags |= TUNNEL_VERSION; - - return tflags; -} - static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, bool *csum_err) { diff --git a/datapath/linux/compat/include/net/gre.h b/datapath/linux/compat/include/net/gre.h index e2473f2..78422c8 100644 --- a/datapath/linux/compat/include/net/gre.h +++ b/datapath/linux/compat/include/net/gre.h @@ -31,7 +31,52 @@ static inline struct net_device *rpl_gretap_fb_dev_create( #include_next #define tnl_flags_to_gre_flags rpl_tnl_flags_to_gre_flags -static inline __be16 tnl_flags_to_gre_flags(__be16 tflags) +static inline __be16 rpl_tnl_flags_to_gre_flags(__be16 tflags) +{ + __be16 flags = 0; + + if (tflags & TUNNEL_CSUM) + flags |= GRE_CSUM; + if (tflags & TUNNEL_ROUTING) + flags |= GRE_ROUTING; + if (tflags & TUNNEL_KEY) + flags |= GRE_KEY; + if (tflags & TUNNEL_SEQ) + flags |= GRE_SEQ; + if (tflags & TUNNEL_STRICT) + flags |= GRE_STRICT; + if (tflags & TUNNEL_REC) + flags |= GRE_REC; + if (tflags & TUNNEL_VERSION) + flags |= GRE_VERSION; + + return flags; +} + +#define gre_flags_to_tnl_flags rpl_gre_flags_to_tnl_flags +static inline __be16 rpl_gre_flags_to_tnl_flags(__be16 flags) +{ + __be16 tflags = 0; + + if (flags & GRE_CSUM) + tflags |= TUNNEL_CSUM; + if (flags & GRE_ROUTING) + tflags |= TUNNEL_ROUTING; + if (flags & GRE_KEY) + tflags |= TUNNEL_KEY; + if (flags & GRE_SEQ) + tflags |= TUNNEL_SEQ; + if (flags & GRE_STRICT) + tflags |= TUNNEL_STRICT; + if (flags & GRE_REC) + tflags |= TUNNEL_REC; + if (flags & GRE_VERSION) + tflags |= TUNNEL_VERSION; + + return tflags; +} +#define gre_tnl_flags_to_gre_flags rpl_gre_tnl_flags_to_gre_flags +static inline __be16 rpl_gre_tnl_flags_to_gre_flags(__be16 tflags) { __be16 flags = 0; diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index 6e75094..7d066ae 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -113,7 +113,7 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, int gre_hdr_len) { struct net *net = dev_net(skb->dev); - struct metadata_dst tun_dst = NULL; + struct metadata_dst *tun_dst = NULL; struct erspan_base_hdr *ershdr; struct erspan_metadata *pkt_md; struct ip_tunnel_net *itn; @@ -123,21 +123,20 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, int len; itn = net_generic(net, erspan_net_id); - iph = ip_hdr(skb); len = gre_hdr_len + sizeof(*ershdr); /* Check based hdr len */ if (unlikely(!pskb_may_pull(skb, len))) - return -ENOMEM; + return PACKET_REJECT; iph = ip_hdr(skb); ershdr = (struct erspan_base_hdr *)(skb->data + gre_hdr_len); - ver = (ntohs(ershdr->ver_vlan) & VER_MASK) >> VER_OFFSET; + ver = ershdr->ver; /* The original GRE header does not have key field, * Use ERSPAN 10-bit session ID as key. */ - tpi->key = cpu_to_be32(ntohs(ershdr->session_id) & ID_MASK); + tpi->key = cpu_to_be32(get_session_id(ershdr)); tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags | TUNNEL_KEY, iph->saddr, iph->daddr, tpi->key); @@ -166,17 +165,17 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, flags = tpi->flags; tun_id = key32_to_tunnel_id(tpi->key); - ovs_ip_tun_rx_dst(&tun_dst, skb, flags, + ovs_ip_tun_rx_dst(tun_dst, skb, flags, tun_id, sizeof(*md)); - md = ip_tunnel_info_opts(&tun_dst.u.tun_info); + md = ip_tunnel_info_opts(&tun_dst->u.tun_info); if (!md) { dst_release((struct dst_entry *)tun_dst); return PACKET_REJECT; } memcpy(md, pkt_md, sizeof(*md)); - info = &tun_dst.u.tun_info; + info = &tun_dst->u.tun_info; info->key.tun_flags |= TUNNEL_ERSPAN_OPT; info->options_len = sizeof(*md); } else { @@ -184,7 +183,7 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, } skb_reset_mac_header(skb); - ovs_ip_tunnel_rcv(tunnel->dev, skb, &tun_dst); + ovs_ip_tunnel_rcv(tunnel->dev, skb, tun_dst); return PACKET_RCVD; } drop: @@ -841,7 +840,9 @@ static const struct net_device_ops erspan_netdev_ops = { static void ipgre_tap_setup(struct net_device *dev) { ether_setup(dev); +#ifdef HAVE_NET_DEVICE_MAX_MTU dev->max_mtu = 0; +#endif dev->netdev_ops = &gre_tap_netdev_ops; dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; ip_tunnel_setup(dev, gre_tap_net_id); From patchwork Thu Mar 22 22:07:35 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Rose X-Patchwork-Id: 889692 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="To8FTe4q"; 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 406gyr5XF5z9s0y for ; Fri, 23 Mar 2018 09:17:40 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id F06FAF8F; Thu, 22 Mar 2018 22:08:27 +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 6B7C0E55 for ; Thu, 22 Mar 2018 22:08:25 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pl0-f68.google.com (mail-pl0-f68.google.com [209.85.160.68]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id EF9FF5D7 for ; Thu, 22 Mar 2018 22:08:17 +0000 (UTC) Received: by mail-pl0-f68.google.com with SMTP id w15-v6so6204499plq.9 for ; Thu, 22 Mar 2018 15:08:17 -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=s/eqqA2t/DM0zf2vs3HR5L26Nez4qeCzanbIxesMfqQ=; b=To8FTe4qjyEbEr3Upazp7PbRAHNQMTvlYbp4BZ0d8b3Q/ZuUmM1WkVbRGSqWiOuv1Z iANmCWEs5vUcdzRCmK/3WYvFQ0tp/9tXvGzAxaRJT4rmkY4XlH8pzXQBlTnUrqWUjxQ5 MawW8pAzMI6H6+95sbRYteRI6UTk2T4kMt6LKwwVDn2nCTdK44L/UIN/3kCb8wAId1uO odxzFZ1qi7k9vOYyZqNRmAffSmzvwEPwThNYYqR9lA4FsIVLt6loXloH11C6v3KZITk1 F007p98t3YhbCZtAUvxAJfCqWx18akYiuzHrrJSOxOnzK16ZizbPXvAEAEmLPIc8VNW7 uqFQ== 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=s/eqqA2t/DM0zf2vs3HR5L26Nez4qeCzanbIxesMfqQ=; b=EPq2L51eK+0zAWk5OO3v8DQvow2dagmo1frPFzAFKgkTEI2WtjH9wYA5MkX2MFsvMO jeX8wLspS1LSn6zZ4pQaTDRjZ3CX7+XgUy56z4NOYoL2XBsWEMaHSY/dEC4EhK/7pCkl ycp3LvP7yR/53r27GZ13q6+qGftuasvr5Gi5Rmc564TJsW3Jz+o6ZkX4jlnNXBI5dsBN jzo9qHkbHABu4L5Uzll0TemaR8D567nN9XvR9fSOdvnqqyo4ff8MthRnVXX/ofBxR7q0 AkLZM0RL68yqswi8xInal2vzrotH8dKA+65wL1JjNgeYuTHefXvOgA2TQDXFiMayBnKY bhwA== X-Gm-Message-State: AElRT7EpjCjdU8/f+l1WyxILdavO0PvBbfBiPylwxbPLtaig8yrKgASw rSMRdPMFAA3J4CBp+pRxGUx0xw== X-Google-Smtp-Source: AG47ELtuXr1b524I28o05dYi5oJ9CCq0e2itNIpt1kstlgxknIhBYv+9gERU9sD5yN63GUVVvNE9Hw== X-Received: by 2002:a17:902:8ecb:: with SMTP id x11-v6mr16666204plo.402.1521756495041; Thu, 22 Mar 2018 15:08:15 -0700 (PDT) Received: from gizo.domain (184-100-240-187.ptld.qwest.net. [184.100.240.187]) by smtp.gmail.com with ESMTPSA id 4sm2280775pfn.32.2018.03.22.15.08.12 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Mar 2018 15:08:14 -0700 (PDT) From: Greg Rose To: dev@openvswitch.org Date: Thu, 22 Mar 2018 15:07:35 -0700 Message-Id: <1521756461-3870-20-git-send-email-gvrose8192@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1521756461-3870-1-git-send-email-gvrose8192@gmail.com> References: <1521756461-3870-1-git-send-email-gvrose8192@gmail.com> X-Spam-Status: No, score=-0.7 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM, FREEMAIL_REPLY,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] [ERSPAN RFC 19/25] compat: Add ipv6 GRE and IPV6 Tunneling 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 This patch backports upstream ipv6 GRE and tunneling into the OVS OOT (Out of Tree) datapath drivers. The primary reason for this is to support the ERSPAN feature. Because there is no previous history of ipv6 GRE and tunneling it is not possible to exactly reproduce the history of all the files in the patch. The two newly added files - ip6_gre.c and ip6_tunnel.c - are cut from whole cloth out of the upstream Linux 4.15 kernel and then modified as necessary with compatibility layer fixups. These two files already included parts of several other upstream commits that also touched other upstream files. As such, this patch may incorporate parts or all of the following commits: d350a82 net: erspan: create erspan metadata uapi header c69de58 net: erspan: use bitfield instead of mask and offset b423d13 net: erspan: fix use-after-free 214bb1c net: erspan: remove md NULL check afb4c97 ip6_gre: fix potential memory leak in ip6erspan_rcv 50670b6 ip_gre: fix potential memory leak in erspan_rcv a734321 ip6_gre: fix error path when ip6erspan_rcv failed dd8d5b8 ip_gre: fix error path when erspan_rcv failed 293a199 ip6_gre: fix a pontential issue in ip6erspan_rcv d91e8db5 net: erspan: reload pointer after pskb_may_pull ae3e133 net: erspan: fix wrong return value c05fad5 ip_gre: fix wrong return value of erspan_rcv 94d7d8f ip6_gre: add erspan v2 support f551c91 net: erspan: introduce erspan v2 for ip_gre 1d7e2ed net: erspan: refactor existing erspan code ef7baf5 ip6_gre: add ip6 erspan collect_md mode 5a963eb ip6_gre: Add ERSPAN native tunnel support ceaa001 openvswitch: Add erspan tunnel support. f192970 ip_gre: check packet length and mtu correctly in erspan tx c84bed4 ip_gre: erspan device should keep dst c122fda ip_gre: set tunnel hlen properly in erspan_tunnel_init 5513d08 ip_gre: check packet length and mtu correctly in erspan_xmit 935a974 ip_gre: get key from session_id correctly in erspan_rcv 1a66a83 gre: add collect_md mode to ERSPAN tunnel 84e54fe gre: introduce native tunnel support for ERSPAN In cases where the listed commits also touched other source code files then the patches are also listed separately within this patch series. Signed-off-by: Greg Rose --- acinclude.m4 | 36 + datapath/linux/Modules.mk | 2 + datapath/linux/compat/include/linux/compiler.h | 4 + datapath/linux/compat/include/linux/if_ether.h | 4 + datapath/linux/compat/include/linux/netdevice.h | 7 + datapath/linux/compat/include/linux/skbuff.h | 11 + datapath/linux/compat/include/net/erspan.h | 254 ++- datapath/linux/compat/include/net/gre.h | 25 + datapath/linux/compat/include/net/ip6_tunnel.h | 206 +- datapath/linux/compat/include/net/ipv6.h | 29 + datapath/linux/compat/ip6_gre.c | 2309 +++++++++++++++++++++++ datapath/linux/compat/ip6_tunnel.c | 2195 +++++++++++++++++++++ datapath/linux/compat/ip_gre.c | 9 +- datapath/vport.c | 10 + 14 files changed, 5060 insertions(+), 41 deletions(-) create mode 100644 datapath/linux/compat/ip6_gre.c create mode 100644 datapath/linux/compat/ip6_tunnel.c diff --git a/acinclude.m4 b/acinclude.m4 index 8ee6a44..e6de83f 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -826,6 +826,42 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [ OVS_FIND_FIELD_IFELSE([$KSRC/include/linux/netdevice.h], [net_device], [max_mtu], [OVS_DEFINE([HAVE_NET_DEVICE_MAX_MTU])]) + OVS_GREP_IFELSE([$KSRC/include/net/erspan.h], + [__LINUX_ERSPAN_H], + [OVS_DEFINE([HAVE_LINUX_ERSPAN_H])]) + OVS_FIND_PARAM_IFELSE([$KSRC/net/ipv6/ip6_gre.c], + [ip6gre_tunnel_validate], [extack], + [OVS_DEFINE([HAVE_IP6GRE_EXTACK])]) + OVS_FIND_FIELD_IFELSE([$KSRC/include/net/ip6_tunnel.h], [__ip6_tnl_parm], + [erspan_ver], + [OVS_DEFINE([HAVE_IP6_TNL_PARM_ERSPAN_VER])]) + OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], + [SKB_GSO_IPXIP6], + [OVS_DEFINE([HAVE_SKB_GSO_IPXIP6])]) + OVS_FIND_PARAM_IFELSE([$KSRC/include/net/ipv6.h], + [ip6_make_flowlabel], [fl6], + [OVS_DEFINE([HAVE_IP6_MAKE_FLOWLABEL_FL6])]) + OVS_FIND_FIELD_IFELSE([$KSRC/include/net/ipv6.h], [netns_sysctl_ipv6], + [auto_flowlabels], + [OVS_DEFINE([HAVE_NETNS_SYSCTL_IPV6_AUTO_FLOWLABELS])]) + OVS_GREP_IFELSE([$KSRC/include/linux/netdevice.h], + [netif_keep_dst], + [OVS_DEFINE([HAVE_NETIF_KEEP_DST])]) + OVS_FIND_FIELD_IFELSE([$KSRC/include/linux/netdevice.h], [net_device_ops], + [ndo_get_iflink], + [OVS_DEFINE([HAVE_NDO_GET_IFLINK])]) + OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], + [skb_set_inner_ipproto], + [OVS_DEFINE([HAVE_SKB_SET_INNER_IPPROTO])]) + OVS_GREP_IFELSE([$KSRC/include/uapi/linux/if_tunnel.h], + [tunnel_encap_types], + [OVS_DEFINE([HAVE_TUNNEL_ENCAP_TYPES])]) + OVS_GREP_IFELSE([$KSRC/include/uapi/linux/if_tunnel.h], + [IFLA_IPTUN_ENCAP_TYPE], + [OVS_DEFINE([HAVE_IFLA_IPTUN_ENCAP_TYPE])]) + OVS_GREP_IFELSE([$KSRC/include/uapi/linux/if_tunnel.h], + [IFLA_IPTUN_COLLECT_METADATA], + [OVS_DEFINE([HAVE_IFLA_IPTUN_COLLECT_METADATA])]) if cmp -s datapath/linux/kcompat.h.new \ datapath/linux/kcompat.h >/dev/null 2>&1; then diff --git a/datapath/linux/Modules.mk b/datapath/linux/Modules.mk index e0a90c3..104c32f 100644 --- a/datapath/linux/Modules.mk +++ b/datapath/linux/Modules.mk @@ -13,6 +13,8 @@ openvswitch_sources += \ linux/compat/ip_tunnel.c \ linux/compat/ip_tunnels_core.c \ linux/compat/ip6_output.c \ + linux/compat/ip6_gre.c \ + linux/compat/ip6_tunnel.c \ linux/compat/lisp.c \ linux/compat/netdevice.c \ linux/compat/nf_conntrack_core.c \ diff --git a/datapath/linux/compat/include/linux/compiler.h b/datapath/linux/compat/include/linux/compiler.h index dbe3ca7..65f3ba6 100644 --- a/datapath/linux/compat/include/linux/compiler.h +++ b/datapath/linux/compat/include/linux/compiler.h @@ -11,4 +11,8 @@ #define __rcu #endif +#ifndef READ_ONCE +#define READ_ONCE(x) (x) +#endif + #endif diff --git a/datapath/linux/compat/include/linux/if_ether.h b/datapath/linux/compat/include/linux/if_ether.h index aaa88db..8dff938 100644 --- a/datapath/linux/compat/include/linux/if_ether.h +++ b/datapath/linux/compat/include/linux/if_ether.h @@ -27,6 +27,10 @@ #define ETH_P_ERSPAN 0x88BE /* ERSPAN TYPE II */ #endif +#ifndef ETH_P_ERSPAN2 +#define ETH_P_ERSPAN2 0x22EB /* ERSPAN version 2 (type III) */ +#endif + #define inner_eth_hdr rpl_inner_eth_hdr static inline struct ethhdr *inner_eth_hdr(const struct sk_buff *skb) { diff --git a/datapath/linux/compat/include/linux/netdevice.h b/datapath/linux/compat/include/linux/netdevice.h index 29ef6c7..cf68ed5 100644 --- a/datapath/linux/compat/include/linux/netdevice.h +++ b/datapath/linux/compat/include/linux/netdevice.h @@ -316,4 +316,11 @@ static inline void skb_gso_error_unwind(struct sk_buff *skb, __be16 protocol, skb->mac_len = mac_len; } #endif + +#ifndef HAVE_NETIF_KEEP_DST +static inline void netif_keep_dst(struct net_device *dev) +{ +} +#endif + #endif /* __LINUX_NETDEVICE_WRAPPER_H */ diff --git a/datapath/linux/compat/include/linux/skbuff.h b/datapath/linux/compat/include/linux/skbuff.h index 45778bd..63ffcaa 100644 --- a/datapath/linux/compat/include/linux/skbuff.h +++ b/datapath/linux/compat/include/linux/skbuff.h @@ -421,4 +421,15 @@ static inline void *skb_put_zero(struct sk_buff *skb, unsigned int len) } #endif +#ifndef HAVE_SKB_GSO_IPXIP6 +#define SKB_GSO_IPXIP6 (1 << 10) +#endif + +#ifndef HAVE_SKB_SET_INNER_IPPROTO +static inline void skb_set_inner_ipproto(struct sk_buff *skb, + __u8 ipproto) +{ +} +#endif + #endif diff --git a/datapath/linux/compat/include/net/erspan.h b/datapath/linux/compat/include/net/erspan.h index b4f13e6..813a9c5 100644 --- a/datapath/linux/compat/include/net/erspan.h +++ b/datapath/linux/compat/include/net/erspan.h @@ -1,4 +1,4 @@ -#ifndef USE_UPSTREAM_TUNNEL +#ifndef HAVE_LINUX_ERSPAN_H #ifndef __LINUX_ERSPAN_H #define __LINUX_ERSPAN_H @@ -16,7 +16,7 @@ * s, Recur, Flags, Version fields only S (bit 03) is set to 1. The * other fields are set to zero, so only a sequence number follows. * - * ERSPAN Type II header (8 octets [42:49]) + * ERSPAN Version 1 (Type II) header (8 octets [42:49]) * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -25,11 +25,66 @@ * | Reserved | Index | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * + * + * ERSPAN Version 2 (Type III) header (12 octets [42:49]) + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Ver | VLAN | COS |BSO|T| Session ID | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Timestamp | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | SGT |P| FT | Hw ID |D|Gra|O| + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Platform Specific SubHeader (8 octets, optional) + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Platf ID | Platform Specific Info | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | Platform Specific Info | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * * GRE proto ERSPAN type II = 0x88BE, type III = 0x22EB */ -#define ERSPAN_VERSION 0x1 +/* #include */ +/* Just insert uapi/linux/erspan.h here since + * we don't pull in uapi to compat + */ +/* ERSPAN version 2 metadata header */ +struct erspan_md2 { + __be32 timestamp; + __be16 sgt; /* security group tag */ +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 hwid_upper:2, + ft:5, + p:1; + __u8 o:1, + gra:2, + dir:1, + hwid:4; +#elif defined(__BIG_ENDIAN_BITFIELD) + __u8 p:1, + ft:5, + hwid_upper:2; + __u8 hwid:4, + dir:1, + gra:2, + o:1; +#else +#error "Please fix " +#endif +}; + +struct erspan_metadata { + int version; + union { + __be32 index; /* Version 1 (type II)*/ + struct erspan_md2 md2; /* Version 2 (type III) */ + } u; +}; +#define ERSPAN_VERSION 0x1 /* ERSPAN type II */ #define VER_MASK 0xf000 #define VLAN_MASK 0x0fff #define COS_MASK 0xe000 @@ -38,6 +93,19 @@ #define ID_MASK 0x03ff #define INDEX_MASK 0xfffff +#define ERSPAN_VERSION2 0x2 /* ERSPAN type III*/ +#define BSO_MASK EN_MASK +#define SGT_MASK 0xffff0000 +#define P_MASK 0x8000 +#define FT_MASK 0x7c00 +#define HWID_MASK 0x03f0 +#define DIR_MASK 0x0008 +#define GRA_MASK 0x0006 +#define O_MASK 0x0001 + +#define HWID_OFFSET 4 +#define DIR_OFFSET 3 + enum erspan_encap_type { ERSPAN_ENCAP_NOVLAN = 0x0, /* originally without VLAN tag */ ERSPAN_ENCAP_ISL = 0x1, /* originally ISL encapsulated */ @@ -45,20 +113,72 @@ enum erspan_encap_type { ERSPAN_ENCAP_INFRAME = 0x3, /* VLAN tag perserved in frame */ }; -struct erspan_metadata { - __be32 index; /* type II */ -}; +#define ERSPAN_V1_MDSIZE 4 +#define ERSPAN_V2_MDSIZE 8 -struct erspanhdr { - __be16 ver_vlan; -#define VER_OFFSET 12 - __be16 session_id; -#define COS_OFFSET 13 -#define EN_OFFSET 11 -#define T_OFFSET 10 - struct erspan_metadata md; +struct erspan_base_hdr { +#if defined(__LITTLE_ENDIAN_BITFIELD) + __u8 vlan_upper:4, + ver:4; + __u8 vlan:8; + __u8 session_id_upper:2, + t:1, + en:2, + cos:3; + __u8 session_id:8; +#elif defined(__BIG_ENDIAN_BITFIELD) + __u8 ver: 4, + vlan_upper:4; + __u8 vlan:8; + __u8 cos:3, + en:2, + t:1, + session_id_upper:2; + __u8 session_id:8; +#else +#error "Please fix " +#endif }; +static inline void set_session_id(struct erspan_base_hdr *ershdr, u16 id) +{ + ershdr->session_id = id & 0xff; + ershdr->session_id_upper = (id >> 8) & 0x3; +} + +static inline u16 get_session_id(const struct erspan_base_hdr *ershdr) +{ + return (ershdr->session_id_upper << 8) + ershdr->session_id; +} + +static inline void set_vlan(struct erspan_base_hdr *ershdr, u16 vlan) +{ + ershdr->vlan = vlan & 0xff; + ershdr->vlan_upper = (vlan >> 8) & 0xf; +} + +static inline u16 get_vlan(const struct erspan_base_hdr *ershdr) +{ + return (ershdr->vlan_upper << 8) + ershdr->vlan; +} + +static inline void set_hwid(struct erspan_md2 *md2, u8 hwid) +{ + md2->hwid = hwid & 0xf; + md2->hwid_upper = (hwid >> 4) & 0x3; +} + +static inline u8 get_hwid(const struct erspan_md2 *md2) +{ + return (md2->hwid_upper << 4) + md2->hwid; +} + +static inline int erspan_hdr_len(int version) +{ + return sizeof(struct erspan_base_hdr) + + (version == 1 ? ERSPAN_V1_MDSIZE : ERSPAN_V2_MDSIZE); +} + static inline u8 tos_to_cos(u8 tos) { u8 dscp, cos; @@ -69,18 +189,19 @@ static inline u8 tos_to_cos(u8 tos) } static inline void erspan_build_header(struct sk_buff *skb, - __be32 id, u32 index, + u32 id, u32 index, bool truncate, bool is_ipv4) { - struct ethhdr *eth = eth_hdr(skb); + struct ethhdr *eth = (struct ethhdr *)skb->data; enum erspan_encap_type enc_type; - struct erspanhdr *ershdr; + struct erspan_base_hdr *ershdr; struct qtag_prefix { __be16 eth_type; __be16 tci; } *qp; u16 vlan_tci = 0; u8 tos; + __be32 *idx; tos = is_ipv4 ? ip_hdr(skb)->tos : (ipv6_hdr(skb)->priority << 4) + @@ -97,17 +218,94 @@ static inline void erspan_build_header(struct sk_buff *skb, enc_type = ERSPAN_ENCAP_INFRAME; } - skb_push(skb, sizeof(*ershdr)); - ershdr = (struct erspanhdr *)skb->data; - memset(ershdr, 0, sizeof(*ershdr)); - - ershdr->ver_vlan = htons((vlan_tci & VLAN_MASK) | - (ERSPAN_VERSION << VER_OFFSET)); - ershdr->session_id = htons((u16)(ntohl(id) & ID_MASK) | - ((tos_to_cos(tos) << COS_OFFSET) & COS_MASK) | - (enc_type << EN_OFFSET & EN_MASK) | - ((truncate << T_OFFSET) & T_MASK)); - ershdr->md.index = htonl(index & INDEX_MASK); + skb_push(skb, sizeof(*ershdr) + ERSPAN_V1_MDSIZE); + ershdr = (struct erspan_base_hdr *)skb->data; + memset(ershdr, 0, sizeof(*ershdr) + ERSPAN_V1_MDSIZE); + + /* Build base header */ + ershdr->ver = ERSPAN_VERSION; + ershdr->cos = tos_to_cos(tos); + ershdr->en = enc_type; + ershdr->t = truncate; + set_vlan(ershdr, vlan_tci); + set_session_id(ershdr, id); + + /* Build metadata */ + idx = (__be32 *)(ershdr + 1); + *idx = htonl(index & INDEX_MASK); +} + +/* ERSPAN GRA: timestamp granularity + * 00b --> granularity = 100 microseconds + * 01b --> granularity = 100 nanoseconds + * 10b --> granularity = IEEE 1588 + * Here we only support 100 microseconds. + */ +static inline __be32 erspan_get_timestamp(void) +{ + u64 h_usecs; + ktime_t kt; + + kt = ktime_get_real(); + h_usecs = ktime_divns(kt, 100 * NSEC_PER_USEC); + + /* ERSPAN base header only has 32-bit, + * so it wraps around 4 days. + */ + return htonl((u32)h_usecs); +} + +static inline void erspan_build_header_v2(struct sk_buff *skb, + u32 id, u8 direction, u16 hwid, + bool truncate, bool is_ipv4) +{ + struct ethhdr *eth = (struct ethhdr *)skb->data; + struct erspan_base_hdr *ershdr; + struct erspan_md2 *md2; + struct qtag_prefix { + __be16 eth_type; + __be16 tci; + } *qp; + u16 vlan_tci = 0; + u8 gra = 0; /* 100 usec */ + u8 bso = 0; /* Bad/Short/Oversized */ + u8 sgt = 0; + u8 tos; + + tos = is_ipv4 ? ip_hdr(skb)->tos : + (ipv6_hdr(skb)->priority << 4) + + (ipv6_hdr(skb)->flow_lbl[0] >> 4); + + /* Unlike v1, v2 does not have En field, + * so only extract vlan tci field. + */ + if (eth->h_proto == htons(ETH_P_8021Q)) { + qp = (struct qtag_prefix *)(skb->data + 2 * ETH_ALEN); + vlan_tci = ntohs(qp->tci); + } + + skb_push(skb, sizeof(*ershdr) + ERSPAN_V2_MDSIZE); + ershdr = (struct erspan_base_hdr *)skb->data; + memset(ershdr, 0, sizeof(*ershdr) + ERSPAN_V2_MDSIZE); + + /* Build base header */ + ershdr->ver = ERSPAN_VERSION2; + ershdr->cos = tos_to_cos(tos); + ershdr->en = bso; + ershdr->t = truncate; + set_vlan(ershdr, vlan_tci); + set_session_id(ershdr, id); + + /* Build metadata */ + md2 = (struct erspan_md2 *)(ershdr + 1); + md2->timestamp = erspan_get_timestamp(); + md2->sgt = htons(sgt); + md2->p = 1; + md2->ft = 0; + md2->dir = direction; + md2->gra = gra; + md2->o = 0; + set_hwid(md2, hwid); } #endif diff --git a/datapath/linux/compat/include/net/gre.h b/datapath/linux/compat/include/net/gre.h index 78422c8..11a95a5 100644 --- a/datapath/linux/compat/include/net/gre.h +++ b/datapath/linux/compat/include/net/gre.h @@ -15,6 +15,23 @@ static inline int rpl_ipgre_init(void) static inline void rpl_ipgre_fini(void) {} +static inline int rpl_ip6gre_init(void) +{ + return 0; +} + +static inline void rpl_ip6gre_fini(void) +{} + +static inline int rpl_ip6_tunnel_init(void) +{ + return 0; +} + +static inline void rpl_ip6_tunnel_cleanup(void) +{ +} + #define gre_fb_xmit dev_queue_xmit #ifdef CONFIG_INET @@ -132,6 +149,10 @@ void rpl_gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi, int rpl_ipgre_init(void); void rpl_ipgre_fini(void); +int rpl_ip6gre_init(void); +void rpl_ip6gre_fini(void); +int rpl_ip6_tunnel_init(void); +void rpl_ip6_tunnel_cleanup(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, @@ -147,6 +168,10 @@ netdev_tx_t rpl_gre_fb_xmit(struct sk_buff *skb); #define ipgre_init rpl_ipgre_init #define ipgre_fini rpl_ipgre_fini +#define ip6gre_init rpl_ip6gre_init +#define ip6gre_fini rpl_ip6gre_fini +#define ip6_tunnel_init rpl_ip6_tunnel_init +#define ip6_tunnel_cleanup rpl_ip6_tunnel_cleanup #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/include/net/ip6_tunnel.h b/datapath/linux/compat/include/net/ip6_tunnel.h index b0917d8..e0a33a6 100644 --- a/datapath/linux/compat/include/net/ip6_tunnel.h +++ b/datapath/linux/compat/include/net/ip6_tunnel.h @@ -1,14 +1,208 @@ -#ifndef _NET_IP6_TUNNEL_WRAPER_H -#define _NET_IP6_TUNNEL_WRAPER_H +#ifndef NET_IP6_TUNNEL_WRAPPER_H +#define NET_IP6_TUNNEL_WRAPPER_H 1 + +#ifdef HAVE_IP6_TNL_PARM_ERSPAN_VER +#include_next +#else #include #include #include #include -#include_next +#include +#include +#include +#include "gso.h" + +#define IP6TUNNEL_ERR_TIMEO (30*HZ) + +/* capable of sending packets */ +#define IP6_TNL_F_CAP_XMIT 0x10000 +/* capable of receiving packets */ +#define IP6_TNL_F_CAP_RCV 0x20000 +/* determine capability on a per-packet basis */ +#define IP6_TNL_F_CAP_PER_PACKET 0x40000 + +#ifndef IP6_TNL_F_ALLOW_LOCAL_REMOTE +#define IP6_TNL_F_ALLOW_LOCAL_REMOTE 0 +#endif + +struct rpl__ip6_tnl_parm { + char name[IFNAMSIZ]; /* name of tunnel device */ + int link; /* ifindex of underlying L2 interface */ + __u8 proto; /* tunnel protocol */ + __u8 encap_limit; /* encapsulation limit for tunnel */ + __u8 hop_limit; /* hop limit for tunnel */ + bool collect_md; + __be32 flowinfo; /* traffic class and flowlabel for tunnel */ + __u32 flags; /* tunnel flags */ + struct in6_addr laddr; /* local tunnel end-point address */ + struct in6_addr raddr; /* remote tunnel end-point address */ + + __be16 i_flags; + __be16 o_flags; + __be32 i_key; + __be32 o_key; + + __u32 fwmark; + __u32 index; /* ERSPAN type II index */ + __u8 erspan_ver; /* ERSPAN version */ + __u8 dir; /* direction */ + __u16 hwid; /* hwid */ +}; + +#define __ip6_tnl_parm rpl__ip6_tnl_parm + +/* IPv6 tunnel */ +struct rpl_ip6_tnl { + struct rpl_ip6_tnl __rcu *next; /* next tunnel in list */ + struct net_device *dev; /* virtual device associated with tunnel */ + struct net *net; /* netns for packet i/o */ + struct __ip6_tnl_parm parms; /* tunnel configuration parameters */ + struct flowi fl; /* flowi template for xmit */ + struct dst_cache dst_cache; /* cached dst */ + struct gro_cells gro_cells; + + int err_count; + unsigned long err_time; + + /* These fields used only by GRE */ + __u32 i_seqno; /* The last seen seqno */ + __u32 o_seqno; /* The last output seqno */ + int hlen; /* tun_hlen + encap_hlen */ + int tun_hlen; /* Precalculated header length */ + int encap_hlen; /* Encap header length (FOU,GUE) */ + struct ip_tunnel_encap encap; + int mlink; +}; + +#define ip6_tnl rpl_ip6_tnl + +struct rpl_ip6_tnl_encap_ops { + size_t (*encap_hlen)(struct ip_tunnel_encap *e); + int (*build_header)(struct sk_buff *skb, struct ip_tunnel_encap *e, + u8 *protocol, struct flowi6 *fl6); +}; + +#define ip6_tnl_encap_ops rpl_ip6_tnl_encap_ops + +#ifdef CONFIG_INET + +#ifndef MAX_IPTUN_ENCAP_OPS +#define MAX_IPTUN_ENCAP_OPS 8 +#endif + +extern const struct ip6_tnl_encap_ops __rcu * + rpl_ip6tun_encaps[MAX_IPTUN_ENCAP_OPS]; + +int rpl_ip6_tnl_encap_add_ops(const struct ip6_tnl_encap_ops *ops, + unsigned int num); +#define ip6_tnl_encap_add_ops rpl_ip6_tnl_encap_add_ops +int rpl_ip6_tnl_encap_del_ops(const struct ip6_tnl_encap_ops *ops, + unsigned int num); +#define ip6_tnl_encap_del_ops rpl_ip6_tnl_encap_del_ops +int rpl_ip6_tnl_encap_setup(struct ip6_tnl *t, + struct ip_tunnel_encap *ipencap); +#define ip6_tnl_encap_setup rpl_ip6_tnl_encap_setup + +#ifndef HAVE_TUNNEL_ENCAP_TYPES +enum tunnel_encap_types { + TUNNEL_ENCAP_NONE, + TUNNEL_ENCAP_FOU, + TUNNEL_ENCAP_GUE, +}; + +#endif +static inline int ip6_encap_hlen(struct ip_tunnel_encap *e) +{ + const struct ip6_tnl_encap_ops *ops; + int hlen = -EINVAL; + + if (e->type == TUNNEL_ENCAP_NONE) + return 0; + + if (e->type >= MAX_IPTUN_ENCAP_OPS) + return -EINVAL; + + rcu_read_lock(); + ops = rcu_dereference(rpl_ip6tun_encaps[e->type]); + if (likely(ops && ops->encap_hlen)) + hlen = ops->encap_hlen(e); + rcu_read_unlock(); + + return hlen; +} + +static inline int ip6_tnl_encap(struct sk_buff *skb, struct ip6_tnl *t, + u8 *protocol, struct flowi6 *fl6) +{ + const struct ip6_tnl_encap_ops *ops; + int ret = -EINVAL; + + if (t->encap.type == TUNNEL_ENCAP_NONE) + return 0; + + if (t->encap.type >= MAX_IPTUN_ENCAP_OPS) + return -EINVAL; + + rcu_read_lock(); + ops = rcu_dereference(rpl_ip6tun_encaps[t->encap.type]); + if (likely(ops && ops->build_header)) + ret = ops->build_header(skb, &t->encap, protocol, fl6); + rcu_read_unlock(); + + return ret; +} + +/* Tunnel encapsulation limit destination sub-option */ + +struct ipv6_tlv_tnl_enc_lim { + __u8 type; /* type-code for option */ + __u8 length; /* option length */ + __u8 encap_limit; /* tunnel encapsulation limit */ +} __packed; + +int rpl_ip6_tnl_rcv_ctl(struct ip6_tnl *t, const struct in6_addr *laddr, + const struct in6_addr *raddr); +#define ip6_tnl_rcv_ctl rpl_ip6_tnl_rcv_ctl +int rpl_ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb, + const struct tnl_ptk_info *tpi, + struct metadata_dst *tun_dst, + bool log_ecn_error); +#define ip6_tnl_rcv rpl_ip6_tnl_rcv +int rpl_ip6_tnl_xmit_ctl(struct ip6_tnl *t, const struct in6_addr *laddr, + const struct in6_addr *raddr); +#define ip6_tnl_xmit_ctl rpl_ip6_tnl_xmit_ctl +int rpl_ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield, + struct flowi6 *fl6, int encap_limit, __u32 *pmtu, + __u8 proto); +#define ip6_tnl_xmit rpl_ip6_tnl_xmit +__u16 rpl_ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw); +#define ip6_tnl_parse_tlv_enc_lim rpl_ip6_tnl_parse_tlv_enc_lim +__u32 rpl_ip6_tnl_get_cap(struct ip6_tnl *t, const struct in6_addr *laddr, + const struct in6_addr *raddr); +#define ip6_tnl_get_cap rpl_ip6_tnl_get_cap +struct net *rpl_ip6_tnl_get_link_net(const struct net_device *dev); +#define ip6_tnl_get_link_net rpl_ip6_tnl_get_link_net +int rpl_ip6_tnl_get_iflink(const struct net_device *dev); +#define ip6_tnl_get_iflink rpl_ip6_tnl_get_iflink +int rpl_ip6_tnl_change_mtu(struct net_device *dev, int new_mtu); +#define ip6_tnl_change_mtu rpl_ip6_tnl_change_mtu + +static inline void ip6tunnel_xmit(struct sock *sk, struct sk_buff *skb, + struct net_device *dev) +{ + int pkt_len, err; + + memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); + pkt_len = skb->len - skb_inner_network_offset(skb); + err = ip6_local_out(dev_net(skb_dst(skb)->dev), sk, skb); + if (unlikely(net_xmit_eval(err))) + pkt_len = -1; + iptunnel_xmit_stats(dev, pkt_len); +} +#endif -#define ip6tunnel_xmit rpl_ip6tunnel_xmit -void rpl_ip6tunnel_xmit(struct sock *sk, struct sk_buff *skb, - struct net_device *dev); +#endif /* HAVE_IP6_TNL_PARM_ERSPAN_VER */ #endif diff --git a/datapath/linux/compat/include/net/ipv6.h b/datapath/linux/compat/include/net/ipv6.h index 7fc0339..6379457 100644 --- a/datapath/linux/compat/include/net/ipv6.h +++ b/datapath/linux/compat/include/net/ipv6.h @@ -39,6 +39,35 @@ static inline __be32 ip6_flowlabel(const struct ipv6hdr *hdr) return *(__be32 *)hdr & IPV6_FLOWLABEL_MASK; } +#ifndef HAVE_IP6_MAKE_FLOWLABEL_FL6 +#define ip6_make_flowlabel rpl_ip6_make_flowlabel +static inline __be32 rpl_ip6_make_flowlabel(struct net *net, + struct sk_buff *skb, + __be32 flowlabel, bool autolabel, + struct flowi6 *fl6) +{ +#ifndef HAVE_NETNS_SYSCTL_IPV6_AUTO_FLOWLABELS + if (!flowlabel && autolabel) { +#else + if (!flowlabel && (autolabel || net->ipv6.sysctl.auto_flowlabels)) { +#endif + u32 hash; + + hash = skb_get_hash(skb); + + /* Since this is being sent on the wire obfuscate hash a bit + * to minimize possbility that any useful information to an + * attacker is leaked. Only lower 20 bits are relevant. + */ + hash ^= hash >> 12; + + flowlabel = (__force __be32)hash & IPV6_FLOWLABEL_MASK; + } + + return flowlabel; +} +#endif + #ifndef IPV6_TCLASS_SHIFT #define IPV6_TCLASS_MASK (IPV6_FLOWINFO_MASK & ~IPV6_FLOWLABEL_MASK) #define IPV6_TCLASS_SHIFT 20 diff --git a/datapath/linux/compat/ip6_gre.c b/datapath/linux/compat/ip6_gre.c new file mode 100644 index 0000000..2832901 --- /dev/null +++ b/datapath/linux/compat/ip6_gre.c @@ -0,0 +1,2309 @@ +/* + * GRE over IPv6 protocol decoder. + * + * Authors: Dmitry Kozlov (xeb@mail.ru) + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#ifndef USE_UPSTREAM_TUNNEL +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define IP6_GRE_HASH_SIZE_SHIFT 5 +#define IP6_GRE_HASH_SIZE (1 << IP6_GRE_HASH_SIZE_SHIFT) + +static unsigned int ip6gre_net_id __read_mostly; +struct ip6gre_net { + struct ip6_tnl __rcu *tunnels[4][IP6_GRE_HASH_SIZE]; + + struct ip6_tnl __rcu *collect_md_tun; + struct net_device *fb_tunnel_dev; +}; + +static struct rtnl_link_ops ip6gre_link_ops __read_mostly; +static struct rtnl_link_ops ip6gre_tap_ops __read_mostly; +static struct rtnl_link_ops ip6erspan_tap_ops __read_mostly; +static int ip6gre_tunnel_init(struct net_device *dev); +static void ip6gre_tunnel_setup(struct net_device *dev); +static void ip6gre_tunnel_link(struct ip6gre_net *ign, struct ip6_tnl *t); +static void ip6gre_tnl_link_config(struct ip6_tnl *t, int set_mtu); + +#define gre_calc_hlen rpl_ip_gre_calc_hlen +static int rpl_ip_gre_calc_hlen(__be16 o_flags) +{ + int addend = 4; + + if (o_flags & TUNNEL_CSUM) + addend += 4; + if (o_flags & TUNNEL_KEY) + addend += 4; + if (o_flags & TUNNEL_SEQ) + addend += 4; + return addend; +} + +/* Tunnel hash table */ + +/* + 4 hash tables: + + 3: (remote,local) + 2: (remote,*) + 1: (*,local) + 0: (*,*) + + We require exact key match i.e. if a key is present in packet + it will match only tunnel with the same key; if it is not present, + it will match only keyless tunnel. + + All keysless packets, if not matched configured keyless tunnels + will match fallback tunnel. + */ + +#define HASH_KEY(key) (((__force u32)key^((__force u32)key>>4))&(IP6_GRE_HASH_SIZE - 1)) +static u32 HASH_ADDR(const struct in6_addr *addr) +{ + u32 hash = ipv6_addr_hash(addr); + + return hash_32(hash, IP6_GRE_HASH_SIZE_SHIFT); +} + +#define tunnels_r_l tunnels[3] +#define tunnels_r tunnels[2] +#define tunnels_l tunnels[1] +#define tunnels_wc tunnels[0] + +/* Given src, dst and key, find appropriate for input tunnel. */ + +static struct ip6_tnl *ip6gre_tunnel_lookup(struct net_device *dev, + const struct in6_addr *remote, const struct in6_addr *local, + __be32 key, __be16 gre_proto) +{ + struct net *net = dev_net(dev); + int link = dev->ifindex; + unsigned int h0 = HASH_ADDR(remote); + unsigned int h1 = HASH_KEY(key); + struct ip6_tnl *t, *cand = NULL; + struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); + int dev_type = (gre_proto == htons(ETH_P_TEB) || + gre_proto == htons(ETH_P_ERSPAN)) ? + ARPHRD_ETHER : ARPHRD_IP6GRE; + int score, cand_score = 4; + + for_each_ip_tunnel_rcu(t, ign->tunnels_r_l[h0 ^ h1]) { + if (!ipv6_addr_equal(local, &t->parms.laddr) || + !ipv6_addr_equal(remote, &t->parms.raddr) || + key != t->parms.i_key || + !(t->dev->flags & IFF_UP)) + continue; + + if (t->dev->type != ARPHRD_IP6GRE && + t->dev->type != dev_type) + continue; + + score = 0; + if (t->parms.link != link) + score |= 1; + if (t->dev->type != dev_type) + score |= 2; + if (score == 0) + return t; + + if (score < cand_score) { + cand = t; + cand_score = score; + } + } + + for_each_ip_tunnel_rcu(t, ign->tunnels_r[h0 ^ h1]) { + if (!ipv6_addr_equal(remote, &t->parms.raddr) || + key != t->parms.i_key || + !(t->dev->flags & IFF_UP)) + continue; + + if (t->dev->type != ARPHRD_IP6GRE && + t->dev->type != dev_type) + continue; + + score = 0; + if (t->parms.link != link) + score |= 1; + if (t->dev->type != dev_type) + score |= 2; + if (score == 0) + return t; + + if (score < cand_score) { + cand = t; + cand_score = score; + } + } + + for_each_ip_tunnel_rcu(t, ign->tunnels_l[h1]) { + if ((!ipv6_addr_equal(local, &t->parms.laddr) && + (!ipv6_addr_equal(local, &t->parms.raddr) || + !ipv6_addr_is_multicast(local))) || + key != t->parms.i_key || + !(t->dev->flags & IFF_UP)) + continue; + + if (t->dev->type != ARPHRD_IP6GRE && + t->dev->type != dev_type) + continue; + + score = 0; + if (t->parms.link != link) + score |= 1; + if (t->dev->type != dev_type) + score |= 2; + if (score == 0) + return t; + + if (score < cand_score) { + cand = t; + cand_score = score; + } + } + + for_each_ip_tunnel_rcu(t, ign->tunnels_wc[h1]) { + if (t->parms.i_key != key || + !(t->dev->flags & IFF_UP)) + continue; + + if (t->dev->type != ARPHRD_IP6GRE && + t->dev->type != dev_type) + continue; + + score = 0; + if (t->parms.link != link) + score |= 1; + if (t->dev->type != dev_type) + score |= 2; + if (score == 0) + return t; + + if (score < cand_score) { + cand = t; + cand_score = score; + } + } + + if (cand) + return cand; + + t = rcu_dereference(ign->collect_md_tun); + if (t && t->dev->flags & IFF_UP) + return t; + + dev = ign->fb_tunnel_dev; + if (dev->flags & IFF_UP) + return netdev_priv(dev); + + return NULL; +} + +static struct ip6_tnl __rcu **__ip6gre_bucket(struct ip6gre_net *ign, + const struct __ip6_tnl_parm *p) +{ + const struct in6_addr *remote = &p->raddr; + const struct in6_addr *local = &p->laddr; + unsigned int h = HASH_KEY(p->i_key); + int prio = 0; + + if (!ipv6_addr_any(local)) + prio |= 1; + if (!ipv6_addr_any(remote) && !ipv6_addr_is_multicast(remote)) { + prio |= 2; + h ^= HASH_ADDR(remote); + } + + return &ign->tunnels[prio][h]; +} + +static inline struct ip6_tnl __rcu **ip6gre_bucket(struct ip6gre_net *ign, + const struct ip6_tnl *t) +{ + return __ip6gre_bucket(ign, &t->parms); +} + +static void ip6gre_tunnel_link(struct ip6gre_net *ign, struct ip6_tnl *t) +{ + struct ip6_tnl __rcu **tp = ip6gre_bucket(ign, t); + + if (t->parms.collect_md) + rcu_assign_pointer(ign->collect_md_tun, t); + + rcu_assign_pointer(t->next, rtnl_dereference(*tp)); + rcu_assign_pointer(*tp, t); +} + +static void ip6gre_tunnel_unlink(struct ip6gre_net *ign, struct ip6_tnl *t) +{ + struct ip6_tnl __rcu **tp; + struct ip6_tnl *iter; + + if (t->parms.collect_md) + rcu_assign_pointer(ign->collect_md_tun, NULL); + + for (tp = ip6gre_bucket(ign, t); + (iter = rtnl_dereference(*tp)) != NULL; + tp = &iter->next) { + if (t == iter) { + rcu_assign_pointer(*tp, t->next); + break; + } + } +} + +static struct ip6_tnl *ip6gre_tunnel_find(struct net *net, + const struct __ip6_tnl_parm *parms, + int type) +{ + const struct in6_addr *remote = &parms->raddr; + const struct in6_addr *local = &parms->laddr; + __be32 key = parms->i_key; + int link = parms->link; + struct ip6_tnl *t; + struct ip6_tnl __rcu **tp; + struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); + + for (tp = __ip6gre_bucket(ign, parms); + (t = rtnl_dereference(*tp)) != NULL; + tp = &t->next) + if (ipv6_addr_equal(local, &t->parms.laddr) && + ipv6_addr_equal(remote, &t->parms.raddr) && + key == t->parms.i_key && + link == t->parms.link && + type == t->dev->type) + break; + + return t; +} + +static struct ip6_tnl *ip6gre_tunnel_locate(struct net *net, + const struct __ip6_tnl_parm *parms, int create) +{ + struct ip6_tnl *t, *nt; + struct net_device *dev; + char name[IFNAMSIZ]; + struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); + + t = ip6gre_tunnel_find(net, parms, ARPHRD_IP6GRE); + if (t && create) + return NULL; + if (t || !create) + return t; + + if (parms->name[0]) + strlcpy(name, parms->name, IFNAMSIZ); + else + strcpy(name, "ip6gre%d"); + + dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, + ip6gre_tunnel_setup); + if (!dev) + return NULL; + + dev_net_set(dev, net); + + nt = netdev_priv(dev); + nt->parms = *parms; + dev->rtnl_link_ops = &ip6gre_link_ops; + + nt->dev = dev; + nt->net = dev_net(dev); + + if (register_netdevice(dev) < 0) + goto failed_free; + + ip6gre_tnl_link_config(nt, 1); + + /* Can use a lockless transmit, unless we generate output sequences */ + if (!(nt->parms.o_flags & TUNNEL_SEQ)) + dev->features |= NETIF_F_LLTX; + + dev_hold(dev); + ip6gre_tunnel_link(ign, nt); + return nt; + +failed_free: + free_netdev(dev); + return NULL; +} + +static void ip6gre_tunnel_uninit(struct net_device *dev) +{ + struct ip6_tnl *t = netdev_priv(dev); + struct ip6gre_net *ign = net_generic(t->net, ip6gre_net_id); + + ip6gre_tunnel_unlink(ign, t); + dst_cache_reset(&t->dst_cache); + dev_put(dev); +} + + +static void ip6gre_err(struct sk_buff *skb, struct inet6_skb_parm *opt, + u8 type, u8 code, int offset, __be32 info) +{ +#if 0 + struct net *net = dev_net(skb->dev); + const struct gre_base_hdr *greh; + const struct ipv6hdr *ipv6h; + int grehlen = sizeof(*greh); + struct ip6_tnl *t; + int key_off = 0; + __be16 flags; + __be32 key; + + if (!pskb_may_pull(skb, offset + grehlen)) + return; + greh = (const struct gre_base_hdr *)(skb->data + offset); + flags = greh->flags; + if (flags & (GRE_VERSION | GRE_ROUTING)) + return; + if (flags & GRE_CSUM) + grehlen += 4; + if (flags & GRE_KEY) { + key_off = grehlen + offset; + grehlen += 4; + } + + if (!pskb_may_pull(skb, offset + grehlen)) + return; + ipv6h = (const struct ipv6hdr *)skb->data; + greh = (const struct gre_base_hdr *)(skb->data + offset); + key = key_off ? *(__be32 *)(skb->data + key_off) : 0; + + t = ip6gre_tunnel_lookup(skb->dev, &ipv6h->daddr, &ipv6h->saddr, + key, greh->protocol); + if (!t) + return; + + switch (type) { + struct ipv6_tlv_tnl_enc_lim *tel; + __u32 teli; + case ICMPV6_DEST_UNREACH: + net_dbg_ratelimited("%s: Path to destination invalid or inactive!\n", + t->parms.name); + if (code != ICMPV6_PORT_UNREACH) + break; + return; + case ICMPV6_TIME_EXCEED: + if (code == ICMPV6_EXC_HOPLIMIT) { + net_dbg_ratelimited("%s: Too small hop limit or routing loop in tunnel!\n", + t->parms.name); + break; + } + return; + case ICMPV6_PARAMPROB: + teli = 0; + if (code == ICMPV6_HDR_FIELD) + teli = ip6_tnl_parse_tlv_enc_lim(skb, skb->data); + + if (teli && teli == be32_to_cpu(info) - 2) { + tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli]; + if (tel->encap_limit == 0) { + net_dbg_ratelimited("%s: Too small encapsulation limit or routing loop in tunnel!\n", + t->parms.name); + } + } else { + net_dbg_ratelimited("%s: Recipient unable to parse tunneled packet!\n", + t->parms.name); + } + return; + case ICMPV6_PKT_TOOBIG: + ip6_update_pmtu(skb, net, info, 0, 0, sock_net_uid(net, NULL)); + return; + case NDISC_REDIRECT: + ip6_redirect(skb, net, skb->dev->ifindex, 0, + sock_net_uid(net, NULL)); + return; + } + + if (time_before(jiffies, t->err_time + IP6TUNNEL_ERR_TIMEO)) + t->err_count++; + else + t->err_count = 1; + t->err_time = jiffies; +#endif +} + +static int ip6gre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi) +{ + const struct ipv6hdr *ipv6h; + struct ip6_tnl *tunnel; + + ipv6h = ipv6_hdr(skb); + tunnel = ip6gre_tunnel_lookup(skb->dev, + &ipv6h->saddr, &ipv6h->daddr, tpi->key, + tpi->proto); + if (tunnel) { + if (tunnel->parms.collect_md) { + struct metadata_dst *tun_dst = NULL; + __be64 tun_id; + __be16 flags; + + flags = tpi->flags; + tun_id = key32_to_tunnel_id(tpi->key); + + ovs_ipv6_tun_rx_dst(tun_dst, skb, flags, tun_id, 0); + if (!tun_dst) + return PACKET_REJECT; + + ip6_tnl_rcv(tunnel, skb, tpi, tun_dst, false); + } else { + ip6_tnl_rcv(tunnel, skb, tpi, NULL, false); + } + + return PACKET_RCVD; + } + + return PACKET_REJECT; +} + +static int ip6erspan_rcv(struct sk_buff *skb, int gre_hdr_len, + struct tnl_ptk_info *tpi) +{ + struct erspan_base_hdr *ershdr; + struct erspan_metadata *pkt_md; + const struct ipv6hdr *ipv6h; + struct erspan_md2 *md2; + struct ip6_tnl *tunnel; + u8 ver; + + if (unlikely(!pskb_may_pull(skb, sizeof(*ershdr)))) + return PACKET_REJECT; + + ipv6h = ipv6_hdr(skb); + ershdr = (struct erspan_base_hdr *)skb->data; + ver = ershdr->ver; + tpi->key = cpu_to_be32(get_session_id(ershdr)); + + tunnel = ip6gre_tunnel_lookup(skb->dev, + &ipv6h->saddr, &ipv6h->daddr, tpi->key, + tpi->proto); + if (tunnel) { + int len = erspan_hdr_len(ver); + + if (unlikely(!pskb_may_pull(skb, len))) + return PACKET_REJECT; + + ershdr = (struct erspan_base_hdr *)skb->data; + pkt_md = (struct erspan_metadata *)(ershdr + 1); + + if (__iptunnel_pull_header(skb, len, + htons(ETH_P_TEB), + false, false) < 0) + return PACKET_REJECT; + + if (tunnel->parms.collect_md) { + struct metadata_dst *tun_dst = NULL; + struct ip_tunnel_info *info; + struct erspan_metadata *md; + __be64 tun_id; + __be16 flags; + + tpi->flags |= TUNNEL_KEY; + flags = tpi->flags; + tun_id = key32_to_tunnel_id(tpi->key); + + ovs_ipv6_tun_rx_dst(tun_dst, skb, flags, tun_id, + sizeof(*md)); + if (!tun_dst) + return PACKET_REJECT; + + info = &tun_dst->u.tun_info; + md = ip_tunnel_info_opts(info); + md->version = ver; + md2 = &md->u.md2; + memcpy(md2, pkt_md, ver == 1 ? ERSPAN_V1_MDSIZE : + ERSPAN_V2_MDSIZE); + info->key.tun_flags |= TUNNEL_ERSPAN_OPT; + info->options_len = sizeof(*md); + + ip6_tnl_rcv(tunnel, skb, tpi, tun_dst, false); + + } else { + ip6_tnl_rcv(tunnel, skb, tpi, NULL, false); + } + + return PACKET_RCVD; + } + + return PACKET_REJECT; +} + +static int gre_rcv(struct sk_buff *skb) +{ + struct tnl_ptk_info tpi; + bool csum_err = false; + int hdr_len; + + hdr_len = gre_parse_header(skb, &tpi, &csum_err, htons(ETH_P_IPV6), 0); + if (hdr_len < 0) + goto drop; + + if (iptunnel_pull_header(skb, hdr_len, tpi.proto, false)) + goto drop; + + if (unlikely(tpi.proto == htons(ETH_P_ERSPAN) || + tpi.proto == htons(ETH_P_ERSPAN2))) { + if (ip6erspan_rcv(skb, hdr_len, &tpi) == PACKET_RCVD) + return 0; + goto out; + } + + if (ip6gre_rcv(skb, &tpi) == PACKET_RCVD) + return 0; + +out: + icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0); +drop: + kfree_skb(skb); + return 0; +} + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0) +#include "gso.h" +/* gre_handle_offloads() has different return type on older kernsl. */ +static void gre_nop_fix(struct sk_buff *skb) { } + +static void gre_csum_fix(struct sk_buff *skb) +{ + struct gre_base_hdr *greh; + __be32 *options; + int gre_offset = skb_transport_offset(skb); + + greh = (struct gre_base_hdr *)skb_transport_header(skb); + options = ((__be32 *)greh + 1); + + *options = 0; + *(__sum16 *)options = csum_fold(skb_checksum(skb, gre_offset, + skb->len - gre_offset, 0)); +} + +#define gre_handle_offloads rpl_gre_handle_offloads +static int rpl_gre_handle_offloads(struct sk_buff *skb, bool gre_csum) +{ + int type = gre_csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE; + gso_fix_segment_t fix_segment; + + if (gre_csum) + fix_segment = gre_csum_fix; + else + fix_segment = gre_nop_fix; + + return ovs_iptunnel_handle_offloads(skb, type, fix_segment); +} +#else +static int gre_handle_offloads(struct sk_buff *skb, bool csum) +{ + return iptunnel_handle_offloads(skb, + csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE); + +#endif + +static void prepare_ip6gre_xmit_ipv4(struct sk_buff *skb, + struct net_device *dev, + struct flowi6 *fl6, __u8 *dsfield, + int *encap_limit) +{ + const struct iphdr *iph = ip_hdr(skb); + struct ip6_tnl *t = netdev_priv(dev); + + if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) + *encap_limit = t->parms.encap_limit; + + memcpy(fl6, &t->fl.u.ip6, sizeof(*fl6)); + + if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS) + *dsfield = ipv4_get_dsfield(iph); + else + *dsfield = ip6_tclass(t->parms.flowinfo); + +#ifndef IP6_TNL_F_USE_ORIG_FWMARK + if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK) + fl6->flowi6_mark = skb->mark; + else + fl6->flowi6_mark = t->parms.fwmark; + + fl6->flowi6_uid = sock_net_uid(dev_net(dev), NULL); +#endif +} + +static int prepare_ip6gre_xmit_ipv6(struct sk_buff *skb, + struct net_device *dev, + struct flowi6 *fl6, __u8 *dsfield, + int *encap_limit) +{ + struct ipv6hdr *ipv6h = ipv6_hdr(skb); + struct ip6_tnl *t = netdev_priv(dev); + __u16 offset; + + offset = ip6_tnl_parse_tlv_enc_lim(skb, skb_network_header(skb)); + /* ip6_tnl_parse_tlv_enc_lim() might have reallocated skb->head */ + + if (offset > 0) { + struct ipv6_tlv_tnl_enc_lim *tel; + + tel = (struct ipv6_tlv_tnl_enc_lim *)&skb_network_header(skb)[offset]; + if (tel->encap_limit == 0) { + icmpv6_send(skb, ICMPV6_PARAMPROB, + ICMPV6_HDR_FIELD, offset + 2); + return -1; + } + *encap_limit = tel->encap_limit - 1; + } else if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) { + *encap_limit = t->parms.encap_limit; + } + + memcpy(fl6, &t->fl.u.ip6, sizeof(*fl6)); + + if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS) + *dsfield = ipv6_get_dsfield(ipv6h); + else + *dsfield = ip6_tclass(t->parms.flowinfo); + + if (t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL) + fl6->flowlabel |= ip6_flowlabel(ipv6h); + +#ifndef IP6_TNL_F_USE_ORIG_FWMARK + if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK) + fl6->flowi6_mark = skb->mark; + else + fl6->flowi6_mark = t->parms.fwmark; + + fl6->flowi6_uid = sock_net_uid(dev_net(dev), NULL); +#endif + + return 0; +} + +static netdev_tx_t __gre6_xmit(struct sk_buff *skb, + struct net_device *dev, __u8 dsfield, + struct flowi6 *fl6, int encap_limit, + __u32 *pmtu, __be16 proto) +{ + struct ip6_tnl *tunnel = netdev_priv(dev); + struct tnl_ptk_info tpi; + __be16 protocol; + + if (dev->type == ARPHRD_ETHER) + IPCB(skb)->flags = 0; + + if (dev->header_ops && dev->type == ARPHRD_IP6GRE) + fl6->daddr = ((struct ipv6hdr *)skb->data)->daddr; + else + fl6->daddr = tunnel->parms.raddr; + + if (tunnel->parms.o_flags & TUNNEL_SEQ) + tunnel->o_seqno++; + + /* Push GRE header. */ + protocol = (dev->type == ARPHRD_ETHER) ? htons(ETH_P_TEB) : proto; + + if (tunnel->parms.collect_md) { + struct ip_tunnel_info *tun_info; + const struct ip_tunnel_key *key; + __be16 flags; + + tun_info = skb_tunnel_info(skb); + if (unlikely(!tun_info || + !(tun_info->mode & IP_TUNNEL_INFO_TX) || + ip_tunnel_info_af(tun_info) != AF_INET6)) + return -EINVAL; + + key = &tun_info->key; + memset(fl6, 0, sizeof(*fl6)); + fl6->flowi6_proto = IPPROTO_GRE; + fl6->daddr = key->u.ipv6.dst; + fl6->flowlabel = key->label; +// FIX ME! +// fl6->flowi6_uid = sock_net_uid(dev_net(dev), NULL); + + dsfield = key->tos; + flags = key->tun_flags & (TUNNEL_CSUM | TUNNEL_KEY); + tunnel->tun_hlen = gre_calc_hlen(flags); + + tpi.flags = flags; + tpi.proto = protocol; + tpi.key = tunnel_id_to_key32(key->tun_id); + tpi.seq = htonl(tunnel->o_seqno++); + tpi.hdr_len = tunnel->tun_hlen; + + gre_build_header(skb, &tpi, 8); + } else { + tpi.flags = tunnel->parms.o_flags; + tpi.proto = protocol; + tpi.key = tunnel->parms.o_key; + tpi.seq = htonl(tunnel->o_seqno++); + tpi.hdr_len = tunnel->tun_hlen; + + gre_build_header(skb, &tpi, 8); + } + + return ip6_tnl_xmit(skb, dev, dsfield, fl6, encap_limit, pmtu, + NEXTHDR_GRE); +} + +static inline int ip6gre_xmit_ipv4(struct sk_buff *skb, struct net_device *dev) +{ + struct ip6_tnl *t = netdev_priv(dev); + int encap_limit = -1; + struct flowi6 fl6; + __u8 dsfield = 0; + __u32 mtu; + int err; + + memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); + + if (!t->parms.collect_md) + prepare_ip6gre_xmit_ipv4(skb, dev, &fl6, + &dsfield, &encap_limit); + + err = gre_handle_offloads(skb, !!(t->parms.o_flags & TUNNEL_CSUM)); + if (err) + return -1; + + err = __gre6_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu, + skb->protocol); + if (err != 0) { + /* XXX: send ICMP error even if DF is not set. */ + if (err == -EMSGSIZE) + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, + htonl(mtu)); + return -1; + } + + return 0; +} + +static inline int ip6gre_xmit_ipv6(struct sk_buff *skb, struct net_device *dev) +{ + struct ip6_tnl *t = netdev_priv(dev); + struct ipv6hdr *ipv6h = ipv6_hdr(skb); + int encap_limit = -1; + struct flowi6 fl6; + __u8 dsfield = 0; + __u32 mtu; + int err; + + if (ipv6_addr_equal(&t->parms.raddr, &ipv6h->saddr)) + return -1; + + if (!t->parms.collect_md && + prepare_ip6gre_xmit_ipv6(skb, dev, &fl6, &dsfield, &encap_limit)) + return -1; + + if (gre_handle_offloads(skb, !!(t->parms.o_flags & TUNNEL_CSUM))) + return -1; + + err = __gre6_xmit(skb, dev, dsfield, &fl6, encap_limit, + &mtu, skb->protocol); + if (err != 0) { + if (err == -EMSGSIZE) + icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); + return -1; + } + + return 0; +} + +/** + * ip6_tnl_addr_conflict - compare packet addresses to tunnel's own + * @t: the outgoing tunnel device + * @hdr: IPv6 header from the incoming packet + * + * Description: + * Avoid trivial tunneling loop by checking that tunnel exit-point + * doesn't match source of incoming packet. + * + * Return: + * 1 if conflict, + * 0 else + **/ + +static inline bool ip6gre_tnl_addr_conflict(const struct ip6_tnl *t, + const struct ipv6hdr *hdr) +{ + return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr); +} + +static int ip6gre_xmit_other(struct sk_buff *skb, struct net_device *dev) +{ + struct ip6_tnl *t = netdev_priv(dev); + int encap_limit = -1; + struct flowi6 fl6; + __u32 mtu; + int err; + + if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) + encap_limit = t->parms.encap_limit; + + if (!t->parms.collect_md) + memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6)); + + err = gre_handle_offloads(skb, !!(t->parms.o_flags & TUNNEL_CSUM)); + if (err) + return err; + + err = __gre6_xmit(skb, dev, 0, &fl6, encap_limit, &mtu, skb->protocol); + + return err; +} + +static netdev_tx_t ip6gre_tunnel_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct ip6_tnl *t = netdev_priv(dev); + struct net_device_stats *stats = &t->dev->stats; + int ret; + + if (!ip6_tnl_xmit_ctl(t, &t->parms.laddr, &t->parms.raddr)) + goto tx_err; + + switch (skb->protocol) { + case htons(ETH_P_IP): + ret = ip6gre_xmit_ipv4(skb, dev); + break; + case htons(ETH_P_IPV6): + ret = ip6gre_xmit_ipv6(skb, dev); + break; + default: + ret = ip6gre_xmit_other(skb, dev); + break; + } + + if (ret < 0) + goto tx_err; + + return NETDEV_TX_OK; + +tx_err: + stats->tx_errors++; + stats->tx_dropped++; + kfree_skb(skb); + return NETDEV_TX_OK; +} + +static netdev_tx_t ip6erspan_tunnel_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct ipv6hdr *ipv6h = ipv6_hdr(skb); + struct ip6_tnl *t = netdev_priv(dev); + struct dst_entry *dst = skb_dst(skb); + struct net_device_stats *stats; + struct tnl_ptk_info tpi; + bool truncate = false; + int encap_limit = -1; + __u8 dsfield = false; + struct flowi6 fl6; + int err = -EINVAL; + __u32 mtu; + + if (!ip6_tnl_xmit_ctl(t, &t->parms.laddr, &t->parms.raddr)) + goto tx_err; + + if (gre_handle_offloads(skb, false)) + goto tx_err; + + if (skb->len > dev->mtu + dev->hard_header_len) { + pskb_trim(skb, dev->mtu + dev->hard_header_len); + truncate = true; + } + + t->parms.o_flags &= ~TUNNEL_KEY; + IPCB(skb)->flags = 0; + + /* For collect_md mode, derive fl6 from the tunnel key, + * for native mode, call prepare_ip6gre_xmit_{ipv4,ipv6}. + */ + if (t->parms.collect_md) { + struct ip_tunnel_info *tun_info; + const struct ip_tunnel_key *key; + struct erspan_metadata *md; + __be32 tun_id; + + tun_info = skb_tunnel_info(skb); + if (unlikely(!tun_info || + !(tun_info->mode & IP_TUNNEL_INFO_TX) || + ip_tunnel_info_af(tun_info) != AF_INET6)) + return -EINVAL; + + key = &tun_info->key; + memset(&fl6, 0, sizeof(fl6)); + fl6.flowi6_proto = IPPROTO_GRE; + fl6.daddr = key->u.ipv6.dst; + fl6.flowlabel = key->label; +// fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL); + + dsfield = key->tos; + md = ip_tunnel_info_opts(tun_info); + if (!md) + goto tx_err; + + tun_id = tunnel_id_to_key32(key->tun_id); + if (md->version == 1) { + erspan_build_header(skb, + ntohl(tun_id), + ntohl(md->u.index), truncate, + false); + } else if (md->version == 2) { + erspan_build_header_v2(skb, + ntohl(tun_id), + md->u.md2.dir, + get_hwid(&md->u.md2), + truncate, false); + } + } else { + switch (skb->protocol) { + case htons(ETH_P_IP): + memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); + prepare_ip6gre_xmit_ipv4(skb, dev, &fl6, + &dsfield, &encap_limit); + break; + case htons(ETH_P_IPV6): + if (ipv6_addr_equal(&t->parms.raddr, &ipv6h->saddr)) + goto tx_err; + if (prepare_ip6gre_xmit_ipv6(skb, dev, &fl6, + &dsfield, &encap_limit)) + goto tx_err; + break; + default: + memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6)); + break; + } + + if (t->parms.erspan_ver == 1) + erspan_build_header(skb, ntohl(t->parms.o_key), + t->parms.index, + truncate, false); + else + erspan_build_header_v2(skb, ntohl(t->parms.o_key), + t->parms.dir, + t->parms.hwid, + truncate, false); + fl6.daddr = t->parms.raddr; + } + + tpi.flags = TUNNEL_SEQ; + tpi.proto = htons(ETH_P_ERSPAN); + tpi.key = 0; + tpi.seq = htonl(t->o_seqno++); + tpi.hdr_len = 8; + + /* Push GRE header. */ + gre_build_header(skb, &tpi, 8); + + /* TooBig packet may have updated dst->dev's mtu */ + if (!t->parms.collect_md && dst && dst_mtu(dst) > dst->dev->mtu) + dst->ops->update_pmtu(dst, NULL, skb, dst->dev->mtu); + + err = ip6_tnl_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu, + NEXTHDR_GRE); + if (err != 0) { + /* XXX: send ICMP error even if DF is not set. */ + if (err == -EMSGSIZE) { + if (skb->protocol == htons(ETH_P_IP)) + icmp_send(skb, ICMP_DEST_UNREACH, + ICMP_FRAG_NEEDED, htonl(mtu)); + else + icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); + } + + goto tx_err; + } + return NETDEV_TX_OK; + +tx_err: + stats = &t->dev->stats; + stats->tx_errors++; + stats->tx_dropped++; + kfree_skb(skb); + return NETDEV_TX_OK; +} + +static void ip6gre_tnl_link_config(struct ip6_tnl *t, int set_mtu) +{ + struct net_device *dev = t->dev; + struct __ip6_tnl_parm *p = &t->parms; + struct flowi6 *fl6 = &t->fl.u.ip6; + int t_hlen; + + if (dev->type != ARPHRD_ETHER) { + memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr)); + memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr)); + } + + /* Set up flowi template */ + fl6->saddr = p->laddr; + fl6->daddr = p->raddr; + fl6->flowi6_oif = p->link; + fl6->flowlabel = 0; + fl6->flowi6_proto = IPPROTO_GRE; + + if (!(p->flags&IP6_TNL_F_USE_ORIG_TCLASS)) + fl6->flowlabel |= IPV6_TCLASS_MASK & p->flowinfo; + if (!(p->flags&IP6_TNL_F_USE_ORIG_FLOWLABEL)) + fl6->flowlabel |= IPV6_FLOWLABEL_MASK & p->flowinfo; + + p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV|IP6_TNL_F_CAP_PER_PACKET); + p->flags |= ip6_tnl_get_cap(t, &p->laddr, &p->raddr); + + if (p->flags&IP6_TNL_F_CAP_XMIT && + p->flags&IP6_TNL_F_CAP_RCV && dev->type != ARPHRD_ETHER) + dev->flags |= IFF_POINTOPOINT; + else + dev->flags &= ~IFF_POINTOPOINT; + + t->tun_hlen = gre_calc_hlen(t->parms.o_flags); + + t->hlen = t->encap_hlen + t->tun_hlen; + + t_hlen = t->hlen + sizeof(struct ipv6hdr); + + if (p->flags & IP6_TNL_F_CAP_XMIT) { + int strict = (ipv6_addr_type(&p->raddr) & + (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL)); + + struct rt6_info *rt = rt6_lookup(t->net, + &p->raddr, &p->laddr, + p->link, strict); + + if (!rt) + return; + + if (rt->dst.dev) { + dev->hard_header_len = rt->dst.dev->hard_header_len + + t_hlen; + + if (set_mtu) { + dev->mtu = rt->dst.dev->mtu - t_hlen; + if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) + dev->mtu -= 8; + if (dev->type == ARPHRD_ETHER) + dev->mtu -= ETH_HLEN; + + if (dev->mtu < IPV6_MIN_MTU) + dev->mtu = IPV6_MIN_MTU; + } + } + ip6_rt_put(rt); + } +} + +static int ip6gre_tnl_change(struct ip6_tnl *t, + const struct __ip6_tnl_parm *p, int set_mtu) +{ + t->parms.laddr = p->laddr; + t->parms.raddr = p->raddr; + t->parms.flags = p->flags; + t->parms.hop_limit = p->hop_limit; + t->parms.encap_limit = p->encap_limit; + t->parms.flowinfo = p->flowinfo; + t->parms.link = p->link; + t->parms.proto = p->proto; + t->parms.i_key = p->i_key; + t->parms.o_key = p->o_key; + t->parms.i_flags = p->i_flags; + t->parms.o_flags = p->o_flags; + t->parms.fwmark = p->fwmark; + dst_cache_reset(&t->dst_cache); + ip6gre_tnl_link_config(t, set_mtu); + return 0; +} + +static void ip6gre_tnl_parm_from_user(struct __ip6_tnl_parm *p, + const struct ip6_tnl_parm2 *u) +{ + p->laddr = u->laddr; + p->raddr = u->raddr; + p->flags = u->flags; + p->hop_limit = u->hop_limit; + p->encap_limit = u->encap_limit; + p->flowinfo = u->flowinfo; + p->link = u->link; + p->i_key = u->i_key; + p->o_key = u->o_key; + p->i_flags = gre_flags_to_tnl_flags(u->i_flags); + p->o_flags = gre_flags_to_tnl_flags(u->o_flags); + memcpy(p->name, u->name, sizeof(u->name)); +} + +static void ip6gre_tnl_parm_to_user(struct ip6_tnl_parm2 *u, + const struct __ip6_tnl_parm *p) +{ + u->proto = IPPROTO_GRE; + u->laddr = p->laddr; + u->raddr = p->raddr; + u->flags = p->flags; + u->hop_limit = p->hop_limit; + u->encap_limit = p->encap_limit; + u->flowinfo = p->flowinfo; + u->link = p->link; + u->i_key = p->i_key; + u->o_key = p->o_key; + u->i_flags = gre_tnl_flags_to_gre_flags(p->i_flags); + u->o_flags = gre_tnl_flags_to_gre_flags(p->o_flags); + memcpy(u->name, p->name, sizeof(u->name)); +} + +static int ip6gre_tunnel_ioctl(struct net_device *dev, + struct ifreq *ifr, int cmd) +{ + int err = 0; + struct ip6_tnl_parm2 p; + struct __ip6_tnl_parm p1; + struct ip6_tnl *t = netdev_priv(dev); + struct net *net = t->net; + struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); + + memset(&p1, 0, sizeof(p1)); + + switch (cmd) { + case SIOCGETTUNNEL: + if (dev == ign->fb_tunnel_dev) { + if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) { + err = -EFAULT; + break; + } + ip6gre_tnl_parm_from_user(&p1, &p); + t = ip6gre_tunnel_locate(net, &p1, 0); + if (!t) + t = netdev_priv(dev); + } + memset(&p, 0, sizeof(p)); + ip6gre_tnl_parm_to_user(&p, &t->parms); + if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) + err = -EFAULT; + break; + + case SIOCADDTUNNEL: + case SIOCCHGTUNNEL: + err = -EPERM; + if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) + goto done; + + err = -EFAULT; + if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) + goto done; + + err = -EINVAL; + if ((p.i_flags|p.o_flags)&(GRE_VERSION|GRE_ROUTING)) + goto done; + + if (!(p.i_flags&GRE_KEY)) + p.i_key = 0; + if (!(p.o_flags&GRE_KEY)) + p.o_key = 0; + + ip6gre_tnl_parm_from_user(&p1, &p); + t = ip6gre_tunnel_locate(net, &p1, cmd == SIOCADDTUNNEL); + + if (dev != ign->fb_tunnel_dev && cmd == SIOCCHGTUNNEL) { + if (t) { + if (t->dev != dev) { + err = -EEXIST; + break; + } + } else { + t = netdev_priv(dev); + + ip6gre_tunnel_unlink(ign, t); + synchronize_net(); + ip6gre_tnl_change(t, &p1, 1); + ip6gre_tunnel_link(ign, t); + netdev_state_change(dev); + } + } + + if (t) { + err = 0; + + memset(&p, 0, sizeof(p)); + ip6gre_tnl_parm_to_user(&p, &t->parms); + if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) + err = -EFAULT; + } else + err = (cmd == SIOCADDTUNNEL ? -ENOBUFS : -ENOENT); + break; + + case SIOCDELTUNNEL: + err = -EPERM; + if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) + goto done; + + if (dev == ign->fb_tunnel_dev) { + err = -EFAULT; + if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) + goto done; + err = -ENOENT; + ip6gre_tnl_parm_from_user(&p1, &p); + t = ip6gre_tunnel_locate(net, &p1, 0); + if (!t) + goto done; + err = -EPERM; + if (t == netdev_priv(ign->fb_tunnel_dev)) + goto done; + dev = t->dev; + } + unregister_netdevice(dev); + err = 0; + break; + + default: + err = -EINVAL; + } + +done: + return err; +} + +static int ip6gre_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, const void *daddr, + const void *saddr, unsigned int len) +{ + struct ip6_tnl *t = netdev_priv(dev); + struct ipv6hdr *ipv6h; + __be16 *p; + + ipv6h = (struct ipv6hdr *)skb_push(skb, t->hlen + sizeof(*ipv6h)); + ip6_flow_hdr(ipv6h, 0, ip6_make_flowlabel(dev_net(dev), skb, + t->fl.u.ip6.flowlabel, + true, &t->fl.u.ip6)); + ipv6h->hop_limit = t->parms.hop_limit; + ipv6h->nexthdr = NEXTHDR_GRE; + ipv6h->saddr = t->parms.laddr; + ipv6h->daddr = t->parms.raddr; + + p = (__be16 *)(ipv6h + 1); + p[0] = t->parms.o_flags; + p[1] = htons(type); + + /* + * Set the source hardware address. + */ + + if (saddr) + memcpy(&ipv6h->saddr, saddr, sizeof(struct in6_addr)); + if (daddr) + memcpy(&ipv6h->daddr, daddr, sizeof(struct in6_addr)); + if (!ipv6_addr_any(&ipv6h->daddr)) + return t->hlen; + + return -t->hlen; +} + +static const struct header_ops ip6gre_header_ops = { + .create = ip6gre_header, +}; + +static const struct net_device_ops ip6gre_netdev_ops = { + .ndo_init = ip6gre_tunnel_init, + .ndo_uninit = ip6gre_tunnel_uninit, + .ndo_start_xmit = ip6gre_tunnel_xmit, + .ndo_do_ioctl = ip6gre_tunnel_ioctl, + .ndo_change_mtu = ip6_tnl_change_mtu, + .ndo_get_stats64 = rpl_ip_tunnel_get_stats64, +#ifdef HAVE_NDO_GET_IFLINK + .ndo_get_iflink = ip6_tnl_get_iflink, +#endif +}; + +#ifdef HAVE_NEEDS_FREE_NETDEV +static void ip6gre_dev_free(struct net_device *dev) +{ + struct ip6_tnl *t = netdev_priv(dev); + + dst_cache_destroy(&t->dst_cache); + free_percpu(dev->tstats); +} + +#endif +static void ip6gre_tunnel_setup(struct net_device *dev) +{ + dev->netdev_ops = &ip6gre_netdev_ops; +#ifndef HAVE_NEEDS_FREE_NETDEV + dev->destructor = free_netdev; +#else + dev->needs_free_netdev = true; + dev->priv_destructor = ip6gre_dev_free; +#endif + + dev->type = ARPHRD_IP6GRE; + + dev->flags |= IFF_NOARP; + dev->addr_len = sizeof(struct in6_addr); + netif_keep_dst(dev); + /* This perm addr will be used as interface identifier by IPv6 */ + dev->addr_assign_type = NET_ADDR_RANDOM; + eth_random_addr(dev->perm_addr); +} + +#define GRE6_FEATURES (NETIF_F_SG | \ + NETIF_F_FRAGLIST | \ + NETIF_F_HIGHDMA | \ + NETIF_F_HW_CSUM) + +static void ip6gre_tnl_init_features(struct net_device *dev) +{ + struct ip6_tnl *nt = netdev_priv(dev); + + dev->features |= GRE6_FEATURES; + dev->hw_features |= GRE6_FEATURES; + + if (!(nt->parms.o_flags & TUNNEL_SEQ)) { + /* TCP offload with GRE SEQ is not supported, nor + * can we support 2 levels of outer headers requiring + * an update. + */ + if (!(nt->parms.o_flags & TUNNEL_CSUM) || + nt->encap.type == TUNNEL_ENCAP_NONE) { + dev->features |= NETIF_F_GSO_SOFTWARE; + dev->hw_features |= NETIF_F_GSO_SOFTWARE; + } + + /* Can use a lockless transmit, unless we generate + * output sequences + */ + dev->features |= NETIF_F_LLTX; + } +} + +static int ip6gre_tunnel_init_common(struct net_device *dev) +{ + struct ip6_tnl *tunnel; + int ret; + int t_hlen; + + tunnel = netdev_priv(dev); + + tunnel->dev = dev; + tunnel->net = dev_net(dev); + strcpy(tunnel->parms.name, dev->name); + + dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); + if (!dev->tstats) + return -ENOMEM; + + ret = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL); + if (ret) { + free_percpu(dev->tstats); + dev->tstats = NULL; + return ret; + } + + tunnel->tun_hlen = gre_calc_hlen(tunnel->parms.o_flags); + tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen; + t_hlen = tunnel->hlen + sizeof(struct ipv6hdr); + + dev->hard_header_len = LL_MAX_HEADER + t_hlen; + dev->mtu = ETH_DATA_LEN - t_hlen; + if (dev->type == ARPHRD_ETHER) + dev->mtu -= ETH_HLEN; + if (!(tunnel->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) + dev->mtu -= 8; + + if (tunnel->parms.collect_md) { + dev->features |= NETIF_F_NETNS_LOCAL; + netif_keep_dst(dev); + } + ip6gre_tnl_init_features(dev); + + return 0; +} + +static int ip6gre_tunnel_init(struct net_device *dev) +{ + struct ip6_tnl *tunnel; + int ret; + + ret = ip6gre_tunnel_init_common(dev); + if (ret) + return ret; + + tunnel = netdev_priv(dev); + + if (tunnel->parms.collect_md) + return 0; + + memcpy(dev->dev_addr, &tunnel->parms.laddr, sizeof(struct in6_addr)); + memcpy(dev->broadcast, &tunnel->parms.raddr, sizeof(struct in6_addr)); + + if (ipv6_addr_any(&tunnel->parms.raddr)) + dev->header_ops = &ip6gre_header_ops; + + return 0; +} + +static void ip6gre_fb_tunnel_init(struct net_device *dev) +{ + struct ip6_tnl *tunnel = netdev_priv(dev); + + tunnel->dev = dev; + tunnel->net = dev_net(dev); + strcpy(tunnel->parms.name, dev->name); + + tunnel->hlen = sizeof(struct ipv6hdr) + 4; + + dev_hold(dev); +} + +static struct inet6_protocol ip6gre_protocol __read_mostly = { + .handler = gre_rcv, + .err_handler = ip6gre_err, + .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, +}; + +static void ip6gre_destroy_tunnels(struct net *net, struct list_head *head) +{ + struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); + struct net_device *dev, *aux; + int prio; + + for_each_netdev_safe(net, dev, aux) + if (dev->rtnl_link_ops == &ip6gre_link_ops || + dev->rtnl_link_ops == &ip6gre_tap_ops || + dev->rtnl_link_ops == &ip6erspan_tap_ops) + unregister_netdevice_queue(dev, head); + + for (prio = 0; prio < 4; prio++) { + int h; + for (h = 0; h < IP6_GRE_HASH_SIZE; h++) { + struct ip6_tnl *t; + + t = rtnl_dereference(ign->tunnels[prio][h]); + + while (t) { + /* If dev is in the same netns, it has already + * been added to the list by the previous loop. + */ + if (!net_eq(dev_net(t->dev), net)) + unregister_netdevice_queue(t->dev, + head); + t = rtnl_dereference(t->next); + } + } + } +} + +static int __net_init ip6gre_init_net(struct net *net) +{ + struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); + int err; + + ign->fb_tunnel_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6gre0", + NET_NAME_UNKNOWN, + ip6gre_tunnel_setup); + if (!ign->fb_tunnel_dev) { + err = -ENOMEM; + goto err_alloc_dev; + } + dev_net_set(ign->fb_tunnel_dev, net); + /* FB netdevice is special: we have one, and only one per netns. + * Allowing to move it to another netns is clearly unsafe. + */ + ign->fb_tunnel_dev->features |= NETIF_F_NETNS_LOCAL; + + + ip6gre_fb_tunnel_init(ign->fb_tunnel_dev); + ign->fb_tunnel_dev->rtnl_link_ops = &ip6gre_link_ops; + + err = register_netdev(ign->fb_tunnel_dev); + if (err) + goto err_reg_dev; + + rcu_assign_pointer(ign->tunnels_wc[0], + netdev_priv(ign->fb_tunnel_dev)); + return 0; + +err_reg_dev: + free_netdev(ign->fb_tunnel_dev); +err_alloc_dev: + return err; +} + +static void __net_exit ip6gre_exit_batch_net(struct list_head *net_list) +{ + struct net *net; + LIST_HEAD(list); + + rtnl_lock(); + list_for_each_entry(net, net_list, exit_list) + ip6gre_destroy_tunnels(net, &list); + unregister_netdevice_many(&list); + rtnl_unlock(); +} + +enum { +#if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0) + IFLA_GRE_ENCAP_TYPE = IFLA_GRE_FLAGS + 1, + IFLA_GRE_ENCAP_FLAGS, + IFLA_GRE_ENCAP_SPORT, + IFLA_GRE_ENCAP_DPORT, +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,3,0) + IFLA_GRE_COLLECT_METADATA = IFLA_GRE_ENCAP_DPORT + 1, +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,8,0) + IFLA_GRE_IGNORE_DF = IFLA_GRE_COLLECT_METADATA + 1, +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,12,0) + IFLA_GRE_FWMARK = IFLA_GRE_IGNORE_DF + 1, +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0) + IFLA_GRE_ERSPAN_INDEX = IFLA_GRE_FWMARK + 1, +#endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,16,0) + IFLA_GRE_ERSPAN_VER = IFLA_GRE_ERSPAN_INDEX + 1, + IFLA_GRE_ERSPAN_DIR, + IFLA_GRE_ERSPAN_HWID, +#endif + +}; + +#define RPL_IFLA_GRE_MAX (IFLA_GRE_ERSPAN_HWID + 1) + +static struct pernet_operations ip6gre_net_ops = { + .init = ip6gre_init_net, + .exit_batch = ip6gre_exit_batch_net, + .id = &ip6gre_net_id, + .size = sizeof(struct ip6gre_net), +}; +#ifdef HAVE_IP6GRE_EXTACK +static int rpl_ip6gre_tunnel_validate(struct nlattr *tb[], + struct nlattr *data[], + struct netlink_ext_ack *extack) +#else +static int rpl_ip6gre_tunnel_validate(struct nlattr *tb[], + struct nlattr *data[]) +#endif +{ + __be16 flags; + + if (!data) + return 0; + + flags = 0; + if (data[IFLA_GRE_IFLAGS]) + flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]); + if (data[IFLA_GRE_OFLAGS]) + flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]); + if (flags & (GRE_VERSION|GRE_ROUTING)) + return -EINVAL; + + return 0; +} +#define ip6gre_tunnel_validate rpl_ip6gre_tunnel_validate + +#ifdef HAVE_IP6GRE_EXTACK +static int rpl_ip6gre_tap_validate(struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) +#else +static int rpl_ip6gre_tap_validate(struct nlattr *tb[], struct nlattr *data[]) +#endif +{ + struct in6_addr daddr; + + if (tb[IFLA_ADDRESS]) { + if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) + return -EINVAL; + if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) + return -EADDRNOTAVAIL; + } + + if (!data) + goto out; + + if (data[IFLA_GRE_REMOTE]) { + daddr = nla_get_in6_addr(data[IFLA_GRE_REMOTE]); + if (ipv6_addr_any(&daddr)) + return -EINVAL; + } + +out: +#ifdef HAVE_IP6GRE_EXTACK + return ip6gre_tunnel_validate(tb, data, extack); +#else + return ip6gre_tunnel_validate(tb, data); +#endif +} +#define ip6gre_tap_validate rpl_ip6gre_tap_validate + +#ifdef HAVE_IP6GRE_EXTACK +static int rpl_ip6erspan_tap_validate(struct nlattr *tb[], + struct nlattr *data[], + struct netlink_ext_ack *extack) +#else +static int rpl_ip6erspan_tap_validate(struct nlattr *tb[], + struct nlattr *data[]) +#endif +{ + __be16 flags = 0; + int ret, ver = 0; + + if (!data) + return 0; + +#ifdef HAVE_IP6GRE_EXTACK + ret = ip6gre_tap_validate(tb, data, extack); +#else + ret = ip6gre_tap_validate(tb, data); +#endif + if (ret) + return ret; + + /* ERSPAN should only have GRE sequence and key flag */ + if (data[IFLA_GRE_OFLAGS]) + flags |= nla_get_be16(data[IFLA_GRE_OFLAGS]); + if (data[IFLA_GRE_IFLAGS]) + flags |= nla_get_be16(data[IFLA_GRE_IFLAGS]); + if (!data[IFLA_GRE_COLLECT_METADATA] && + flags != (GRE_SEQ | GRE_KEY)) + return -EINVAL; + + /* ERSPAN Session ID only has 10-bit. Since we reuse + * 32-bit key field as ID, check it's range. + */ + if (data[IFLA_GRE_IKEY] && + (ntohl(nla_get_be32(data[IFLA_GRE_IKEY])) & ~ID_MASK)) + return -EINVAL; + + if (data[IFLA_GRE_OKEY] && + (ntohl(nla_get_be32(data[IFLA_GRE_OKEY])) & ~ID_MASK)) + return -EINVAL; + + if (data[IFLA_GRE_ERSPAN_VER]) { + ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]); + if (ver != 1 && ver != 2) + return -EINVAL; + } + + if (ver == 1) { + if (data[IFLA_GRE_ERSPAN_INDEX]) { + u32 index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]); + + if (index & ~INDEX_MASK) + return -EINVAL; + } + } else if (ver == 2) { + if (data[IFLA_GRE_ERSPAN_DIR]) { + u16 dir = nla_get_u8(data[IFLA_GRE_ERSPAN_DIR]); + + if (dir & ~(DIR_MASK >> DIR_OFFSET)) + return -EINVAL; + } + + if (data[IFLA_GRE_ERSPAN_HWID]) { + u16 hwid = nla_get_u16(data[IFLA_GRE_ERSPAN_HWID]); + + if (hwid & ~(HWID_MASK >> HWID_OFFSET)) + return -EINVAL; + } + } + + return 0; +} +#define ip6erspan_tap_validate rpl_ip6erspan_tap_validate + +static void ip6gre_netlink_parms(struct nlattr *data[], + struct __ip6_tnl_parm *parms) +{ + memset(parms, 0, sizeof(*parms)); + + if (!data) + return; + + if (data[IFLA_GRE_LINK]) + parms->link = nla_get_u32(data[IFLA_GRE_LINK]); + + if (data[IFLA_GRE_IFLAGS]) + parms->i_flags = gre_flags_to_tnl_flags( + nla_get_be16(data[IFLA_GRE_IFLAGS])); + + if (data[IFLA_GRE_OFLAGS]) + parms->o_flags = gre_flags_to_tnl_flags( + nla_get_be16(data[IFLA_GRE_OFLAGS])); + + if (data[IFLA_GRE_IKEY]) + parms->i_key = nla_get_be32(data[IFLA_GRE_IKEY]); + + if (data[IFLA_GRE_OKEY]) + parms->o_key = nla_get_be32(data[IFLA_GRE_OKEY]); + + if (data[IFLA_GRE_LOCAL]) + parms->laddr = nla_get_in6_addr(data[IFLA_GRE_LOCAL]); + + if (data[IFLA_GRE_REMOTE]) + parms->raddr = nla_get_in6_addr(data[IFLA_GRE_REMOTE]); + + if (data[IFLA_GRE_TTL]) + parms->hop_limit = nla_get_u8(data[IFLA_GRE_TTL]); + + if (data[IFLA_GRE_ENCAP_LIMIT]) + parms->encap_limit = nla_get_u8(data[IFLA_GRE_ENCAP_LIMIT]); + + if (data[IFLA_GRE_FLOWINFO]) + parms->flowinfo = nla_get_be32(data[IFLA_GRE_FLOWINFO]); + + if (data[IFLA_GRE_FLAGS]) + parms->flags = nla_get_u32(data[IFLA_GRE_FLAGS]); + + if (data[IFLA_GRE_FWMARK]) + parms->fwmark = nla_get_u32(data[IFLA_GRE_FWMARK]); + + if (data[IFLA_GRE_COLLECT_METADATA]) + parms->collect_md = true; + + if (data[IFLA_GRE_ERSPAN_VER]) + parms->erspan_ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]); + + if (parms->erspan_ver == 1) { + if (data[IFLA_GRE_ERSPAN_INDEX]) + parms->index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]); + } else if (parms->erspan_ver == 2) { + if (data[IFLA_GRE_ERSPAN_DIR]) + parms->dir = nla_get_u8(data[IFLA_GRE_ERSPAN_DIR]); + if (data[IFLA_GRE_ERSPAN_HWID]) + parms->hwid = nla_get_u16(data[IFLA_GRE_ERSPAN_HWID]); + } +} + +static int ip6gre_tap_init(struct net_device *dev) +{ + int ret; + + ret = ip6gre_tunnel_init_common(dev); + if (ret) + return ret; + + dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; + + return 0; +} + +static const struct net_device_ops ip6gre_tap_netdev_ops = { + .ndo_init = ip6gre_tap_init, + .ndo_uninit = ip6gre_tunnel_uninit, + .ndo_start_xmit = ip6gre_tunnel_xmit, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = ip6_tnl_change_mtu, + .ndo_get_stats64 = rpl_ip_tunnel_get_stats64, +#ifdef HAVE_NDO_GET_IFLINK + .ndo_get_iflink = ip6_tnl_get_iflink, +#endif +}; + +static int ip6erspan_tap_init(struct net_device *dev) +{ + struct ip6_tnl *tunnel; + int t_hlen; + int ret; + + tunnel = netdev_priv(dev); + + tunnel->dev = dev; + tunnel->net = dev_net(dev); + strcpy(tunnel->parms.name, dev->name); + + dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); + if (!dev->tstats) + return -ENOMEM; + + ret = dst_cache_init(&tunnel->dst_cache, GFP_KERNEL); + if (ret) { + free_percpu(dev->tstats); + dev->tstats = NULL; + return ret; + } + + tunnel->tun_hlen = 8; + tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen + + erspan_hdr_len(tunnel->parms.erspan_ver); + t_hlen = tunnel->hlen + sizeof(struct ipv6hdr); + + dev->hard_header_len = LL_MAX_HEADER + t_hlen; + dev->mtu = ETH_DATA_LEN - t_hlen; + if (dev->type == ARPHRD_ETHER) + dev->mtu -= ETH_HLEN; + if (!(tunnel->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) + dev->mtu -= 8; + + dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; + tunnel = netdev_priv(dev); + ip6gre_tnl_link_config(tunnel, 1); + + return 0; +} + +static const struct net_device_ops ip6erspan_netdev_ops = { + .ndo_init = ip6erspan_tap_init, + .ndo_uninit = ip6gre_tunnel_uninit, + .ndo_start_xmit = ip6erspan_tunnel_xmit, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = ip6_tnl_change_mtu, + .ndo_get_stats64 = ip_tunnel_get_stats64, +#ifdef HAVE_NDO_GET_IFLINK + .ndo_get_iflink = ip6_tnl_get_iflink, +#endif +}; + +static void ip6gre_tap_setup(struct net_device *dev) +{ + + ether_setup(dev); +#ifdef HAVE_NET_DEVICE_MAX_MTU + dev->max_mtu = 0; +#endif + dev->netdev_ops = &ip6gre_tap_netdev_ops; +#ifndef HAVE_NEEDS_FREE_NETDEV + dev->destructor = free_netdev; +#else + dev->needs_free_netdev = true; + dev->priv_destructor = ip6gre_dev_free; +#endif + + dev->features |= NETIF_F_NETNS_LOCAL; + dev->priv_flags &= ~IFF_TX_SKB_SHARING; + dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; + netif_keep_dst(dev); +} + +static bool ip6gre_netlink_encap_parms(struct nlattr *data[], + struct ip_tunnel_encap *ipencap) +{ + bool ret = false; + + memset(ipencap, 0, sizeof(*ipencap)); + + if (!data) + return ret; + + if (data[IFLA_GRE_ENCAP_TYPE]) { + ret = true; + ipencap->type = nla_get_u16(data[IFLA_GRE_ENCAP_TYPE]); + } + + if (data[IFLA_GRE_ENCAP_FLAGS]) { + ret = true; + ipencap->flags = nla_get_u16(data[IFLA_GRE_ENCAP_FLAGS]); + } + + if (data[IFLA_GRE_ENCAP_SPORT]) { + ret = true; + ipencap->sport = nla_get_be16(data[IFLA_GRE_ENCAP_SPORT]); + } + + if (data[IFLA_GRE_ENCAP_DPORT]) { + ret = true; + ipencap->dport = nla_get_be16(data[IFLA_GRE_ENCAP_DPORT]); + } + + return ret; +} + +#ifdef HAVE_IP6GRE_EXTACK +static int rpl_ip6gre_newlink(struct net *src_net, struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) +#else +static int rpl_ip6gre_newlink(struct net *src_net, struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[]) +#endif +{ + struct ip6_tnl *nt; + struct net *net = dev_net(dev); + struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); + struct ip_tunnel_encap ipencap; + int err; + + nt = netdev_priv(dev); + + if (ip6gre_netlink_encap_parms(data, &ipencap)) { + int err = ip6_tnl_encap_setup(nt, &ipencap); + + if (err < 0) + return err; + } + + ip6gre_netlink_parms(data, &nt->parms); + + if (nt->parms.collect_md) { + if (rtnl_dereference(ign->collect_md_tun)) + return -EEXIST; + } else { + if (ip6gre_tunnel_find(net, &nt->parms, dev->type)) + return -EEXIST; + } + + if (dev->type == ARPHRD_ETHER && !tb[IFLA_ADDRESS]) + eth_hw_addr_random(dev); + + nt->dev = dev; + nt->net = dev_net(dev); + + err = register_netdevice(dev); + if (err) + goto out; + + ip6gre_tnl_link_config(nt, !tb[IFLA_MTU]); + + if (tb[IFLA_MTU]) + ip6_tnl_change_mtu(dev, nla_get_u32(tb[IFLA_MTU])); + + dev_hold(dev); + ip6gre_tunnel_link(ign, nt); + +out: + return err; +} +#define ip6gre_newlink rpl_ip6gre_newlink + +#ifdef HAVE_IP6GRE_EXTACK +static int rpl_ip6gre_changelink(struct net_device *dev, struct nlattr *tb[], + struct nlattr *data[], + struct netlink_ext_ack *extack) +#else +static int rpl_ip6gre_changelink(struct net_device *dev, struct nlattr *tb[], + struct nlattr *data[]) +#endif +{ + struct ip6_tnl *t, *nt = netdev_priv(dev); + struct net *net = nt->net; + struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); + struct __ip6_tnl_parm p; + struct ip_tunnel_encap ipencap; + + if (dev == ign->fb_tunnel_dev) + return -EINVAL; + + if (ip6gre_netlink_encap_parms(data, &ipencap)) { + int err = ip6_tnl_encap_setup(nt, &ipencap); + + if (err < 0) + return err; + } + + ip6gre_netlink_parms(data, &p); + + t = ip6gre_tunnel_locate(net, &p, 0); + + if (t) { + if (t->dev != dev) + return -EEXIST; + } else { + t = nt; + } + + ip6gre_tunnel_unlink(ign, t); + ip6gre_tnl_change(t, &p, !tb[IFLA_MTU]); + ip6gre_tunnel_link(ign, t); + return 0; +} +#define ip6gre_changelink rpl_ip6gre_changelink + +static void ip6gre_dellink(struct net_device *dev, struct list_head *head) +{ + struct net *net = dev_net(dev); + struct ip6gre_net *ign = net_generic(net, ip6gre_net_id); + + if (dev != ign->fb_tunnel_dev) + unregister_netdevice_queue(dev, head); +} + +static size_t ip6gre_get_size(const struct net_device *dev) +{ + return + /* IFLA_GRE_LINK */ + nla_total_size(4) + + /* IFLA_GRE_IFLAGS */ + nla_total_size(2) + + /* IFLA_GRE_OFLAGS */ + nla_total_size(2) + + /* IFLA_GRE_IKEY */ + nla_total_size(4) + + /* IFLA_GRE_OKEY */ + nla_total_size(4) + + /* IFLA_GRE_LOCAL */ + nla_total_size(sizeof(struct in6_addr)) + + /* IFLA_GRE_REMOTE */ + nla_total_size(sizeof(struct in6_addr)) + + /* IFLA_GRE_TTL */ + nla_total_size(1) + + /* IFLA_GRE_ENCAP_LIMIT */ + nla_total_size(1) + + /* IFLA_GRE_FLOWINFO */ + nla_total_size(4) + + /* IFLA_GRE_FLAGS */ + nla_total_size(4) + + /* IFLA_GRE_ENCAP_TYPE */ + nla_total_size(2) + + /* IFLA_GRE_ENCAP_FLAGS */ + nla_total_size(2) + + /* IFLA_GRE_ENCAP_SPORT */ + nla_total_size(2) + + /* IFLA_GRE_ENCAP_DPORT */ + nla_total_size(2) + + /* IFLA_GRE_COLLECT_METADATA */ + nla_total_size(0) + + /* IFLA_GRE_FWMARK */ + nla_total_size(4) + + /* IFLA_GRE_ERSPAN_INDEX */ + nla_total_size(4) + + 0; +} + +static int ip6gre_fill_info(struct sk_buff *skb, const struct net_device *dev) +{ + struct ip6_tnl *t = netdev_priv(dev); + struct __ip6_tnl_parm *p = &t->parms; + + if (nla_put_u32(skb, IFLA_GRE_LINK, p->link) || + nla_put_be16(skb, IFLA_GRE_IFLAGS, + gre_tnl_flags_to_gre_flags(p->i_flags)) || + nla_put_be16(skb, IFLA_GRE_OFLAGS, + gre_tnl_flags_to_gre_flags(p->o_flags)) || + nla_put_be32(skb, IFLA_GRE_IKEY, p->i_key) || + nla_put_be32(skb, IFLA_GRE_OKEY, p->o_key) || + nla_put_in6_addr(skb, IFLA_GRE_LOCAL, &p->laddr) || + nla_put_in6_addr(skb, IFLA_GRE_REMOTE, &p->raddr) || + nla_put_u8(skb, IFLA_GRE_TTL, p->hop_limit) || + nla_put_u8(skb, IFLA_GRE_ENCAP_LIMIT, p->encap_limit) || + nla_put_be32(skb, IFLA_GRE_FLOWINFO, p->flowinfo) || + nla_put_u32(skb, IFLA_GRE_FLAGS, p->flags) || + nla_put_u32(skb, IFLA_GRE_FWMARK, p->fwmark) || + nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, p->index)) + goto nla_put_failure; + + if (nla_put_u16(skb, IFLA_GRE_ENCAP_TYPE, + t->encap.type) || + nla_put_be16(skb, IFLA_GRE_ENCAP_SPORT, + t->encap.sport) || + nla_put_be16(skb, IFLA_GRE_ENCAP_DPORT, + t->encap.dport) || + nla_put_u16(skb, IFLA_GRE_ENCAP_FLAGS, + t->encap.flags)) + goto nla_put_failure; + + if (p->collect_md) { + if (nla_put_flag(skb, IFLA_GRE_COLLECT_METADATA)) + goto nla_put_failure; + } + + if (nla_put_u8(skb, IFLA_GRE_ERSPAN_VER, p->erspan_ver)) + goto nla_put_failure; + + if (p->erspan_ver == 1) { + if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, p->index)) + goto nla_put_failure; + } else if (p->erspan_ver == 2) { + if (nla_put_u8(skb, IFLA_GRE_ERSPAN_DIR, p->dir)) + goto nla_put_failure; + if (nla_put_u16(skb, IFLA_GRE_ERSPAN_HWID, p->hwid)) + goto nla_put_failure; + } + + return 0; + +nla_put_failure: + return -EMSGSIZE; +} + +static const struct nla_policy ip6gre_policy[RPL_IFLA_GRE_MAX + 1] = { + [IFLA_GRE_LINK] = { .type = NLA_U32 }, + [IFLA_GRE_IFLAGS] = { .type = NLA_U16 }, + [IFLA_GRE_OFLAGS] = { .type = NLA_U16 }, + [IFLA_GRE_IKEY] = { .type = NLA_U32 }, + [IFLA_GRE_OKEY] = { .type = NLA_U32 }, + [IFLA_GRE_LOCAL] = { .len = FIELD_SIZEOF(struct ipv6hdr, saddr) }, + [IFLA_GRE_REMOTE] = { .len = FIELD_SIZEOF(struct ipv6hdr, daddr) }, + [IFLA_GRE_TTL] = { .type = NLA_U8 }, + [IFLA_GRE_ENCAP_LIMIT] = { .type = NLA_U8 }, + [IFLA_GRE_FLOWINFO] = { .type = NLA_U32 }, + [IFLA_GRE_FLAGS] = { .type = NLA_U32 }, + [IFLA_GRE_ENCAP_TYPE] = { .type = NLA_U16 }, + [IFLA_GRE_ENCAP_FLAGS] = { .type = NLA_U16 }, + [IFLA_GRE_ENCAP_SPORT] = { .type = NLA_U16 }, + [IFLA_GRE_ENCAP_DPORT] = { .type = NLA_U16 }, + [IFLA_GRE_COLLECT_METADATA] = { .type = NLA_FLAG }, + [IFLA_GRE_FWMARK] = { .type = NLA_U32 }, + [IFLA_GRE_ERSPAN_INDEX] = { .type = NLA_U32 }, + [IFLA_GRE_ERSPAN_VER] = { .type = NLA_U8 }, + [IFLA_GRE_ERSPAN_DIR] = { .type = NLA_U8 }, + [IFLA_GRE_ERSPAN_HWID] = { .type = NLA_U16 }, +}; + +static void ip6erspan_tap_setup(struct net_device *dev) +{ + ether_setup(dev); + + dev->netdev_ops = &ip6erspan_netdev_ops; +#ifndef HAVE_NEEDS_FREE_NETDEV + dev->destructor = free_netdev; +#else + dev->needs_free_netdev = true; + dev->priv_destructor = ip6gre_dev_free; +#endif + + dev->features |= NETIF_F_NETNS_LOCAL; + dev->priv_flags &= ~IFF_TX_SKB_SHARING; + dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; + netif_keep_dst(dev); +} + +static struct rtnl_link_ops ip6gre_link_ops __read_mostly = { + .kind = "ip6gre", + .maxtype = RPL_IFLA_GRE_MAX, + .policy = ip6gre_policy, + .priv_size = sizeof(struct ip6_tnl), + .setup = ip6gre_tunnel_setup, + .validate = ip6gre_tunnel_validate, + .newlink = ip6gre_newlink, + .changelink = ip6gre_changelink, + .dellink = ip6gre_dellink, + .get_size = ip6gre_get_size, + .fill_info = ip6gre_fill_info, +#ifdef HAVE_GET_LINK_NET + .get_link_net = ip6_tnl_get_link_net, +#endif +}; + +static struct rtnl_link_ops ip6gre_tap_ops __read_mostly = { + .kind = "ip6gretap", + .maxtype = RPL_IFLA_GRE_MAX, + .policy = ip6gre_policy, + .priv_size = sizeof(struct ip6_tnl), + .setup = ip6gre_tap_setup, + .validate = ip6gre_tap_validate, + .newlink = ip6gre_newlink, + .changelink = ip6gre_changelink, + .get_size = ip6gre_get_size, + .fill_info = ip6gre_fill_info, +#ifdef HAVE_GET_LINK_NET + .get_link_net = ip6_tnl_get_link_net, +#endif +}; + +static struct rtnl_link_ops ip6erspan_tap_ops __read_mostly = { + .kind = "ip6erspan", + .maxtype = RPL_IFLA_GRE_MAX, + .policy = ip6gre_policy, + .priv_size = sizeof(struct ip6_tnl), + .setup = ip6erspan_tap_setup, + .validate = ip6erspan_tap_validate, + .newlink = ip6gre_newlink, + .changelink = ip6gre_changelink, + .get_size = ip6gre_get_size, + .fill_info = ip6gre_fill_info, +#ifdef HAVE_GET_LINK_NET + .get_link_net = ip6_tnl_get_link_net, +#endif +}; + +/* + * And now the modules code and kernel interface. + */ + +int rpl_ip6gre_init(void) +{ + int err; + + pr_info("GRE over IPv6 tunneling driver\n"); + + err = register_pernet_device(&ip6gre_net_ops); + if (err < 0) + return err; + + err = inet6_add_protocol(&ip6gre_protocol, IPPROTO_GRE); + if (err < 0) { + pr_info("%s: can't add protocol\n", __func__); + goto add_proto_failed; + } + + err = rtnl_link_register(&ip6gre_link_ops); + if (err < 0) + goto rtnl_link_failed; + + err = rtnl_link_register(&ip6gre_tap_ops); + if (err < 0) + goto tap_ops_failed; + + err = rtnl_link_register(&ip6erspan_tap_ops); + if (err < 0) + goto erspan_link_failed; + +out: + return err; + +erspan_link_failed: + rtnl_link_unregister(&ip6gre_tap_ops); +tap_ops_failed: + rtnl_link_unregister(&ip6gre_link_ops); +rtnl_link_failed: + inet6_del_protocol(&ip6gre_protocol, IPPROTO_GRE); +add_proto_failed: + unregister_pernet_device(&ip6gre_net_ops); + goto out; +} + +void rpl_ip6gre_fini(void) +{ + rtnl_link_unregister(&ip6gre_tap_ops); + rtnl_link_unregister(&ip6gre_link_ops); + rtnl_link_unregister(&ip6erspan_tap_ops); + inet6_del_protocol(&ip6gre_protocol, IPPROTO_GRE); + unregister_pernet_device(&ip6gre_net_ops); +} +#endif /* USE_UPSTREAM_TUNNEL */ diff --git a/datapath/linux/compat/ip6_tunnel.c b/datapath/linux/compat/ip6_tunnel.c new file mode 100644 index 0000000..fafeec0 --- /dev/null +++ b/datapath/linux/compat/ip6_tunnel.c @@ -0,0 +1,2195 @@ +/* + * IPv6 tunneling device + * Linux INET6 implementation + * + * Authors: + * Ville Nuorvala + * Yasuyuki Kozakai + * + * Based on: + * linux/net/ipv6/sit.c and linux/net/ipv4/ipip.c + * + * RFC 2473 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + * + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#ifndef USE_UPSTREAM_TUNNEL +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "gso.h" +#include + +#define IP6_TUNNEL_HASH_SIZE_SHIFT 5 +#define IP6_TUNNEL_HASH_SIZE (1 << IP6_TUNNEL_HASH_SIZE_SHIFT) + +enum { +#ifndef HAVE_IFLA_IPTUN_ENCAP_TYPE + IFLA_IPTUN_ENCAP_TYPE = IFLA_IPTUN_6RD_RELAY_PREFIXLEN + 1, + IFLA_IPTUN_ENCAP_FLAGS, + IFLA_IPTUN_ENCAP_SPORT, + IFLA_IPTUN_ENCAP_DPORT, +#endif +#ifndef HAVE_IFLA_IPTUN_COLLECT_METADTA + IFLA_IPTUN_COLLECT_METADATA = IFLA_IPTUN_ENCAP_DPORT + 1, + IFLA_IPTUN_FWMARK, +#endif + RPL__IFLA_IPTUN_MAX = IFLA_IPTUN_FWMARK + 1, +}; + +#define RPL_IFLA_IPTUN_MAX RPL__IFLA_IPTUN_MAX + +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0) +/* Undef the one from ip_tunnels.h - we need a different one here */ +/* At least I think... */ +#undef iptunnel_handle_offloads +/* gre_handle_offloads() has different return type on older kernsl. */ +static void gre_nop_fix(struct sk_buff *skb) { } + +static void gre_csum_fix(struct sk_buff *skb) +{ + struct gre_base_hdr *greh; + __be32 *options; + int gre_offset = skb_transport_offset(skb); + + greh = (struct gre_base_hdr *)skb_transport_header(skb); + options = ((__be32 *)greh + 1); + + *options = 0; + *(__sum16 *)options = csum_fold(skb_checksum(skb, gre_offset, + skb->len - gre_offset, 0)); +} + +#define iptunnel_handle_offloads rpl__iptunnel_handle_offloads +static int rpl__iptunnel_handle_offloads(struct sk_buff *skb, bool gre_csum) +{ + int type = gre_csum ? SKB_GSO_GRE_CSUM : SKB_GSO_GRE; + gso_fix_segment_t fix_segment; + + if (gre_csum) + fix_segment = gre_csum_fix; + else + fix_segment = gre_nop_fix; + + return ovs_iptunnel_handle_offloads(skb, type, fix_segment); +} + +#endif +static bool log_ecn_error = true; + +static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2) +{ + u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2); + + return hash_32(hash, IP6_TUNNEL_HASH_SIZE_SHIFT); +} + +static int ip6_tnl_dev_init(struct net_device *dev); +static void ip6_tnl_dev_setup(struct net_device *dev); +static struct rtnl_link_ops ip6_link_ops __read_mostly; + +static unsigned int ip6_tnl_net_id __read_mostly; +struct ip6_tnl_net { + /* the IPv6 tunnel fallback device */ + struct net_device *fb_tnl_dev; + /* lists for storing tunnels in use */ + struct ip6_tnl __rcu *tnls_r_l[IP6_TUNNEL_HASH_SIZE]; + struct ip6_tnl __rcu *tnls_wc[1]; + struct ip6_tnl __rcu **tnls[2]; + struct ip6_tnl __rcu *collect_md_tun; +}; + +static struct net_device_stats *ip6_get_stats(struct net_device *dev) +{ + struct pcpu_sw_netstats tmp, sum = { 0 }; + int i; + + for_each_possible_cpu(i) { + unsigned int start; + const struct pcpu_sw_netstats *tstats = + per_cpu_ptr(dev->tstats, i); + + do { + start = u64_stats_fetch_begin_irq(&tstats->syncp); + tmp.rx_packets = tstats->rx_packets; + tmp.rx_bytes = tstats->rx_bytes; + tmp.tx_packets = tstats->tx_packets; + tmp.tx_bytes = tstats->tx_bytes; + } while (u64_stats_fetch_retry_irq(&tstats->syncp, start)); + + sum.rx_packets += tmp.rx_packets; + sum.rx_bytes += tmp.rx_bytes; + sum.tx_packets += tmp.tx_packets; + sum.tx_bytes += tmp.tx_bytes; + } + dev->stats.rx_packets = sum.rx_packets; + dev->stats.rx_bytes = sum.rx_bytes; + dev->stats.tx_packets = sum.tx_packets; + dev->stats.tx_bytes = sum.tx_bytes; + return &dev->stats; +} + +/** + * ip6_tnl_lookup - fetch tunnel matching the end-point addresses + * @remote: the address of the tunnel exit-point + * @local: the address of the tunnel entry-point + * + * Return: + * tunnel matching given end-points if found, + * else fallback tunnel if its device is up, + * else %NULL + **/ + +#define for_each_ip6_tunnel_rcu(start) \ + for (t = rcu_dereference(start); t; t = rcu_dereference(t->next)) + +static struct ip6_tnl * +ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_addr *local) +{ + unsigned int hash = HASH(remote, local); + struct ip6_tnl *t; + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + struct in6_addr any; + + for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (ipv6_addr_equal(local, &t->parms.laddr) && + ipv6_addr_equal(remote, &t->parms.raddr) && + (t->dev->flags & IFF_UP)) + return t; + } + + memset(&any, 0, sizeof(any)); + hash = HASH(&any, local); + for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (ipv6_addr_equal(local, &t->parms.laddr) && + ipv6_addr_any(&t->parms.raddr) && + (t->dev->flags & IFF_UP)) + return t; + } + + hash = HASH(remote, &any); + for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) { + if (ipv6_addr_equal(remote, &t->parms.raddr) && + ipv6_addr_any(&t->parms.laddr) && + (t->dev->flags & IFF_UP)) + return t; + } + + t = rcu_dereference(ip6n->collect_md_tun); + if (t && t->dev->flags & IFF_UP) + return t; + + t = rcu_dereference(ip6n->tnls_wc[0]); + if (t && (t->dev->flags & IFF_UP)) + return t; + + return NULL; +} + +/** + * ip6_tnl_bucket - get head of list matching given tunnel parameters + * @p: parameters containing tunnel end-points + * + * Description: + * ip6_tnl_bucket() returns the head of the list matching the + * &struct in6_addr entries laddr and raddr in @p. + * + * Return: head of IPv6 tunnel list + **/ + +static struct ip6_tnl __rcu ** +ip6_tnl_bucket(struct ip6_tnl_net *ip6n, const struct __ip6_tnl_parm *p) +{ + const struct in6_addr *remote = &p->raddr; + const struct in6_addr *local = &p->laddr; + unsigned int h = 0; + int prio = 0; + + if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) { + prio = 1; + h = HASH(remote, local); + } + return &ip6n->tnls[prio][h]; +} + +/** + * ip6_tnl_link - add tunnel to hash table + * @t: tunnel to be added + **/ + +static void +ip6_tnl_link(struct ip6_tnl_net *ip6n, struct ip6_tnl *t) +{ + struct ip6_tnl __rcu **tp = ip6_tnl_bucket(ip6n, &t->parms); + + if (t->parms.collect_md) + rcu_assign_pointer(ip6n->collect_md_tun, t); + rcu_assign_pointer(t->next , rtnl_dereference(*tp)); + rcu_assign_pointer(*tp, t); +} + +/** + * ip6_tnl_unlink - remove tunnel from hash table + * @t: tunnel to be removed + **/ + +static void +ip6_tnl_unlink(struct ip6_tnl_net *ip6n, struct ip6_tnl *t) +{ + struct ip6_tnl __rcu **tp; + struct ip6_tnl *iter; + + if (t->parms.collect_md) + rcu_assign_pointer(ip6n->collect_md_tun, NULL); + + for (tp = ip6_tnl_bucket(ip6n, &t->parms); + (iter = rtnl_dereference(*tp)) != NULL; + tp = &iter->next) { + if (t == iter) { + rcu_assign_pointer(*tp, t->next); + break; + } + } +} + +#ifdef HAVE_NEEDS_FREE_NETDEV +static void ip6_dev_free(struct net_device *dev) +{ + struct ip6_tnl *t = netdev_priv(dev); + + gro_cells_destroy(&t->gro_cells); + dst_cache_destroy(&t->dst_cache); + free_percpu(dev->tstats); +} + +#endif +static int ip6_tnl_create2(struct net_device *dev) +{ + struct ip6_tnl *t = netdev_priv(dev); + struct net *net = dev_net(dev); + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + int err; + + t = netdev_priv(dev); + + dev->rtnl_link_ops = &ip6_link_ops; + err = register_netdevice(dev); + if (err < 0) + goto out; + + strcpy(t->parms.name, dev->name); + + dev_hold(dev); + ip6_tnl_link(ip6n, t); + return 0; + +out: + return err; +} + +/** + * ip6_tnl_create - create a new tunnel + * @p: tunnel parameters + * @pt: pointer to new tunnel + * + * Description: + * Create tunnel matching given parameters. + * + * Return: + * created tunnel or error pointer + **/ + +static struct ip6_tnl *ip6_tnl_create(struct net *net, struct __ip6_tnl_parm *p) +{ + struct net_device *dev; + struct ip6_tnl *t; + char name[IFNAMSIZ]; + int err = -ENOMEM; + + if (p->name[0]) + strlcpy(name, p->name, IFNAMSIZ); + else + sprintf(name, "ip6tnl%%d"); + + dev = alloc_netdev(sizeof(*t), name, NET_NAME_UNKNOWN, + ip6_tnl_dev_setup); + if (!dev) + goto failed; + + dev_net_set(dev, net); + + t = netdev_priv(dev); + t->parms = *p; + t->net = dev_net(dev); + err = ip6_tnl_create2(dev); + if (err < 0) + goto failed_free; + + return t; + +failed_free: + free_netdev(dev); +failed: + return ERR_PTR(err); +} + +/** + * ip6_tnl_locate - find or create tunnel matching given parameters + * @p: tunnel parameters + * @create: != 0 if allowed to create new tunnel if no match found + * + * Description: + * ip6_tnl_locate() first tries to locate an existing tunnel + * based on @parms. If this is unsuccessful, but @create is set a new + * tunnel device is created and registered for use. + * + * Return: + * matching tunnel or error pointer + **/ + +static struct ip6_tnl *ip6_tnl_locate(struct net *net, + struct __ip6_tnl_parm *p, int create) +{ + const struct in6_addr *remote = &p->raddr; + const struct in6_addr *local = &p->laddr; + struct ip6_tnl __rcu **tp; + struct ip6_tnl *t; + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + + for (tp = ip6_tnl_bucket(ip6n, p); + (t = rtnl_dereference(*tp)) != NULL; + tp = &t->next) { + if (ipv6_addr_equal(local, &t->parms.laddr) && + ipv6_addr_equal(remote, &t->parms.raddr)) { + if (create) + return ERR_PTR(-EEXIST); + + return t; + } + } + if (!create) + return ERR_PTR(-ENODEV); + return ip6_tnl_create(net, p); +} + +/** + * ip6_tnl_dev_uninit - tunnel device uninitializer + * @dev: the device to be destroyed + * + * Description: + * ip6_tnl_dev_uninit() removes tunnel from its list + **/ + +static void +ip6_tnl_dev_uninit(struct net_device *dev) +{ + struct ip6_tnl *t = netdev_priv(dev); + struct net *net = t->net; + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + + if (dev == ip6n->fb_tnl_dev) + RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL); + else + ip6_tnl_unlink(ip6n, t); + dst_cache_reset(&t->dst_cache); + dev_put(dev); +} + +/** + * parse_tvl_tnl_enc_lim - handle encapsulation limit option + * @skb: received socket buffer + * + * Return: + * 0 if none was found, + * else index to encapsulation limit + **/ + +__u16 rpl_ip6_tnl_parse_tlv_enc_lim(struct sk_buff *skb, __u8 *raw) +{ + const struct ipv6hdr *ipv6h = (const struct ipv6hdr *)raw; + unsigned int nhoff = raw - skb->data; + unsigned int off = nhoff + sizeof(*ipv6h); + u8 next, nexthdr = ipv6h->nexthdr; + + while (ipv6_ext_hdr(nexthdr) && nexthdr != NEXTHDR_NONE) { + struct ipv6_opt_hdr *hdr; + u16 optlen; + + if (!pskb_may_pull(skb, off + sizeof(*hdr))) + break; + + hdr = (struct ipv6_opt_hdr *)(skb->data + off); + if (nexthdr == NEXTHDR_FRAGMENT) { + struct frag_hdr *frag_hdr = (struct frag_hdr *) hdr; + if (frag_hdr->frag_off) + break; + optlen = 8; + } else if (nexthdr == NEXTHDR_AUTH) { + optlen = (hdr->hdrlen + 2) << 2; + } else { + optlen = ipv6_optlen(hdr); + } + /* cache hdr->nexthdr, since pskb_may_pull() might + * invalidate hdr + */ + next = hdr->nexthdr; + if (nexthdr == NEXTHDR_DEST) { + u16 i = 2; + + /* Remember : hdr is no longer valid at this point. */ + if (!pskb_may_pull(skb, off + optlen)) + break; + + while (1) { + struct ipv6_tlv_tnl_enc_lim *tel; + + /* No more room for encapsulation limit */ + if (i + sizeof(*tel) > optlen) + break; + + tel = (struct ipv6_tlv_tnl_enc_lim *)(skb->data + off + i); + /* return index of option if found and valid */ + if (tel->type == IPV6_TLV_TNL_ENCAP_LIMIT && + tel->length == 1) + return i + off - nhoff; + /* else jump to next option */ + if (tel->type) + i += tel->length + 2; + else + i++; + } + } + nexthdr = next; + off += optlen; + } + return 0; +} + +static int +ip4ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, + u8 type, u8 code, int offset, __be32 info) +{ + return PACKET_REJECT; +} + +static int +ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, + u8 type, u8 code, int offset, __be32 info) +{ + return PACKET_REJECT; +} + +static int ip4ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t, + const struct ipv6hdr *ipv6h, + struct sk_buff *skb) +{ + __u8 dsfield = ipv6_get_dsfield(ipv6h) & ~INET_ECN_MASK; + + if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY) + ipv4_change_dsfield(ip_hdr(skb), INET_ECN_MASK, dsfield); + + return IP6_ECN_decapsulate(ipv6h, skb); +} + +static int ip6ip6_dscp_ecn_decapsulate(const struct ip6_tnl *t, + const struct ipv6hdr *ipv6h, + struct sk_buff *skb) +{ + if (t->parms.flags & IP6_TNL_F_RCV_DSCP_COPY) + ipv6_copy_dscp(ipv6_get_dsfield(ipv6h), ipv6_hdr(skb)); + + return IP6_ECN_decapsulate(ipv6h, skb); +} + +__u32 rpl_ip6_tnl_get_cap(struct ip6_tnl *t, + const struct in6_addr *laddr, + const struct in6_addr *raddr) +{ + struct __ip6_tnl_parm *p = &t->parms; + int ltype = ipv6_addr_type(laddr); + int rtype = ipv6_addr_type(raddr); + __u32 flags = 0; + + if (ltype == IPV6_ADDR_ANY || rtype == IPV6_ADDR_ANY) { + flags = IP6_TNL_F_CAP_PER_PACKET; + } else if (ltype & (IPV6_ADDR_UNICAST|IPV6_ADDR_MULTICAST) && + rtype & (IPV6_ADDR_UNICAST|IPV6_ADDR_MULTICAST) && + !((ltype|rtype) & IPV6_ADDR_LOOPBACK) && + (!((ltype|rtype) & IPV6_ADDR_LINKLOCAL) || p->link)) { + if (ltype&IPV6_ADDR_UNICAST) + flags |= IP6_TNL_F_CAP_XMIT; + if (rtype&IPV6_ADDR_UNICAST) + flags |= IP6_TNL_F_CAP_RCV; + } + return flags; +} + +/* called with rcu_read_lock() */ +int rpl_ip6_tnl_rcv_ctl(struct ip6_tnl *t, + const struct in6_addr *laddr, + const struct in6_addr *raddr) +{ + struct __ip6_tnl_parm *p = &t->parms; + int ret = 0; + struct net *net = t->net; + + if ((p->flags & IP6_TNL_F_CAP_RCV) || + ((p->flags & IP6_TNL_F_CAP_PER_PACKET) && + (rpl_ip6_tnl_get_cap(t, laddr, raddr) & IP6_TNL_F_CAP_RCV))) { + struct net_device *ldev = NULL; + + if (p->link) + ldev = dev_get_by_index_rcu(net, p->link); + + if ((ipv6_addr_is_multicast(laddr) || + likely(ipv6_chk_addr(net, laddr, ldev, 0))) && + ((p->flags & IP6_TNL_F_ALLOW_LOCAL_REMOTE) || + likely(!ipv6_chk_addr(net, raddr, NULL, 0)))) + ret = 1; + } + return ret; +} + +static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb, + const struct tnl_ptk_info *tpi, + struct metadata_dst *tun_dst, + int (*dscp_ecn_decapsulate)(const struct ip6_tnl *t, + const struct ipv6hdr *ipv6h, + struct sk_buff *skb), + bool log_ecn_err) +{ + struct pcpu_sw_netstats *tstats; + const struct ipv6hdr *ipv6h = ipv6_hdr(skb); + int err; + + if ((!(tpi->flags & TUNNEL_CSUM) && + (tunnel->parms.i_flags & TUNNEL_CSUM)) || + ((tpi->flags & TUNNEL_CSUM) && + !(tunnel->parms.i_flags & TUNNEL_CSUM))) { + tunnel->dev->stats.rx_crc_errors++; + tunnel->dev->stats.rx_errors++; + goto drop; + } + + if (tunnel->parms.i_flags & TUNNEL_SEQ) { + if (!(tpi->flags & TUNNEL_SEQ) || + (tunnel->i_seqno && + (s32)(ntohl(tpi->seq) - tunnel->i_seqno) < 0)) { + tunnel->dev->stats.rx_fifo_errors++; + tunnel->dev->stats.rx_errors++; + goto drop; + } + tunnel->i_seqno = ntohl(tpi->seq) + 1; + } + + skb->protocol = tpi->proto; + + /* Warning: All skb pointers will be invalidated! */ + if (tunnel->dev->type == ARPHRD_ETHER) { + if (!pskb_may_pull(skb, ETH_HLEN)) { + tunnel->dev->stats.rx_length_errors++; + tunnel->dev->stats.rx_errors++; + goto drop; + } + + ipv6h = ipv6_hdr(skb); + skb->protocol = eth_type_trans(skb, tunnel->dev); + skb_postpull_rcsum(skb, eth_hdr(skb), ETH_HLEN); + } else { + skb->dev = tunnel->dev; + } + + skb_reset_network_header(skb); + memset(skb->cb, 0, sizeof(struct inet6_skb_parm)); + + __skb_tunnel_rx(skb, tunnel->dev, tunnel->net); + + err = dscp_ecn_decapsulate(tunnel, ipv6h, skb); + if (unlikely(err)) { + if (log_ecn_err) + net_info_ratelimited("non-ECT from %pI6 with DS=%#x\n", + &ipv6h->saddr, + ipv6_get_dsfield(ipv6h)); + if (err > 1) { + ++tunnel->dev->stats.rx_frame_errors; + ++tunnel->dev->stats.rx_errors; + goto drop; + } + } + + tstats = this_cpu_ptr(tunnel->dev->tstats); + u64_stats_update_begin(&tstats->syncp); + tstats->rx_packets++; + tstats->rx_bytes += skb->len; + u64_stats_update_end(&tstats->syncp); + + skb_scrub_packet(skb, !net_eq(tunnel->net, dev_net(tunnel->dev))); + + if (tun_dst) + skb_dst_set(skb, (struct dst_entry *)tun_dst); + + gro_cells_receive(&tunnel->gro_cells, skb); + return 0; + +drop: + if (tun_dst) + dst_release((struct dst_entry *)tun_dst); + kfree_skb(skb); + return 0; +} + +int rpl_ip6_tnl_rcv(struct ip6_tnl *t, struct sk_buff *skb, + const struct tnl_ptk_info *tpi, + struct metadata_dst *tun_dst, + bool log_ecn_err) +{ + return __ip6_tnl_rcv(t, skb, tpi, tun_dst, ip6ip6_dscp_ecn_decapsulate, + log_ecn_err); +} + +static const struct tnl_ptk_info tpi_v6 = { + /* no tunnel info required for ipxip6. */ + .proto = htons(ETH_P_IPV6), +}; + +static const struct tnl_ptk_info tpi_v4 = { + /* no tunnel info required for ipxip6. */ + .proto = htons(ETH_P_IP), +}; + +static int ipxip6_rcv(struct sk_buff *skb, u8 ipproto, + const struct tnl_ptk_info *tpi, + int (*dscp_ecn_decapsulate)(const struct ip6_tnl *t, + const struct ipv6hdr *ipv6h, + struct sk_buff *skb)) +{ + struct ip6_tnl *t; + const struct ipv6hdr *ipv6h = ipv6_hdr(skb); + struct metadata_dst *tun_dst = NULL; + int ret = -1; + + rcu_read_lock(); + t = ip6_tnl_lookup(dev_net(skb->dev), &ipv6h->saddr, &ipv6h->daddr); + + if (t) { + u8 tproto = READ_ONCE(t->parms.proto); + + if (tproto != ipproto && tproto != 0) + goto drop; + if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) + goto drop; + if (!rpl_ip6_tnl_rcv_ctl(t, &ipv6h->daddr, &ipv6h->saddr)) + goto drop; + if (iptunnel_pull_header(skb, 0, tpi->proto, false)) + goto drop; + if (t->parms.collect_md) { + ovs_ipv6_tun_rx_dst(tun_dst, skb, 0, 0, 0); + if (!tun_dst) + goto drop; + } + ret = __ip6_tnl_rcv(t, skb, tpi, tun_dst, dscp_ecn_decapsulate, + log_ecn_error); + } + + rcu_read_unlock(); + + return ret; + +drop: + rcu_read_unlock(); + kfree_skb(skb); + return 0; +} + +static int ip4ip6_rcv(struct sk_buff *skb) +{ + return ipxip6_rcv(skb, IPPROTO_IPIP, &tpi_v4, + ip4ip6_dscp_ecn_decapsulate); +} + +static int ip6ip6_rcv(struct sk_buff *skb) +{ + return ipxip6_rcv(skb, IPPROTO_IPV6, &tpi_v6, + ip6ip6_dscp_ecn_decapsulate); +} + +struct ipv6_tel_txoption { + struct ipv6_txoptions ops; + __u8 dst_opt[8]; +}; + +static void init_tel_txopt(struct ipv6_tel_txoption *opt, __u8 encap_limit) +{ + memset(opt, 0, sizeof(struct ipv6_tel_txoption)); + + opt->dst_opt[2] = IPV6_TLV_TNL_ENCAP_LIMIT; + opt->dst_opt[3] = 1; + opt->dst_opt[4] = encap_limit; + opt->dst_opt[5] = IPV6_TLV_PADN; + opt->dst_opt[6] = 1; + + opt->ops.dst1opt = (struct ipv6_opt_hdr *) opt->dst_opt; + opt->ops.opt_nflen = 8; +} + +/** + * ip6_tnl_addr_conflict - compare packet addresses to tunnel's own + * @t: the outgoing tunnel device + * @hdr: IPv6 header from the incoming packet + * + * Description: + * Avoid trivial tunneling loop by checking that tunnel exit-point + * doesn't match source of incoming packet. + * + * Return: + * 1 if conflict, + * 0 else + **/ + +static inline bool +ip6_tnl_addr_conflict(const struct ip6_tnl *t, const struct ipv6hdr *hdr) +{ + return ipv6_addr_equal(&t->parms.raddr, &hdr->saddr); +} + +int rpl_ip6_tnl_xmit_ctl(struct ip6_tnl *t, + const struct in6_addr *laddr, + const struct in6_addr *raddr) +{ + struct __ip6_tnl_parm *p = &t->parms; + int ret = 0; + struct net *net = t->net; + + if (t->parms.collect_md) + return 1; + + if ((p->flags & IP6_TNL_F_CAP_XMIT) || + ((p->flags & IP6_TNL_F_CAP_PER_PACKET) && + (rpl_ip6_tnl_get_cap(t, laddr, raddr) & IP6_TNL_F_CAP_XMIT))) { + struct net_device *ldev = NULL; + + rcu_read_lock(); + if (p->link) + ldev = dev_get_by_index_rcu(net, p->link); + + if (unlikely(!ipv6_chk_addr(net, laddr, ldev, 0))) + pr_warn("%s xmit: Local address not yet configured!\n", + p->name); + else if (!(p->flags & IP6_TNL_F_ALLOW_LOCAL_REMOTE) && + !ipv6_addr_is_multicast(raddr) && + unlikely(ipv6_chk_addr(net, raddr, NULL, 0))) + pr_warn("%s xmit: Routing loop! Remote address found on this node!\n", + p->name); + else + ret = 1; + rcu_read_unlock(); + } + return ret; +} + +static void ipv6_push_exthdr(struct sk_buff *skb, u8 *proto, + u8 type, struct ipv6_opt_hdr *opt) +{ + struct ipv6_opt_hdr *h = + (struct ipv6_opt_hdr *)skb_push(skb, ipv6_optlen(opt)); + + memcpy(h, opt, ipv6_optlen(opt)); + h->nexthdr = *proto; + *proto = type; +} + +void ipv6_push_frag_opts(struct sk_buff *skb, struct ipv6_txoptions *opt, + u8 *proto) +{ + if (opt->dst1opt) + ipv6_push_exthdr(skb, proto, NEXTHDR_DEST, opt->dst1opt); +} + +/** + * ip6_tnl_xmit - encapsulate packet and send + * @skb: the outgoing socket buffer + * @dev: the outgoing tunnel device + * @dsfield: dscp code for outer header + * @fl6: flow of tunneled packet + * @encap_limit: encapsulation limit + * @pmtu: Path MTU is stored if packet is too big + * @proto: next header value + * + * Description: + * Build new header and do some sanity checks on the packet before sending + * it. + * + * Return: + * 0 on success + * -1 fail + * %-EMSGSIZE message too big. return mtu in this case. + **/ + +int ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev, __u8 dsfield, + struct flowi6 *fl6, int encap_limit, __u32 *pmtu, + __u8 proto) +{ + struct ip6_tnl *t = netdev_priv(dev); + struct net *net = t->net; + struct net_device_stats *stats = &t->dev->stats; + struct ipv6hdr *ipv6h; + struct ipv6_tel_txoption opt; + struct dst_entry *dst = NULL, *ndst = NULL; + struct net_device *tdev; + int mtu; + unsigned int eth_hlen = t->dev->type == ARPHRD_ETHER ? ETH_HLEN : 0; + unsigned int psh_hlen = sizeof(struct ipv6hdr) + t->encap_hlen; + unsigned int max_headroom = psh_hlen; + bool use_cache = false; + u8 hop_limit; + int err = -1; + + if (t->parms.collect_md) { + hop_limit = skb_tunnel_info(skb)->key.ttl; + goto route_lookup; + } else { + hop_limit = t->parms.hop_limit; + } + + /* NBMA tunnel */ + if (ipv6_addr_any(&t->parms.raddr)) { + if (skb->protocol == htons(ETH_P_IPV6)) { + struct in6_addr *addr6; + struct neighbour *neigh; + int addr_type; + + if (!skb_dst(skb)) + goto tx_err_link_failure; + + neigh = dst_neigh_lookup(skb_dst(skb), + &ipv6_hdr(skb)->daddr); + if (!neigh) + goto tx_err_link_failure; + + addr6 = (struct in6_addr *)&neigh->primary_key; + addr_type = ipv6_addr_type(addr6); + + if (addr_type == IPV6_ADDR_ANY) + addr6 = &ipv6_hdr(skb)->daddr; + + memcpy(&fl6->daddr, addr6, sizeof(fl6->daddr)); + neigh_release(neigh); + } + } else if (t->parms.proto != 0 && !(t->parms.flags & + (IP6_TNL_F_USE_ORIG_TCLASS | + IP6_TNL_F_USE_ORIG_FWMARK))) { + /* enable the cache only if neither the outer protocol nor the + * routing decision depends on the current inner header value + */ + use_cache = true; + } + + if (use_cache) + dst = dst_cache_get(&t->dst_cache); + + if (!rpl_ip6_tnl_xmit_ctl(t, &fl6->saddr, &fl6->daddr)) + goto tx_err_link_failure; + + if (!dst) { +route_lookup: + /* add dsfield to flowlabel for route lookup */ + fl6->flowlabel = ip6_make_flowinfo(dsfield, fl6->flowlabel); + + dst = ip6_route_output(net, NULL, fl6); + + if (dst->error) + goto tx_err_link_failure; + dst = xfrm_lookup(net, dst, flowi6_to_flowi(fl6), NULL, 0); + if (IS_ERR(dst)) { + err = PTR_ERR(dst); + dst = NULL; + goto tx_err_link_failure; + } + if (t->parms.collect_md && + ipv6_dev_get_saddr(net, ip6_dst_idev(dst)->dev, + &fl6->daddr, 0, &fl6->saddr)) + goto tx_err_link_failure; + ndst = dst; + } + + tdev = dst->dev; + + if (tdev == dev) { + stats->collisions++; + net_warn_ratelimited("%s: Local routing loop detected!\n", + t->parms.name); + goto tx_err_dst_release; + } + mtu = dst_mtu(dst) - eth_hlen - psh_hlen - t->tun_hlen; + if (encap_limit >= 0) { + max_headroom += 8; + mtu -= 8; + } + if (skb->protocol == htons(ETH_P_IPV6)) { + if (mtu < IPV6_MIN_MTU) + mtu = IPV6_MIN_MTU; + } else if (mtu < 576) { + mtu = 576; + } + +// FIX ME +// skb_dst_update_pmtu(skb, mtu); + if (skb->len - t->tun_hlen - eth_hlen > mtu && !skb_is_gso(skb)) { + *pmtu = mtu; + err = -EMSGSIZE; + goto tx_err_dst_release; + } + + if (t->err_count > 0) { + if (time_before(jiffies, + t->err_time + IP6TUNNEL_ERR_TIMEO)) { + t->err_count--; + + dst_link_failure(skb); + } else { + t->err_count = 0; + } + } + + skb_scrub_packet(skb, !net_eq(t->net, dev_net(dev))); + + /* + * Okay, now see if we can stuff it in the buffer as-is. + */ + max_headroom += LL_RESERVED_SPACE(tdev); + + if (skb_headroom(skb) < max_headroom || skb_shared(skb) || + (skb_cloned(skb) && !skb_clone_writable(skb, 0))) { + struct sk_buff *new_skb; + + new_skb = skb_realloc_headroom(skb, max_headroom); + if (!new_skb) + goto tx_err_dst_release; + + if (skb->sk) + skb_set_owner_w(new_skb, skb->sk); + consume_skb(skb); + skb = new_skb; + } + + if (t->parms.collect_md) { + if (t->encap.type != TUNNEL_ENCAP_NONE) + goto tx_err_dst_release; + } else { + if (use_cache && ndst) + dst_cache_set_ip6(&t->dst_cache, ndst, &fl6->saddr); + } + skb_dst_set(skb, dst); + + if (encap_limit >= 0) { + init_tel_txopt(&opt, encap_limit); + ipv6_push_frag_opts(skb, &opt.ops, &proto); + } + hop_limit = hop_limit ? : ip6_dst_hoplimit(dst); + + /* Calculate max headroom for all the headers and adjust + * needed_headroom if necessary. + */ + max_headroom = LL_RESERVED_SPACE(dst->dev) + sizeof(struct ipv6hdr) + + dst->header_len + t->hlen; + if (max_headroom > dev->needed_headroom) + dev->needed_headroom = max_headroom; + + err = ip6_tnl_encap(skb, t, &proto, fl6); + if (err) + return err; + + skb_push(skb, sizeof(struct ipv6hdr)); + skb_reset_network_header(skb); + ipv6h = ipv6_hdr(skb); + ip6_flow_hdr(ipv6h, dsfield, + ip6_make_flowlabel(net, skb, fl6->flowlabel, true, fl6)); + ipv6h->hop_limit = hop_limit; + ipv6h->nexthdr = proto; + ipv6h->saddr = fl6->saddr; + ipv6h->daddr = fl6->daddr; + ip6tunnel_xmit(NULL, skb, dev); + return 0; +tx_err_link_failure: + stats->tx_carrier_errors++; + dst_link_failure(skb); +tx_err_dst_release: + dst_release(dst); + return err; +} +EXPORT_SYMBOL(ip6_tnl_xmit); + +static inline int +ip4ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct ip6_tnl *t = netdev_priv(dev); + const struct iphdr *iph = ip_hdr(skb); + int encap_limit = -1; + struct flowi6 fl6; + __u8 dsfield; + __u32 mtu; + u8 tproto; + int err; + + memset(&(IPCB(skb)->opt), 0, sizeof(IPCB(skb)->opt)); + + tproto = READ_ONCE(t->parms.proto); + if (tproto != IPPROTO_IPIP && tproto != 0) + return -1; + + if (t->parms.collect_md) { + struct ip_tunnel_info *tun_info; + const struct ip_tunnel_key *key; + + tun_info = skb_tunnel_info(skb); + if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) || + ip_tunnel_info_af(tun_info) != AF_INET6)) + return -1; + key = &tun_info->key; + memset(&fl6, 0, sizeof(fl6)); + fl6.flowi6_proto = IPPROTO_IPIP; + fl6.daddr = key->u.ipv6.dst; + fl6.flowlabel = key->label; + dsfield = key->tos; + } else { + if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) + encap_limit = t->parms.encap_limit; + + memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6)); + fl6.flowi6_proto = IPPROTO_IPIP; + + if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS) + dsfield = ipv4_get_dsfield(iph); + else + dsfield = ip6_tclass(t->parms.flowinfo); + if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK) + fl6.flowi6_mark = skb->mark; + else + fl6.flowi6_mark = t->parms.fwmark; + } + +// FIX ME +// fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL); + + if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6)) + return -1; + + dsfield = INET_ECN_encapsulate(dsfield, ipv4_get_dsfield(iph)); + + skb_set_inner_ipproto(skb, IPPROTO_IPIP); + + err = ip6_tnl_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu, + IPPROTO_IPIP); + if (err != 0) { + /* XXX: send ICMP error even if DF is not set. */ + if (err == -EMSGSIZE) + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, + htonl(mtu)); + return -1; + } + + return 0; +} + +static inline int +ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct ip6_tnl *t = netdev_priv(dev); + struct ipv6hdr *ipv6h = ipv6_hdr(skb); + int encap_limit = -1; + __u16 offset; + struct flowi6 fl6; + __u8 dsfield; + __u32 mtu; + u8 tproto; + int err; + + tproto = READ_ONCE(t->parms.proto); + if ((tproto != IPPROTO_IPV6 && tproto != 0) || + ip6_tnl_addr_conflict(t, ipv6h)) + return -1; + + if (t->parms.collect_md) { + struct ip_tunnel_info *tun_info; + const struct ip_tunnel_key *key; + + tun_info = skb_tunnel_info(skb); + if (unlikely(!tun_info || !(tun_info->mode & IP_TUNNEL_INFO_TX) || + ip_tunnel_info_af(tun_info) != AF_INET6)) + return -1; + key = &tun_info->key; + memset(&fl6, 0, sizeof(fl6)); + fl6.flowi6_proto = IPPROTO_IPV6; + fl6.daddr = key->u.ipv6.dst; + fl6.flowlabel = key->label; + dsfield = key->tos; + } else { + offset = rpl_ip6_tnl_parse_tlv_enc_lim(skb, + skb_network_header(skb)); + /* + * ip6_tnl_parse_tlv_enc_lim() might + * have reallocated skb->head + */ + ipv6h = ipv6_hdr(skb); + if (offset > 0) { + struct ipv6_tlv_tnl_enc_lim *tel; + + tel = (void *)&skb_network_header(skb)[offset]; + if (tel->encap_limit == 0) { + icmpv6_send(skb, ICMPV6_PARAMPROB, + ICMPV6_HDR_FIELD, offset + 2); + return -1; + } + encap_limit = tel->encap_limit - 1; + } else if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) { + encap_limit = t->parms.encap_limit; + } + + memcpy(&fl6, &t->fl.u.ip6, sizeof(fl6)); + fl6.flowi6_proto = IPPROTO_IPV6; + + if (t->parms.flags & IP6_TNL_F_USE_ORIG_TCLASS) + dsfield = ipv6_get_dsfield(ipv6h); + else + dsfield = ip6_tclass(t->parms.flowinfo); + if (t->parms.flags & IP6_TNL_F_USE_ORIG_FLOWLABEL) + fl6.flowlabel |= ip6_flowlabel(ipv6h); + if (t->parms.flags & IP6_TNL_F_USE_ORIG_FWMARK) + fl6.flowi6_mark = skb->mark; + else + fl6.flowi6_mark = t->parms.fwmark; + } + +// FIX ME +// fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL); + + if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6)) + return -1; + + dsfield = INET_ECN_encapsulate(dsfield, ipv6_get_dsfield(ipv6h)); + + skb_set_inner_ipproto(skb, IPPROTO_IPV6); + + err = ip6_tnl_xmit(skb, dev, dsfield, &fl6, encap_limit, &mtu, + IPPROTO_IPV6); + if (err != 0) { + if (err == -EMSGSIZE) + icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu); + return -1; + } + + return 0; +} + +static netdev_tx_t +ip6_tnl_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct ip6_tnl *t = netdev_priv(dev); + struct net_device_stats *stats = &t->dev->stats; + int ret; + + switch (skb->protocol) { + case htons(ETH_P_IP): + ret = ip4ip6_tnl_xmit(skb, dev); + break; + case htons(ETH_P_IPV6): + ret = ip6ip6_tnl_xmit(skb, dev); + break; + default: + goto tx_err; + } + + if (ret < 0) + goto tx_err; + + return NETDEV_TX_OK; + +tx_err: + stats->tx_errors++; + stats->tx_dropped++; + kfree_skb(skb); + return NETDEV_TX_OK; +} + +static void ip6_tnl_link_config(struct ip6_tnl *t) +{ + struct net_device *dev = t->dev; + struct __ip6_tnl_parm *p = &t->parms; + struct flowi6 *fl6 = &t->fl.u.ip6; + int t_hlen; + + memcpy(dev->dev_addr, &p->laddr, sizeof(struct in6_addr)); + memcpy(dev->broadcast, &p->raddr, sizeof(struct in6_addr)); + + /* Set up flowi template */ + fl6->saddr = p->laddr; + fl6->daddr = p->raddr; + fl6->flowi6_oif = p->link; + fl6->flowlabel = 0; + + if (!(p->flags&IP6_TNL_F_USE_ORIG_TCLASS)) + fl6->flowlabel |= IPV6_TCLASS_MASK & p->flowinfo; + if (!(p->flags&IP6_TNL_F_USE_ORIG_FLOWLABEL)) + fl6->flowlabel |= IPV6_FLOWLABEL_MASK & p->flowinfo; + + p->flags &= ~(IP6_TNL_F_CAP_XMIT|IP6_TNL_F_CAP_RCV|IP6_TNL_F_CAP_PER_PACKET); + p->flags |= rpl_ip6_tnl_get_cap(t, &p->laddr, &p->raddr); + + if (p->flags&IP6_TNL_F_CAP_XMIT && p->flags&IP6_TNL_F_CAP_RCV) + dev->flags |= IFF_POINTOPOINT; + else + dev->flags &= ~IFF_POINTOPOINT; + + t->tun_hlen = 0; + t->hlen = t->encap_hlen + t->tun_hlen; + t_hlen = t->hlen + sizeof(struct ipv6hdr); + + if (p->flags & IP6_TNL_F_CAP_XMIT) { + int strict = (ipv6_addr_type(&p->raddr) & + (IPV6_ADDR_MULTICAST|IPV6_ADDR_LINKLOCAL)); + + struct rt6_info *rt = rt6_lookup(t->net, + &p->raddr, &p->laddr, + p->link, strict); + + if (!rt) + return; + + if (rt->dst.dev) { + dev->hard_header_len = rt->dst.dev->hard_header_len + + t_hlen; + + dev->mtu = rt->dst.dev->mtu - t_hlen; + if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) + dev->mtu -= 8; + + if (dev->mtu < IPV6_MIN_MTU) + dev->mtu = IPV6_MIN_MTU; + } + ip6_rt_put(rt); + } +} + +/** + * ip6_tnl_change - update the tunnel parameters + * @t: tunnel to be changed + * @p: tunnel configuration parameters + * + * Description: + * ip6_tnl_change() updates the tunnel parameters + **/ + +static int +ip6_tnl_change(struct ip6_tnl *t, const struct __ip6_tnl_parm *p) +{ + t->parms.laddr = p->laddr; + t->parms.raddr = p->raddr; + t->parms.flags = p->flags; + t->parms.hop_limit = p->hop_limit; + t->parms.encap_limit = p->encap_limit; + t->parms.flowinfo = p->flowinfo; + t->parms.link = p->link; + t->parms.proto = p->proto; + t->parms.fwmark = p->fwmark; + dst_cache_reset(&t->dst_cache); + ip6_tnl_link_config(t); + return 0; +} + +static int ip6_tnl_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p) +{ + struct net *net = t->net; + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + int err; + + ip6_tnl_unlink(ip6n, t); + synchronize_net(); + err = ip6_tnl_change(t, p); + ip6_tnl_link(ip6n, t); + netdev_state_change(t->dev); + return err; +} + +static int ip6_tnl0_update(struct ip6_tnl *t, struct __ip6_tnl_parm *p) +{ + /* for default tnl0 device allow to change only the proto */ + t->parms.proto = p->proto; + netdev_state_change(t->dev); + return 0; +} + +static void +ip6_tnl_parm_from_user(struct __ip6_tnl_parm *p, const struct ip6_tnl_parm *u) +{ + p->laddr = u->laddr; + p->raddr = u->raddr; + p->flags = u->flags; + p->hop_limit = u->hop_limit; + p->encap_limit = u->encap_limit; + p->flowinfo = u->flowinfo; + p->link = u->link; + p->proto = u->proto; + memcpy(p->name, u->name, sizeof(u->name)); +} + +static void +ip6_tnl_parm_to_user(struct ip6_tnl_parm *u, const struct __ip6_tnl_parm *p) +{ + u->laddr = p->laddr; + u->raddr = p->raddr; + u->flags = p->flags; + u->hop_limit = p->hop_limit; + u->encap_limit = p->encap_limit; + u->flowinfo = p->flowinfo; + u->link = p->link; + u->proto = p->proto; + memcpy(u->name, p->name, sizeof(u->name)); +} + +/** + * ip6_tnl_ioctl - configure ipv6 tunnels from userspace + * @dev: virtual device associated with tunnel + * @ifr: parameters passed from userspace + * @cmd: command to be performed + * + * Description: + * ip6_tnl_ioctl() is used for managing IPv6 tunnels + * from userspace. + * + * The possible commands are the following: + * %SIOCGETTUNNEL: get tunnel parameters for device + * %SIOCADDTUNNEL: add tunnel matching given tunnel parameters + * %SIOCCHGTUNNEL: change tunnel parameters to those given + * %SIOCDELTUNNEL: delete tunnel + * + * The fallback device "ip6tnl0", created during module + * initialization, can be used for creating other tunnel devices. + * + * Return: + * 0 on success, + * %-EFAULT if unable to copy data to or from userspace, + * %-EPERM if current process hasn't %CAP_NET_ADMIN set + * %-EINVAL if passed tunnel parameters are invalid, + * %-EEXIST if changing a tunnel's parameters would cause a conflict + * %-ENODEV if attempting to change or delete a nonexisting device + **/ + +static int +ip6_tnl_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + int err = 0; + struct ip6_tnl_parm p; + struct __ip6_tnl_parm p1; + struct ip6_tnl *t = netdev_priv(dev); + struct net *net = t->net; + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + + memset(&p1, 0, sizeof(p1)); + + switch (cmd) { + case SIOCGETTUNNEL: + if (dev == ip6n->fb_tnl_dev) { + if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) { + err = -EFAULT; + break; + } + ip6_tnl_parm_from_user(&p1, &p); + t = ip6_tnl_locate(net, &p1, 0); + if (IS_ERR(t)) + t = netdev_priv(dev); + } else { + memset(&p, 0, sizeof(p)); + } + ip6_tnl_parm_to_user(&p, &t->parms); + if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) { + err = -EFAULT; + } + break; + case SIOCADDTUNNEL: + case SIOCCHGTUNNEL: + err = -EPERM; + if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) + break; + err = -EFAULT; + if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) + break; + err = -EINVAL; + if (p.proto != IPPROTO_IPV6 && p.proto != IPPROTO_IPIP && + p.proto != 0) + break; + ip6_tnl_parm_from_user(&p1, &p); + t = ip6_tnl_locate(net, &p1, cmd == SIOCADDTUNNEL); + if (cmd == SIOCCHGTUNNEL) { + if (!IS_ERR(t)) { + if (t->dev != dev) { + err = -EEXIST; + break; + } + } else + t = netdev_priv(dev); + if (dev == ip6n->fb_tnl_dev) + err = ip6_tnl0_update(t, &p1); + else + err = ip6_tnl_update(t, &p1); + } + if (!IS_ERR(t)) { + err = 0; + ip6_tnl_parm_to_user(&p, &t->parms); + if (copy_to_user(ifr->ifr_ifru.ifru_data, &p, sizeof(p))) + err = -EFAULT; + + } else { + err = PTR_ERR(t); + } + break; + case SIOCDELTUNNEL: + err = -EPERM; + if (!ns_capable(net->user_ns, CAP_NET_ADMIN)) + break; + + if (dev == ip6n->fb_tnl_dev) { + err = -EFAULT; + if (copy_from_user(&p, ifr->ifr_ifru.ifru_data, sizeof(p))) + break; + err = -ENOENT; + ip6_tnl_parm_from_user(&p1, &p); + t = ip6_tnl_locate(net, &p1, 0); + if (IS_ERR(t)) + break; + err = -EPERM; + if (t->dev == ip6n->fb_tnl_dev) + break; + dev = t->dev; + } + err = 0; + unregister_netdevice(dev); + break; + default: + err = -EINVAL; + } + return err; +} + +/** + * ip6_tnl_change_mtu - change mtu manually for tunnel device + * @dev: virtual device associated with tunnel + * @new_mtu: the new mtu + * + * Return: + * 0 on success, + * %-EINVAL if mtu too small + **/ + +int rpl_ip6_tnl_change_mtu(struct net_device *dev, int new_mtu) +{ + struct ip6_tnl *tnl = netdev_priv(dev); + + if (tnl->parms.proto == IPPROTO_IPV6) { + if (new_mtu < IPV6_MIN_MTU) + return -EINVAL; + } else { + if (new_mtu < ETH_MIN_MTU) + return -EINVAL; + } + if (new_mtu > 0xFFF8 - dev->hard_header_len) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + +#ifdef HAVE_NDO_GET_IFLINK +int rpl_ip6_tnl_get_iflink(const struct net_device *dev) +{ + struct ip6_tnl *t = netdev_priv(dev); + + return t->parms.link; +} + +#endif +const struct ip6_tnl_encap_ops __rcu * + rpl_ip6tun_encaps[MAX_IPTUN_ENCAP_OPS] __read_mostly; + +int rpl_ip6_tnl_encap_add_ops(const struct ip6_tnl_encap_ops *ops, + unsigned int num) +{ + if (num >= MAX_IPTUN_ENCAP_OPS) + return -ERANGE; + + return !cmpxchg((const struct ip6_tnl_encap_ops **) + &rpl_ip6tun_encaps[num], + NULL, ops) ? 0 : -1; +} + +int rpl_ip6_tnl_encap_del_ops(const struct ip6_tnl_encap_ops *ops, + unsigned int num) +{ + int ret; + + if (num >= MAX_IPTUN_ENCAP_OPS) + return -ERANGE; + + ret = (cmpxchg((const struct ip6_tnl_encap_ops **) + &rpl_ip6tun_encaps[num], + ops, NULL) == ops) ? 0 : -1; + + synchronize_net(); + + return ret; +} + +int rpl_ip6_tnl_encap_setup(struct ip6_tnl *t, + struct ip_tunnel_encap *ipencap) +{ + int hlen; + + memset(&t->encap, 0, sizeof(t->encap)); + + hlen = ip6_encap_hlen(ipencap); + if (hlen < 0) + return hlen; + + t->encap.type = ipencap->type; + t->encap.sport = ipencap->sport; + t->encap.dport = ipencap->dport; + t->encap.flags = ipencap->flags; + + t->encap_hlen = hlen; + t->hlen = t->encap_hlen + t->tun_hlen; + + return 0; +} + +static const struct net_device_ops ip6_tnl_netdev_ops = { + .ndo_init = ip6_tnl_dev_init, + .ndo_uninit = ip6_tnl_dev_uninit, + .ndo_start_xmit = ip6_tnl_start_xmit, + .ndo_do_ioctl = ip6_tnl_ioctl, + .ndo_change_mtu = ip6_tnl_change_mtu, + .ndo_get_stats = ip6_get_stats, +#ifdef HAVE_NDO_GET_IFLINK + .ndo_get_iflink = ip6_tnl_get_iflink, +#endif +}; + +#define IPXIPX_FEATURES (NETIF_F_SG | \ + NETIF_F_FRAGLIST | \ + NETIF_F_HIGHDMA | \ + NETIF_F_GSO_SOFTWARE | \ + NETIF_F_HW_CSUM) + +/** + * ip6_tnl_dev_setup - setup virtual tunnel device + * @dev: virtual device associated with tunnel + * + * Description: + * Initialize function pointers and device parameters + **/ + +static void ip6_tnl_dev_setup(struct net_device *dev) +{ + dev->netdev_ops = &ip6_tnl_netdev_ops; +#ifndef HAVE_NEEDS_FREE_NETDEV + dev->destructor = free_netdev; +#else + dev->needs_free_netdev = true; + dev->priv_destructor = ip6_dev_free; +#endif + + dev->type = ARPHRD_TUNNEL6; + dev->flags |= IFF_NOARP; + dev->addr_len = sizeof(struct in6_addr); + dev->features |= NETIF_F_LLTX; + netif_keep_dst(dev); + + dev->features |= IPXIPX_FEATURES; + dev->hw_features |= IPXIPX_FEATURES; + + /* This perm addr will be used as interface identifier by IPv6 */ + dev->addr_assign_type = NET_ADDR_RANDOM; + eth_random_addr(dev->perm_addr); +} + + +/** + * ip6_tnl_dev_init_gen - general initializer for all tunnel devices + * @dev: virtual device associated with tunnel + **/ + +static inline int +ip6_tnl_dev_init_gen(struct net_device *dev) +{ + struct ip6_tnl *t = netdev_priv(dev); + int ret; + int t_hlen; + + t->dev = dev; + t->net = dev_net(dev); + dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats); + if (!dev->tstats) + return -ENOMEM; + + ret = dst_cache_init(&t->dst_cache, GFP_KERNEL); + if (ret) + goto free_stats; + + ret = gro_cells_init(&t->gro_cells, dev); + if (ret) + goto destroy_dst; + + t->tun_hlen = 0; + t->hlen = t->encap_hlen + t->tun_hlen; + t_hlen = t->hlen + sizeof(struct ipv6hdr); + + dev->type = ARPHRD_TUNNEL6; + dev->hard_header_len = LL_MAX_HEADER + t_hlen; + dev->mtu = ETH_DATA_LEN - t_hlen; + if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT)) + dev->mtu -= 8; +#ifdef HAVE_NET_DEVICE_MAX_MTU + dev->min_mtu = ETH_MIN_MTU; + dev->max_mtu = 0xFFF8 - dev->hard_header_len; +#endif + + return 0; + +destroy_dst: + dst_cache_destroy(&t->dst_cache); +free_stats: + free_percpu(dev->tstats); + dev->tstats = NULL; + + return ret; +} + +/** + * ip6_tnl_dev_init - initializer for all non fallback tunnel devices + * @dev: virtual device associated with tunnel + **/ + +static int ip6_tnl_dev_init(struct net_device *dev) +{ + struct ip6_tnl *t = netdev_priv(dev); + int err = ip6_tnl_dev_init_gen(dev); + + if (err) + return err; + ip6_tnl_link_config(t); + if (t->parms.collect_md) { + dev->features |= NETIF_F_NETNS_LOCAL; + netif_keep_dst(dev); + } + return 0; +} + +/** + * ip6_fb_tnl_dev_init - initializer for fallback tunnel device + * @dev: fallback device + * + * Return: 0 + **/ + +static int __net_init ip6_fb_tnl_dev_init(struct net_device *dev) +{ + struct ip6_tnl *t = netdev_priv(dev); + struct net *net = dev_net(dev); + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + + t->parms.proto = IPPROTO_IPV6; + dev_hold(dev); + + rcu_assign_pointer(ip6n->tnls_wc[0], t); + return 0; +} + +#ifdef HAVE_IP6GRE_EXTACK +static int rpl_ip6_tnl_validate(struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) +#else +static int rpl_ip6_tnl_validate(struct nlattr *tb[], struct nlattr *data[]) +#endif +{ + u8 proto; + + if (!data || !data[IFLA_IPTUN_PROTO]) + return 0; + + proto = nla_get_u8(data[IFLA_IPTUN_PROTO]); + if (proto != IPPROTO_IPV6 && + proto != IPPROTO_IPIP && + proto != 0) + return -EINVAL; + + return 0; +} +#define ip6_tnl_validate rpl_ip6_tnl_validate + +static void ip6_tnl_netlink_parms(struct nlattr *data[], + struct __ip6_tnl_parm *parms) +{ + memset(parms, 0, sizeof(*parms)); + + if (!data) + return; + + if (data[IFLA_IPTUN_LINK]) + parms->link = nla_get_u32(data[IFLA_IPTUN_LINK]); + + if (data[IFLA_IPTUN_LOCAL]) + parms->laddr = nla_get_in6_addr(data[IFLA_IPTUN_LOCAL]); + + if (data[IFLA_IPTUN_REMOTE]) + parms->raddr = nla_get_in6_addr(data[IFLA_IPTUN_REMOTE]); + + if (data[IFLA_IPTUN_TTL]) + parms->hop_limit = nla_get_u8(data[IFLA_IPTUN_TTL]); + + if (data[IFLA_IPTUN_ENCAP_LIMIT]) + parms->encap_limit = nla_get_u8(data[IFLA_IPTUN_ENCAP_LIMIT]); + + if (data[IFLA_IPTUN_FLOWINFO]) + parms->flowinfo = nla_get_be32(data[IFLA_IPTUN_FLOWINFO]); + + if (data[IFLA_IPTUN_FLAGS]) + parms->flags = nla_get_u32(data[IFLA_IPTUN_FLAGS]); + + if (data[IFLA_IPTUN_PROTO]) + parms->proto = nla_get_u8(data[IFLA_IPTUN_PROTO]); + + if (data[IFLA_IPTUN_COLLECT_METADATA]) + parms->collect_md = true; + + if (data[IFLA_IPTUN_FWMARK]) + parms->fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]); +} + +static bool ip6_tnl_netlink_encap_parms(struct nlattr *data[], + struct ip_tunnel_encap *ipencap) +{ + bool ret = false; + + memset(ipencap, 0, sizeof(*ipencap)); + + if (!data) + return ret; + + if (data[IFLA_IPTUN_ENCAP_TYPE]) { + ret = true; + ipencap->type = nla_get_u16(data[IFLA_IPTUN_ENCAP_TYPE]); + } + + if (data[IFLA_IPTUN_ENCAP_FLAGS]) { + ret = true; + ipencap->flags = nla_get_u16(data[IFLA_IPTUN_ENCAP_FLAGS]); + } + + if (data[IFLA_IPTUN_ENCAP_SPORT]) { + ret = true; + ipencap->sport = nla_get_be16(data[IFLA_IPTUN_ENCAP_SPORT]); + } + + if (data[IFLA_IPTUN_ENCAP_DPORT]) { + ret = true; + ipencap->dport = nla_get_be16(data[IFLA_IPTUN_ENCAP_DPORT]); + } + + return ret; +} + +#ifdef HAVE_IP6GRE_EXTACK +static int rpl_ip6_tnl_newlink(struct net *src_net, struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[], + struct netlink_ext_ack *extack) +#else +static int rpl_ip6_tnl_newlink(struct net *src_net, struct net_device *dev, + struct nlattr *tb[], struct nlattr *data[]) +#endif +{ + struct net *net = dev_net(dev); + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + struct ip_tunnel_encap ipencap; + struct ip6_tnl *nt, *t; + int err; + + nt = netdev_priv(dev); + + if (ip6_tnl_netlink_encap_parms(data, &ipencap)) { + err = ip6_tnl_encap_setup(nt, &ipencap); + if (err < 0) + return err; + } + + ip6_tnl_netlink_parms(data, &nt->parms); + + if (nt->parms.collect_md) { + if (rtnl_dereference(ip6n->collect_md_tun)) + return -EEXIST; + } else { + t = ip6_tnl_locate(net, &nt->parms, 0); + if (!IS_ERR(t)) + return -EEXIST; + } + + err = ip6_tnl_create2(dev); + if (!err && tb[IFLA_MTU]) + ip6_tnl_change_mtu(dev, nla_get_u32(tb[IFLA_MTU])); + + return err; +} +#define ip6_tnl_newlink rpl_ip6_tnl_newlink + +#ifdef HAVE_IP6GRE_EXTACK +static int rpl_ip6_tnl_changelink(struct net_device *dev, struct nlattr *tb[], + struct nlattr *data[], + struct netlink_ext_ack *extack) +#else +static int rpl_ip6_tnl_changelink(struct net_device *dev, struct nlattr *tb[], + struct nlattr *data[]) +#endif +{ + struct ip6_tnl *t = netdev_priv(dev); + struct __ip6_tnl_parm p; + struct net *net = t->net; + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + struct ip_tunnel_encap ipencap; + + if (dev == ip6n->fb_tnl_dev) + return -EINVAL; + + if (ip6_tnl_netlink_encap_parms(data, &ipencap)) { + int err = ip6_tnl_encap_setup(t, &ipencap); + + if (err < 0) + return err; + } + ip6_tnl_netlink_parms(data, &p); + if (p.collect_md) + return -EINVAL; + + t = ip6_tnl_locate(net, &p, 0); + if (!IS_ERR(t)) { + if (t->dev != dev) + return -EEXIST; + } else + t = netdev_priv(dev); + + return ip6_tnl_update(t, &p); +} +#define ip6_tnl_changelink rpl_ip6_tnl_changelink + +static void ip6_tnl_dellink(struct net_device *dev, struct list_head *head) +{ + struct net *net = dev_net(dev); + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + + if (dev != ip6n->fb_tnl_dev) + unregister_netdevice_queue(dev, head); +} + +static size_t ip6_tnl_get_size(const struct net_device *dev) +{ + return + /* IFLA_IPTUN_LINK */ + nla_total_size(4) + + /* IFLA_IPTUN_LOCAL */ + nla_total_size(sizeof(struct in6_addr)) + + /* IFLA_IPTUN_REMOTE */ + nla_total_size(sizeof(struct in6_addr)) + + /* IFLA_IPTUN_TTL */ + nla_total_size(1) + + /* IFLA_IPTUN_ENCAP_LIMIT */ + nla_total_size(1) + + /* IFLA_IPTUN_FLOWINFO */ + nla_total_size(4) + + /* IFLA_IPTUN_FLAGS */ + nla_total_size(4) + + /* IFLA_IPTUN_PROTO */ + nla_total_size(1) + + /* IFLA_IPTUN_ENCAP_TYPE */ + nla_total_size(2) + + /* IFLA_IPTUN_ENCAP_FLAGS */ + nla_total_size(2) + + /* IFLA_IPTUN_ENCAP_SPORT */ + nla_total_size(2) + + /* IFLA_IPTUN_ENCAP_DPORT */ + nla_total_size(2) + + /* IFLA_IPTUN_COLLECT_METADATA */ + nla_total_size(0) + + /* IFLA_IPTUN_FWMARK */ + nla_total_size(4) + + 0; +} + +static int ip6_tnl_fill_info(struct sk_buff *skb, const struct net_device *dev) +{ + struct ip6_tnl *tunnel = netdev_priv(dev); + struct __ip6_tnl_parm *parm = &tunnel->parms; + + if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) || + nla_put_in6_addr(skb, IFLA_IPTUN_LOCAL, &parm->laddr) || + nla_put_in6_addr(skb, IFLA_IPTUN_REMOTE, &parm->raddr) || + nla_put_u8(skb, IFLA_IPTUN_TTL, parm->hop_limit) || + nla_put_u8(skb, IFLA_IPTUN_ENCAP_LIMIT, parm->encap_limit) || + nla_put_be32(skb, IFLA_IPTUN_FLOWINFO, parm->flowinfo) || + nla_put_u32(skb, IFLA_IPTUN_FLAGS, parm->flags) || + nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto) || + nla_put_u32(skb, IFLA_IPTUN_FWMARK, parm->fwmark)) + goto nla_put_failure; + + if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE, tunnel->encap.type) || + nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT, tunnel->encap.sport) || + nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT, tunnel->encap.dport) || + nla_put_u16(skb, IFLA_IPTUN_ENCAP_FLAGS, tunnel->encap.flags)) + goto nla_put_failure; + + if (parm->collect_md) + if (nla_put_flag(skb, IFLA_IPTUN_COLLECT_METADATA)) + goto nla_put_failure; + + return 0; + +nla_put_failure: + return -EMSGSIZE; +} + +#ifdef HAVE_GET_LINK_NET +struct net *rpl_ip6_tnl_get_link_net(const struct net_device *dev) +{ + struct ip6_tnl *tunnel = netdev_priv(dev); + + return tunnel->net; +} + +#endif +static const struct nla_policy ip6_tnl_policy[RPL_IFLA_IPTUN_MAX + 1] = { + [IFLA_IPTUN_LINK] = { .type = NLA_U32 }, + [IFLA_IPTUN_LOCAL] = { .len = sizeof(struct in6_addr) }, + [IFLA_IPTUN_REMOTE] = { .len = sizeof(struct in6_addr) }, + [IFLA_IPTUN_TTL] = { .type = NLA_U8 }, + [IFLA_IPTUN_ENCAP_LIMIT] = { .type = NLA_U8 }, + [IFLA_IPTUN_FLOWINFO] = { .type = NLA_U32 }, + [IFLA_IPTUN_FLAGS] = { .type = NLA_U32 }, + [IFLA_IPTUN_PROTO] = { .type = NLA_U8 }, + [IFLA_IPTUN_ENCAP_TYPE] = { .type = NLA_U16 }, + [IFLA_IPTUN_ENCAP_FLAGS] = { .type = NLA_U16 }, + [IFLA_IPTUN_ENCAP_SPORT] = { .type = NLA_U16 }, + [IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 }, + [IFLA_IPTUN_COLLECT_METADATA] = { .type = NLA_FLAG }, + [IFLA_IPTUN_FWMARK] = { .type = NLA_U32 }, +}; + +static struct rtnl_link_ops ip6_link_ops __read_mostly = { + .kind = "ip6tnl", + .maxtype = RPL_IFLA_IPTUN_MAX, + .policy = ip6_tnl_policy, + .priv_size = sizeof(struct ip6_tnl), + .setup = ip6_tnl_dev_setup, + .validate = ip6_tnl_validate, + .newlink = ip6_tnl_newlink, + .changelink = ip6_tnl_changelink, + .dellink = ip6_tnl_dellink, + .get_size = ip6_tnl_get_size, + .fill_info = ip6_tnl_fill_info, +#ifdef HAVE_GET_LINK_NET + .get_link_net = ip6_tnl_get_link_net, +#endif +}; + +static struct xfrm6_tunnel ip4ip6_handler __read_mostly = { + .handler = ip4ip6_rcv, + .err_handler = ip4ip6_err, + .priority = 1, +}; + +static struct xfrm6_tunnel ip6ip6_handler __read_mostly = { + .handler = ip6ip6_rcv, + .err_handler = ip6ip6_err, + .priority = 1, +}; + +static void __net_exit ip6_tnl_destroy_tunnels(struct net *net, struct list_head *list) +{ + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + struct net_device *dev, *aux; + int h; + struct ip6_tnl *t; + + for_each_netdev_safe(net, dev, aux) + if (dev->rtnl_link_ops == &ip6_link_ops) + unregister_netdevice_queue(dev, list); + + for (h = 0; h < IP6_TUNNEL_HASH_SIZE; h++) { + t = rtnl_dereference(ip6n->tnls_r_l[h]); + while (t) { + /* If dev is in the same netns, it has already + * been added to the list by the previous loop. + */ + if (!net_eq(dev_net(t->dev), net)) + unregister_netdevice_queue(t->dev, list); + t = rtnl_dereference(t->next); + } + } +} + +static int __net_init ip6_tnl_init_net(struct net *net) +{ + struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id); + struct ip6_tnl *t = NULL; + int err; + + ip6n->tnls[0] = ip6n->tnls_wc; + ip6n->tnls[1] = ip6n->tnls_r_l; + + err = -ENOMEM; + ip6n->fb_tnl_dev = alloc_netdev(sizeof(struct ip6_tnl), "ip6tnl0", + NET_NAME_UNKNOWN, ip6_tnl_dev_setup); + + if (!ip6n->fb_tnl_dev) + goto err_alloc_dev; + dev_net_set(ip6n->fb_tnl_dev, net); + ip6n->fb_tnl_dev->rtnl_link_ops = &ip6_link_ops; + /* FB netdevice is special: we have one, and only one per netns. + * Allowing to move it to another netns is clearly unsafe. + */ + ip6n->fb_tnl_dev->features |= NETIF_F_NETNS_LOCAL; + + err = ip6_fb_tnl_dev_init(ip6n->fb_tnl_dev); + if (err < 0) + goto err_register; + + err = register_netdev(ip6n->fb_tnl_dev); + if (err < 0) + goto err_register; + + t = netdev_priv(ip6n->fb_tnl_dev); + + strcpy(t->parms.name, ip6n->fb_tnl_dev->name); + return 0; + +err_register: + free_netdev(ip6n->fb_tnl_dev); +err_alloc_dev: + return err; +} + +static void __net_exit ip6_tnl_exit_batch_net(struct list_head *net_list) +{ + struct net *net; + LIST_HEAD(list); + + rtnl_lock(); + list_for_each_entry(net, net_list, exit_list) + ip6_tnl_destroy_tunnels(net, &list); + unregister_netdevice_many(&list); + rtnl_unlock(); +} + +static struct pernet_operations ip6_tnl_net_ops = { + .init = ip6_tnl_init_net, + .exit_batch = ip6_tnl_exit_batch_net, + .id = &ip6_tnl_net_id, + .size = sizeof(struct ip6_tnl_net), +}; + +/** + * ip6_tunnel_init - register protocol and reserve needed resources + * + * Return: 0 on success + **/ + +int rpl_ip6_tunnel_init(void) +{ + int err; + +#if 0 + if (!ipv6_mod_enabled()) + return -EOPNOTSUPP; +#endif + err = register_pernet_device(&ip6_tnl_net_ops); + if (err < 0) + goto out_pernet; + + err = xfrm6_tunnel_register(&ip4ip6_handler, AF_INET); + if (err < 0) { + pr_err("%s: can't register ip4ip6\n", __func__); + goto out_ip4ip6; + } + + err = xfrm6_tunnel_register(&ip6ip6_handler, AF_INET6); + if (err < 0) { + pr_err("%s: can't register ip6ip6\n", __func__); + goto out_ip6ip6; + } + err = rtnl_link_register(&ip6_link_ops); + if (err < 0) + goto rtnl_link_failed; + + return 0; + +rtnl_link_failed: + xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6); +out_ip6ip6: + xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET); +out_ip4ip6: + unregister_pernet_device(&ip6_tnl_net_ops); +out_pernet: + return err; +} + +/** + * ip6_tunnel_cleanup - free resources and unregister protocol + **/ + +void rpl_ip6_tunnel_cleanup(void) +{ + rtnl_link_unregister(&ip6_link_ops); + if (xfrm6_tunnel_deregister(&ip4ip6_handler, AF_INET)) + pr_info("%s: can't deregister ip4ip6\n", __func__); + + if (xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6)) + pr_info("%s: can't deregister ip6ip6\n", __func__); + + unregister_pernet_device(&ip6_tnl_net_ops); +} + +#endif /* USE_UPSTREAM_TUNNEL */ diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index 7d066ae..37c434d 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -169,11 +169,6 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, tun_id, sizeof(*md)); md = ip_tunnel_info_opts(&tun_dst->u.tun_info); - if (!md) { - dst_release((struct dst_entry *)tun_dst); - return PACKET_REJECT; - } - memcpy(md, pkt_md, sizeof(*md)); info = &tun_dst->u.tun_info; info->key.tun_flags |= TUNNEL_ERSPAN_OPT; @@ -791,9 +786,9 @@ static const struct net_device_ops gre_tap_netdev_ops = { .ndo_set_mac_address = eth_mac_addr, .ndo_validate_addr = eth_validate_addr, .ndo_change_mtu = ip_tunnel_change_mtu, - .ndo_get_stats64 = ip_tunnel_get_stats64, + .ndo_get_stats64 = rpl_ip_tunnel_get_stats64, #ifdef HAVE_NDO_GET_IFLINK - .ndo_get_iflink = ip_tunnel_get_iflink, + .ndo_get_iflink = rpl_ip_tunnel_get_iflink, #endif #ifdef HAVE_NDO_FILL_METADATA_DST .ndo_fill_metadata_dst = gre_fill_metadata_dst, diff --git a/datapath/vport.c b/datapath/vport.c index 711c29f..e5221e9 100644 --- a/datapath/vport.c +++ b/datapath/vport.c @@ -67,6 +67,12 @@ int ovs_vport_init(void) err = ipgre_init(); if (err) goto err_gre; + err = ip6gre_init(); + if (err) + goto err_ip6gre; + err = ip6_tunnel_init(); + if (err) + goto err_ip6_tunnel; err = geneve_init_module(); if (err) goto err_geneve; @@ -84,6 +90,10 @@ err_stt: err_vxlan: geneve_cleanup_module(); err_geneve: + ip6_tunnel_cleanup(); +err_ip6_tunnel: + ip6gre_fini(); +err_ip6gre: ipgre_fini(); err_gre: lisp_cleanup_module(); From patchwork Thu Mar 22 22:07:36 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Rose X-Patchwork-Id: 889687 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="oFsyGUF8"; 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 406gwc02qkz9s0y for ; Fri, 23 Mar 2018 09:15:44 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 36FB2F73; Thu, 22 Mar 2018 22:08:21 +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 9978BF4E for ; Thu, 22 Mar 2018 22:08:18 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pl0-f67.google.com (mail-pl0-f67.google.com [209.85.160.67]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id DB55F5D4 for ; Thu, 22 Mar 2018 22:08:17 +0000 (UTC) Received: by mail-pl0-f67.google.com with SMTP id w15-v6so6204498plq.9 for ; Thu, 22 Mar 2018 15:08:17 -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=jb28PJOqI4S9dHbITqZhpJG2Hu/bs2baWaWi5NG3Pks=; b=oFsyGUF8CsJDpr5t+M2l8gHoB1et7DicbYnfKwybXfqJw3IWeXo6hj7/YQFyjTZuVQ WABG4LPR/mEAe/2KJ2OYvViYhYuc0axi89ZA5Sz469s0XzH6onaJygl3SiHblbmmDBtV eZd6t3/8w6tkslnonwxJjvtfJbqo4mKFOo+elCBsvwwxsQ/nkYKmQ2olvTqpZW9rBfH2 x7DHwxTKzjzPzR0AqCKjlWP6JlwudPoNJO8evgSLTMFWu0pC36GTI4RKdIetG+chvid7 zaCIKEbuI4XRA0775ETpoUTs4rHao7Iy0RYn4Rqn6G81Xjvb4pUWki0d6EHfWJ0w8RiC fJfg== 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=jb28PJOqI4S9dHbITqZhpJG2Hu/bs2baWaWi5NG3Pks=; b=kS4I3S9PGSQiEm7jXYbsBTEAtiGvV0CDp3zsyHs0aMxJMIMv5QOcwdG3YXI2dn1epy UmAihSmkETDjwQd7KAa6qAw8iPKDWV7KTFsTGzlYgJdGxCeNaB17t7aiKtFFBiMYVdO9 bJemVNzwZEt3o5zrJkU9P7t4q8LynxHOus/EHYXcVtlLgJO5zXf1AO4XHHEm4LU+78K/ xltHgXvy8uuoV9P2DpRKswhkgfxTF7BI/06DRWHydeauy/IcXn+pWgLcxWQZqvr3ATC7 71Dn5xxBMxKpl3FEOKC+/C34mlWU4uYhkiODOZRszS1PrZpqOozq4UqTultw3JNwuy85 VgEQ== X-Gm-Message-State: AElRT7EAvb2CVcXzlUeIp8zktAdZICo5b7A1Fpm0YzHHVYgvdVoSCYg3 jtjVcAR6t1zgmgb2QtF+zExe5g== X-Google-Smtp-Source: AG47ELsxQPOcxfRPWuACkogqCcYIKBQguZrr23U3s0AVhLiCtzkW6PS6clBAu3QrgdTAX7RtfR6AXQ== X-Received: by 2002:a17:902:b287:: with SMTP id u7-v6mr9534580plr.236.1521756496969; Thu, 22 Mar 2018 15:08:16 -0700 (PDT) Received: from gizo.domain (184-100-240-187.ptld.qwest.net. [184.100.240.187]) by smtp.gmail.com with ESMTPSA id 4sm2280775pfn.32.2018.03.22.15.08.15 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Mar 2018 15:08:15 -0700 (PDT) From: Greg Rose To: dev@openvswitch.org Date: Thu, 22 Mar 2018 15:07:36 -0700 Message-Id: <1521756461-3870-21-git-send-email-gvrose8192@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1521756461-3870-1-git-send-email-gvrose8192@gmail.com> References: <1521756461-3870-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] [ERSPAN RFC 20/25] datapath: erspan: introduce erspan v2 for ip_gre 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 From: William Tu Upstream commit: commit f551c91de262ba36b20c3ac19538afb4f4507441 Author: William Tu Date: Wed Dec 13 16:38:56 2017 -0800 net: erspan: introduce erspan v2 for ip_gre The patch adds support for erspan version 2. Not all features are supported in this patch. The SGT (security group tag), GRA (timestamp granularity), FT (frame type) are set to fixed value. Only hardware ID and direction are configurable. Optional subheader is also not supported. Signed-off-by: William Tu Signed-off-by: David S. Miller Includes some compatability layer adjustments and portions of this commit were introduced earlier while pulling in ipv6 erspan. Cc: William Tu Signed-off-by: Greg Rose --- datapath/linux/compat/include/net/ip_tunnels.h | 10 +-- datapath/linux/compat/ip_gre.c | 88 ++++++++++++++++++++++---- 2 files changed, 79 insertions(+), 19 deletions(-) diff --git a/datapath/linux/compat/include/net/ip_tunnels.h b/datapath/linux/compat/include/net/ip_tunnels.h index 4c1f0a1..fb70f9d 100644 --- a/datapath/linux/compat/include/net/ip_tunnels.h +++ b/datapath/linux/compat/include/net/ip_tunnels.h @@ -258,7 +258,7 @@ struct rpl_ip_tunnel_dst { }; #define ip_tunnel rpl_ip_tunnel -struct ip_tunnel { +struct rpl_ip_tunnel { struct ip_tunnel __rcu *next; struct hlist_node hash_node; struct net_device *dev; @@ -302,7 +302,7 @@ struct ip_tunnel { }; #define ip_tunnel_net rpl_ip_tunnel_net -struct ip_tunnel_net { +struct rpl_ip_tunnel_net { struct net_device *fb_tunnel_dev; struct hlist_head tunnels[IP_TNL_HASH_SIZE]; struct ip_tunnel __rcu *collect_md_tun; @@ -369,8 +369,8 @@ struct rtnl_link_stats64 *rpl_ip_tunnel_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *tot); #define ip_tunnel_get_dsfield rpl_ip_tunnel_get_dsfield -static inline u8 ip_tunnel_get_dsfield(const struct iphdr *iph, - const struct sk_buff *skb) +static inline u8 rpl_ip_tunnel_get_dsfield(const struct iphdr *iph, + const struct sk_buff *skb) { if (skb->protocol == htons(ETH_P_IP)) return iph->tos; @@ -381,7 +381,7 @@ static inline u8 ip_tunnel_get_dsfield(const struct iphdr *iph, } #define ip_tunnel_ecn_encap rpl_ip_tunnel_ecn_encap -static inline u8 ip_tunnel_ecn_encap(u8 tos, const struct iphdr *iph, +static inline u8 rpl_ip_tunnel_ecn_encap(u8 tos, const struct iphdr *iph, const struct sk_buff *skb) { u8 inner = ip_tunnel_get_dsfield(iph, skb); diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index 37c434d..9b3613a 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -170,11 +170,25 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, md = ip_tunnel_info_opts(&tun_dst->u.tun_info); memcpy(md, pkt_md, sizeof(*md)); + md->version = ver; + info = &tun_dst->u.tun_info; info->key.tun_flags |= TUNNEL_ERSPAN_OPT; info->options_len = sizeof(*md); } else { - tunnel->index = ntohl(pkt_md->u.index); + tunnel->erspan_ver = ver; + if (ver == 1) { + tunnel->index = ntohl(pkt_md->u.index); + } else { + u16 md2_flags; + u16 dir, hwid; + + md2_flags = ntohs(pkt_md->u.md2.flags); + dir = (md2_flags & DIR_MASK) >> DIR_OFFSET; + hwid = (md2_flags & HWID_MASK) >> HWID_OFFSET; + tunnel->dir = dir; + tunnel->hwid = hwid; + } } skb_reset_mac_header(skb); @@ -260,7 +274,8 @@ static int gre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *unused_tpi) if (hdr_len < 0) goto drop; - if (unlikely(tpi.proto == htons(ETH_P_ERSPAN))) { + if (unlikely(tpi.proto == htons(ETH_P_ERSPAN) || + tpi.proto == htons(ETH_P_ERSPAN2))) { if (erspan_rcv(skb, &tpi, hdr_len) == PACKET_RCVD) return 0; goto drop; @@ -506,6 +521,7 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev, bool truncate = false; struct flowi4 fl; int tunnel_hlen; + int version; __be16 df; tun_info = skb_tunnel_info(skb); @@ -514,9 +530,13 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev, goto err_free_skb; key = &tun_info->key; + md = ip_tunnel_info_opts(tun_info); + if (!md) + goto err_free_rt; /* ERSPAN has fixed 8 byte GRE header */ - tunnel_hlen = 8 + sizeof(struct erspan_base_hdr) + ERSPAN_V1_MDSIZE; + version = md->version; + tunnel_hlen = 8 + erspan_hdr_len(version); rt = prepare_fb_xmit(skb, dev, &fl, tunnel_hlen); if (!rt) @@ -530,12 +550,23 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev, truncate = true; } - md = ip_tunnel_info_opts(tun_info); - if (!md) + if (version == 1) { + erspan_build_header(skb, tunnel_id_to_key32(key->tun_id), + ntohl(md->u.index), truncate, true); + } else if (version == 2) { + u16 md2_flags; + u8 direction; + u16 hwid; + + md2_flags = ntohs(md->u.md2.flags); + direction = (md2_flags & DIR_MASK) >> DIR_OFFSET; + hwid = (md2_flags & HWID_MASK) >> HWID_OFFSET; + + erspan_build_header_v2(skb, tunnel_id_to_key32(key->tun_id), + direction, hwid, truncate, true); + } else { goto err_free_rt; - - erspan_build_header(skb, tunnel_id_to_key32(key->tun_id), - ntohl(md->u.index), truncate, true); + } tpi.flags = (TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_SEQ); tpi.proto = htons(ETH_P_ERSPAN); @@ -661,9 +692,14 @@ enum { #if LINUX_VERSION_CODE < KERNEL_VERSION(4,15,0) IFLA_GRE_ERSPAN_INDEX = IFLA_GRE_FWMARK + 1, #endif +#if LINUX_VERSION_CODE < KERNEL_VERSION(4,16,0) + IFLA_GRE_ERSPAN_VER = IFLA_GRE_ERSPAN_INDEX + 1, + IFLA_GRE_ERSPAN_DIR, + IFLA_GRE_ERSPAN_HWID, +#endif }; -#define RPL_IFLA_GRE_MAX (IFLA_GRE_ERSPAN_INDEX + 1) +#define RPL_IFLA_GRE_MAX (IFLA_GRE_ERSPAN_HWID + 1) static int erspan_validate(struct nlattr *tb[], struct nlattr *data[]) { @@ -748,8 +784,14 @@ static netdev_tx_t erspan_xmit(struct sk_buff *skb, } /* Push ERSPAN header */ - erspan_build_header(skb, tunnel->parms.o_key, tunnel->index, - truncate, true); + if (tunnel->erspan_ver == 1) + erspan_build_header(skb, tunnel->parms.o_key, tunnel->index, + truncate, true); + else + erspan_build_header_v2(skb, tunnel->parms.o_key, + tunnel->dir, tunnel->hwid, + truncate, true); + tunnel->parms.o_flags &= ~TUNNEL_KEY; __gre_xmit(skb, dev, &tunnel->parms.iph, htons(ETH_P_ERSPAN)); return NETDEV_TX_OK; @@ -803,7 +845,7 @@ static int erspan_tunnel_init(struct net_device *dev) tunnel->tun_hlen = 8; tunnel->parms.iph.protocol = IPPROTO_GRE; tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen + - sizeof(struct erspan_base_hdr) + ERSPAN_V1_MDSIZE; + erspan_hdr_len(tunnel->erspan_ver); t_hlen = tunnel->hlen + sizeof(struct iphdr); dev->needed_headroom = LL_MAX_HEADER + t_hlen + 4; @@ -890,6 +932,12 @@ static size_t ipgre_get_size(const struct net_device *dev) nla_total_size(0) + /* IFLA_GRE_ERSPAN_INDEX */ nla_total_size(4) + + /* IFLA_GRE_ERSPAN_VER */ + nla_total_size(1) + + /* IFLA_GRE_ERSPAN_DIR */ + nla_total_size(1) + + /* IFLA_GRE_ERSPAN_HWID */ + nla_total_size(2) + 0; } @@ -911,9 +959,18 @@ static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev) !!(p->iph.frag_off & htons(IP_DF)))) goto nla_put_failure; - if (t->index) - if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, t->index)) + if (nla_put_u8(skb, IFLA_GRE_ERSPAN_VER, t->erspan_ver)) + goto nla_put_failure; + + if (t->erspan_ver == 1) { + if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, t->index)) + goto nla_put_failure; + } else if (t->erspan_ver == 2) { + if (nla_put_u8(skb, IFLA_GRE_ERSPAN_DIR, t->dir)) goto nla_put_failure; + if (nla_put_u16(skb, IFLA_GRE_ERSPAN_HWID, t->hwid)) + goto nla_put_failure; + } return 0; @@ -942,6 +999,9 @@ static const struct nla_policy ipgre_policy[RPL_IFLA_GRE_MAX + 1] = { [IFLA_GRE_TOS] = { .type = NLA_U8 }, [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 }, [IFLA_GRE_ERSPAN_INDEX] = { .type = NLA_U32 }, + [IFLA_GRE_ERSPAN_VER] = { .type = NLA_U8 }, + [IFLA_GRE_ERSPAN_DIR] = { .type = NLA_U8 }, + [IFLA_GRE_ERSPAN_HWID] = { .type = NLA_U16 }, }; static struct rtnl_link_ops ipgre_tap_ops __read_mostly = { From patchwork Thu Mar 22 22:07:37 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Rose X-Patchwork-Id: 889688 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="c/BX71ok"; 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 406gwz0VFzz9s0y for ; Fri, 23 Mar 2018 09:16:03 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 46FCFF70; Thu, 22 Mar 2018 22:08:22 +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 058A2F43 for ; Thu, 22 Mar 2018 22:08:20 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pl0-f68.google.com (mail-pl0-f68.google.com [209.85.160.68]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 57DF95D3 for ; Thu, 22 Mar 2018 22:08:19 +0000 (UTC) Received: by mail-pl0-f68.google.com with SMTP id m22-v6so6209408pls.5 for ; Thu, 22 Mar 2018 15:08:19 -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=KM7NIAePkDsLxFAWI+VKo35bDjaw4Ri3rHGbtHXAHAw=; b=c/BX71okBROrm3uapW+nbGvNOQEuEj2BRD01MhK5RaImW+YXOZGwnnerS1R6JL5Gni 0/aH9Eua6KfTamPAbvnoB7MUwsRxJTVjviv/zBGPbsIQ377+uv1YWA5JIb8e4zhhJ4CB mfiruTKTK7UjD3Q9mNoWwPUkzKkGUFUzKtHRPfKu1FLKWfREi2BFWYUUzNu3WdS2pqS3 1A/g4iCDYq1dDnwWO9r59T4JKu3ES78zgnIx3RD19Rxqz1IQZkmdw4FhHUO1gncgGHPJ 4oXT75j7EwYzYaAX1HrCGq2EJNcz/UHfFzaDVyjzrA5YY99zeIG/tJqhIpYteJDFCp+A wpcw== 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=KM7NIAePkDsLxFAWI+VKo35bDjaw4Ri3rHGbtHXAHAw=; b=ALpQN5F2Y8H+ZNx45JLOu6MpAk1MQ3xv78BVSxPhyBAwiM/mpqLBTcQjAnU6iX6Jj+ wY0kAnozdPJQ0cCTEnI0byvIjh8LS1J8shv+b08T8PI2rsNoZz9gFfkIJscSv1R1Kmt8 mcyivEUAl4A//+g+YICIKkucS0rels0QHCkxomyJOoooWppDQnHpmklbVXixorhPaTsA yyT+2aKo/tI29xATOyxh68I0HMfQnIpiPdA1Ga+inC1KshWYMvX0UUVaa7yClaLlmmHe X/og1ajh9V+ux8fyWgTdMF/dkSgJzIGr1/he771xVKEUnrSM0KYsk16wSNOEef5yMKXK +ZXQ== X-Gm-Message-State: AElRT7G98/270BMoNoGKr4JYtsNRtXAad+0BWWmBgjVxpHgjhxigJA9U m6QmndBwCce16AuAHzjiDv+eNQ== X-Google-Smtp-Source: AG47ELsmgLNSXeykpMdoG1ucjoahyIrjAeVFebdXoQDhCC+Ec/b1EWht/5dN7cjmIF/tptuxqU8GXA== X-Received: by 2002:a17:902:d03:: with SMTP id 3-v6mr26966669plu.245.1521756498603; Thu, 22 Mar 2018 15:08:18 -0700 (PDT) Received: from gizo.domain (184-100-240-187.ptld.qwest.net. [184.100.240.187]) by smtp.gmail.com with ESMTPSA id 4sm2280775pfn.32.2018.03.22.15.08.17 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Mar 2018 15:08:17 -0700 (PDT) From: Greg Rose To: dev@openvswitch.org Date: Thu, 22 Mar 2018 15:07:37 -0700 Message-Id: <1521756461-3870-22-git-send-email-gvrose8192@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1521756461-3870-1-git-send-email-gvrose8192@gmail.com> References: <1521756461-3870-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] [ERSPAN RFC 21/25] compat: erspan: use bitfield instead of mask and offset 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 From: William Tu Upstream commit: commit c69de58ba84f480879de64571d9dae5102d10ed6 Author: William Tu Date: Thu Jan 25 13:20:09 2018 -0800 net: erspan: use bitfield instead of mask and offset Originally the erspan fields are defined as a group into a __be16 field, and use mask and offset to access each field. This is more costly due to calling ntohs/htons. The patch changes it to use bitfields. Signed-off-by: William Tu Acked-by: Pravin B Shelar Signed-off-by: David S. Miller Folds in the ip_gre portions of this commit. Other portions of this commit are included in a previous patch where it is called out. Cc: William Tu Signed-off-by: Greg Rose --- datapath/linux/compat/ip_gre.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index 9b3613a..f99ef1b 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -551,19 +551,15 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev, } if (version == 1) { - erspan_build_header(skb, tunnel_id_to_key32(key->tun_id), + erspan_build_header(skb, ntohl(tunnel_id_to_key32(key->tun_id)), ntohl(md->u.index), truncate, true); } else if (version == 2) { - u16 md2_flags; - u8 direction; - u16 hwid; - - md2_flags = ntohs(md->u.md2.flags); - direction = (md2_flags & DIR_MASK) >> DIR_OFFSET; - hwid = (md2_flags & HWID_MASK) >> HWID_OFFSET; + erspan_build_header_v2(skb, + ntohl(tunnel_id_to_key32(key->tun_id)), + md->u.md2.dir, + get_hwid(&md->u.md2), + truncate, true); - erspan_build_header_v2(skb, tunnel_id_to_key32(key->tun_id), - direction, hwid, truncate, true); } else { goto err_free_rt; } @@ -785,10 +781,11 @@ static netdev_tx_t erspan_xmit(struct sk_buff *skb, /* Push ERSPAN header */ if (tunnel->erspan_ver == 1) - erspan_build_header(skb, tunnel->parms.o_key, tunnel->index, + erspan_build_header(skb, ntohl(tunnel->parms.o_key), + tunnel->index, truncate, true); else - erspan_build_header_v2(skb, tunnel->parms.o_key, + erspan_build_header_v2(skb, ntohl(tunnel->parms.o_key), tunnel->dir, tunnel->hwid, truncate, true); From patchwork Thu Mar 22 22:07:38 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Rose X-Patchwork-Id: 889689 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="nl1pNVbN"; 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 406gxQ0jG6z9s0y for ; Fri, 23 Mar 2018 09:16:26 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 85118F7F; Thu, 22 Mar 2018 22:08:24 +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 25624F71 for ; Thu, 22 Mar 2018 22:08:21 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pg0-f67.google.com (mail-pg0-f67.google.com [74.125.83.67]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id D36EF5D3 for ; Thu, 22 Mar 2018 22:08:20 +0000 (UTC) Received: by mail-pg0-f67.google.com with SMTP id g12so3816900pgs.0 for ; Thu, 22 Mar 2018 15:08:20 -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=N41w9QB+HOdw8ZcCMOOioYRR7ktjmnzkQCImEF7jX8k=; b=nl1pNVbNGP+zh52yRK+THCeLZ8b2pEDRUubATpb5FE5fe1ES/62VD+zA9pHrB5AL1x +Ar02CPwd4DgUK1A1GiN37LUIjCICr834p7jI1pRNufs13BABtFquSZGBA2MRE+Vs+5r r1ZtBwNqvz7KvaoeYc17LZ+GRgf0UUKxTA1dMbXgRaAyXXY39ur/gXJqoYqFy7tsIRVC Ey73ddmY7TxVERJPhFHd2LnCgVJupfH71D65KWrraG2yIp/ZXsRUYXJyGgxlnAgebP9t oT+JOe8eHF+ak/vEwXX8EHWoJDRelbcfoHmiu60Hfm+iB/2CDSXt/ki+NY+d4H/FkiHs wzJQ== 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=N41w9QB+HOdw8ZcCMOOioYRR7ktjmnzkQCImEF7jX8k=; b=k/GhqmlmqCBWi+Ta97aHLc3NNKdC5qbcgTl/RZae2asY+RgyRM7EeJqdKlSjqWjV17 zZlQRoDtxXDHCYGo0tjh+bCRrkWLS71HtAGOST30ZxH0sKsZSgDeLfxkETRFLIrjCXuK YNW8/td8+YdMMU9fnkyZ+Ld+EiHVK/vpy9mFJNM4tSDIJbUOLWGNkL1GKiTlUbHTxQUx gCkSygSyyDgfDuaQHd/cpuUqNHPf1qNY0BGfE5uhWDuA9cWPEkb4EYMOIVu96ttuvBsS Ox6K6eDSek7ThfKAmB06imxSWLAFdZP8CddbPON4+I5TfdgOMAhIbZvb4oRDz9ayI4+z 7V4A== X-Gm-Message-State: AElRT7GmPkxLHwetUzViZaGUcsAvMSEUahabj/I5iR41w/kicsqazPTk OEmxkgJdEC9da4zuaQOJnpeRLA== X-Google-Smtp-Source: AG47ELtDsB02iCt3d33M70K8rkS3uaOeaI8c+JtcEXG3v4wsP7eW+WLLu7cFA2OORo0vjNPmK2pMdg== X-Received: by 10.98.49.135 with SMTP id x129mr21748540pfx.75.1521756500056; Thu, 22 Mar 2018 15:08:20 -0700 (PDT) Received: from gizo.domain (184-100-240-187.ptld.qwest.net. [184.100.240.187]) by smtp.gmail.com with ESMTPSA id 4sm2280775pfn.32.2018.03.22.15.08.18 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Mar 2018 15:08:19 -0700 (PDT) From: Greg Rose To: dev@openvswitch.org Date: Thu, 22 Mar 2018 15:07:38 -0700 Message-Id: <1521756461-3870-23-git-send-email-gvrose8192@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1521756461-3870-1-git-send-email-gvrose8192@gmail.com> References: <1521756461-3870-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] [ERSPAN RFC 22/25] net: erspan: fix metadata extraction 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 From: William Tu Upstream commit: commit 3df1928302950dfa728ab2eade28eea0da291567 Author: William Tu Date: Mon Feb 5 13:35:34 2018 -0800 net: erspan: fix metadata extraction Commit d350a823020e ("net: erspan: create erspan metadata uapi header") moves the erspan 'version' in front of the 'struct erspan_md2' for later extensibility reason. This breaks the existing erspan metadata extraction code because the erspan_md2 then has a 4-byte offset to between the erspan_metadata and erspan_base_hdr. This patch fixes it. Fixes: 1a66a836da63 ("gre: add collect_md mode to ERSPAN tunnel") Fixes: ef7baf5e083c ("ip6_gre: add ip6 erspan collect_md mode") Fixes: 1d7e2ed22f8d ("net: erspan: refactor existing erspan code") Signed-off-by: William Tu Signed-off-by: David S. Miller This is just the ip_gre portion of this upstream commit. The portions of the upstream commit that went to erpsan.h and ip6_gre.c were folded in during a previous commit to introduce ip6 gre. Cc: William Tu Signed-off-by: Greg Rose --- datapath/linux/compat/ip_gre.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index f99ef1b..5ebbdb5 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -119,6 +119,7 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, struct ip_tunnel_net *itn; struct ip_tunnel *tunnel; const struct iphdr *iph; + struct erspan_md2 *md2; int ver; int len; @@ -169,8 +170,10 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, tun_id, sizeof(*md)); md = ip_tunnel_info_opts(&tun_dst->u.tun_info); - memcpy(md, pkt_md, sizeof(*md)); md->version = ver; + md2 = &md->u.md2; + memcpy(md2, pkt_md, ver == 1 ? ERSPAN_V1_MDSIZE : + ERSPAN_V2_MDSIZE); info = &tun_dst->u.tun_info; info->key.tun_flags |= TUNNEL_ERSPAN_OPT; From patchwork Thu Mar 22 22:07:39 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Rose X-Patchwork-Id: 889690 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="Dod81PO7"; 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 406gxw2Tlvz9s0y for ; Fri, 23 Mar 2018 09:16:52 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 9C8ACF74; Thu, 22 Mar 2018 22:08:25 +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 6DA99F7D for ; Thu, 22 Mar 2018 22:08:22 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pf0-f195.google.com (mail-pf0-f195.google.com [209.85.192.195]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 2FF2C360 for ; Thu, 22 Mar 2018 22:08:22 +0000 (UTC) Received: by mail-pf0-f195.google.com with SMTP id h11so3926335pfn.4 for ; Thu, 22 Mar 2018 15:08:22 -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=Rt79x/jAg2TfRhcj+BLx8vLK/RmXn++2BAavF5KZ/H0=; b=Dod81PO7tJ0J5zF+iIAORe1DArofPcHgcJIkiyLoLshE/WDLra2wpDFkCFqwxUDB/a GzupVpOZvqLViET2+NodJUNuVncUMxEdz/hum46AinAdVRuR5Pp5YxRnVmqRmqmDx7im TTDErd0UkcUBHa01PhHGqIXoI+aVojcX17hIch9dAzqTOEd0nduOuNhf8xxxuy4WBq3f oi2SZWzzUBP698JpVQVHOc1Rz2WalsoykTT1YtNvdd3vUlVqAj9ZxZua3yiI268bb8O7 wqEe6FP2arq0VCqO5HVHSUtovvZu54bva9bZmN4P6JOfv5iUafH2rBCCNeC35Nl+npXj Uykw== 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=Rt79x/jAg2TfRhcj+BLx8vLK/RmXn++2BAavF5KZ/H0=; b=Ceqh3V4TbNVFnPF8llBmH7kBao1CdbS7tPKfX/AO00LJlS1zyIcwX8zWN4uu6ly3B9 OQ6caLMV3rLewDbtFC6dt+oT17TF/kHrM85bRFk7kv5K4d7Y++s7H0V+lTCUhVSUk5S8 T9wp8R/yzlI605cGeP91kM5UMiA84mwKv83mmLwnIgEDJQN6AA1nPvMMh100pUM5QNzR LQK9FssKByFeSya/iAg7MF5BeYd1vQdOqNTcNvYqsV1CEzraiJ5HbRdSJS8MCEvuqtmK yee1bfks7lUr3G11zUJcHLmhmAwX0kl2DRsXY02ky46Eec7hL+OkNSJ/sXRmcFpRqPX5 s2Xg== X-Gm-Message-State: AElRT7F5d8Ke5Ouwd/goh4jyxHuvP9EEdFeoLin8JUi/1my4jn6mWXEP FOOLnIN2EUB2Ry7u0gthstY1Yw== X-Google-Smtp-Source: AG47ELt33/b0ulYvAibXtnPTV1dnERaAruRuKmU9R17+3lLEoxp+i0MWpSZA0Fnl/d4RCS87Dwu/dQ== X-Received: by 10.98.156.16 with SMTP id f16mr21884841pfe.180.1521756501398; Thu, 22 Mar 2018 15:08:21 -0700 (PDT) Received: from gizo.domain (184-100-240-187.ptld.qwest.net. [184.100.240.187]) by smtp.gmail.com with ESMTPSA id 4sm2280775pfn.32.2018.03.22.15.08.20 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Mar 2018 15:08:20 -0700 (PDT) From: Greg Rose To: dev@openvswitch.org Date: Thu, 22 Mar 2018 15:07:39 -0700 Message-Id: <1521756461-3870-24-git-send-email-gvrose8192@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1521756461-3870-1-git-send-email-gvrose8192@gmail.com> References: <1521756461-3870-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] [ERSPAN RFC 23/25] erspan: fix erspan config overwrite 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 From: William Tu Upsteam commit: commit 39f57f6799cdd437277122d4cd1c470c08f527c0 Author: William Tu Date: Mon Feb 5 13:35:35 2018 -0800 net: erspan: fix erspan config overwrite When an erspan tunnel device receives an erpsan packet with different tunnel metadata (ex: version, index, hwid, direction), existing code overwrites the tunnel device's erspan configuration with the received packet's metadata. The patch fixes it. Fixes: 1a66a836da63 ("gre: add collect_md mode to ERSPAN tunnel") Fixes: f551c91de262 ("net: erspan: introduce erspan v2 for ip_gre") Fixes: ef7baf5e083c ("ip6_gre: add ip6 erspan collect_md mode") Fixes: 94d7d8f29287 ("ip6_gre: add erspan v2 support") Signed-off-by: William Tu Signed-off-by: David S. Miller This is just the ip_gre portion of the commit. The ip6_gre part of the commit was folded in during the prior commit to introduce ip6 gre and ip6 tunneling. Cc: William Tu Signed-off-by: Greg Rose --- datapath/linux/compat/ip_gre.c | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index 5ebbdb5..08d3351 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -178,20 +178,6 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, info = &tun_dst->u.tun_info; info->key.tun_flags |= TUNNEL_ERSPAN_OPT; info->options_len = sizeof(*md); - } else { - tunnel->erspan_ver = ver; - if (ver == 1) { - tunnel->index = ntohl(pkt_md->u.index); - } else { - u16 md2_flags; - u16 dir, hwid; - - md2_flags = ntohs(pkt_md->u.md2.flags); - dir = (md2_flags & DIR_MASK) >> DIR_OFFSET; - hwid = (md2_flags & HWID_MASK) >> HWID_OFFSET; - tunnel->dir = dir; - tunnel->hwid = hwid; - } } skb_reset_mac_header(skb); From patchwork Thu Mar 22 22:07:40 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Rose X-Patchwork-Id: 889691 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="OAT68l84"; 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 406gyR6Nslz9s0y for ; Fri, 23 Mar 2018 09:17:19 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id 145B8E55; Thu, 22 Mar 2018 22:08:27 +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 F0E97E4C for ; Thu, 22 Mar 2018 22:08:23 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pg0-f65.google.com (mail-pg0-f65.google.com [74.125.83.65]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id 8AA8B5D3 for ; Thu, 22 Mar 2018 22:08:23 +0000 (UTC) Received: by mail-pg0-f65.google.com with SMTP id v26so1302346pge.11 for ; Thu, 22 Mar 2018 15:08:23 -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=bckLMGl8+z75MYF4z8rhZ4EA2QVjyQl6K2YRA1FNd+I=; b=OAT68l84WPubwvF9dZoHk/rJBs+l8y8OCnnJhbkSoe5bYBgF23mml7RFebQaYwaoAY W7V90F9ktYQ5vo6wApkNjRCyJp45aDAmBY8Kc9Nc3fuGJLNgayED76sC3iMc6Ajdr+En yXYbOOA9z+bhztkEdkzkqm92U9wD2KX/uPXrR+fm7ycvxKrt9FDimAIQK0R241dBCqQ5 sEPlEKHD/W+20/9IqKphaihaOkLejZtmv8NfeyIvASZ7fDkWnkfY3SzrhNLv3lZy3v2F uS6NnFl5UjMy8oT0noFMuaqkzwiEyE+2iyxvd3JNuWdE5hjht+u9vnziyS6Yt9Q5ctMe /zxQ== 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=bckLMGl8+z75MYF4z8rhZ4EA2QVjyQl6K2YRA1FNd+I=; b=RdbJbna9S9mnE8LwCDnBYYC+CiLY/RIrFCnJN6rXVQ2P/t118D0UgxHdNTOBiRxHAf WjLbuBKBd5drcrfzUkiDvugOMZVEfiPq0LkBnESXQH51gIH6kZul6Wtw8s1DFthqcMB7 kOf8HgkVOiKlPWdJMo4FQF6ieAsVB18xj6iaU6fdULaHc+fZ5K2M1bt3tTDqXl6D98pZ SydQVtxQZGcnUwi5gEPC85dmC9xEE+iPD+GHD29Qk9EJhGNlwTT28zNPUCBd8PS6S+sq NYZcp/2d3OZZB0rSrHv97M7c5ezyeMkLWe6EWXWtleYVRFGmrMv4PDZYzJO84/lZ00gP KEJg== X-Gm-Message-State: AElRT7EyZDyy0CdCiNDJje3EZ6I1Q1nzn9N7n3yhlfn2ZiuyohOJyTPN cEqx+LnS4AhEGv7pIPus1Sessg== X-Google-Smtp-Source: AG47ELtAvIRaeW8PUwMv5aofx7mksQt8u/6JXkPZ4Qf1ndoVDV4EV8MUKqqbqAwOmSicIswTD/FWNA== X-Received: by 10.98.138.144 with SMTP id o16mr2377192pfk.216.1521756502753; Thu, 22 Mar 2018 15:08:22 -0700 (PDT) Received: from gizo.domain (184-100-240-187.ptld.qwest.net. [184.100.240.187]) by smtp.gmail.com with ESMTPSA id 4sm2280775pfn.32.2018.03.22.15.08.21 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Mar 2018 15:08:21 -0700 (PDT) From: Greg Rose To: dev@openvswitch.org Date: Thu, 22 Mar 2018 15:07:40 -0700 Message-Id: <1521756461-3870-25-git-send-email-gvrose8192@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1521756461-3870-1-git-send-email-gvrose8192@gmail.com> References: <1521756461-3870-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] [ERSPAN RFC 24/25] datapath: add erspan version I and II support 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 From: William Tu Upstream commit: commit fc1372f89ffe1f58b589643b75f679e452350703 Author: William Tu Date: Thu Jan 25 13:20:11 2018 -0800 openvswitch: add erspan version I and II support The patch adds support for openvswitch to configure erspan v1 and v2. The OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS attr is added to uapi as a binary blob to support all ERSPAN v1 and v2's fields. Note that Previous commit "openvswitch: Add erspan tunnel support." was reverted since it does not design properly. Signed-off-by: William Tu Acked-by: Pravin B Shelar Signed-off-by: David S. Miller Cc: William Tu Signed-off-by: Greg Rose --- datapath/flow_netlink.c | 52 ++++++++++++++++++++++- datapath/linux/compat/include/linux/openvswitch.h | 1 + lib/odp-util.c | 2 + 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/datapath/flow_netlink.c b/datapath/flow_netlink.c index e2ccf91..1b7bad8 100644 --- a/datapath/flow_netlink.c +++ b/datapath/flow_netlink.c @@ -47,6 +47,7 @@ #include #include #include +#include #include "datapath.h" #include "conntrack.h" @@ -330,7 +331,8 @@ size_t ovs_tun_key_attr_size(void) + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_CSUM */ + nla_total_size(0) /* OVS_TUNNEL_KEY_ATTR_OAM */ + nla_total_size(256) /* OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS */ - /* OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS is mutually exclusive with + /* OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS and + * OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS is mutually exclusive with * OVS_TUNNEL_KEY_ATTR_GENEVE_OPTS and covered by it. */ + nla_total_size(2) /* OVS_TUNNEL_KEY_ATTR_TP_SRC */ @@ -401,6 +403,7 @@ static const struct ovs_len_tbl ovs_tunnel_key_lens[OVS_TUNNEL_KEY_ATTR_MAX + 1] .next = ovs_vxlan_ext_key_lens }, [OVS_TUNNEL_KEY_ATTR_IPV6_SRC] = { .len = sizeof(struct in6_addr) }, [OVS_TUNNEL_KEY_ATTR_IPV6_DST] = { .len = sizeof(struct in6_addr) }, + [OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS] = { .len = OVS_ATTR_VARIABLE }, }; static const struct ovs_len_tbl @@ -632,6 +635,33 @@ static int vxlan_tun_opt_from_nlattr(const struct nlattr *attr, return 0; } +static int erspan_tun_opt_from_nlattr(const struct nlattr *a, + struct sw_flow_match *match, bool is_mask, + bool log) +{ + unsigned long opt_key_offset; + + BUILD_BUG_ON(sizeof(struct erspan_metadata) > + sizeof(match->key->tun_opts)); + + if (nla_len(a) > sizeof(match->key->tun_opts)) { + OVS_NLERR(log, "ERSPAN option length err (len %d, max %zu).", + nla_len(a), sizeof(match->key->tun_opts)); + return -EINVAL; + } + + if (!is_mask) + SW_FLOW_KEY_PUT(match, tun_opts_len, + sizeof(struct erspan_metadata), false); + else + SW_FLOW_KEY_PUT(match, tun_opts_len, 0xff, true); + + opt_key_offset = TUN_METADATA_OFFSET(nla_len(a)); + SW_FLOW_KEY_MEMCPY_OFFSET(match, opt_key_offset, nla_data(a), + nla_len(a), is_mask); + return 0; +} + static int ip_tun_from_nlattr(const struct nlattr *attr, struct sw_flow_match *match, bool is_mask, bool log) @@ -739,6 +769,20 @@ static int ip_tun_from_nlattr(const struct nlattr *attr, break; case OVS_TUNNEL_KEY_ATTR_PAD: break; + case OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS: + if (opts_type) { + OVS_NLERR(log, "Multiple metadata blocks provided"); + return -EINVAL; + } + + err = erspan_tun_opt_from_nlattr(a, match, is_mask, + log); + if (err) + return err; + + tun_flags |= TUNNEL_ERSPAN_OPT; + opts_type = type; + break; default: OVS_NLERR(log, "Unknown IP tunnel attribute %d", type); @@ -863,6 +907,10 @@ static int __ip_tun_to_nlattr(struct sk_buff *skb, else if (output->tun_flags & TUNNEL_VXLAN_OPT && vxlan_opt_to_nlattr(skb, tun_opts, swkey_tun_opts_len)) return -EMSGSIZE; + else if (output->tun_flags & TUNNEL_ERSPAN_OPT && + nla_put(skb, OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS, + swkey_tun_opts_len, tun_opts)) + return -EMSGSIZE; } return 0; @@ -2490,6 +2538,8 @@ static int validate_and_copy_set_tun(const struct nlattr *attr, break; case OVS_TUNNEL_KEY_ATTR_VXLAN_OPTS: break; + case OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS: + break; } } diff --git a/datapath/linux/compat/include/linux/openvswitch.h b/datapath/linux/compat/include/linux/openvswitch.h index 84ebcaf..a4a1fdb 100644 --- a/datapath/linux/compat/include/linux/openvswitch.h +++ b/datapath/linux/compat/include/linux/openvswitch.h @@ -395,6 +395,7 @@ enum ovs_tunnel_key_attr { OVS_TUNNEL_KEY_ATTR_IPV6_SRC, /* struct in6_addr src IPv6 address. */ OVS_TUNNEL_KEY_ATTR_IPV6_DST, /* struct in6_addr dst IPv6 address. */ OVS_TUNNEL_KEY_ATTR_PAD, + OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS, /* struct erspan_metadata */ __OVS_TUNNEL_KEY_ATTR_MAX }; diff --git a/lib/odp-util.c b/lib/odp-util.c index 8743503..1c09db4 100644 --- a/lib/odp-util.c +++ b/lib/odp-util.c @@ -3479,6 +3479,8 @@ format_odp_tun_attr(const struct nlattr *attr, const struct nlattr *mask_attr, break; case OVS_TUNNEL_KEY_ATTR_PAD: break; + case OVS_TUNNEL_KEY_ATTR_ERSPAN_OPTS: + break; case __OVS_TUNNEL_KEY_ATTR_MAX: default: format_unknown_key(ds, a, ma); From patchwork Thu Mar 22 22:07:41 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gregory Rose X-Patchwork-Id: 889693 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="ETmkmF7n"; 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 406gzY4cbbz9s0y for ; Fri, 23 Mar 2018 09:18:17 +1100 (AEDT) Received: from mail.linux-foundation.org (localhost [127.0.0.1]) by mail.linuxfoundation.org (Postfix) with ESMTP id F2AF5F9A; Thu, 22 Mar 2018 22:08:32 +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 F121CF9C for ; Thu, 22 Mar 2018 22:08:27 +0000 (UTC) X-Greylist: whitelisted by SQLgrey-1.7.6 Received: from mail-pg0-f66.google.com (mail-pg0-f66.google.com [74.125.83.66]) by smtp1.linuxfoundation.org (Postfix) with ESMTPS id D9B27360 for ; Thu, 22 Mar 2018 22:08:25 +0000 (UTC) Received: by mail-pg0-f66.google.com with SMTP id t12so2045803pgp.13 for ; Thu, 22 Mar 2018 15:08:25 -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=7sJW5srIeZ/eB2bmdqL5eQVfLhs+lFkjQ/ingYyv3MM=; b=ETmkmF7nDVfAsS1XMjpHZMl75Mvth1dLqQRiAjmSIEdkjufkXzCxjHo6SJPO62pmaX PxD/FjqURx8Yuywwgn4LIhbgDAJczkPFdVPzzpmK4UWI+zHBul32J7o79IYtSTPP94fb 6WhP4kqF7kAJCTTLBM2TV39/m1METzrQ9ZU+5gSW0BzP4nlpQUvnbMS37wkzK/BWNxZ0 1zAZdnYKxxGwFWWpbdglNxT5f7RWCmxVeGS5o32RMSXUDslAuT66emAsoa5wpk0FLzla YdHB+dF2KxaRqKwMQoWE8emEcm+70vpNTekGorb80uXIt8g5h5yW3ljG/OZFYAzBBKO8 3zLA== 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=7sJW5srIeZ/eB2bmdqL5eQVfLhs+lFkjQ/ingYyv3MM=; b=HVzJoJP6l07BFpf+bofgoAUYHfQbAQtkm33+FXePxiWuUubpLyftICkE19CuP3fbJX /Yn1JnegQKikBunmd58rhzdxbIDpLOOk/+D6l40iE3iY/b9iU7uM5QnE+qgePBS4zAJe j5JIv/QE8FeZ0fHqGSbrD0EEFMk1z1zEOjsu4ccKYuXVaZDJ2DIwMgu89kookVqX2phN O8+zTU3MZdBy9z9HtFnDyprDQngE0H3USs1maWXi5c3fW48PCzXskBC1nppiGUZbMCU4 a+KYOgKBCXRW2CbDPTiovRc+yaXClICUC97QOWhb/5nZ5cSkwPAF/JpH+/nIrUeUgSwv mLRQ== X-Gm-Message-State: AElRT7HPqc80OPOKprA0fyr4iJwU0lA9fhF217IxJNxU22lUWWHotLNv SyOgaLW+GE5d7IboEdhYTTd5Pw== X-Google-Smtp-Source: AG47ELspSvXlkKaNQz8kFR2oBKfRNvqDOiNiJllVRKfFaKA1Qk4xlEVcqpKqUHfQ3D79LsHyfv6jpw== X-Received: by 10.101.99.17 with SMTP id g17mr19522982pgv.48.1521756504301; Thu, 22 Mar 2018 15:08:24 -0700 (PDT) Received: from gizo.domain (184-100-240-187.ptld.qwest.net. [184.100.240.187]) by smtp.gmail.com with ESMTPSA id 4sm2280775pfn.32.2018.03.22.15.08.22 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Thu, 22 Mar 2018 15:08:23 -0700 (PDT) From: Greg Rose To: dev@openvswitch.org Date: Thu, 22 Mar 2018 15:07:41 -0700 Message-Id: <1521756461-3870-26-git-send-email-gvrose8192@gmail.com> X-Mailer: git-send-email 1.8.3.1 In-Reply-To: <1521756461-3870-1-git-send-email-gvrose8192@gmail.com> References: <1521756461-3870-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] [ERSPAN RFC 25/25] datapath: More ipgre fixes 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 After the initial backport of gre/ipgre/erspan code in the first patch of this series and as continued development and debugging occurred a number of fixes were made as well as more code being pulled in from upstream. This is a big, ugly patch with all of that stuff... For now let's pretend this patch doesn't really exist. All of this code will be folded into previous patches and this patch series re-ordered. Signed-off-by: Greg Rose --- acinclude.m4 | 6 +- datapath/linux/compat/gre.c | 27 +- datapath/linux/compat/include/net/dst_metadata.h | 23 +- datapath/linux/compat/include/net/ip_tunnels.h | 3 +- datapath/linux/compat/ip6_gre.c | 81 ++- datapath/linux/compat/ip_gre.c | 692 +++++++++++++++++++---- datapath/linux/compat/ip_tunnel.c | 93 ++- datapath/vport.c | 2 + 8 files changed, 764 insertions(+), 163 deletions(-) diff --git a/acinclude.m4 b/acinclude.m4 index e6de83f..9cde520 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -814,9 +814,6 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [ OVS_GREP_IFELSE([$KSRC/include/net/inet_frag.h], frag_percpu_counter_batch[], [OVS_DEFINE([HAVE_FRAG_PERCPU_COUNTER_BATCH])]) - OVS_FIND_FIELD_IFELSE([$KSRC/include/net/ip_tunnels.h], [tnl_ptk_info], - [hdr_len], - [OVS_DEFINE([HAVE_TNL_PTK_INFO_HDR_LEN])]) OVS_GREP_IFELSE([$KSRC/include/linux/skbuff.h], [null_compute_pseudo], [OVS_DEFINE([HAVE_NULL_COMPUTE_PSEUDO])]) @@ -862,6 +859,9 @@ AC_DEFUN([OVS_CHECK_LINUX_COMPAT], [ OVS_GREP_IFELSE([$KSRC/include/uapi/linux/if_tunnel.h], [IFLA_IPTUN_COLLECT_METADATA], [OVS_DEFINE([HAVE_IFLA_IPTUN_COLLECT_METADATA])]) + OVS_GREP_IFELSE([$KSRC/net/ipv4/gre_demux.c], + [parse_gre_header], + [OVS_DEFINE([HAVE_DEMUX_PARSE_GRE_HEADER])]) if cmp -s datapath/linux/kcompat.h.new \ datapath/linux/kcompat.h >/dev/null 2>&1; then diff --git a/datapath/linux/compat/gre.c b/datapath/linux/compat/gre.c index 6a6dc91..03ce91d 100644 --- a/datapath/linux/compat/gre.c +++ b/datapath/linux/compat/gre.c @@ -57,9 +57,9 @@ static int rpl_ip_gre_calc_hlen(__be16 o_flags) } #ifndef HAVE_GRE_HANDLE_OFFLOADS - #ifndef HAVE_GRE_CISCO_REGISTER +#ifdef HAVE_DEMUX_PARSE_GRE_HEADER static __sum16 check_checksum(struct sk_buff *skb) { __sum16 csum = 0; @@ -99,13 +99,12 @@ static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, tpi->flags = gre_flags_to_tnl_flags(greh->flags); hdr_len = ip_gre_calc_hlen(tpi->flags); + tpi->hdr_len = hdr_len; + tpi->proto = greh->protocol; if (!pskb_may_pull(skb, hdr_len)) return -EINVAL; - greh = (struct gre_base_hdr *)(skb_network_header(skb) + ip_hlen); - tpi->proto = greh->protocol; - options = (__be32 *)(greh + 1); if (greh->flags & GRE_CSUM) { if (check_checksum(skb)) { @@ -143,20 +142,25 @@ 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; - bool csum_err = false; struct gre_cisco_protocol *proto; rcu_read_lock(); proto = rcu_dereference(gre_cisco_proto); if (!proto) goto drop; - - if (parse_gre_header(skb, &tpi, &csum_err) < 0) - goto drop; +#ifdef HAVE_DEMUX_PARSE_GRE_HEADER + { + bool csum_err = false; + if (parse_gre_header(skb, &tpi, &csum_err) < 0) + goto drop; + } +#endif proto->handler(skb, &tpi); rcu_read_unlock(); return 0; @@ -288,10 +292,11 @@ int rpl_gre_parse_header(struct sk_buff *skb, struct tnl_ptk_info *tpi, } else { tpi->seq = 0; } + /* WCCP version 1 and 2 protocol decoding. - * * - Change protocol to IPv4/IPv6 - * * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header - * */ + * - Change protocol to IPv4/IPv6 + * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header + */ if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) { tpi->proto = proto; if ((*(u8 *)options & 0xF0) != 0x40) diff --git a/datapath/linux/compat/include/net/dst_metadata.h b/datapath/linux/compat/include/net/dst_metadata.h index e401eb4..93ea954 100644 --- a/datapath/linux/compat/include/net/dst_metadata.h +++ b/datapath/linux/compat/include/net/dst_metadata.h @@ -1,6 +1,11 @@ #ifndef __NET_DST_METADATA_WRAPPER_H #define __NET_DST_METADATA_WRAPPER_H 1 +enum metadata_type { + METADATA_IP_TUNNEL, + METADATA_HW_PORT_MUX, +}; + #ifdef USE_UPSTREAM_TUNNEL #include_next #else @@ -11,19 +16,26 @@ #include #include +struct hw_port_info { + struct net_device *lower_dev; + u32 port_id; +}; + struct metadata_dst { - unsigned long dst; + struct dst_entry dst; + enum metadata_type type; union { struct ip_tunnel_info tun_info; + struct hw_port_info port_info; } u; }; static void __metadata_dst_init(struct metadata_dst *md_dst, u8 optslen) { - unsigned long *dst; + struct dst_entry *dst; dst = &md_dst->dst; - *dst = 0; + #if 0 dst_init(dst, &md_dst_ops, NULL, 1, DST_OBSOLETE_NONE, DST_METADATA | DST_NOCACHE | DST_NOCOUNT); @@ -105,11 +117,6 @@ void ovs_ip_tunnel_rcv(struct net_device *dev, struct sk_buff *skb, struct metadata_dst *tun_dst); #ifndef HAVE_METADATA_DST_ALLOC_WITH_METADATA_TYPE -enum metadata_type { - METADATA_IP_TUNNEL, - METADATA_HW_PORT_MUX, -}; - static inline struct metadata_dst * rpl_metadata_dst_alloc(u8 optslen, enum metadata_type type, gfp_t flags) { diff --git a/datapath/linux/compat/include/net/ip_tunnels.h b/datapath/linux/compat/include/net/ip_tunnels.h index fb70f9d..9b2621e 100644 --- a/datapath/linux/compat/include/net/ip_tunnels.h +++ b/datapath/linux/compat/include/net/ip_tunnels.h @@ -99,13 +99,12 @@ struct tnl_ptk_info { __be16 proto; __be32 key; __be32 seq; -#ifndef HAVE_TNL_PTK_INFO_HDR_LEN int hdr_len; -#endif }; #define PACKET_RCVD 0 #define PACKET_REJECT 1 +#define PACKET_NEXT 2 #endif #define IP_TNL_HASH_BITS 7 diff --git a/datapath/linux/compat/ip6_gre.c b/datapath/linux/compat/ip6_gre.c index 2832901..1057539 100644 --- a/datapath/linux/compat/ip6_gre.c +++ b/datapath/linux/compat/ip6_gre.c @@ -59,6 +59,8 @@ #include #include +#include "vport-netdev.h" + #define IP6_GRE_HASH_SIZE_SHIFT 5 #define IP6_GRE_HASH_SIZE (1 << IP6_GRE_HASH_SIZE_SHIFT) @@ -583,6 +585,7 @@ static int ip6erspan_rcv(struct sk_buff *skb, int gre_hdr_len, return PACKET_REJECT; } + static int gre_rcv(struct sk_buff *skb) { struct tnl_ptk_info tpi; @@ -1073,6 +1076,11 @@ tx_err: return NETDEV_TX_OK; } +static netdev_tx_t __ip6erspan_tunnel_xmit(struct sk_buff *skb) +{ + return ip6erspan_tunnel_xmit(skb, skb->dev); +} + static void ip6gre_tnl_link_config(struct ip6_tnl *t, int set_mtu) { struct net_device *dev = t->dev; @@ -2252,6 +2260,60 @@ static struct rtnl_link_ops ip6erspan_tap_ops __read_mostly = { #endif }; +static struct vport_ops ovs_erspan6_vport_ops; + +static struct vport *erspan6_tnl_create(const struct vport_parms *parms) +{ + struct net *net = ovs_dp_get_net(parms->dp); + struct net_device *dev; + struct vport *vport; + int err; + + vport = ovs_vport_alloc(0, &ovs_erspan6_vport_ops, parms); + if (IS_ERR(vport)) + return vport; + + rtnl_lock(); + dev = gretap_fb_dev_create(net, parms->name, NET_NAME_USER); + if (IS_ERR(dev)) { + rtnl_unlock(); + ovs_vport_free(vport); + return ERR_CAST(dev); + } + + err = dev_change_flags(dev, dev->flags | IFF_UP); + if (err < 0) { + rtnl_delete_link(dev); + rtnl_unlock(); + ovs_vport_free(vport); + return ERR_PTR(err); + } + + rtnl_unlock(); + return vport; +} + +static struct vport *erspan6_create(const struct vport_parms *parms) +{ + struct vport *vport; + + vport = erspan6_tnl_create(parms); + if (IS_ERR(vport)) + return vport; + + return ovs_netdev_link(vport, parms->name); +} + +static struct vport_ops ovs_erspan6_vport_ops = { + .type = OVS_VPORT_TYPE_IP6ERSPAN, + .create = erspan6_create, + .send = __ip6erspan_tunnel_xmit, +#ifndef USE_UPSTREAM_TUNNEL + .fill_metadata_dst = gre_fill_metadata_dst, +#endif + .destroy = ovs_netdev_tunnel_destroy, +}; + /* * And now the modules code and kernel interface. */ @@ -2260,8 +2322,6 @@ int rpl_ip6gre_init(void) { int err; - pr_info("GRE over IPv6 tunneling driver\n"); - err = register_pernet_device(&ip6gre_net_ops); if (err < 0) return err; @@ -2272,26 +2332,16 @@ int rpl_ip6gre_init(void) goto add_proto_failed; } - err = rtnl_link_register(&ip6gre_link_ops); - if (err < 0) - goto rtnl_link_failed; - err = rtnl_link_register(&ip6gre_tap_ops); if (err < 0) goto tap_ops_failed; - err = rtnl_link_register(&ip6erspan_tap_ops); - if (err < 0) - goto erspan_link_failed; - + pr_info("GRE over IPv6 tunneling driver\n"); + return ovs_vport_ops_register(&ovs_erspan6_vport_ops); out: return err; -erspan_link_failed: - rtnl_link_unregister(&ip6gre_tap_ops); tap_ops_failed: - rtnl_link_unregister(&ip6gre_link_ops); -rtnl_link_failed: inet6_del_protocol(&ip6gre_protocol, IPPROTO_GRE); add_proto_failed: unregister_pernet_device(&ip6gre_net_ops); @@ -2300,9 +2350,8 @@ add_proto_failed: void rpl_ip6gre_fini(void) { + ovs_vport_ops_unregister(&ovs_erspan6_vport_ops); rtnl_link_unregister(&ip6gre_tap_ops); - rtnl_link_unregister(&ip6gre_link_ops); - rtnl_link_unregister(&ip6erspan_tap_ops); inet6_del_protocol(&ip6gre_protocol, IPPROTO_GRE); unregister_pernet_device(&ip6gre_net_ops); } diff --git a/datapath/linux/compat/ip_gre.c b/datapath/linux/compat/ip_gre.c index 08d3351..59a9fb3 100644 --- a/datapath/linux/compat/ip_gre.c +++ b/datapath/linux/compat/ip_gre.c @@ -64,11 +64,14 @@ #include "vport-netdev.h" static int gre_tap_net_id __read_mostly; +static int ipgre_net_id __read_mostly; static unsigned int erspan_net_id __read_mostly; static void erspan_build_header(struct sk_buff *skb, __be32 id, u32 index, bool truncate, bool is_ipv4); +static struct rtnl_link_ops ipgre_link_ops __read_mostly; + #define ip_gre_calc_hlen rpl_ip_gre_calc_hlen static int ip_gre_calc_hlen(__be16 o_flags) { @@ -83,15 +86,6 @@ static int ip_gre_calc_hlen(__be16 o_flags) return addend; } -static __be64 key_to_tunnel_id(__be32 key) -{ -#ifdef __BIG_ENDIAN - return (__force __be64)((__force u32)key); -#else - return (__force __be64)((__force u64)key << 32); -#endif -} - /* Returns the least-significant 32 bits of a __be64. */ static __be32 tunnel_id_to_key(__be64 x) { @@ -109,6 +103,89 @@ static int gre_err(struct sk_buff *skb, u32 info, return PACKET_REJECT; } +static struct dst_ops md_dst_ops = { + .family = AF_UNSPEC, +}; + +#ifndef DST_METADATA +#define DST_METADATA 0x0080 +#endif + +static void rpl__metadata_dst_init(struct metadata_dst *md_dst, + enum metadata_type type, u8 optslen) + +{ + struct dst_entry *dst; + + dst = &md_dst->dst; + dst_init(dst, &md_dst_ops, NULL, 1, DST_OBSOLETE_NONE, + DST_METADATA | DST_NOCOUNT); + +#if 0 + /* unused in OVS */ + dst->input = dst_md_discard; + dst->output = dst_md_discard_out; +#endif + memset(dst + 1, 0, sizeof(*md_dst) + optslen - sizeof(*dst)); + md_dst->type = type; +} + +struct metadata_dst *erspan_rpl_metadata_dst_alloc(u8 optslen, enum metadata_type type, + gfp_t flags) +{ + struct metadata_dst *md_dst; + + md_dst = kmalloc(sizeof(*md_dst) + optslen, flags); + if (!md_dst) + return NULL; + + rpl__metadata_dst_init(md_dst, type, optslen); + + return md_dst; +} +static inline struct metadata_dst *rpl_tun_rx_dst(int md_size) +{ + struct metadata_dst *tun_dst; + + tun_dst = erspan_rpl_metadata_dst_alloc(md_size, METADATA_IP_TUNNEL, GFP_ATOMIC); + if (!tun_dst) + return NULL; + + tun_dst->u.tun_info.options_len = 0; + tun_dst->u.tun_info.mode = 0; + return tun_dst; +} +static inline struct metadata_dst *rpl__ip_tun_set_dst(__be32 saddr, + __be32 daddr, + __u8 tos, __u8 ttl, + __be16 tp_dst, + __be16 flags, + __be64 tunnel_id, + int md_size) +{ + struct metadata_dst *tun_dst; + + tun_dst = rpl_tun_rx_dst(md_size); + if (!tun_dst) + return NULL; + + ip_tunnel_key_init(&tun_dst->u.tun_info.key, + saddr, daddr, tos, ttl, + 0, 0, tp_dst, tunnel_id, flags); + return tun_dst; +} + +static inline struct metadata_dst *rpl_ip_tun_rx_dst(struct sk_buff *skb, + __be16 flags, + __be64 tunnel_id, + int md_size) +{ + const struct iphdr *iph = ip_hdr(skb); + + return rpl__ip_tun_set_dst(iph->saddr, iph->daddr, iph->tos, iph->ttl, + 0, flags, tunnel_id, md_size); +} + static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, int gre_hdr_len) { @@ -138,9 +215,16 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, * Use ERSPAN 10-bit session ID as key. */ tpi->key = cpu_to_be32(get_session_id(ershdr)); + /* OVS doesn't set tunnel key - so don't bother with it */ +#if 0 tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags | TUNNEL_KEY, iph->saddr, iph->daddr, tpi->key); +#else + tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, + tpi->flags, + iph->saddr, iph->daddr, 0); +#endif if (tunnel) { len = gre_hdr_len + erspan_hdr_len(ver); @@ -166,8 +250,9 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, flags = tpi->flags; tun_id = key32_to_tunnel_id(tpi->key); - ovs_ip_tun_rx_dst(tun_dst, skb, flags, - tun_id, sizeof(*md)); + tun_dst = rpl_ip_tun_rx_dst(skb, flags, tun_id, sizeof(*md)); + if (!tun_dst) + return PACKET_REJECT; md = ip_tunnel_info_opts(&tun_dst->u.tun_info); md->version = ver; @@ -182,6 +267,7 @@ static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi, skb_reset_mac_header(skb); ovs_ip_tunnel_rcv(tunnel->dev, skb, tun_dst); + kfree(tun_dst); return PACKET_RCVD; } drop: @@ -189,48 +275,68 @@ drop: return PACKET_RCVD; } -static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi) + +static int __ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi, + struct ip_tunnel_net *itn, int hdr_len, bool raw_proto) { - struct net *net = dev_net(skb->dev); struct metadata_dst tun_dst; - struct ip_tunnel_net *itn; const struct iphdr *iph; struct ip_tunnel *tunnel; - if (tpi->proto != htons(ETH_P_TEB)) - return PACKET_REJECT; - - itn = net_generic(net, gre_tap_net_id); - iph = ip_hdr(skb); - tunnel = rcu_dereference(itn->collect_md_tun); + tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags, + iph->saddr, iph->daddr, tpi->key); + if (tunnel) { - __be16 flags; - __be64 tun_id; - int err; + if (__iptunnel_pull_header(skb, hdr_len, tpi->proto, + raw_proto, false) < 0) + goto drop; - if (iptunnel_pull_offloads(skb)) - return PACKET_REJECT; + if (tunnel->dev->type != ARPHRD_NONE) + skb_pop_mac_header(skb); + else + skb_reset_mac_header(skb); + if (tunnel->collect_md) { + __be16 flags; + __be64 tun_id; - skb_pop_mac_header(skb); - flags = tpi->flags & (TUNNEL_CSUM | TUNNEL_KEY); - tun_id = key_to_tunnel_id(tpi->key); - ovs_ip_tun_rx_dst(&tun_dst, skb, flags, tun_id, 0); - - skb_reset_network_header(skb); - err = IP_ECN_decapsulate(iph, skb); - if (unlikely(err)) { - if (err > 1) { - ++tunnel->dev->stats.rx_frame_errors; - ++tunnel->dev->stats.rx_errors; - return PACKET_REJECT; - } + flags = tpi->flags & (TUNNEL_CSUM | TUNNEL_KEY); + tun_id = key32_to_tunnel_id(tpi->key); + ovs_ip_tun_rx_dst(&tun_dst, skb, flags, tun_id, 0); } ovs_ip_tunnel_rcv(tunnel->dev, skb, &tun_dst); return PACKET_RCVD; } - return PACKET_REJECT; + return PACKET_NEXT; + +drop: + kfree_skb(skb); + return PACKET_RCVD; +} + + +static int ipgre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *tpi, + int hdr_len) +{ + struct net *net = dev_net(skb->dev); + struct ip_tunnel_net *itn; + int res; + + if (tpi->proto == htons(ETH_P_TEB)) + itn = net_generic(net, gre_tap_net_id); + else + itn = net_generic(net, ipgre_net_id); + + res = __ipgre_rcv(skb, tpi, itn, hdr_len, false); + if (res == PACKET_NEXT && tpi->proto == htons(ETH_P_TEB)) { + /* ipgre tunnels in collect metadata mode should receive + * also ETH_P_TEB traffic. + */ + itn = net_generic(net, ipgre_net_id); + res = __ipgre_rcv(skb, tpi, itn, hdr_len, true); + } + return res; } static void __gre_xmit(struct sk_buff *skb, struct net_device *dev, @@ -253,6 +359,7 @@ static void __gre_xmit(struct sk_buff *skb, struct net_device *dev, ip_tunnel_xmit(skb, dev, tnl_params, tnl_params->protocol); } +#ifndef HAVE_DEMUX_PARSE_GRE_HEADER static int gre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *unused_tpi) { struct tnl_ptk_info tpi; @@ -270,13 +377,33 @@ static int gre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *unused_tpi) goto drop; } - if (ipgre_rcv(skb, &tpi) == PACKET_RCVD) + if (ipgre_rcv(skb, &tpi, hdr_len) == PACKET_RCVD) + return 0; +drop: + + kfree_skb(skb); + return 0; +} +#else +static int gre_rcv(struct sk_buff *skb, const struct tnl_ptk_info *__tpi) +{ + struct tnl_ptk_info tpi = *__tpi; + + if (unlikely(tpi.proto == htons(ETH_P_ERSPAN) || + tpi.proto == htons(ETH_P_ERSPAN2))) { + if (erspan_rcv(skb, &tpi, 0) == PACKET_RCVD) + return 0; + goto drop; + } + + if (ipgre_rcv(skb, &tpi, 0) == PACKET_RCVD) return 0; drop: kfree_skb(skb); return 0; } +#endif #if LINUX_VERSION_CODE < KERNEL_VERSION(4,7,0) /* gre_handle_offloads() has different return type on older kernsl. */ @@ -542,24 +669,25 @@ static void erspan_fb_xmit(struct sk_buff *skb, struct net_device *dev, if (version == 1) { erspan_build_header(skb, ntohl(tunnel_id_to_key32(key->tun_id)), ntohl(md->u.index), truncate, true); + tpi.hdr_len = ERSPAN_V1_MDSIZE; + tpi.proto = htons(ETH_P_ERSPAN); } else if (version == 2) { erspan_build_header_v2(skb, ntohl(tunnel_id_to_key32(key->tun_id)), md->u.md2.dir, get_hwid(&md->u.md2), truncate, true); - + tpi.hdr_len = ERSPAN_V2_MDSIZE; + tpi.proto = htons(ETH_P_ERSPAN2); } else { goto err_free_rt; } tpi.flags = (TUNNEL_KEY | TUNNEL_CSUM | TUNNEL_SEQ); - tpi.proto = htons(ETH_P_ERSPAN); tpi.key = tunnel_id_to_key32(key->tun_id); tpi.seq = htonl(tunnel->o_seqno++); - tpi.hdr_len = 8; - gre_build_header(skb, &tpi, 8); + gre_build_header(skb, &tpi, tunnel_hlen); df = key->tun_flags & TUNNEL_DONT_FRAGMENT ? htons(IP_DF) : 0; @@ -586,23 +714,27 @@ static void __gre_tunnel_init(struct net_device *dev) int t_hlen; tunnel = netdev_priv(dev); - tunnel->parms.iph.protocol = IPPROTO_GRE; tunnel->tun_hlen = ip_gre_calc_hlen(tunnel->parms.o_flags); + tunnel->parms.iph.protocol = IPPROTO_GRE; tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen; t_hlen = tunnel->hlen + sizeof(struct iphdr); - dev->needed_headroom = LL_MAX_HEADER + t_hlen + 4; - dev->mtu = ETH_DATA_LEN - t_hlen - 4; - dev->features |= GRE_FEATURES; dev->hw_features |= GRE_FEATURES; if (!(tunnel->parms.o_flags & TUNNEL_SEQ)) { - /* TCP offload with GRE SEQ is not supported. */ - dev->features |= NETIF_F_GSO_SOFTWARE; - dev->hw_features |= NETIF_F_GSO_SOFTWARE; + /* TCP offload with GRE SEQ is not supported, nor + * can we support 2 levels of outer headers requiring + * an update. + */ + if (!(tunnel->parms.o_flags & TUNNEL_CSUM) || + (tunnel->encap.type == TUNNEL_ENCAP_NONE)) { + dev->features |= NETIF_F_GSO_SOFTWARE; + dev->hw_features |= NETIF_F_GSO_SOFTWARE; + } + /* Can use a lockless transmit, unless we generate * output sequences */ @@ -616,6 +748,25 @@ static struct gre_cisco_protocol ipgre_protocol = { .priority = 1, }; +static int __net_init ipgre_init_net(struct net *net) +{ + return ip_tunnel_init_net(net, ipgre_net_id, &ipgre_link_ops, NULL); +} + +static void __net_exit ipgre_exit_net(struct net *net) +{ + struct ip_tunnel_net *itn = net_generic(net, ipgre_net_id); + + ip_tunnel_delete_net(itn, &ipgre_link_ops); +} + +static struct pernet_operations ipgre_net_ops = { + .init = ipgre_init_net, + .exit = ipgre_exit_net, + .id = &ipgre_net_id, + .size = sizeof(struct ip_tunnel_net), +}; + static int ipgre_tunnel_validate(struct nlattr *tb[], struct nlattr *data[]) { __be16 flags; @@ -717,14 +868,74 @@ static int erspan_validate(struct nlattr *tb[], struct nlattr *data[]) return 0; } -static void ipgre_netlink_parms(struct net_device *dev, - struct nlattr *data[], - struct nlattr *tb[], - struct ip_tunnel_parm *parms) +static int ipgre_netlink_parms(struct net_device *dev, + struct nlattr *data[], + struct nlattr *tb[], + struct ip_tunnel_parm *parms) { + struct ip_tunnel *t = netdev_priv(dev); + memset(parms, 0, sizeof(*parms)); parms->iph.protocol = IPPROTO_GRE; + + if (!data) + return 0; + + if (data[IFLA_GRE_LINK]) + parms->link = nla_get_u32(data[IFLA_GRE_LINK]); + + if (data[IFLA_GRE_IFLAGS]) + parms->i_flags = gre_flags_to_tnl_flags(nla_get_be16(data[IFLA_GRE_IFLAGS])); + + if (data[IFLA_GRE_OFLAGS]) + parms->o_flags = gre_flags_to_tnl_flags(nla_get_be16(data[IFLA_GRE_OFLAGS])); + + if (data[IFLA_GRE_IKEY]) + parms->i_key = nla_get_be32(data[IFLA_GRE_IKEY]); + + if (data[IFLA_GRE_OKEY]) + parms->o_key = nla_get_be32(data[IFLA_GRE_OKEY]); + + if (data[IFLA_GRE_LOCAL]) + parms->iph.saddr = nla_get_in_addr(data[IFLA_GRE_LOCAL]); + + if (data[IFLA_GRE_REMOTE]) + parms->iph.daddr = nla_get_in_addr(data[IFLA_GRE_REMOTE]); + + if (data[IFLA_GRE_TTL]) + parms->iph.ttl = nla_get_u8(data[IFLA_GRE_TTL]); + + if (data[IFLA_GRE_TOS]) + parms->iph.tos = nla_get_u8(data[IFLA_GRE_TOS]); + + if (!data[IFLA_GRE_PMTUDISC] || nla_get_u8(data[IFLA_GRE_PMTUDISC])) { + if (t->ignore_df) + return -EINVAL; + parms->iph.frag_off = htons(IP_DF); + } + + if (data[IFLA_GRE_COLLECT_METADATA]) { + t->collect_md = true; + if (dev->type == ARPHRD_IPGRE) + dev->type = ARPHRD_NONE; + } + + if (data[IFLA_GRE_IGNORE_DF]) { + if (nla_get_u8(data[IFLA_GRE_IGNORE_DF]) + && (parms->iph.frag_off & htons(IP_DF))) + return -EINVAL; + t->ignore_df = !!nla_get_u8(data[IFLA_GRE_IGNORE_DF]); + } + + if (data[IFLA_GRE_ERSPAN_INDEX]) { + t->index = nla_get_u32(data[IFLA_GRE_ERSPAN_INDEX]); + + if (t->index & ~INDEX_MASK) + return -EINVAL; + } + + return 0; } static int gre_tap_init(struct net_device *dev) @@ -788,6 +999,12 @@ free_skb: return NETDEV_TX_OK; } +static netdev_tx_t __erspan_fb_xmit(struct sk_buff *skb) +{ + erspan_fb_xmit(skb, skb->dev, skb->protocol); + return NETDEV_TX_OK; +} + int ovs_gre_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb) { struct ip_tunnel_info *info = skb_tunnel_info(skb); @@ -807,22 +1024,6 @@ int ovs_gre_fill_metadata_dst(struct net_device *dev, struct sk_buff *skb) } EXPORT_SYMBOL_GPL(ovs_gre_fill_metadata_dst); -static const struct net_device_ops gre_tap_netdev_ops = { - .ndo_init = gre_tap_init, - .ndo_uninit = ip_tunnel_uninit, - .ndo_start_xmit = gre_dev_xmit, - .ndo_set_mac_address = eth_mac_addr, - .ndo_validate_addr = eth_validate_addr, - .ndo_change_mtu = ip_tunnel_change_mtu, - .ndo_get_stats64 = rpl_ip_tunnel_get_stats64, -#ifdef HAVE_NDO_GET_IFLINK - .ndo_get_iflink = rpl_ip_tunnel_get_iflink, -#endif -#ifdef HAVE_NDO_FILL_METADATA_DST - .ndo_fill_metadata_dst = gre_fill_metadata_dst, -#endif -}; - static int erspan_tunnel_init(struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); @@ -844,6 +1045,135 @@ static int erspan_tunnel_init(struct net_device *dev) return ip_tunnel_init(dev); } +static int ipgre_header(struct sk_buff *skb, struct net_device *dev, + unsigned short type, + const void *daddr, const void *saddr, unsigned int len) +{ + struct ip_tunnel *t = netdev_priv(dev); + struct iphdr *iph; + struct gre_base_hdr *greh; + + iph = (struct iphdr *)__skb_push(skb, t->hlen + sizeof(*iph)); + greh = (struct gre_base_hdr *)(iph+1); + greh->flags = gre_tnl_flags_to_gre_flags(t->parms.o_flags); + greh->protocol = htons(type); + + memcpy(iph, &t->parms.iph, sizeof(struct iphdr)); + + /* Set the source hardware address. */ + if (saddr) + memcpy(&iph->saddr, saddr, 4); + if (daddr) + memcpy(&iph->daddr, daddr, 4); + if (iph->daddr) + return t->hlen + sizeof(*iph); + + return -(t->hlen + sizeof(*iph)); +} + +static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr) +{ + const struct iphdr *iph = (const struct iphdr *) skb_mac_header(skb); + memcpy(haddr, &iph->saddr, 4); + return 4; +} + +static const struct header_ops ipgre_header_ops = { + .create = ipgre_header, + .parse = ipgre_header_parse, +}; + +static int ipgre_tunnel_init(struct net_device *dev) +{ + struct ip_tunnel *tunnel = netdev_priv(dev); + struct iphdr *iph = &tunnel->parms.iph; + + __gre_tunnel_init(dev); + + memcpy(dev->dev_addr, &iph->saddr, 4); + memcpy(dev->broadcast, &iph->daddr, 4); + + dev->flags = IFF_NOARP; + netif_keep_dst(dev); + dev->addr_len = 4; + + if (!tunnel->collect_md) { + dev->header_ops = &ipgre_header_ops; + } + + return ip_tunnel_init(dev); +} + +static netdev_tx_t ipgre_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct ip_tunnel *tunnel = netdev_priv(dev); + const struct iphdr *tnl_params; + + if (tunnel->collect_md) { + gre_fb_xmit(skb); + return NETDEV_TX_OK; + } + + if (dev->header_ops) { + /* Need space for new headers */ + if (skb_cow_head(skb, dev->needed_headroom - + (tunnel->hlen + sizeof(struct iphdr)))) + goto free_skb; + + tnl_params = (const struct iphdr *)skb->data; + + /* Pull skb since ip_tunnel_xmit() needs skb->data pointing + * to gre header. + */ + skb_pull(skb, tunnel->hlen + sizeof(struct iphdr)); + skb_reset_mac_header(skb); + } else { + if (skb_cow_head(skb, dev->needed_headroom)) + goto free_skb; + + tnl_params = &tunnel->parms.iph; + } + + if (gre_handle_offloads(skb, !!(tunnel->parms.o_flags & TUNNEL_CSUM))) + goto free_skb; + + __gre_xmit(skb, dev, tnl_params, skb->protocol); + return NETDEV_TX_OK; + +free_skb: + kfree_skb(skb); + dev->stats.tx_dropped++; + return NETDEV_TX_OK; +} + +static const struct net_device_ops ipgre_netdev_ops = { + .ndo_init = ipgre_tunnel_init, + .ndo_uninit = rpl_ip_tunnel_uninit, + .ndo_start_xmit = ipgre_xmit, + .ndo_change_mtu = ip_tunnel_change_mtu, + .ndo_get_stats64 = ip_tunnel_get_stats64, +#ifdef HAVE_GET_LINK_NET + .ndo_get_iflink = ip_tunnel_get_iflink, +#endif +}; + +static const struct net_device_ops gre_tap_netdev_ops = { + .ndo_init = gre_tap_init, + .ndo_uninit = rpl_ip_tunnel_uninit, + .ndo_start_xmit = gre_dev_xmit, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = ip_tunnel_change_mtu, + .ndo_get_stats64 = rpl_ip_tunnel_get_stats64, +#ifdef HAVE_NDO_GET_IFLINK + .ndo_get_iflink = rpl_ip_tunnel_get_iflink, +#endif +#ifdef HAVE_NDO_FILL_METADATA_DST + .ndo_fill_metadata_dst = gre_fill_metadata_dst, +#endif +}; + static const struct net_device_ops erspan_netdev_ops = { .ndo_init = erspan_tunnel_init, .ndo_uninit = rpl_ip_tunnel_uninit, @@ -860,6 +1190,13 @@ static const struct net_device_ops erspan_netdev_ops = { #endif }; +static void ipgre_tunnel_setup(struct net_device *dev) +{ + dev->netdev_ops = &ipgre_netdev_ops; + dev->type = ARPHRD_IPGRE; + ip_tunnel_setup(dev, ipgre_net_id); +} + static void ipgre_tap_setup(struct net_device *dev) { ether_setup(dev); @@ -871,6 +1208,16 @@ static void ipgre_tap_setup(struct net_device *dev) ip_tunnel_setup(dev, gre_tap_net_id); } +static void erspan_setup(struct net_device *dev) +{ + eth_hw_addr_random(dev); + ether_setup(dev); + dev->netdev_ops = &erspan_netdev_ops; + dev->priv_flags &= ~IFF_TX_SKB_SHARING; + dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; + ip_tunnel_setup(dev, erspan_net_id); +} + static int ipgre_newlink(struct net *src_net, struct net_device *dev, struct nlattr *tb[], struct nlattr *data[]) { @@ -964,15 +1311,6 @@ nla_put_failure: return -EMSGSIZE; } -static void erspan_setup(struct net_device *dev) -{ - ether_setup(dev); - dev->netdev_ops = &erspan_netdev_ops; - dev->priv_flags &= ~IFF_TX_SKB_SHARING; - dev->priv_flags |= IFF_LIVE_ADDR_CHANGE; - ip_tunnel_setup(dev, erspan_net_id); -} - static const struct nla_policy ipgre_policy[RPL_IFLA_GRE_MAX + 1] = { [IFLA_GRE_LINK] = { .type = NLA_U32 }, [IFLA_GRE_IFLAGS] = { .type = NLA_U16 }, @@ -990,6 +1328,22 @@ static const struct nla_policy ipgre_policy[RPL_IFLA_GRE_MAX + 1] = { [IFLA_GRE_ERSPAN_HWID] = { .type = NLA_U16 }, }; +static struct rtnl_link_ops ipgre_link_ops __read_mostly = { + .kind = "gre", + .maxtype = RPL_IFLA_GRE_MAX, + .policy = ipgre_policy, + .priv_size = sizeof(struct ip_tunnel), + .setup = ipgre_tunnel_setup, + .validate = ipgre_tunnel_validate, + .newlink = ipgre_newlink, + .dellink = ip_tunnel_dellink, + .get_size = ipgre_get_size, + .fill_info = ipgre_fill_info, +#ifdef HAVE_GET_LINK_NET + .get_link_net = ip_tunnel_get_link_net, +#endif +}; + static struct rtnl_link_ops ipgre_tap_ops __read_mostly = { .kind = "ovs_gretap", .maxtype = RPL_IFLA_GRE_MAX, @@ -1065,7 +1419,7 @@ EXPORT_SYMBOL_GPL(rpl_gretap_fb_dev_create); static int __net_init erspan_init_net(struct net *net) { return ip_tunnel_init_net(net, erspan_net_id, - &erspan_link_ops, "erspan0"); + &erspan_link_ops, NULL); } static void __net_exit erspan_exit_net(struct net *net) @@ -1101,6 +1455,154 @@ static struct pernet_operations ipgre_tap_net_ops = { .size = sizeof(struct ip_tunnel_net), }; +static struct net_device *erspan_fb_dev_create(struct net *net, + const char *name, + u8 name_assign_type) +{ + struct nlattr *tb[IFLA_MAX + 1]; + struct net_device *dev; + LIST_HEAD(list_kill); + struct ip_tunnel *t; + int err; + + memset(&tb, 0, sizeof(tb)); + + dev = rtnl_create_link(net, (char *)name, name_assign_type, + &erspan_link_ops, tb); + if (IS_ERR(dev)) + return dev; + + t = netdev_priv(dev); + t->collect_md = true; + /* Configure flow based GRE device. */ + err = ipgre_newlink(net, dev, tb, NULL); + if (err < 0) { + free_netdev(dev); + return ERR_PTR(err); + } + + /* openvswitch users expect packet sizes to be unrestricted, + * so set the largest MTU we can. + */ + err = __ip_tunnel_change_mtu(dev, IP_MAX_MTU, false); + if (err) + goto out; + + return dev; +out: + ip_tunnel_dellink(dev, &list_kill); + unregister_netdevice_many(&list_kill); + return ERR_PTR(err); +} + +static struct vport_ops ovs_erspan_vport_ops; + +static struct vport *erspan_tnl_create(const struct vport_parms *parms) +{ + struct net *net = ovs_dp_get_net(parms->dp); + struct net_device *dev; + struct vport *vport; + int err; + + vport = ovs_vport_alloc(0, &ovs_erspan_vport_ops, parms); + if (IS_ERR(vport)) + return vport; + + rtnl_lock(); + dev = erspan_fb_dev_create(net, parms->name, NET_NAME_USER); + if (IS_ERR(dev)) { + rtnl_unlock(); + ovs_vport_free(vport); + return ERR_CAST(dev); + } + + err = dev_change_flags(dev, dev->flags | IFF_UP); + if (err < 0) { + rtnl_delete_link(dev); + rtnl_unlock(); + ovs_vport_free(vport); + return ERR_PTR(err); + } + + rtnl_unlock(); + return vport; +} + +static struct vport *erspan_create(const struct vport_parms *parms) +{ + struct vport *vport; + + vport = erspan_tnl_create(parms); + if (IS_ERR(vport)) + return vport; + + return ovs_netdev_link(vport, parms->name); +} + +static struct vport_ops ovs_erspan_vport_ops = { + .type = OVS_VPORT_TYPE_ERSPAN, + .create = erspan_create, + .send = __erspan_fb_xmit, +#ifndef USE_UPSTREAM_TUNNEL + .fill_metadata_dst = gre_fill_metadata_dst, +#endif + .destroy = ovs_netdev_tunnel_destroy, +}; + +static struct vport_ops ovs_ipgre_vport_ops; + +static struct vport *ipgre_tnl_create(const struct vport_parms *parms) +{ + struct net *net = ovs_dp_get_net(parms->dp); + struct net_device *dev; + struct vport *vport; + int err; + + vport = ovs_vport_alloc(0, &ovs_ipgre_vport_ops, parms); + if (IS_ERR(vport)) + return vport; + + rtnl_lock(); + dev = gretap_fb_dev_create(net, parms->name, NET_NAME_USER); + if (IS_ERR(dev)) { + rtnl_unlock(); + ovs_vport_free(vport); + return ERR_CAST(dev); + } + + err = dev_change_flags(dev, dev->flags | IFF_UP); + if (err < 0) { + rtnl_delete_link(dev); + rtnl_unlock(); + ovs_vport_free(vport); + return ERR_PTR(err); + } + + rtnl_unlock(); + return vport; +} + +static struct vport *ipgre_create(const struct vport_parms *parms) +{ + struct vport *vport; + + vport = ipgre_tnl_create(parms); + if (IS_ERR(vport)) + return vport; + + return ovs_netdev_link(vport, parms->name); +} + +static struct vport_ops ovs_ipgre_vport_ops = { + .type = OVS_VPORT_TYPE_GRE, + .create = ipgre_create, + .send = gre_fb_xmit, +#ifndef USE_UPSTREAM_TUNNEL + .fill_metadata_dst = gre_fill_metadata_dst, +#endif + .destroy = ovs_netdev_tunnel_destroy, +}; + int rpl_ipgre_init(void) { int err; @@ -1113,28 +1615,25 @@ int rpl_ipgre_init(void) if (err < 0) goto pnet_erspan_failed; + err = register_pernet_device(&ipgre_net_ops); + if (err < 0) + goto pnet_ipgre_failed; + err = gre_cisco_register(&ipgre_protocol); if (err < 0) { pr_info("%s: can't add protocol\n", __func__); goto add_proto_failed; } - err = rtnl_link_register(&ipgre_tap_ops); - if (err < 0) - goto tap_ops_failed; - - err = rtnl_link_register(&erspan_link_ops); - if (err < 0) - goto erspan_link_failed; - pr_info("GRE over IPv4 tunneling driver\n"); + + ovs_vport_ops_register(&ovs_ipgre_vport_ops); + ovs_vport_ops_register(&ovs_erspan_vport_ops); return 0; -erspan_link_failed: - rtnl_link_unregister(&ipgre_tap_ops); -tap_ops_failed: - gre_cisco_unregister(&ipgre_protocol); add_proto_failed: + unregister_pernet_device(&ipgre_net_ops); +pnet_ipgre_failed: unregister_pernet_device(&erspan_net_ops); pnet_erspan_failed: unregister_pernet_device(&ipgre_tap_net_ops); @@ -1145,11 +1644,12 @@ pnet_tap_failed: void rpl_ipgre_fini(void) { - rtnl_link_unregister(&ipgre_tap_ops); - rtnl_link_unregister(&erspan_link_ops); + ovs_vport_ops_unregister(&ovs_erspan_vport_ops); + ovs_vport_ops_unregister(&ovs_ipgre_vport_ops); gre_cisco_unregister(&ipgre_protocol); - unregister_pernet_device(&ipgre_tap_net_ops); + unregister_pernet_device(&ipgre_net_ops); unregister_pernet_device(&erspan_net_ops); + unregister_pernet_device(&ipgre_tap_net_ops); } #endif diff --git a/datapath/linux/compat/ip_tunnel.c b/datapath/linux/compat/ip_tunnel.c index d8cd798..68855c7 100644 --- a/datapath/linux/compat/ip_tunnel.c +++ b/datapath/linux/compat/ip_tunnel.c @@ -64,18 +64,58 @@ const struct ip_tunnel_encap_ops __rcu * rpl_iptun_encaps[MAX_IPTUN_ENCAP_OPS] __read_mostly; +static unsigned int rpl_ip_tunnel_hash(__be32 key, __be32 remote) +{ + return hash_32((__force u32)key ^ (__force u32)remote, + IP_TNL_HASH_BITS); +} + +static bool rpl_ip_tunnel_key_match(const struct ip_tunnel_parm *p, + __be16 flags, __be32 key) +{ + if (p->i_flags & TUNNEL_KEY) { + if (flags & TUNNEL_KEY) + return key == p->i_key; + else + /* key expected, none present */ + return false; + } else + return !(flags & TUNNEL_KEY); +} + +static struct hlist_head *ip_bucket(struct ip_tunnel_net *itn, + struct ip_tunnel_parm *parms) +{ + unsigned int h; + __be32 remote; + __be32 i_key = parms->i_key; + + if (parms->iph.daddr && !ipv4_is_multicast(parms->iph.daddr)) + remote = parms->iph.daddr; + else + remote = 0; + + if (!(parms->i_flags & TUNNEL_KEY) && (parms->i_flags & VTI_ISVTI)) + i_key = 0; + + h = rpl_ip_tunnel_hash(i_key, remote); + return &itn->tunnels[h]; +} + static void ip_tunnel_add(struct ip_tunnel_net *itn, struct ip_tunnel *t) { + struct hlist_head *head = ip_bucket(itn, &t->parms); + if (t->collect_md) rcu_assign_pointer(itn->collect_md_tun, t); - else - WARN_ONCE(1, "%s: collect md not set\n", t->dev->name); + hlist_add_head_rcu(&t->hash_node, head); } static void ip_tunnel_del(struct ip_tunnel_net *itn, struct ip_tunnel *t) { if (t->collect_md) rcu_assign_pointer(itn->collect_md_tun, NULL); + hlist_del_init_rcu(&t->hash_node); } static struct net_device *__ip_tunnel_create(struct net *net, @@ -165,6 +205,8 @@ static int ip_tunnel_bind_dev(struct net_device *dev) } if (dev->type != ARPHRD_ETHER) dev->flags |= IFF_POINTOPOINT; + + dst_cache_reset(&tunnel->dst_cache); } if (!tdev && tunnel->parms.link) @@ -479,15 +521,31 @@ int rpl_ip_tunnel_init_net(struct net *net, int ip_tnl_net_id, static void ip_tunnel_destroy(struct ip_tunnel_net *itn, struct list_head *head, struct rtnl_link_ops *ops) { - struct ip_tunnel *t; + struct net *net = dev_net(itn->fb_tunnel_dev); + struct net_device *dev, *aux; + int h; + + for_each_netdev_safe(net, dev, aux) + if (dev->rtnl_link_ops == ops) + unregister_netdevice_queue(dev, head); + + for (h = 0; h < IP_TNL_HASH_SIZE; h++) { + struct ip_tunnel *t; + struct hlist_node *n; + struct hlist_head *thead = &itn->tunnels[h]; + + hlist_for_each_entry_safe(t, n, thead, hash_node) + /* If dev is in the same netns, it has already + * been added to the list by the previous loop. + */ + if (!net_eq(dev_net(t->dev), net)) + unregister_netdevice_queue(t->dev, head); + } - t = rtnl_dereference(itn->collect_md_tun); - if (!t) - return; - unregister_netdevice_queue(t->dev, head); } -void rpl_ip_tunnel_delete_net(struct ip_tunnel_net *itn, struct rtnl_link_ops *ops) +void rpl_ip_tunnel_delete_net(struct ip_tunnel_net *itn, + struct rtnl_link_ops *ops) { LIST_HEAD(list); @@ -608,25 +666,6 @@ struct net *rpl_ip_tunnel_get_link_net(const struct net_device *dev) return tunnel->net; } -static unsigned int rpl_ip_tunnel_hash(__be32 key, __be32 remote) -{ - return hash_32((__force u32)key ^ (__force u32)remote, - IP_TNL_HASH_BITS); -} - -static bool rpl_ip_tunnel_key_match(const struct ip_tunnel_parm *p, - __be16 flags, __be32 key) -{ - if (p->i_flags & TUNNEL_KEY) { - if (flags & TUNNEL_KEY) - return key == p->i_key; - else - /* key expected, none present */ - return false; - } else - return !(flags & TUNNEL_KEY); -} - struct ip_tunnel *rpl_ip_tunnel_lookup(struct ip_tunnel_net *itn, int link, __be16 flags, __be32 remote, __be32 local, diff --git a/datapath/vport.c b/datapath/vport.c index e5221e9..f4131be 100644 --- a/datapath/vport.c +++ b/datapath/vport.c @@ -112,6 +112,8 @@ void ovs_vport_exit(void) ovs_stt_cleanup_module(); vxlan_cleanup_module(); geneve_cleanup_module(); + ip6_tunnel_cleanup(); + ip6gre_fini(); ipgre_fini(); lisp_cleanup_module(); kfree(dev_table);