[SEG6_LOCAL_ACTION_END_S] = "End.S",
[SEG6_LOCAL_ACTION_END_AS] = "End.AS",
[SEG6_LOCAL_ACTION_END_AM] = "End.AM",
+ [SEG6_LOCAL_ACTION_END_BPF] = "End.BPF",
};
static const char *format_action_type(int action)
return SEG6_LOCAL_ACTION_UNSPEC;
}
+static void print_encap_bpf_prog(FILE *fp, struct rtattr *encap,
+ const char *str)
+{
+ struct rtattr *tb[LWT_BPF_PROG_MAX+1];
+ const char *progname = NULL;
+
+ parse_rtattr_nested(tb, LWT_BPF_PROG_MAX, encap);
+
+ if (tb[LWT_BPF_PROG_NAME])
+ progname = rta_getattr_str(tb[LWT_BPF_PROG_NAME]);
+
+ if (is_json_context())
+ print_string(PRINT_JSON, str, NULL,
+ progname ? : "<unknown>");
+ else {
+ fprintf(fp, "%s ", str);
+ if (progname)
+ fprintf(fp, "%s ", progname);
+ }
+}
+
static void print_encap_seg6local(FILE *fp, struct rtattr *encap)
{
struct rtattr *tb[SEG6_LOCAL_MAX + 1];
print_string(PRINT_ANY, "oif",
"oif %s ", ll_index_to_name(oif));
}
+
+ if (tb[SEG6_LOCAL_BPF])
+ print_encap_bpf_prog(fp, tb[SEG6_LOCAL_BPF], "endpoint");
}
static void print_encap_mpls(FILE *fp, struct rtattr *encap)
"tc %u ", rta_getattr_u8(tb[LWTUNNEL_IP6_TC]));
}
-static void print_encap_bpf_prog(FILE *fp, struct rtattr *encap,
- const char *str)
-{
- struct rtattr *tb[LWT_BPF_PROG_MAX+1];
- const char *progname = NULL;
-
- parse_rtattr_nested(tb, LWT_BPF_PROG_MAX, encap);
-
- if (tb[LWT_BPF_PROG_NAME])
- progname = rta_getattr_str(tb[LWT_BPF_PROG_NAME]);
-
- if (is_json_context())
- print_string(PRINT_JSON, str, NULL,
- progname ? : "<unknown>");
- else {
- fprintf(fp, "%s ", str);
- if (progname)
- fprintf(fp, "%s ", progname);
- }
-}
-
static void print_encap_bpf(FILE *fp, struct rtattr *encap)
{
struct rtattr *tb[LWT_BPF_MAX+1];
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);
- rta_addattr_l(rta, len, SEG6_IPTUNNEL_SRH, tuninfo,
- sizeof(*tuninfo) + srhlen);
+ if (rta_addattr_l(rta, len, SEG6_IPTUNNEL_SRH, tuninfo,
+ sizeof(*tuninfo) + srhlen)) {
+ ret = -1;
+ goto out;
+ }
+
+ *argcp = argc + 1;
+ *argvp = argv - 1;
+out:
free(tuninfo);
free(srh);
- *argcp = argc + 1;
- *argvp = argv - 1;
+ return ret;
+}
+
+struct lwt_x {
+ struct rtattr *rta;
+ size_t len;
+};
+
+static void bpf_lwt_cb(void *lwt_ptr, int fd, const char *annotation)
+{
+ struct lwt_x *x = lwt_ptr;
+
+ rta_addattr32(x->rta, x->len, LWT_BPF_PROG_FD, fd);
+ rta_addattr_l(x->rta, x->len, LWT_BPF_PROG_NAME, annotation,
+ strlen(annotation) + 1);
+}
+
+static const struct bpf_cfg_ops bpf_cb_ops = {
+ .ebpf_cb = bpf_lwt_cb,
+};
+
+static int lwt_parse_bpf(struct rtattr *rta, size_t len,
+ int *argcp, char ***argvp,
+ int attr, const enum bpf_prog_type bpf_type)
+{
+ struct bpf_cfg_in cfg = {
+ .type = bpf_type,
+ .argc = *argcp,
+ .argv = *argvp,
+ };
+ struct lwt_x x = {
+ .rta = rta,
+ .len = len,
+ };
+ struct rtattr *nest;
+ int err;
+
+ nest = rta_nest(rta, len, attr);
+ err = bpf_parse_and_load_common(&cfg, &bpf_cb_ops, &x);
+ if (err < 0) {
+ fprintf(stderr, "Failed to parse eBPF program: %s\n",
+ strerror(-err));
+ return -1;
+ }
+ rta_nest_end(rta, nest);
+
+ *argcp = cfg.argc;
+ *argvp = cfg.argv;
return 0;
}
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;
+ int iif_ok = 0, oif_ok = 0, action_ok = 0, srh_ok = 0, bpf_ok = 0;
__u32 action = 0, table, iif, oif;
struct ipv6_sr_hdr *srh;
char **argv = *argvp;
char segbuf[1024];
inet_prefix addr;
__u32 hmac = 0;
+ int ret = 0;
while (argc > 0) {
if (strcmp(*argv, "action") == 0) {
action = read_action_type(*argv);
if (!action)
invarg("\"action\" value is invalid\n", *argv);
- rta_addattr32(rta, len, SEG6_LOCAL_ACTION, action);
+ ret = rta_addattr32(rta, len, SEG6_LOCAL_ACTION,
+ action);
} else if (strcmp(*argv, "table") == 0) {
NEXT_ARG();
if (table_ok++)
duparg2("table", *argv);
get_u32(&table, *argv, 0);
- rta_addattr32(rta, len, SEG6_LOCAL_TABLE, table);
+ ret = rta_addattr32(rta, len, SEG6_LOCAL_TABLE, table);
} else if (strcmp(*argv, "nh4") == 0) {
NEXT_ARG();
if (nh4_ok++)
duparg2("nh4", *argv);
get_addr(&addr, *argv, AF_INET);
- rta_addattr_l(rta, len, SEG6_LOCAL_NH4, &addr.data,
- addr.bytelen);
+ ret = rta_addattr_l(rta, len, SEG6_LOCAL_NH4,
+ &addr.data, addr.bytelen);
} else if (strcmp(*argv, "nh6") == 0) {
NEXT_ARG();
if (nh6_ok++)
duparg2("nh6", *argv);
get_addr(&addr, *argv, AF_INET6);
- rta_addattr_l(rta, len, SEG6_LOCAL_NH6, &addr.data,
- addr.bytelen);
+ ret = rta_addattr_l(rta, len, SEG6_LOCAL_NH6,
+ &addr.data, addr.bytelen);
} else if (strcmp(*argv, "iif") == 0) {
NEXT_ARG();
if (iif_ok++)
iif = ll_name_to_index(*argv);
if (!iif)
exit(nodev(*argv));
- rta_addattr32(rta, len, SEG6_LOCAL_IIF, iif);
+ ret = rta_addattr32(rta, len, SEG6_LOCAL_IIF, iif);
} else if (strcmp(*argv, "oif") == 0) {
NEXT_ARG();
if (oif_ok++)
oif = ll_name_to_index(*argv);
if (!oif)
exit(nodev(*argv));
- rta_addattr32(rta, len, SEG6_LOCAL_OIF, oif);
+ ret = rta_addattr32(rta, len, SEG6_LOCAL_OIF, oif);
} else if (strcmp(*argv, "srh") == 0) {
NEXT_ARG();
if (srh_ok++)
} else {
continue;
}
+ } else if (strcmp(*argv, "endpoint") == 0) {
+ NEXT_ARG();
+ if (bpf_ok++)
+ duparg2("endpoint", *argv);
+
+ if (lwt_parse_bpf(rta, len, &argc, &argv, SEG6_LOCAL_BPF,
+ BPF_PROG_TYPE_LWT_SEG6LOCAL) < 0)
+ exit(-1);
} else {
break;
}
+ if (ret)
+ return ret;
argc--; argv++;
}
srh = parse_srh(segbuf, hmac,
action == SEG6_LOCAL_ACTION_END_B6_ENCAP);
srhlen = (srh->hdrlen + 1) << 3;
- rta_addattr_l(rta, len, SEG6_LOCAL_SRH, srh, srhlen);
+ ret = rta_addattr_l(rta, len, SEG6_LOCAL_SRH, srh, srhlen);
free(srh);
}
*argcp = argc + 1;
*argvp = argv - 1;
- return 0;
+ return ret;
}
static int parse_encap_mpls(struct rtattr *rta, size_t len,
exit(1);
}
- rta_addattr_l(rta, len, MPLS_IPTUNNEL_DST, &addr.data,
- addr.bytelen);
+ if (rta_addattr_l(rta, len, MPLS_IPTUNNEL_DST,
+ &addr.data, addr.bytelen))
+ return -1;
argc--;
argv++;
duparg2("ttl", *argv);
if (get_u8(&ttl, *argv, 0))
invarg("\"ttl\" value is invalid\n", *argv);
- rta_addattr8(rta, len, MPLS_IPTUNNEL_TTL, ttl);
+ if (rta_addattr8(rta, len, MPLS_IPTUNNEL_TTL, ttl))
+ return -1;
} else {
break;
}
static int parse_encap_ip(struct rtattr *rta, size_t len,
int *argcp, char ***argvp)
{
- int id_ok = 0, dst_ok = 0, tos_ok = 0, ttl_ok = 0;
+ int id_ok = 0, dst_ok = 0, src_ok = 0, tos_ok = 0, ttl_ok = 0;
char **argv = *argvp;
int argc = *argcp;
+ int ret = 0;
while (argc > 0) {
if (strcmp(*argv, "id") == 0) {
duparg2("id", *argv);
if (get_be64(&id, *argv, 0))
invarg("\"id\" value is invalid\n", *argv);
- rta_addattr64(rta, len, LWTUNNEL_IP_ID, id);
+ ret = rta_addattr64(rta, len, LWTUNNEL_IP_ID, id);
} else if (strcmp(*argv, "dst") == 0) {
inet_prefix addr;
if (dst_ok++)
duparg2("dst", *argv);
get_addr(&addr, *argv, AF_INET);
- rta_addattr_l(rta, len, LWTUNNEL_IP_DST,
- &addr.data, addr.bytelen);
+ ret = rta_addattr_l(rta, len, LWTUNNEL_IP_DST,
+ &addr.data, addr.bytelen);
+ } else if (strcmp(*argv, "src") == 0) {
+ inet_prefix addr;
+
+ NEXT_ARG();
+ if (src_ok++)
+ duparg2("src", *argv);
+ get_addr(&addr, *argv, AF_INET);
+ ret = rta_addattr_l(rta, len, LWTUNNEL_IP_SRC,
+ &addr.data, addr.bytelen);
} else if (strcmp(*argv, "tos") == 0) {
__u32 tos;
duparg2("tos", *argv);
if (rtnl_dsfield_a2n(&tos, *argv))
invarg("\"tos\" value is invalid\n", *argv);
- rta_addattr8(rta, len, LWTUNNEL_IP_TOS, tos);
+ ret = rta_addattr8(rta, len, LWTUNNEL_IP_TOS, tos);
} else if (strcmp(*argv, "ttl") == 0) {
__u8 ttl;
duparg2("ttl", *argv);
if (get_u8(&ttl, *argv, 0))
invarg("\"ttl\" value is invalid\n", *argv);
- rta_addattr8(rta, len, LWTUNNEL_IP_TTL, ttl);
+ ret = rta_addattr8(rta, len, LWTUNNEL_IP_TTL, ttl);
} else {
break;
}
+ if (ret)
+ break;
argc--; argv++;
}
*argcp = argc + 1;
*argvp = argv - 1;
- return 0;
+ return ret;
}
static int parse_encap_ila(struct rtattr *rta, size_t len,
__u64 locator;
int argc = *argcp;
char **argv = *argvp;
+ int ret = 0;
if (get_addr64(&locator, *argv) < 0) {
fprintf(stderr, "Bad locator: %s\n", *argv);
argc--; argv++;
- rta_addattr64(rta, 1024, ILA_ATTR_LOCATOR, locator);
+ if (rta_addattr64(rta, 1024, ILA_ATTR_LOCATOR, locator))
+ return -1;
while (argc > 0) {
if (strcmp(*argv, "csum-mode") == 0) {
invarg("\"csum-mode\" value is invalid\n",
*argv);
- rta_addattr8(rta, 1024, ILA_ATTR_CSUM_MODE,
- (__u8)csum_mode);
+ ret = rta_addattr8(rta, 1024, ILA_ATTR_CSUM_MODE,
+ (__u8)csum_mode);
argc--; argv++;
} else if (strcmp(*argv, "ident-type") == 0) {
invarg("\"ident-type\" value is invalid\n",
*argv);
- rta_addattr8(rta, 1024, ILA_ATTR_IDENT_TYPE,
- (__u8)ident_type);
+ ret = rta_addattr8(rta, 1024, ILA_ATTR_IDENT_TYPE,
+ (__u8)ident_type);
argc--; argv++;
} else if (strcmp(*argv, "hook-type") == 0) {
invarg("\"hook-type\" value is invalid\n",
*argv);
- rta_addattr8(rta, 1024, ILA_ATTR_HOOK_TYPE,
- (__u8)hook_type);
+ ret = rta_addattr8(rta, 1024, ILA_ATTR_HOOK_TYPE,
+ (__u8)hook_type);
argc--; argv++;
} else {
break;
}
+ if (ret)
+ break;
}
/* argv is currently the first unparsed argument,
*argcp = argc + 1;
*argvp = argv - 1;
- return 0;
+ return ret;
}
static int parse_encap_ip6(struct rtattr *rta, size_t len,
int *argcp, char ***argvp)
{
- int id_ok = 0, dst_ok = 0, tos_ok = 0, ttl_ok = 0;
+ int id_ok = 0, dst_ok = 0, src_ok = 0, tos_ok = 0, ttl_ok = 0;
char **argv = *argvp;
int argc = *argcp;
+ int ret = 0;
while (argc > 0) {
if (strcmp(*argv, "id") == 0) {
duparg2("id", *argv);
if (get_be64(&id, *argv, 0))
invarg("\"id\" value is invalid\n", *argv);
- rta_addattr64(rta, len, LWTUNNEL_IP6_ID, id);
+ ret = rta_addattr64(rta, len, LWTUNNEL_IP6_ID, id);
} else if (strcmp(*argv, "dst") == 0) {
inet_prefix addr;
if (dst_ok++)
duparg2("dst", *argv);
get_addr(&addr, *argv, AF_INET6);
- rta_addattr_l(rta, len, LWTUNNEL_IP6_DST,
- &addr.data, addr.bytelen);
+ ret = rta_addattr_l(rta, len, LWTUNNEL_IP6_DST,
+ &addr.data, addr.bytelen);
+ } else if (strcmp(*argv, "src") == 0) {
+ inet_prefix addr;
+
+ NEXT_ARG();
+ if (src_ok++)
+ duparg2("src", *argv);
+ get_addr(&addr, *argv, AF_INET6);
+ ret = rta_addattr_l(rta, len, LWTUNNEL_IP6_SRC,
+ &addr.data, addr.bytelen);
} else if (strcmp(*argv, "tc") == 0) {
__u32 tc;
duparg2("tc", *argv);
if (rtnl_dsfield_a2n(&tc, *argv))
invarg("\"tc\" value is invalid\n", *argv);
- rta_addattr8(rta, len, LWTUNNEL_IP6_TC, tc);
+ ret = rta_addattr8(rta, len, LWTUNNEL_IP6_TC, tc);
} else if (strcmp(*argv, "hoplimit") == 0) {
__u8 hoplimit;
if (get_u8(&hoplimit, *argv, 0))
invarg("\"hoplimit\" value is invalid\n",
*argv);
- rta_addattr8(rta, len, LWTUNNEL_IP6_HOPLIMIT, hoplimit);
+ ret = rta_addattr8(rta, len, LWTUNNEL_IP6_HOPLIMIT,
+ hoplimit);
} else {
break;
}
+ if (ret)
+ break;
argc--; argv++;
}
*argcp = argc + 1;
*argvp = argv - 1;
- return 0;
-}
-
-struct lwt_x {
- struct rtattr *rta;
- size_t len;
-};
-
-static void bpf_lwt_cb(void *lwt_ptr, int fd, const char *annotation)
-{
- struct lwt_x *x = lwt_ptr;
-
- rta_addattr32(x->rta, x->len, LWT_BPF_PROG_FD, fd);
- rta_addattr_l(x->rta, x->len, LWT_BPF_PROG_NAME, annotation,
- strlen(annotation) + 1);
-}
-
-static const struct bpf_cfg_ops bpf_cb_ops = {
- .ebpf_cb = bpf_lwt_cb,
-};
-
-static int lwt_parse_bpf(struct rtattr *rta, size_t len,
- int *argcp, char ***argvp,
- int attr, const enum bpf_prog_type bpf_type)
-{
- struct bpf_cfg_in cfg = {
- .type = bpf_type,
- .argc = *argcp,
- .argv = *argvp,
- };
- struct lwt_x x = {
- .rta = rta,
- .len = len,
- };
- struct rtattr *nest;
- int err;
-
- nest = rta_nest(rta, len, attr);
- err = bpf_parse_and_load_common(&cfg, &bpf_cb_ops, &x);
- if (err < 0) {
- fprintf(stderr, "Failed to parse eBPF program: %s\n",
- strerror(-err));
- return -1;
- }
- rta_nest_end(rta, nest);
-
- *argcp = cfg.argc;
- *argvp = cfg.argv;
-
- return 0;
+ return ret;
}
static void lwt_bpf_usage(void)
int argc = *argcp;
char **argv = *argvp;
__u16 type;
+ int ret = 0;
NEXT_ARG();
type = read_encap_type(*argv);
nest = rta_nest(rta, 1024, RTA_ENCAP);
switch (type) {
case LWTUNNEL_ENCAP_MPLS:
- parse_encap_mpls(rta, len, &argc, &argv);
+ ret = parse_encap_mpls(rta, len, &argc, &argv);
break;
case LWTUNNEL_ENCAP_IP:
- parse_encap_ip(rta, len, &argc, &argv);
+ ret = parse_encap_ip(rta, len, &argc, &argv);
break;
case LWTUNNEL_ENCAP_ILA:
- parse_encap_ila(rta, len, &argc, &argv);
+ ret = parse_encap_ila(rta, len, &argc, &argv);
break;
case LWTUNNEL_ENCAP_IP6:
- parse_encap_ip6(rta, len, &argc, &argv);
+ ret = parse_encap_ip6(rta, len, &argc, &argv);
break;
case LWTUNNEL_ENCAP_BPF:
if (parse_encap_bpf(rta, len, &argc, &argv) < 0)
exit(-1);
break;
case LWTUNNEL_ENCAP_SEG6:
- parse_encap_seg6(rta, len, &argc, &argv);
+ ret = parse_encap_seg6(rta, len, &argc, &argv);
break;
case LWTUNNEL_ENCAP_SEG6_LOCAL:
- parse_encap_seg6local(rta, len, &argc, &argv);
+ ret = parse_encap_seg6local(rta, len, &argc, &argv);
break;
default:
fprintf(stderr, "Error: unsupported encap type\n");
break;
}
+ if (ret)
+ return ret;
+
rta_nest_end(rta, nest);
- rta_addattr16(rta, 1024, RTA_ENCAP_TYPE, type);
+ ret = rta_addattr16(rta, 1024, RTA_ENCAP_TYPE, type);
*argcp = argc;
*argvp = argv;
- return 0;
+ return ret;
}