ip: add support for seg6local End.BPF action
This patch adds support for the End.BPF action of the seg6local
lightweight tunnel. Functions from the BPF lightweight tunnel are
re-used in this patch. Example:
$ ip -6 route add fc00::18 encap seg6local action End.BPF endpoint
obj my_bpf.o sec my_func dev eth0
$ ip -6 route show fc00::18
fc00::18 encap seg6local action End.BPF endpoint my_bpf.o:[my_func]
dev eth0 metric 1024 pref medium
v2: - re-use of print_encap_bpf_prog instead of fprintf
- introduction of "endpoint" keyword for more consistency with
others parameters
Signed-off-by: Mathieu Xhonneux <m.xhonneux@gmail.com>
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
This commit is contained in:
parent
8df708afd6
commit
04cb3c0d43
|
|
@ -177,6 +177,7 @@ static const char *seg6_action_names[SEG6_LOCAL_ACTION_MAX + 1] = {
|
|||
[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)
|
||||
|
|
@ -202,6 +203,27 @@ static int read_action_type(const char *name)
|
|||
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];
|
||||
|
|
@ -250,6 +272,9 @@ static void print_encap_seg6local(FILE *fp, struct rtattr *encap)
|
|||
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)
|
||||
|
|
@ -356,27 +381,6 @@ static void print_encap_ip6(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];
|
||||
|
|
@ -546,11 +550,60 @@ static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp,
|
|||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
|
|
@ -627,6 +680,14 @@ static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp,
|
|||
} 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;
|
||||
}
|
||||
|
|
@ -896,55 +957,6 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len,
|
|||
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;
|
||||
}
|
||||
|
||||
static void lwt_bpf_usage(void)
|
||||
{
|
||||
fprintf(stderr, "Usage: ip route ... encap bpf [ in BPF ] [ out BPF ] [ xmit BPF ] [...]\n");
|
||||
|
|
|
|||
|
|
@ -95,6 +95,11 @@ static const struct bpf_prog_meta __bpf_prog_meta[] = {
|
|||
.subdir = "ip",
|
||||
.section = ELF_SECTION_PROG,
|
||||
},
|
||||
[BPF_PROG_TYPE_LWT_SEG6LOCAL] = {
|
||||
.type = "lwt_seg6local",
|
||||
.subdir = "ip",
|
||||
.section = ELF_SECTION_PROG,
|
||||
},
|
||||
};
|
||||
|
||||
static bool bpf_map_offload_neutral(enum bpf_map_type type)
|
||||
|
|
|
|||
Loading…
Reference in New Issue