The patch adds support for configuring the erspan v2, for both
ipv4 and ipv6 erspan implementation.  Three additional fields
are added: 'erspan_ver' for distinguishing v1 or v2, 'erspan_dir'
for specifying direction of the mirrored traffic, and 'erspan_hwid'
for users to set ERSPAN engine ID within a system.

For details of version II, see
https://tools.ietf.org/html/draft-foschiano-erspan-03

Signed-off-by: William Tu <u9012...@gmail.com>
---
 include/uapi/linux/if_ether.h  |  1 +
 include/uapi/linux/if_tunnel.h |  3 +++
 ip/link_gre.c                  | 59 +++++++++++++++++++++++++++++++++++++---
 ip/link_gre6.c                 | 61 +++++++++++++++++++++++++++++++++++++++---
 4 files changed, 117 insertions(+), 7 deletions(-)

diff --git a/include/uapi/linux/if_ether.h b/include/uapi/linux/if_ether.h
index 2eb529a90250..5fd5c12ef8e9 100644
--- a/include/uapi/linux/if_ether.h
+++ b/include/uapi/linux/if_ether.h
@@ -47,6 +47,7 @@
 #define ETH_P_PUP      0x0200          /* Xerox PUP packet             */
 #define ETH_P_PUPAT    0x0201          /* Xerox PUP Addr Trans packet  */
 #define ETH_P_TSN      0x22F0          /* TSN (IEEE 1722) packet       */
+#define ETH_P_ERsPAN2  0x22EB          /* ERSPAN version 2 (type III)  */
 #define ETH_P_IP       0x0800          /* Internet Protocol packet     */
 #define ETH_P_X25      0x0805          /* CCITT X.25                   */
 #define ETH_P_ARP      0x0806          /* Address Resolution packet    */
diff --git a/include/uapi/linux/if_tunnel.h b/include/uapi/linux/if_tunnel.h
index 38cdf90692f8..29602df037e9 100644
--- a/include/uapi/linux/if_tunnel.h
+++ b/include/uapi/linux/if_tunnel.h
@@ -137,6 +137,9 @@ enum {
        IFLA_GRE_IGNORE_DF,
        IFLA_GRE_FWMARK,
        IFLA_GRE_ERSPAN_INDEX,
+        IFLA_GRE_ERSPAN_VER,
+        IFLA_GRE_ERSPAN_DIR,
+        IFLA_GRE_ERSPAN_HWID,
        __IFLA_GRE_MAX,
 };
 
