| From 2fb8c115a8031d893fff588181cc42764391e4d5 Mon Sep 17 00:00:00 2001 |
| From: Andrea Claudi <aclaudi@redhat.com> |
| Date: Thu, 4 Jun 2020 21:43:50 +0200 |
| Subject: [PATCH] tc: m_tunnel_key: add options support for erpsan |
| |
| Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1830485 |
| Upstream Status: unknown commit 668fd9b25d9ec |
| |
| commit 668fd9b25d9eca3067040273239f7825db95442b |
| Author: Xin Long <lucien.xin@gmail.com> |
| Date: Mon Apr 27 18:27:49 2020 +0800 |
| |
| tc: m_tunnel_key: add options support for erpsan |
| |
| 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 | 12 +++- |
| tc/m_tunnel_key.c | 117 ++++++++++++++++++++++++++++++++++++++- |
| 2 files changed, 127 insertions(+), 2 deletions(-) |
| |
| diff --git a/man/man8/tc-tunnel_key.8 b/man/man8/tc-tunnel_key.8 |
| index c208e2c82a181..ad9972402c0e5 100644 |
| |
| |
| @@ -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 |
| diff --git a/tc/m_tunnel_key.c b/tc/m_tunnel_key.c |
| index 76391d6c85fb2..a56fe24413fa0 100644 |
| |
| |
| @@ -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, |
| -- |
| 2.26.2 |
| |