]> git.proxmox.com Git - mirror_iproute2.git/commitdiff
tc: m_tunnel_key: add options support for erpsan
authorXin Long <lucien.xin@gmail.com>
Mon, 27 Apr 2020 10:27:49 +0000 (18:27 +0800)
committerDavid Ahern <dsahern@gmail.com>
Fri, 1 May 2020 16:33:18 +0000 (16:33 +0000)
This patch is to add TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN's parse and
print to implement erspan options support in m_tunnel_key, like
Commit 6217917a3826 ("tc: m_tunnel_key: Add tunnel option support
to act_tunnel_key") for geneve options support.

Option is expressed as version:index:dir:hwid, dir and hwid will
be parsed when version is 2, while index will be parsed when
version is 1. erspan doesn't support multiple options.

With this patch, users can add and dump erspan options like:

  # ip link add name erspan1 type erspan external
  # tc qdisc add dev eth0 ingress
  # tc filter add dev eth0 protocol ip parent ffff: \
      flower indev eth0 \
        ip_proto udp \
        action tunnel_key \
          set src_ip 10.0.99.192 \
          dst_ip 10.0.99.193 \
          dst_port 6081 \
          id 11 \
          erspan_opts 1:2:0:0 \
      action mirred egress redirect dev erspan1
  # tc -s filter show dev eth0 parent ffff:

     filter protocol ip pref 49151 flower chain 0 handle 0x1
       indev eth0
       eth_type ipv4
       ip_proto udp
       not_in_hw
         action order 1: tunnel_key  set
         src_ip 10.0.99.192
         dst_ip 10.0.99.193
         key_id 11
         dst_port 6081
         erspan_opts 1:2:0:0
         csum pipe
           index 2 ref 1 bind 1
         ...
v1->v2:
  - no change.
v2->v3:
  - no change.
v3->v4:
  - keep the same format between input and output, json and non json.
  - print version, index, dir and hwid as uint.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Signed-off-by: David Ahern <dsahern@gmail.com>
man/man8/tc-tunnel_key.8
tc/m_tunnel_key.c

index c208e2c82a181b6be1fecd6e00b47f1ce32b52fe..ad9972402c0e53efe85b02d0461aeb3398ad5a7f 100644 (file)
@@ -68,8 +68,10 @@ options.
 .B dst_port
 ,
 .B geneve_opts
-and
+,
 .B vxlan_opts
+and
+.B erspan_opts
 are optional.
 .RS
 .TP
@@ -99,6 +101,14 @@ Vxlan metatdata options.
 is specified in the form GBP, as a 32bit number. Multiple options is not
 supported.
 .TP
+.B erspan_opts
+Erspan metatdata options.
+.B erspan_opts
+is specified in the form VERSION:INDEX:DIR:HWID, where VERSION is represented
+as a 8bit number, INDEX as an 32bit number, DIR and HWID as a 8bit number.
+Multiple options is not supported. Note INDEX is used when VERSION is 1,
+and DIR and HWID are used when VERSION is 2.
+.TP
 .B tos
 Outer header TOS
 .TP
index 76391d6c85fb22b63d7b9c1f2923921ad536f87b..a56fe24413fa0d3646aded301d119abdc90540fc 100644 (file)
@@ -29,7 +29,7 @@ static void explain(void)
                "src_ip <IP> (mandatory)\n"
                "dst_ip <IP> (mandatory)\n"
                "dst_port <UDP_PORT>\n"
-               "geneve_opts | vxlan_opts <OPTIONS>\n"
+               "geneve_opts | vxlan_opts | erspan_opts <OPTIONS>\n"
                "csum | nocsum (default is \"csum\")\n");
 }
 
@@ -97,6 +97,21 @@ static int tunnel_key_parse_be16(char *str, int base, int type,
        return 0;
 }
 
+static int tunnel_key_parse_be32(char *str, int base, int type,
+                                struct nlmsghdr *n)
+{
+       __be32 value;
+       int ret;
+
+       ret = get_be32(&value, str, base);
+       if (ret)
+               return ret;
+
+       addattr32(n, MAX_MSG, type, value);
+
+       return 0;
+}
+
 static int tunnel_key_parse_u8(char *str, int base, int type,
                               struct nlmsghdr *n)
 {
@@ -226,6 +241,63 @@ static int tunnel_key_parse_vxlan_opt(char *str, struct nlmsghdr *n)
        return 0;
 }
 
