tc: m_tunnel_key: add options support for vxlan

This patch is to add TCA_TUNNEL_KEY_ENC_OPTS_VXLAN's parse and
print to implement vxlan options support in m_tunnel_key, like
Commit 6217917a38 ("tc: m_tunnel_key: Add tunnel option support
to act_tunnel_key") for geneve options support.

Option is expressed a 32bit number for gbp only, and vxlan
doesn't support multiple options.

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

  # ip link add name vxlan1 type vxlan dstport 0 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 \
          vxlan_opts 65793 \
      action mirred egress redirect dev vxlan1
  # tc -s filter show dev eth0 parent ffff:

     filter protocol ip pref 49152 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
         vxlan_opts 65793
         ...

v1->v2:
  - get_u32 with base = 0 for gbp.
  - use to print_unint("0x%x") to print gbp.
v2->v3:
  - implement proper JSON array for opts.
v3->v4:
  - keep the same format between input and output, json and non json.
  - print gbp as uint.

Signed-off-by: Xin Long <lucien.xin@gmail.com>
Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
Xin Long 2020-04-27 18:27:48 +08:00 committed by David Ahern
parent 39fa047938
commit f72c3ad00f
2 changed files with 84 additions and 10 deletions

View File

@ -66,8 +66,10 @@ options.
.B id
,
.B dst_port
and
,
.B geneve_opts
and
.B vxlan_opts
are optional.
.RS
.TP
@ -91,6 +93,12 @@ is specified in the form CLASS:TYPE:DATA, where CLASS is represented as a
variable length hexadecimal value. Additionally multiple options may be
listed using a comma delimiter.
.TP
.B vxlan_opts
Vxlan metatdata options.
.B vxlan_opts
is specified in the form GBP, as a 32bit number. Multiple options is not
supported.
.TP
.B tos
Outer header TOS
.TP

View 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 <OPTIONS>\n"
"geneve_opts | vxlan_opts <OPTIONS>\n"
"csum | nocsum (default is \"csum\")\n");
}
@ -112,6 +112,21 @@ static int tunnel_key_parse_u8(char *str, int base, int type,
return 0;
}
static int tunnel_key_parse_u32(char *str, int base, int type,
struct nlmsghdr *n)
{
__u32 value;
int ret;
ret = get_u32(&value, str, base);
if (ret)
return ret;
addattr32(n, MAX_MSG, type, value);
return 0;
}
static int tunnel_key_parse_geneve_opt(char *str, struct nlmsghdr *n)
{
char *token, *saveptr = NULL;
@ -190,6 +205,27 @@ static int tunnel_key_parse_geneve_opts(char *str, struct nlmsghdr *n)
return 0;
}
static int tunnel_key_parse_vxlan_opt(char *str, struct nlmsghdr *n)
{
struct rtattr *encap, *nest;
int 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_VXLAN | NLA_F_NESTED);
ret = tunnel_key_parse_u32(str, 0,
TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP, n);
if (ret)
return ret;
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;
@ -287,6 +323,13 @@ static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p,
fprintf(stderr, "Illegal \"geneve_opts\"\n");
return -1;
}
} else if (matches(*argv, "vxlan_opts") == 0) {
NEXT_ARG();
if (tunnel_key_parse_vxlan_opt(*argv, n)) {
fprintf(stderr, "Illegal \"vxlan_opts\"\n");
return -1;
}
} else if (matches(*argv, "tos") == 0) {
NEXT_ARG();
ret = tunnel_key_parse_tos_ttl(*argv,
@ -406,13 +449,13 @@ static void tunnel_key_print_flag(FILE *f, const char *name_on,
rta_getattr_u8(attr) ? name_on : name_off);
}
static void tunnel_key_print_geneve_options(const char *name,
struct rtattr *attr)
static void tunnel_key_print_geneve_options(struct rtattr *attr)
{
struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX + 1];
struct rtattr *i = RTA_DATA(attr);
int ii, data_len = 0, offset = 0;
int rem = RTA_PAYLOAD(attr);
char *name = "geneve_opts";
char strbuf[rem * 2 + 1];
char data[rem * 2 + 1];
uint8_t data_r[rem];
@ -421,7 +464,7 @@ static void tunnel_key_print_geneve_options(const char *name,
open_json_array(PRINT_JSON, name);
print_nl();
print_string(PRINT_FP, name, "\t%s ", "geneve_opt");
print_string(PRINT_FP, name, "\t%s ", name);
while (rem) {
parse_rtattr(tb, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX, i, rem);
@ -454,7 +497,27 @@ static void tunnel_key_print_geneve_options(const char *name,
close_json_array(PRINT_JSON, name);
}
static void tunnel_key_print_key_opt(const char *name, struct rtattr *attr)
static void tunnel_key_print_vxlan_options(struct rtattr *attr)
{
struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX + 1];
struct rtattr *i = RTA_DATA(attr);
int rem = RTA_PAYLOAD(attr);
char *name = "vxlan_opts";
__u32 gbp;
parse_rtattr(tb, TCA_TUNNEL_KEY_ENC_OPT_VXLAN_MAX, i, rem);
gbp = rta_getattr_u32(tb[TCA_TUNNEL_KEY_ENC_OPT_VXLAN_GBP]);
print_nl();
print_string(PRINT_FP, name, "\t%s ", name);
open_json_array(PRINT_JSON, name);
open_json_object(NULL);
print_uint(PRINT_ANY, "gbp", "%u", gbp);
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];
@ -462,8 +525,12 @@ static void tunnel_key_print_key_opt(const char *name, struct rtattr *attr)
return;
parse_rtattr_nested(tb, TCA_TUNNEL_KEY_ENC_OPTS_MAX, attr);
tunnel_key_print_geneve_options(name,
tb[TCA_TUNNEL_KEY_ENC_OPTS_GENEVE]);
if (tb[TCA_TUNNEL_KEY_ENC_OPTS_GENEVE])
tunnel_key_print_geneve_options(
tb[TCA_TUNNEL_KEY_ENC_OPTS_GENEVE]);
else if (tb[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN])
tunnel_key_print_vxlan_options(
tb[TCA_TUNNEL_KEY_ENC_OPTS_VXLAN]);
}
static void tunnel_key_print_tos_ttl(FILE *f, char *name,
@ -519,8 +586,7 @@ static int print_tunnel_key(struct action_util *au, FILE *f, struct rtattr *arg)
tb[TCA_TUNNEL_KEY_ENC_KEY_ID]);
tunnel_key_print_dst_port(f, "dst_port",
tb[TCA_TUNNEL_KEY_ENC_DST_PORT]);
tunnel_key_print_key_opt("geneve_opts",
tb[TCA_TUNNEL_KEY_ENC_OPTS]);
tunnel_key_print_key_opt(tb[TCA_TUNNEL_KEY_ENC_OPTS]);
tunnel_key_print_flag(f, "nocsum", "csum",
tb[TCA_TUNNEL_KEY_NO_CSUM]);
tunnel_key_print_tos_ttl(f, "tos",