From: William Tu <u9012...@gmail.com>
Date: Wed,  9 Aug 2017 13:53:05 -0700

> 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 traffic can
> also be encapsulated into ERSPAN and sent out.
> 
> The implementation reuses the 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
> 
> [1] https://tools.ietf.org/html/draft-foschiano-erspan-01
> [2] iproute patch: http://marc.info/?l=linux-netdev&m=150231090207544&w=2
> 
> Signed-off-by: William Tu <u9012...@gmail.com>
> Signed-off-by: Meenakshi Vohra <mvo...@vmware.com>
> Cc: Alexey Kuznetsov <kuz...@ms2.inr.ac.ru>
> Cc: Hideaki YOSHIFUJI <yoshf...@linux-ipv6.org>
> ---
> v1->v2: 
>  Add missing erspan.h header
> 
> ---
>  include/net/erspan.h           |  62 +++++++++++
>  include/net/ip_tunnels.h       |   3 +
>  include/uapi/linux/if_ether.h  |   1 +
>  include/uapi/linux/if_tunnel.h |   1 +
>  net/ipv4/ip_gre.c              | 248 
> +++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 315 insertions(+)
>  create mode 100644 include/net/erspan.h
> 
> diff --git a/include/net/erspan.h b/include/net/erspan.h
> new file mode 100644
> index 000000000000..cafe387a2cae
> --- /dev/null
> +++ b/include/net/erspan.h
> @@ -0,0 +1,62 @@
> +#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 BOS_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
> diff --git a/include/net/ip_tunnels.h b/include/net/ip_tunnels.h
> index 520809912f03..625c29329372 100644
> --- a/include/net/ip_tunnels.h
> +++ b/include/net/ip_tunnels.h
> @@ -115,6 +115,9 @@ struct ip_tunnel {
>       u32             o_seqno;        /* The last output seqno */
>       int             tun_hlen;       /* Precalculated header length */
>  
> +     /* This field used only by ERSPAN */
> +     u32             index;          /* ERSPAN type II index */
> +
>       struct dst_cache dst_cache;
>  
>       struct ip_tunnel_parm parms;
> diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h
> index 5bc9bfd816b7..efeb1190c2ca 100644
> --- a/include/uapi/linux/if_ether.h
> +++ b/include/uapi/linux/if_ether.h
> @@ -66,6 +66,7 @@
>  #define ETH_P_ATALK  0x809B          /* Appletalk DDP                */
>  #define ETH_P_AARP   0x80F3          /* Appletalk AARP               */
>  #define ETH_P_8021Q  0x8100          /* 802.1Q VLAN Extended Header  */
> +#define ETH_P_ERSPAN 0x88BE          /* ERSPAN type II               */
>  #define ETH_P_IPX    0x8137          /* IPX over DIX                 */
>  #define ETH_P_IPV6   0x86DD          /* IPv6 over bluebook           */
>  #define ETH_P_PAUSE  0x8808          /* IEEE Pause frames. See 802.3 31B */
> diff --git a/include/uapi/linux/if_tunnel.h b/include/uapi/linux/if_tunnel.h
> index 6792d1967d31..2e520883c054 100644
> --- a/include/uapi/linux/if_tunnel.h
> +++ b/include/uapi/linux/if_tunnel.h
> @@ -134,6 +134,7 @@ enum {
>       IFLA_GRE_COLLECT_METADATA,
>       IFLA_GRE_IGNORE_DF,
>       IFLA_GRE_FWMARK,
> +     IFLA_GRE_ERSPAN_INDEX,
>       __IFLA_GRE_MAX,
>  };
>  
> diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
> index 7a7829e839c2..e15d5f01cdb5 100644
> --- a/net/ipv4/ip_gre.c
> +++ b/net/ipv4/ip_gre.c
> @@ -48,6 +48,7 @@
>  #include <net/rtnetlink.h>
>  #include <net/gre.h>
>  #include <net/dst_metadata.h>
> +#include <net/erspan.h>
>  
>  /*
>     Problems & solutions
> @@ -115,6 +116,7 @@ static int ipgre_tunnel_init(struct net_device *dev);
>  
>  static unsigned int ipgre_net_id __read_mostly;
>  static unsigned int gre_tap_net_id __read_mostly;
> +static unsigned int erspan_net_id __read_mostly;
>  
>  static void ipgre_err(struct sk_buff *skb, u32 info,
>                     const struct tnl_ptk_info *tpi)
> @@ -246,6 +248,48 @@ static void gre_err(struct sk_buff *skb, u32 info)
>       ipgre_err(skb, info, &tpi);
>  }
>  
> +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 ip_tunnel_net *itn;
> +     struct ip_tunnel *tunnel;
> +     struct metadata_dst *tun_dst = NULL;
> +     const struct iphdr *iph;
> +     struct erspanhdr *ershdr;
> +     __be32 index;
> +     __be32 session_id;
> +
> +     itn = net_generic(net, erspan_net_id);
> +     iph = ip_hdr(skb);
> +     ershdr = (struct erspanhdr *)(skb->data + gre_hdr_len);

You're not guaranteed the this ershdr area is pulled linearly in the
SKB.  Only the GRE header and it's options have that guarantee.

So you'll need to add appropriate pskb_may_pull() checks here then
reaload all of the packet pointers (including 'iph') afterwards.

Reply via email to