"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");
}
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)
{
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;
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,
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];
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,