erspan: Add type I version 0 support.
authorWilliam Tu <u9012063@gmail.com>
Tue, 5 May 2020 16:05:06 +0000 (09:05 -0700)
committerDavid S. Miller <davem@davemloft.net>
Tue, 5 May 2020 20:23:29 +0000 (13:23 -0700)
The Type I ERSPAN frame format is based on the barebones
IP + GRE(4-byte) encapsulation on top of the raw mirrored frame.
Both type I and II use 0x88BE as protocol type. Unlike type II
and III, no sequence number or key is required.
To creat a type I erspan tunnel device:
  $ ip link add dev erspan11 type erspan \
            local 172.16.1.100 remote 172.16.1.200 \
            erspan_ver 0

Signed-off-by: William Tu <u9012063@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/erspan.h
net/ipv4/ip_gre.c

index b39643ef4c95fa0727bea05b15d26625e80940c4..0d9e86bd98934be23d3d699ca421b59754047755 100644 (file)
@@ -2,7 +2,19 @@
 #define __LINUX_ERSPAN_H
 
 /*
- * GRE header for ERSPAN encapsulation (8 octets [34:41]) -- 8 bytes
+ * GRE header for ERSPAN type I encapsulation (4 octets [34:37])
+ *      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|0|0|00000|000000000|00000|    Protocol Type for ERSPAN   |
+ *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *
+ *  The Type I ERSPAN frame format is based on the barebones IP + GRE
+ *  encapsulation (as described above) on top of the raw mirrored frame.
+ *  There is no extra ERSPAN header.
+ *
+ *
+ * GRE header for ERSPAN type II and II encapsulation (8 octets [34:41])
  *       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
  *     +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
@@ -43,7 +55,7 @@
  * |                  Platform Specific Info                       |
  * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  *
- * GRE proto ERSPAN type II = 0x88BE, type III = 0x22EB
+ * GRE proto ERSPAN type I/II = 0x88BE, type III = 0x22EB
  */
 
 #include <uapi/linux/erspan.h>
@@ -139,6 +151,9 @@ static inline u8 get_hwid(const struct erspan_md2 *md2)
 
 static inline int erspan_hdr_len(int version)
 {
+       if (version == 0)
+               return 0;
+
        return sizeof(struct erspan_base_hdr) +
               (version == 1 ? ERSPAN_V1_MDSIZE : ERSPAN_V2_MDSIZE);
 }
index 029b24eeafbaf8ec28b0f55ff08de58b8fb0efdd..e29cd48674d7ebbf03f0a4b74c0a8a8adcd181f6 100644 (file)
@@ -248,6 +248,15 @@ static void gre_err(struct sk_buff *skb, u32 info)
        ipgre_err(skb, info, &tpi);
 }
 
+static bool is_erspan_type1(int gre_hdr_len)
+{
+       /* Both ERSPAN type I (version 0) and type II (version 1) use
+        * protocol 0x88BE, but the type I has only 4-byte GRE header,
+        * while type II has 8-byte.
+        */
+       return gre_hdr_len == 4;
+}
+
 static int erspan_rcv(struct sk_buff *skb, struct tnl_ptk_info *tpi,
                      int gre_hdr_len)
 {
@@ -262,17 +271,26 @@ 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);
-       ershdr = (struct erspan_base_hdr *)(skb->data + gre_hdr_len);
-       ver = ershdr->ver;
-
-       tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex,
-                                 tpi->flags | TUNNEL_KEY,
-                                 iph->saddr, iph->daddr, tpi->key);
+       if (is_erspan_type1(gre_hdr_len)) {
+               ver = 0;
+               tunnel = ip_tunnel_lookup(itn, skb->dev->ifindex,
+                                         tpi->flags | TUNNEL_NO_KEY,
+                                         iph->saddr, iph->daddr, 0);
+       } else {
+               ershdr = (struct erspan_base_hdr *)(skb->data + gre_hdr_len);
+               ver = ershdr->ver;
+               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 (is_erspan_type1(gre_hdr_len))
+                       len = gre_hdr_len;
+               else
+                       len = gre_hdr_len + erspan_hdr_len(ver);
+
                if (unlikely(!pskb_may_pull(skb, len)))
                        return PACKET_REJECT;
 
@@ -665,7 +683,10 @@ static netdev_tx_t erspan_xmit(struct sk_buff *skb,
        }
 
        /* Push ERSPAN header */
-       if (tunnel->erspan_ver == 1) {
+       if (tunnel->erspan_ver == 0) {
+               proto = htons(ETH_P_ERSPAN);
+               tunnel->parms.o_flags &= ~TUNNEL_SEQ;
+       } else if (tunnel->erspan_ver == 1) {
                erspan_build_header(skb, ntohl(tunnel->parms.o_key),
                                    tunnel->index,
                                    truncate, true);
@@ -1066,7 +1087,10 @@ static int erspan_validate(struct nlattr *tb[], struct nlattr *data[],
        if (ret)
                return ret;
 
-       /* ERSPAN should only have GRE sequence and key flag */
+       if (nla_get_u8(data[IFLA_GRE_ERSPAN_VER]) == 0)
+               return 0;
+
+       /* ERSPAN type II/III 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])
@@ -1174,7 +1198,7 @@ static int erspan_netlink_parms(struct net_device *dev,
        if (data[IFLA_GRE_ERSPAN_VER]) {
                t->erspan_ver = nla_get_u8(data[IFLA_GRE_ERSPAN_VER]);
 
-               if (t->erspan_ver != 1 && t->erspan_ver != 2)
+               if (t->erspan_ver > 2)
                        return -EINVAL;
        }
 
@@ -1259,7 +1283,11 @@ static int erspan_tunnel_init(struct net_device *dev)
 {
        struct ip_tunnel *tunnel = netdev_priv(dev);
 
-       tunnel->tun_hlen = 8;
+       if (tunnel->erspan_ver == 0)
+               tunnel->tun_hlen = 4; /* 4-byte GRE hdr. */
+       else
+               tunnel->tun_hlen = 8; /* 8-byte GRE hdr. */
+
        tunnel->parms.iph.protocol = IPPROTO_GRE;
        tunnel->hlen = tunnel->tun_hlen + tunnel->encap_hlen +
                       erspan_hdr_len(tunnel->erspan_ver);
@@ -1456,8 +1484,8 @@ static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
        struct ip_tunnel_parm *p = &t->parms;
        __be16 o_flags = p->o_flags;
 
-       if (t->erspan_ver == 1 || t->erspan_ver == 2) {
-               if (!t->collect_md)
+       if (t->erspan_ver <= 2) {
+               if (t->erspan_ver != 0 && !t->collect_md)
                        o_flags |= TUNNEL_KEY;
 
                if (nla_put_u8(skb, IFLA_GRE_ERSPAN_VER, t->erspan_ver))
@@ -1466,7 +1494,7 @@ static int ipgre_fill_info(struct sk_buff *skb, const struct net_device *dev)
                if (t->erspan_ver == 1) {
                        if (nla_put_u32(skb, IFLA_GRE_ERSPAN_INDEX, t->index))
                                goto nla_put_failure;
-               } else {
+               } 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))