+static int tunnel_key_parse_erspan_opt(char *str, struct nlmsghdr *n)
+{
+       char *token, *saveptr = NULL;
+       struct rtattr *encap, *nest;
+       int i, ret;
+
+       encap = addattr_nest(n, MAX_MSG,
+                            TCA_TUNNEL_KEY_ENC_OPTS | NLA_F_NESTED);
+       nest = addattr_nest(n, MAX_MSG,
+                           TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN | NLA_F_NESTED);
+
+       token = strtok_r(str, ":", &saveptr);
+       i = 1;
+       while (token) {
+               switch (i) {
+               case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER:
+               {
+                       ret = tunnel_key_parse_u8(token, 0, i, n);
+                       if (ret)
+                               return ret;
+                       break;
+               }
+               case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX:
+               {
+                       ret = tunnel_key_parse_be32(token, 0, i, n);
+                       if (ret)
+                               return ret;
+                       break;
+               }
+               case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR:
+               {
+                       ret = tunnel_key_parse_u8(token, 0, i, n);
+                       if (ret)
+                               return ret;
+                       break;
+               }
+               case TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID:
+               {
+                       ret = tunnel_key_parse_u8(token, 0, i, n);
+                       if (ret)
+                               return ret;
+                       break;
+               }
+               default:
+                       return -1;
+               }
+
+               token = strtok_r(NULL, ":", &saveptr);
+               i++;
+       }
+
+       addattr_nest_end(n, nest);
+       addattr_nest_end(n, encap);
+
+       return 0;
+}
+
 static int tunnel_key_parse_tos_ttl(char *str, int type, struct nlmsghdr *n)
 {
        int ret;
@@ -330,6 +402,13 @@ static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p,
                                fprintf(stderr, "Illegal \"vxlan_opts\"\n");
                                return -1;
                        }
+               } else if (matches(*argv, "erspan_opts") == 0) {
+                       NEXT_ARG();
+
+                       if (tunnel_key_parse_erspan_opt(*argv, n)) {
+                               fprintf(stderr, "Illegal \"erspan_opts\"\n");
+                               return -1;
+                       }
                } else if (matches(*argv, "tos") == 0) {
                        NEXT_ARG();
                        ret = tunnel_key_parse_tos_ttl(*argv,
@@ -517,6 +596,39 @@ static void tunnel_key_print_vxlan_options(struct rtattr *attr)
        close_json_array(PRINT_JSON, name);
 }
 
+static void tunnel_key_print_erspan_options(struct rtattr *attr)
+{
+       struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX + 1];
+       struct rtattr *i = RTA_DATA(attr);
+       int rem = RTA_PAYLOAD(attr);
+       char *name = "erspan_opts";
+       __u8 ver, hwid, dir;
+       __u32 idx;
+
+       parse_rtattr(tb, TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_MAX, i, rem);
+       ver = rta_getattr_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_VER]);
+       if (ver == 1) {
+               idx = rta_getattr_be32(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_INDEX]);
+               dir = 0;
+               hwid = 0;
+       } else {
+               idx = 0;
+               dir = rta_getattr_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_DIR]);
+               hwid = rta_getattr_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_ERSPAN_HWID]);
+       }
+
+       print_nl();
+       print_string(PRINT_FP, name, "\t%s ", name);
+       open_json_array(PRINT_JSON, name);
+       open_json_object(NULL);
+       print_uint(PRINT_ANY, "ver", "%u", ver);
+       print_uint(PRINT_ANY, "index", ":%u", idx);
+       print_uint(PRINT_ANY, "dir", ":%u", dir);
+       print_uint(PRINT_ANY, "hwid", ":%u", hwid);
+       close_json_object();
+       close_json_array(PRINT_JSON, name);
+}
+
 static void tunnel_key_print_key_opt(struct rtattr *attr)
 {
        struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPTS_MAX + 1];
@@ -531,6 +643,9 @@ static void tunnel_key_print_key_opt(struct rtattr *attr)
        else if (tb[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN])
                tunnel_key_print_vxlan_options(
                        tb[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN]);
+       else if (tb[TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN])
+               tunnel_key_print_erspan_options(
+                       tb[TCA_TUNNEL_KEY_ENC_OPTS_ERSPAN]);
 }
 
 static void tunnel_key_print_tos_ttl(FILE *f, char *name,