#include <linux/seg6.h>
#include <linux/seg6_iptunnel.h>
+#include <linux/rpl.h>
+#include <linux/rpl_iptunnel.h>
#include <linux/seg6_hmac.h>
#include <linux/seg6_local.h>
-#include <net/if.h>
+#include <linux/if_tunnel.h>
static const char *format_encap_type(int type)
{
return "seg6";
case LWTUNNEL_ENCAP_SEG6_LOCAL:
return "seg6local";
+ case LWTUNNEL_ENCAP_RPL:
+ return "rpl";
default:
return "unknown";
}
return LWTUNNEL_ENCAP_SEG6;
else if (strcmp(name, "seg6local") == 0)
return LWTUNNEL_ENCAP_SEG6_LOCAL;
+ else if (strcmp(name, "rpl") == 0)
+ return LWTUNNEL_ENCAP_RPL;
else if (strcmp(name, "help") == 0)
encap_type_usage();
tlv = (struct sr6_tlv_hmac *)((char *)srh + offset);
print_0xhex(PRINT_ANY, "hmac",
- "hmac 0x%X ", ntohl(tlv->hmackeyid));
+ "hmac %llX ", ntohl(tlv->hmackeyid));
}
}
print_srh(fp, tuninfo->srh);
}
+static void print_rpl_srh(FILE *fp, struct ipv6_rpl_sr_hdr *srh)
+{
+ int i;
+
+ if (is_json_context())
+ open_json_array(PRINT_JSON, "segs");
+ else
+ fprintf(fp, "segs %d [ ", srh->segments_left);
+
+ for (i = srh->segments_left - 1; i >= 0; i--) {
+ print_color_string(PRINT_ANY, COLOR_INET6,
+ NULL, "%s ",
+ rt_addr_n2a(AF_INET6, 16, &srh->rpl_segaddr[i]));
+ }
+
+ if (is_json_context())
+ close_json_array(PRINT_JSON, NULL);
+ else
+ fprintf(fp, "] ");
+}
+
+static void print_encap_rpl(FILE *fp, struct rtattr *encap)
+{
+ struct rtattr *tb[RPL_IPTUNNEL_MAX + 1];
+ struct ipv6_rpl_sr_hdr *srh;
+
+ parse_rtattr_nested(tb, RPL_IPTUNNEL_MAX, encap);
+
+ if (!tb[RPL_IPTUNNEL_SRH])
+ return;
+
+ srh = RTA_DATA(tb[RPL_IPTUNNEL_SRH]);
+
+ print_rpl_srh(fp, srh);
+}
+
static const char *seg6_action_names[SEG6_LOCAL_ACTION_MAX + 1] = {
[SEG6_LOCAL_ACTION_END] = "End",
[SEG6_LOCAL_ACTION_END_X] = "End.X",
struct rtattr *tb[SEG6_LOCAL_MAX + 1];
int action;
+ SPRINT_BUF(b1);
+
parse_rtattr_nested(tb, SEG6_LOCAL_MAX, encap);
if (!tb[SEG6_LOCAL_ACTION])
}
if (tb[SEG6_LOCAL_TABLE])
- print_uint(PRINT_ANY, "table",
- "table %u ", rta_getattr_u32(tb[SEG6_LOCAL_TABLE]));
+ print_string(PRINT_ANY, "table", "table %s ",
+ rtnl_rttable_n2a(rta_getattr_u32(tb[SEG6_LOCAL_TABLE]),
+ b1, sizeof(b1)));
+
+ if (tb[SEG6_LOCAL_VRFTABLE])
+ print_string(PRINT_ANY, "vrftable", "vrftable %s ",
+ rtnl_rttable_n2a(rta_getattr_u32(tb[SEG6_LOCAL_VRFTABLE]),
+ b1, sizeof(b1)));
if (tb[SEG6_LOCAL_NH4]) {
print_string(PRINT_ANY, "nh4",
rta_getattr_u8(tb[MPLS_IPTUNNEL_TTL]));
}
+static void lwtunnel_print_geneve_opts(struct rtattr *attr)
+{
+ struct rtattr *tb[LWTUNNEL_IP_OPT_GENEVE_MAX + 1];
+ struct rtattr *i = RTA_DATA(attr);
+ int rem = RTA_PAYLOAD(attr);
+ char *name = "geneve_opts";
+ int data_len, offset = 0;
+ char data[rem * 2 + 1];
+ __u16 class;
+ __u8 type;
+
+ print_nl();
+ print_string(PRINT_FP, name, "\t%s ", name);
+ open_json_array(PRINT_JSON, name);
+
+ while (rem) {
+ parse_rtattr(tb, LWTUNNEL_IP_OPT_GENEVE_MAX, i, rem);
+ class = rta_getattr_be16(tb[LWTUNNEL_IP_OPT_GENEVE_CLASS]);
+ type = rta_getattr_u8(tb[LWTUNNEL_IP_OPT_GENEVE_TYPE]);
+ data_len = RTA_PAYLOAD(tb[LWTUNNEL_IP_OPT_GENEVE_DATA]);
+ hexstring_n2a(RTA_DATA(tb[LWTUNNEL_IP_OPT_GENEVE_DATA]),
+ data_len, data, sizeof(data));
+ offset += data_len + 20;
+ rem -= data_len + 20;
+ i = RTA_DATA(attr) + offset;
+
+ open_json_object(NULL);
+ print_uint(PRINT_ANY, "class", "%u", class);
+ print_uint(PRINT_ANY, "type", ":%u", type);
+ if (rem)
+ print_string(PRINT_ANY, "data", ":%s,", data);
+ else
+ print_string(PRINT_ANY, "data", ":%s ", data);
+ close_json_object();
+ }
+
+ close_json_array(PRINT_JSON, name);
+}
+
+static void lwtunnel_print_vxlan_opts(struct rtattr *attr)
+{
+ struct rtattr *tb[LWTUNNEL_IP_OPT_VXLAN_MAX + 1];
+ struct rtattr *i = RTA_DATA(attr);
+ int rem = RTA_PAYLOAD(attr);
+ char *name = "vxlan_opts";
+ __u32 gbp;
+
+ parse_rtattr(tb, LWTUNNEL_IP_OPT_VXLAN_MAX, i, rem);
+ gbp = rta_getattr_u32(tb[LWTUNNEL_IP_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 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];
+
+ parse_rtattr_nested(tb_opt, LWTUNNEL_IP_OPTS_MAX, attr);
+ if (tb_opt[LWTUNNEL_IP_OPTS_GENEVE])
+ 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)
{
struct rtattr *tb[LWTUNNEL_IP_MAX+1];
+ __u16 flags;
parse_rtattr_nested(tb, LWTUNNEL_IP_MAX, encap);
if (tb[LWTUNNEL_IP_TOS])
print_uint(PRINT_ANY, "tos",
"tos %d ", rta_getattr_u8(tb[LWTUNNEL_IP_TOS]));
+
+ if (tb[LWTUNNEL_IP_FLAGS]) {
+ flags = rta_getattr_u16(tb[LWTUNNEL_IP_FLAGS]);
+ if (flags & TUNNEL_KEY)
+ print_bool(PRINT_ANY, "key", "key ", true);
+ if (flags & TUNNEL_CSUM)
+ print_bool(PRINT_ANY, "csum", "csum ", true);
+ if (flags & TUNNEL_SEQ)
+ print_bool(PRINT_ANY, "seq", "seq ", true);
+ }
+
+ if (tb[LWTUNNEL_IP_OPTS])
+ lwtunnel_print_opts(tb[LWTUNNEL_IP_OPTS]);
}
static void print_encap_ila(FILE *fp, struct rtattr *encap)
static void print_encap_ip6(FILE *fp, struct rtattr *encap)
{
struct rtattr *tb[LWTUNNEL_IP6_MAX+1];
+ __u16 flags;
parse_rtattr_nested(tb, LWTUNNEL_IP6_MAX, encap);
if (tb[LWTUNNEL_IP6_TC])
print_uint(PRINT_ANY, "tc",
"tc %u ", rta_getattr_u8(tb[LWTUNNEL_IP6_TC]));
+
+ if (tb[LWTUNNEL_IP6_FLAGS]) {
+ flags = rta_getattr_u16(tb[LWTUNNEL_IP6_FLAGS]);
+ if (flags & TUNNEL_KEY)
+ print_bool(PRINT_ANY, "key", "key ", true);
+ if (flags & TUNNEL_CSUM)
+ print_bool(PRINT_ANY, "csum", "csum ", true);
+ if (flags & TUNNEL_SEQ)
+ print_bool(PRINT_ANY, "seq", "seq ", true);
+ }
+
+ if (tb[LWTUNNEL_IP6_OPTS])
+ lwtunnel_print_opts(tb[LWTUNNEL_IP6_OPTS]);
}
static void print_encap_bpf(FILE *fp, struct rtattr *encap)
case LWTUNNEL_ENCAP_SEG6_LOCAL:
print_encap_seg6local(fp, encap);
break;
+ case LWTUNNEL_ENCAP_RPL:
+ print_encap_rpl(fp, encap);
+ break;
}
}
struct seg6_iptunnel_encap *tuninfo;
struct ipv6_sr_hdr *srh;
char **argv = *argvp;
- char segbuf[1024];
+ char segbuf[1024] = "";
int argc = *argcp;
int encap = -1;
__u32 hmac = 0;
+ int ret = 0;
int srhlen;
while (argc > 0) {
memcpy(tuninfo->srh, srh, srhlen);
if (rta_addattr_l(rta, len, SEG6_IPTUNNEL_SRH, tuninfo,
- sizeof(*tuninfo) + srhlen))
- return -1;
+ sizeof(*tuninfo) + srhlen)) {
+ ret = -1;
+ goto out;
+ }
+ *argcp = argc + 1;
+ *argvp = argv - 1;
+
+out:
free(tuninfo);
free(srh);
+ return ret;
+}
+
+static struct ipv6_rpl_sr_hdr *parse_rpl_srh(char *segbuf)
+{
+ struct ipv6_rpl_sr_hdr *srh;
+ int nsegs = 0;
+ int srhlen;
+ char *s;
+ int i;
+
+ s = segbuf;
+ for (i = 0; *s; *s++ == ',' ? i++ : *s);
+ nsegs = i + 1;
+
+ srhlen = 8 + 16 * nsegs;
+
+ srh = calloc(1, srhlen);
+
+ srh->hdrlen = (srhlen >> 3) - 1;
+ srh->type = 3;
+ srh->segments_left = nsegs;
+
+ for (s = strtok(segbuf, ","); s; s = strtok(NULL, ",")) {
+ inet_prefix addr;
+
+ get_addr(&addr, s, AF_INET6);
+ memcpy(&srh->rpl_segaddr[i], addr.data, sizeof(struct in6_addr));
+ i--;
+ }
+
+ return srh;
+}
+
+static int parse_encap_rpl(struct rtattr *rta, size_t len, int *argcp,
+ char ***argvp)
+{
+ struct ipv6_rpl_sr_hdr *srh;
+ char **argv = *argvp;
+ char segbuf[1024] = "";
+ int argc = *argcp;
+ int segs_ok = 0;
+ int ret = 0;
+ int srhlen;
+
+ while (argc > 0) {
+ if (strcmp(*argv, "segs") == 0) {
+ NEXT_ARG();
+ if (segs_ok++)
+ duparg2("segs", *argv);
+
+ strlcpy(segbuf, *argv, 1024);
+ } else {
+ break;
+ }
+ argc--; argv++;
+ }
+
+ srh = parse_rpl_srh(segbuf);
+ srhlen = (srh->hdrlen + 1) << 3;
+
+ if (rta_addattr_l(rta, len, RPL_IPTUNNEL_SRH, srh,
+ srhlen)) {
+ ret = -1;
+ goto out;
+ }
+
*argcp = argc + 1;
*argvp = argv - 1;
- return 0;
+out:
+ free(srh);
+
+ return ret;
}
struct lwt_x {
static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp,
char ***argvp)
{
- int segs_ok = 0, hmac_ok = 0, table_ok = 0, nh4_ok = 0, nh6_ok = 0;
- int iif_ok = 0, oif_ok = 0, action_ok = 0, srh_ok = 0, bpf_ok = 0;
- __u32 action = 0, table, iif, oif;
+ int segs_ok = 0, hmac_ok = 0, table_ok = 0, vrftable_ok = 0;
+ int nh4_ok = 0, nh6_ok = 0, iif_ok = 0, oif_ok = 0;
+ __u32 action = 0, table, vrftable, iif, oif;
+ int action_ok = 0, srh_ok = 0, bpf_ok = 0;
struct ipv6_sr_hdr *srh;
char **argv = *argvp;
int argc = *argcp;
NEXT_ARG();
if (table_ok++)
duparg2("table", *argv);
- get_u32(&table, *argv, 0);
+ if (rtnl_rttable_a2n(&table, *argv))
+ invarg("invalid table id\n", *argv);
ret = rta_addattr32(rta, len, SEG6_LOCAL_TABLE, table);
+ } else if (strcmp(*argv, "vrftable") == 0) {
+ NEXT_ARG();
+ if (vrftable_ok++)
+ duparg2("vrftable", *argv);
+ if (rtnl_rttable_a2n(&vrftable, *argv))
+ invarg("invalid vrf table id\n", *argv);
+ ret = rta_addattr32(rta, len, SEG6_LOCAL_VRFTABLE,
+ vrftable);
} else if (strcmp(*argv, "nh4") == 0) {
NEXT_ARG();
if (nh4_ok++)
return 0;
}
+static int lwtunnel_parse_geneve_opt(char *str, size_t len, struct rtattr *rta)
+{
+ struct rtattr *nest;
+ char *token;
+ int i, err;
+
+ nest = rta_nest(rta, len, LWTUNNEL_IP_OPTS_GENEVE | NLA_F_NESTED);
+ i = 1;
+ token = strsep(&str, ":");
+ while (token) {
+ switch (i) {
+ case LWTUNNEL_IP_OPT_GENEVE_CLASS:
+ {
+ __be16 opt_class;
+
+ if (!strlen(token))
+ break;
+ err = get_be16(&opt_class, token, 0);
+ if (err)
+ return err;
+
+ rta_addattr16(rta, len, i, opt_class);
+ break;
+ }
+ case LWTUNNEL_IP_OPT_GENEVE_TYPE:
+ {
+ __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_GENEVE_DATA:
+ {
+ size_t token_len = strlen(token);
+ __u8 *opts;
+
+ if (!token_len)
+ break;
+ opts = malloc(token_len / 2);
+ if (!opts)
+ return -1;
+ if (hex2mem(token, opts, token_len / 2) < 0) {
+ free(opts);
+ return -1;
+ }
+ rta_addattr_l(rta, len, i, opts, token_len / 2);
+ free(opts);
+
+ break;
+ }
+ default:
+ fprintf(stderr, "Unknown \"geneve_opts\" type\n");
+ return -1;
+ }
+
+ token = strsep(&str, ":");
+ i++;
+ }
+ rta_nest_end(rta, nest);
+
+ return 0;
+}
+
+static int lwtunnel_parse_geneve_opts(char *str, size_t len, struct rtattr *rta)
+{
+ char *token;
+ int err;
+
+ token = strsep(&str, ",");
+ while (token) {
+ err = lwtunnel_parse_geneve_opt(token, len, rta);
+ if (err)
+ return err;
+
+ token = strsep(&str, ",");
+ }
+
+ return 0;
+}
+
+static int lwtunnel_parse_vxlan_opts(char *str, size_t len, struct rtattr *rta)
+{
+ struct rtattr *nest;
+ __u32 gbp;
+ int err;
+
+ nest = rta_nest(rta, len, LWTUNNEL_IP_OPTS_VXLAN | NLA_F_NESTED);
+ err = get_u32(&gbp, str, 0);
+ if (err)
+ return err;
+ rta_addattr32(rta, len, LWTUNNEL_IP_OPT_VXLAN_GBP, gbp);
+
+ rta_nest_end(rta, nest);
+ 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)
{
int id_ok = 0, dst_ok = 0, src_ok = 0, tos_ok = 0, ttl_ok = 0;
+ int key_ok = 0, csum_ok = 0, seq_ok = 0, opts_ok = 0;
char **argv = *argvp;
int argc = *argcp;
int ret = 0;
+ __u16 flags = 0;
while (argc > 0) {
if (strcmp(*argv, "id") == 0) {
if (get_u8(&ttl, *argv, 0))
invarg("\"ttl\" value is invalid\n", *argv);
ret = rta_addattr8(rta, len, LWTUNNEL_IP_TTL, ttl);
+ } else if (strcmp(*argv, "geneve_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_geneve_opts(*argv, len, rta);
+ if (ret)
+ invarg("\"geneve_opts\" value is invalid\n",
+ *argv);
+ rta_nest_end(rta, nest);
+ } else if (strcmp(*argv, "vxlan_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_vxlan_opts(*argv, len, rta);
+ if (ret)
+ 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);
+ flags |= TUNNEL_KEY;
+ } else if (strcmp(*argv, "csum") == 0) {
+ if (csum_ok++)
+ duparg2("csum", *argv);
+ flags |= TUNNEL_CSUM;
+ } else if (strcmp(*argv, "seq") == 0) {
+ if (seq_ok++)
+ duparg2("seq", *argv);
+ flags |= TUNNEL_SEQ;
} else {
break;
}
argc--; argv++;
}
+ if (flags)
+ ret = rta_addattr16(rta, len, LWTUNNEL_IP_FLAGS, flags);
+
/* argv is currently the first unparsed argument,
* but the lwt_parse_encap() caller will move to the next,
* so step back
argc--; argv++;
- if (rta_addattr64(rta, 1024, ILA_ATTR_LOCATOR, locator))
+ if (rta_addattr64(rta, len, ILA_ATTR_LOCATOR, locator))
return -1;
while (argc > 0) {
invarg("\"csum-mode\" value is invalid\n",
*argv);
- ret = rta_addattr8(rta, 1024, ILA_ATTR_CSUM_MODE,
+ ret = rta_addattr8(rta, len, ILA_ATTR_CSUM_MODE,
(__u8)csum_mode);
argc--; argv++;
invarg("\"ident-type\" value is invalid\n",
*argv);
- ret = rta_addattr8(rta, 1024, ILA_ATTR_IDENT_TYPE,
+ ret = rta_addattr8(rta, len, ILA_ATTR_IDENT_TYPE,
(__u8)ident_type);
argc--; argv++;
invarg("\"hook-type\" value is invalid\n",
*argv);
- ret = rta_addattr8(rta, 1024, ILA_ATTR_HOOK_TYPE,
+ ret = rta_addattr8(rta, len, ILA_ATTR_HOOK_TYPE,
(__u8)hook_type);
argc--; argv++;
int *argcp, char ***argvp)
{
int id_ok = 0, dst_ok = 0, src_ok = 0, tos_ok = 0, ttl_ok = 0;
+ int key_ok = 0, csum_ok = 0, seq_ok = 0, opts_ok = 0;
char **argv = *argvp;
int argc = *argcp;
int ret = 0;
+ __u16 flags = 0;
while (argc > 0) {
if (strcmp(*argv, "id") == 0) {
*argv);
ret = rta_addattr8(rta, len, LWTUNNEL_IP6_HOPLIMIT,
hoplimit);
+ } else if (strcmp(*argv, "geneve_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_geneve_opts(*argv, len, rta);
+ if (ret)
+ invarg("\"geneve_opts\" value is invalid\n",
+ *argv);
+ rta_nest_end(rta, nest);
+ } else if (strcmp(*argv, "vxlan_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_vxlan_opts(*argv, len, rta);
+ if (ret)
+ 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);
+ flags |= TUNNEL_KEY;
+ } else if (strcmp(*argv, "csum") == 0) {
+ if (csum_ok++)
+ duparg2("csum", *argv);
+ flags |= TUNNEL_CSUM;
+ } else if (strcmp(*argv, "seq") == 0) {
+ if (seq_ok++)
+ duparg2("seq", *argv);
+ flags |= TUNNEL_SEQ;
} else {
break;
}
argc--; argv++;
}
+ if (flags)
+ ret = rta_addattr16(rta, len, LWTUNNEL_IP6_FLAGS, flags);
+
/* argv is currently the first unparsed argument,
* but the lwt_parse_encap() caller will move to the next,
* so step back
if (get_unsigned(&headroom, *argv, 0) || headroom == 0)
invarg("headroom is invalid\n", *argv);
if (!headroom_set)
- rta_addattr32(rta, 1024, LWT_BPF_XMIT_HEADROOM,
+ rta_addattr32(rta, len, LWT_BPF_XMIT_HEADROOM,
headroom);
headroom_set = 1;
} else if (strcmp(*argv, "help") == 0) {
return 0;
}
-int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp)
+int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp,
+ int encap_attr, int encap_type_attr)
{
struct rtattr *nest;
int argc = *argcp;
exit(-1);
}
- nest = rta_nest(rta, 1024, RTA_ENCAP);
+ nest = rta_nest(rta, len, encap_attr);
switch (type) {
case LWTUNNEL_ENCAP_MPLS:
ret = parse_encap_mpls(rta, len, &argc, &argv);
case LWTUNNEL_ENCAP_SEG6_LOCAL:
ret = parse_encap_seg6local(rta, len, &argc, &argv);
break;
+ case LWTUNNEL_ENCAP_RPL:
+ ret = parse_encap_rpl(rta, len, &argc, &argv);
+ break;
default:
fprintf(stderr, "Error: unsupported encap type\n");
break;
rta_nest_end(rta, nest);
- ret = rta_addattr16(rta, 1024, RTA_ENCAP_TYPE, type);
+ ret = rta_addattr16(rta, len, encap_type_attr, type);
*argcp = argc;
*argvp = argv;