mirror of
https://git.proxmox.com/git/mirror_iproute2
synced 2025-08-10 10:28:55 +00:00
tc: m_tunnel_key: Add tunnel option support to act_tunnel_key
Allow setting tunnel options using the act_tunnel_key action. Options are expressed as class:type:data and multiple options may be listed using a comma delimiter. # ip link add name geneve0 type geneve 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 \ geneve_opts 0102:80:00800022,0102:80:00800022 \ action mirred egress redirect dev geneve0 Signed-off-by: Simon Horman <simon.horman@netronome.com> Signed-off-by: Pieter Jansen van Vuuren <pieter.jansenvanvuuren@netronome.com> Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com> Signed-off-by: David Ahern <dsahern@gmail.com>
This commit is contained in:
parent
13925ae9eb
commit
6217917a38
@ -64,7 +64,9 @@ and
|
|||||||
.B dst_ip
|
.B dst_ip
|
||||||
options.
|
options.
|
||||||
.B dst_port
|
.B dst_port
|
||||||
is optional.
|
and
|
||||||
|
.B geneve_opts
|
||||||
|
are optional.
|
||||||
.RS
|
.RS
|
||||||
.TP
|
.TP
|
||||||
.B id
|
.B id
|
||||||
@ -79,6 +81,14 @@ Outer header destination IP address (IPv4 or IPv6)
|
|||||||
.B dst_port
|
.B dst_port
|
||||||
Outer header destination UDP port
|
Outer header destination UDP port
|
||||||
.TP
|
.TP
|
||||||
|
.B geneve_opts
|
||||||
|
Geneve variable length options.
|
||||||
|
.B geneve_opts
|
||||||
|
is specified in the form CLASS:TYPE:DATA, where CLASS is represented as a
|
||||||
|
16bit hexadecimal value, TYPE as an 8bit hexadecimal value and DATA as a
|
||||||
|
variable length hexadecimal value. Additionally multiple options may be
|
||||||
|
listed using a comma delimiter.
|
||||||
|
.TP
|
||||||
.RB [ no ] csum
|
.RB [ no ] csum
|
||||||
Controlls outer UDP checksum. When set to
|
Controlls outer UDP checksum. When set to
|
||||||
.B csum
|
.B csum
|
||||||
|
@ -29,6 +29,7 @@ static void explain(void)
|
|||||||
"src_ip <IP> (mandatory)\n"
|
"src_ip <IP> (mandatory)\n"
|
||||||
"dst_ip <IP> (mandatory)\n"
|
"dst_ip <IP> (mandatory)\n"
|
||||||
"dst_port <UDP_PORT>\n"
|
"dst_port <UDP_PORT>\n"
|
||||||
|
"geneve_opts <OPTIONS>\n"
|
||||||
"csum | nocsum (default is \"csum\")\n");
|
"csum | nocsum (default is \"csum\")\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,6 +82,114 @@ static int tunnel_key_parse_dst_port(char *str, int type, struct nlmsghdr *n)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int tunnel_key_parse_be16(char *str, int base, int type,
|
||||||
|
struct nlmsghdr *n)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
__be16 value;
|
||||||
|
|
||||||
|
ret = get_be16(&value, str, base);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
addattr16(n, MAX_MSG, type, value);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tunnel_key_parse_u8(char *str, int base, int type,
|
||||||
|
struct nlmsghdr *n)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
__u8 value;
|
||||||
|
|
||||||
|
ret = get_u8(&value, str, base);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
addattr8(n, MAX_MSG, type, value);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tunnel_key_parse_geneve_opt(char *str, struct nlmsghdr *n)
|
||||||
|
{
|
||||||
|
char *token, *saveptr = NULL;
|
||||||
|
struct rtattr *nest;
|
||||||
|
int i, ret;
|
||||||
|
|
||||||
|
nest = addattr_nest(n, MAX_MSG, TCA_TUNNEL_KEY_ENC_OPTS_GENEVE);
|
||||||
|
|
||||||
|
token = strtok_r(str, ":", &saveptr);
|
||||||
|
i = 1;
|
||||||
|
while (token) {
|
||||||
|
switch (i) {
|
||||||
|
case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS:
|
||||||
|
{
|
||||||
|
ret = tunnel_key_parse_be16(token, 16, i, n);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE:
|
||||||
|
{
|
||||||
|
ret = tunnel_key_parse_u8(token, 16, i, n);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA:
|
||||||
|
{
|
||||||
|
size_t token_len = strlen(token);
|
||||||
|
uint8_t *opts;
|
||||||
|
|
||||||
|
opts = malloc(token_len / 2);
|
||||||
|
if (!opts)
|
||||||
|
return -1;
|
||||||
|
if (hex2mem(token, opts, token_len / 2) < 0) {
|
||||||
|
free(opts);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
addattr_l(n, MAX_MSG, i, opts, token_len / 2);
|
||||||
|
free(opts);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
token = strtok_r(NULL, ":", &saveptr);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
addattr_nest_end(n, nest);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tunnel_key_parse_geneve_opts(char *str, struct nlmsghdr *n)
|
||||||
|
{
|
||||||
|
char *token, *saveptr = NULL;
|
||||||
|
struct rtattr *nest;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
nest = addattr_nest(n, MAX_MSG, TCA_TUNNEL_KEY_ENC_OPTS);
|
||||||
|
|
||||||
|
token = strtok_r(str, ",", &saveptr);
|
||||||
|
while (token) {
|
||||||
|
ret = tunnel_key_parse_geneve_opt(token, n);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
token = strtok_r(NULL, ",", &saveptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
addattr_nest_end(n, nest);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p,
|
static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p,
|
||||||
int tca_id, struct nlmsghdr *n)
|
int tca_id, struct nlmsghdr *n)
|
||||||
{
|
{
|
||||||
@ -157,6 +266,13 @@ static int parse_tunnel_key(struct action_util *a, int *argc_p, char ***argv_p,
|
|||||||
fprintf(stderr, "Illegal \"dst port\"\n");
|
fprintf(stderr, "Illegal \"dst port\"\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
} else if (matches(*argv, "geneve_opts") == 0) {
|
||||||
|
NEXT_ARG();
|
||||||
|
|
||||||
|
if (tunnel_key_parse_geneve_opts(*argv, n)) {
|
||||||
|
fprintf(stderr, "Illegal \"geneve_opts\"\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
} else if (matches(*argv, "csum") == 0) {
|
} else if (matches(*argv, "csum") == 0) {
|
||||||
csum = 1;
|
csum = 1;
|
||||||
} else if (matches(*argv, "nocsum") == 0) {
|
} else if (matches(*argv, "nocsum") == 0) {
|
||||||
@ -260,6 +376,65 @@ static void tunnel_key_print_flag(FILE *f, const char *name_on,
|
|||||||
rta_getattr_u8(attr) ? name_on : name_off);
|
rta_getattr_u8(attr) ? name_on : name_off);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void tunnel_key_print_geneve_options(const char *name,
|
||||||
|
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 strbuf[rem * 2 + 1];
|
||||||
|
char data[rem * 2 + 1];
|
||||||
|
uint8_t data_r[rem];
|
||||||
|
uint16_t clss;
|
||||||
|
uint8_t type;
|
||||||
|
|
||||||
|
open_json_array(PRINT_JSON, name);
|
||||||
|
print_string(PRINT_FP, name, "\n\t%s ", "geneve_opt");
|
||||||
|
|
||||||
|
while (rem) {
|
||||||
|
parse_rtattr(tb, TCA_TUNNEL_KEY_ENC_OPT_GENEVE_MAX, i, rem);
|
||||||
|
clss = rta_getattr_be16(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_CLASS]);
|
||||||
|
type = rta_getattr_u8(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_TYPE]);
|
||||||
|
data_len = RTA_PAYLOAD(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA]);
|
||||||
|
hexstring_n2a(RTA_DATA(tb[TCA_TUNNEL_KEY_ENC_OPT_GENEVE_DATA]),
|
||||||
|
data_len, data, sizeof(data));
|
||||||
|
hex2mem(data, data_r, data_len);
|
||||||
|
offset += data_len + 20;
|
||||||
|
rem -= data_len + 20;
|
||||||
|
i = RTA_DATA(attr) + offset;
|
||||||
|
|
||||||
|
open_json_object(NULL);
|
||||||
|
print_uint(PRINT_JSON, "class", NULL, clss);
|
||||||
|
print_uint(PRINT_JSON, "type", NULL, type);
|
||||||
|
open_json_array(PRINT_JSON, "data");
|
||||||
|
for (ii = 0; ii < data_len; ii++)
|
||||||
|
print_uint(PRINT_JSON, NULL, NULL, data_r[ii]);
|
||||||
|
close_json_array(PRINT_JSON, "data");
|
||||||
|
close_json_object();
|
||||||
|
|
||||||
|
sprintf(strbuf, "%04x:%02x:%s", clss, type, data);
|
||||||
|
if (rem)
|
||||||
|
print_string(PRINT_FP, NULL, "%s,", strbuf);
|
||||||
|
else
|
||||||
|
print_string(PRINT_FP, NULL, "%s", strbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
close_json_array(PRINT_JSON, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void tunnel_key_print_key_opt(const char *name, struct rtattr *attr)
|
||||||
|
{
|
||||||
|
struct rtattr *tb[TCA_TUNNEL_KEY_ENC_OPTS_MAX + 1];
|
||||||
|
|
||||||
|
if (!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]);
|
||||||
|
}
|
||||||
|
|
||||||
static int print_tunnel_key(struct action_util *au, FILE *f, struct rtattr *arg)
|
static int print_tunnel_key(struct action_util *au, FILE *f, struct rtattr *arg)
|
||||||
{
|
{
|
||||||
struct rtattr *tb[TCA_TUNNEL_KEY_MAX + 1];
|
struct rtattr *tb[TCA_TUNNEL_KEY_MAX + 1];
|
||||||
@ -297,6 +472,8 @@ static int print_tunnel_key(struct action_util *au, FILE *f, struct rtattr *arg)
|
|||||||
tb[TCA_TUNNEL_KEY_ENC_KEY_ID]);
|
tb[TCA_TUNNEL_KEY_ENC_KEY_ID]);
|
||||||
tunnel_key_print_dst_port(f, "dst_port",
|
tunnel_key_print_dst_port(f, "dst_port",
|
||||||
tb[TCA_TUNNEL_KEY_ENC_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_flag(f, "nocsum", "csum",
|
tunnel_key_print_flag(f, "nocsum", "csum",
|
||||||
tb[TCA_TUNNEL_KEY_NO_CSUM]);
|
tb[TCA_TUNNEL_KEY_NO_CSUM]);
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user