]> git.proxmox.com Git - mirror_iproute2.git/commitdiff
ip: add support for seg6local End.BPF action
authorMathieu Xhonneux <m.xhonneux@gmail.com>
Tue, 17 Jul 2018 14:49:52 +0000 (14:49 +0000)
committerStephen Hemminger <stephen@networkplumber.org>
Wed, 18 Jul 2018 22:56:18 +0000 (15:56 -0700)
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>
ip/iproute_lwtunnel.c
lib/bpf.c

index 46a212c8721e01209b0fbbbd82957433ece813fc..e604481142ec1e2eb03c68ccf11526917bbd47da 100644 (file)
@@ -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");
index 4e26c0df76c51d9748b2c86df9de1c43c7945470..65e26989a1f30537d3eed4599f3ab212395527b0 100644 (file)
--- a/lib/bpf.c
+++ b/lib/bpf.c
@@ -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)