diff --git a/ip/link_gre.c b/ip/link_gre.c
index 43cb1af6196a..924a05530f5c 100644
--- a/ip/link_gre.c
+++ b/ip/link_gre.c
@@ -98,6 +98,9 @@ static int gre_parse_opt(struct link_util *lu, int argc, char 
**argv,
        __u8 ignore_df = 0;
        __u32 fwmark = 0;
        __u32 erspan_idx = 0;
+       __u8 erspan_ver = 0;
+       __u8 erspan_dir = 0;
+       __u16 erspan_hwid = 0;
 
        if (!(n->nlmsg_flags & NLM_F_CREATE)) {
                if (rtnl_talk(&rth, &req.n, &answer) < 0) {
@@ -179,6 +182,15 @@ get_failed:
                if (greinfo[IFLA_GRE_ERSPAN_INDEX])
                        erspan_idx = 
rta_getattr_u32(greinfo[IFLA_GRE_ERSPAN_INDEX]);
 
+               if (greinfo[IFLA_GRE_ERSPAN_VER])
+                       erspan_ver = 
rta_getattr_u8(greinfo[IFLA_GRE_ERSPAN_VER]);
+
+               if (greinfo[IFLA_GRE_ERSPAN_DIR])
+                       erspan_dir = 
rta_getattr_u8(greinfo[IFLA_GRE_ERSPAN_DIR]);
+
+               if (greinfo[IFLA_GRE_ERSPAN_HWID])
+                       erspan_hwid = 
rta_getattr_u16(greinfo[IFLA_GRE_ERSPAN_HWID]);
+
                free(answer);
        }
 
@@ -343,6 +355,22 @@ get_failed:
                                invarg("invalid erspan index\n", *argv);
                        if (erspan_idx & ~((1<<20) - 1) || erspan_idx == 0)
                                invarg("erspan index must be > 0 and <= 
20-bit\n", *argv);
+               } else if (strcmp(*argv, "erspan_ver") == 0) {
+                       NEXT_ARG();
+                       if (get_u8(&erspan_ver, *argv, 0))
+                               invarg("invalid erspan version\n", *argv);
+                       if (erspan_ver != 1 && erspan_ver != 2)
+                               invarg("erspan version must be 1 or 2\n", 
*argv);
+               } else if (strcmp(*argv, "erspan_dir") == 0) {
+                       NEXT_ARG();
+                       if (get_u8(&erspan_dir, *argv, 0))
+                               invarg("invalid erspan direction\n", *argv);
+                       if (erspan_dir != 0 && erspan_dir != 1)
+                               invarg("erspan direction must be 0(Ingress) or 
1(Egress)\n", *argv);
+               } else if (strcmp(*argv, "erspan_hwid") == 0) {
+                       NEXT_ARG();
+                       if (get_u16(&erspan_hwid, *argv, 0))
+                               invarg("invalid erspan hwid\n", *argv);
                } else
                        usage();
                argc--; argv++;
@@ -374,8 +402,15 @@ get_failed:
                addattr_l(n, 1024, IFLA_GRE_TTL, &ttl, 1);
                addattr_l(n, 1024, IFLA_GRE_TOS, &tos, 1);
                addattr32(n, 1024, IFLA_GRE_FWMARK, fwmark);
-               if (erspan_idx != 0)
-                       addattr32(n, 1024, IFLA_GRE_ERSPAN_INDEX, erspan_idx);
+               if (erspan_ver) {
+                       addattr8(n, 1024, IFLA_GRE_ERSPAN_VER, erspan_ver);
+                       if (erspan_ver == 1 && erspan_idx != 0) {
+                               addattr32(n, 1024, IFLA_GRE_ERSPAN_INDEX, 
erspan_idx);
+                       } else if (erspan_ver == 2) {
+                               addattr8(n, 1024, IFLA_GRE_ERSPAN_DIR, 
erspan_dir);
+                               addattr16(n, 1024, IFLA_GRE_ERSPAN_HWID, 
erspan_hwid);
+                       }
+               }
        } else {
                addattr_l(n, 1024, IFLA_GRE_COLLECT_METADATA, NULL, 0);
        }
@@ -514,7 +549,25 @@ static void gre_print_opt(struct link_util *lu, FILE *f, 
struct rtattr *tb[])
        if (tb[IFLA_GRE_ERSPAN_INDEX]) {
                __u32 erspan_idx = rta_getattr_u32(tb[IFLA_GRE_ERSPAN_INDEX]);
 
-               fprintf(f, "erspan_index %u ", erspan_idx);
+               print_uint(PRINT_ANY, "erspan_index", "erspan_index %u", 
erspan_idx);
+       }
+
+       if (tb[IFLA_GRE_ERSPAN_VER]) {
+               __u8 erspan_ver = rta_getattr_u8(tb[IFLA_GRE_ERSPAN_VER]);
+
+               print_uint(PRINT_ANY, "erspan_ver", "erspan_ver %u", 
erspan_ver);
+       }
+
+       if (tb[IFLA_GRE_ERSPAN_DIR]) {
+               __u8 erspan_dir = rta_getattr_u8(tb[IFLA_GRE_ERSPAN_DIR]);
+
+               print_uint(PRINT_ANY, "erspan_dir", "erspan_dir %u", 
erspan_dir);
+       }
+
+       if (tb[IFLA_GRE_ERSPAN_HWID]) {
+               __u16 erspan_hwid = rta_getattr_u16(tb[IFLA_GRE_ERSPAN_HWID]);
+
+               print_hex(PRINT_ANY, "erspan_hwid", "erspan_hwid %x", 
erspan_hwid);
        }
 
        if (tb[IFLA_GRE_ENCAP_TYPE] &&
diff --git a/ip/link_gre6.c b/ip/link_gre6.c
index 2cb46ca116d0..71181af91bc8 100644
--- a/ip/link_gre6.c
+++ b/ip/link_gre6.c
@@ -109,6 +109,9 @@ static int gre_parse_opt(struct link_util *lu, int argc, 
char **argv,
        int len;
        __u32 fwmark = 0;
        __u32 erspan_idx = 0;
+       __u8 erspan_ver = 0;
+       __u8 erspan_dir = 0;
+       __u16 erspan_hwid = 0;
 
        if (!(n->nlmsg_flags & NLM_F_CREATE)) {
                if (rtnl_talk(&rth, &req.n, &answer) < 0) {
@@ -191,6 +194,15 @@ get_failed:
                if (greinfo[IFLA_GRE_ERSPAN_INDEX])
                        erspan_idx = 
rta_getattr_u32(greinfo[IFLA_GRE_ERSPAN_INDEX]);
 
+               if (greinfo[IFLA_GRE_ERSPAN_VER])
+                       erspan_ver = 
rta_getattr_u8(greinfo[IFLA_GRE_ERSPAN_VER]);
+
+               if (greinfo[IFLA_GRE_ERSPAN_DIR])
+                       erspan_dir = 
rta_getattr_u8(greinfo[IFLA_GRE_ERSPAN_DIR]);
+
+               if (greinfo[IFLA_GRE_ERSPAN_HWID])
+                       erspan_hwid = 
rta_getattr_u16(greinfo[IFLA_GRE_ERSPAN_HWID]);
+
                free(answer);
        }
 
@@ -389,6 +401,22 @@ get_failed:
                                invarg("invalid erspan index\n", *argv);
                        if (erspan_idx & ~((1<<20) - 1) || erspan_idx == 0)
                                invarg("erspan index must be > 0 and <= 
20-bit\n", *argv);
+               } else if (strcmp(*argv, "erspan_ver") == 0) {
+                       NEXT_ARG();
+                       if (get_u8(&erspan_ver, *argv, 0))
+                               invarg("invalid erspan version\n", *argv);
+                       if (erspan_ver != 1 && erspan_ver != 2)
+                               invarg("erspan version must be 1 or 2\n", 
*argv);
+               } else if (strcmp(*argv, "erspan_dir") == 0) {
+                       NEXT_ARG();
+                       if (get_u8(&erspan_dir, *argv, 0))
+                               invarg("invalid erspan direction\n", *argv);
+                       if (erspan_dir != 0 && erspan_dir != 1)
+                               invarg("erspan direction must be 0(Ingress) or 
1(Egress)\n", *argv);
+               } else if (strcmp(*argv, "erspan_hwid") == 0) {
+                       NEXT_ARG();
+                       if (get_u16(&erspan_hwid, *argv, 0))
+                               invarg("invalid erspan hwid\n", *argv);
                } else
                        usage();
                argc--; argv++;
@@ -408,9 +436,15 @@ get_failed:
                addattr_l(n, 1024, IFLA_GRE_FLOWINFO, &flowinfo, 4);
                addattr32(n, 1024, IFLA_GRE_FLAGS, flags);
                addattr32(n, 1024, IFLA_GRE_FWMARK, fwmark);
-               if (erspan_idx != 0)
-                       addattr32(n, 1024, IFLA_GRE_ERSPAN_INDEX, erspan_idx);
-
+               if (erspan_ver) {
+                       addattr8(n, 1024, IFLA_GRE_ERSPAN_VER, erspan_ver);
+                       if (erspan_ver == 1 && erspan_idx != 0) {
+                               addattr32(n, 1024, IFLA_GRE_ERSPAN_INDEX, 
erspan_idx);
+                       } else {
+                               addattr8(n, 1024, IFLA_GRE_ERSPAN_DIR, 
erspan_dir);
+                               addattr16(n, 1024, IFLA_GRE_ERSPAN_HWID, 
erspan_hwid);
+                       }
+               }
                addattr16(n, 1024, IFLA_GRE_ENCAP_TYPE, encaptype);
                addattr16(n, 1024, IFLA_GRE_ENCAP_FLAGS, encapflags);
                addattr16(n, 1024, IFLA_GRE_ENCAP_SPORT, htons(encapsport));
@@ -587,9 +621,28 @@ static void gre_print_opt(struct link_util *lu, FILE *f, 
struct rtattr *tb[])
 
        if (tb[IFLA_GRE_ERSPAN_INDEX]) {
                __u32 erspan_idx = rta_getattr_u32(tb[IFLA_GRE_ERSPAN_INDEX]);
-               fprintf(f, "erspan_index %u ", erspan_idx);
+               print_uint(PRINT_ANY, "erspan_index", "erspan_index %u ", 
erspan_idx);
        }
 
+       if (tb[IFLA_GRE_ERSPAN_VER]) {
+               __u8 erspan_ver = rta_getattr_u8(tb[IFLA_GRE_ERSPAN_VER]);
+
+               print_uint(PRINT_ANY, "erspan_ver", "erspan_ver %u", 
erspan_ver);
+       }
+
+       if (tb[IFLA_GRE_ERSPAN_DIR]) {
+               __u8 erspan_dir = rta_getattr_u8(tb[IFLA_GRE_ERSPAN_DIR]);
+
+               print_uint(PRINT_ANY, "erspan_dir", "erspan_dir %u", 
erspan_dir);
+       }
+
+       if (tb[IFLA_GRE_ERSPAN_HWID]) {
+               __u16 erspan_hwid = rta_getattr_u16(tb[IFLA_GRE_ERSPAN_HWID]);
+
+               print_hex(PRINT_ANY, "erspan_hwid", "erspan_hwid %x", 
erspan_hwid);
+       }
+
+
        if (tb[IFLA_GRE_ENCAP_TYPE] &&
            rta_getattr_u16(tb[IFLA_GRE_ENCAP_TYPE]) != TUNNEL_ENCAP_NONE) {
                __u16 type = rta_getattr_u16(tb[IFLA_GRE_ENCAP_TYPE]);
-- 
2.7.4

Reply via email to