close_json_array(PRINT_JSON, name);
}
+static void lwtunnel_print_erspan_opts(struct rtattr *attr)
+{
+ struct rtattr *tb[LWTUNNEL_IP_OPT_ERSPAN_MAX + 1];
+ struct rtattr *i = RTA_DATA(attr);
+ char *name = "erspan_opts";
+ __u8 ver, hwid, dir;
+ __u32 idx;
+
+ parse_rtattr(tb, LWTUNNEL_IP_OPT_ERSPAN_MAX, i, RTA_PAYLOAD(attr));
+ ver = rta_getattr_u8(tb[LWTUNNEL_IP_OPT_ERSPAN_VER]);
+ if (ver == 1) {
+ idx = rta_getattr_be32(tb[LWTUNNEL_IP_OPT_ERSPAN_INDEX]);
+ dir = 0;
+ hwid = 0;
+ } else {
+ idx = 0;
+ dir = rta_getattr_u8(tb[LWTUNNEL_IP_OPT_ERSPAN_DIR]);
+ hwid = rta_getattr_u8(tb[LWTUNNEL_IP_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 lwtunnel_print_opts(struct rtattr *attr)
{
struct rtattr *tb_opt[LWTUNNEL_IP_OPTS_MAX + 1];
lwtunnel_print_geneve_opts(tb_opt[LWTUNNEL_IP_OPTS_GENEVE]);
else if (tb_opt[LWTUNNEL_IP_OPTS_VXLAN])
lwtunnel_print_vxlan_opts(tb_opt[LWTUNNEL_IP_OPTS_VXLAN]);
+ else if (tb_opt[LWTUNNEL_IP_OPTS_ERSPAN])
+ lwtunnel_print_erspan_opts(tb_opt[LWTUNNEL_IP_OPTS_ERSPAN]);
}
static void print_encap_ip(FILE *fp, struct rtattr *encap)
return 0;
}
+static int lwtunnel_parse_erspan_opts(char *str, size_t len, struct rtattr *rta)
+{
+ struct rtattr *nest;
+ char *token;
+ int i, err;
+
+ nest = rta_nest(rta, len, LWTUNNEL_IP_OPTS_ERSPAN | NLA_F_NESTED);
+ i = 1;
+ token = strsep(&str, ":");
+ while (token) {
+ switch (i) {
+ case LWTUNNEL_IP_OPT_ERSPAN_VER:
+ {
+ __u8 opt_type;
+
+ if (!strlen(token))
+ break;
+ err = get_u8(&opt_type, token, 0);
+ if (err)
+ return err;
+
+ rta_addattr8(rta, len, i, opt_type);
+ break;
+ }
+ case LWTUNNEL_IP_OPT_ERSPAN_INDEX:
+ {
+ __be32 opt_class;
+
+ if (!strlen(token))
+ break;
+ err = get_be32(&opt_class, token, 0);
+ if (err)
+ return err;
+
+ rta_addattr32(rta, len, i, opt_class);
+ break;
+ }
+ case LWTUNNEL_IP_OPT_ERSPAN_DIR:
+ {
+ __u8 opt_type;
+
+ if (!strlen(token))
+ break;
+ err = get_u8(&opt_type, token, 0);
+ if (err)
+ return err;
+
+ rta_addattr8(rta, len, i, opt_type);
+ break;
+ }
+ case LWTUNNEL_IP_OPT_ERSPAN_HWID:
+ {
+ __u8 opt_type;
+
+ if (!strlen(token))
+ break;
+ err = get_u8(&opt_type, token, 0);
+ if (err)
+ return err;
+
+ rta_addattr8(rta, len, i, opt_type);
+ break;
+ }
+ default:
+ fprintf(stderr, "Unknown \"geneve_opts\" type\n");
+ return -1;
+ }
+
+ token = strsep(&str, ":");
+ i++;
+ }
+
+ rta_nest_end(rta, nest);
+ return 0;
+}
+
static int parse_encap_ip(struct rtattr *rta, size_t len,
int *argcp, char ***argvp)
{
invarg("\"vxlan_opts\" value is invalid\n",
*argv);
rta_nest_end(rta, nest);
+ } else if (strcmp(*argv, "erspan_opts") == 0) {
+ struct rtattr *nest;
+
+ if (opts_ok++)
+ duparg2("opts", *argv);
+
+ NEXT_ARG();
+
+ nest = rta_nest(rta, len,
+ LWTUNNEL_IP_OPTS | NLA_F_NESTED);
+ ret = lwtunnel_parse_erspan_opts(*argv, len, rta);
+ if (ret)
+ invarg("\"erspan_opts\" value is invalid\n",
+ *argv);
+ rta_nest_end(rta, nest);
} else if (strcmp(*argv, "key") == 0) {
if (key_ok++)
duparg2("key", *argv);
invarg("\"vxlan_opts\" value is invalid\n",
*argv);
rta_nest_end(rta, nest);
+ } else if (strcmp(*argv, "erspan_opts") == 0) {
+ struct rtattr *nest;
+
+ if (opts_ok++)
+ duparg2("opts", *argv);
+
+ NEXT_ARG();
+
+ nest = rta_nest(rta, len,
+ LWTUNNEL_IP_OPTS | NLA_F_NESTED);
+ ret = lwtunnel_parse_erspan_opts(*argv, len, rta);
+ if (ret)
+ invarg("\"erspan_opts\" value is invalid\n",
+ *argv);
+ rta_nest_end(rta, nest);
} else if (strcmp(*argv, "key") == 0) {
if (key_ok++)
duparg2("key", *argv);