diff mbox series

[iproute2] ip: add support for seg6local End.BPF action

Message ID 20180716144741.20478-1-m.xhonneux@gmail.com
State Changes Requested, archived
Delegated to: stephen hemminger
Headers show
Series [iproute2] ip: add support for seg6local End.BPF action | expand

Commit Message

Mathieu Xhonneux July 16, 2018, 2:47 p.m. UTC
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 obj my_bpf.o
sec my_func dev eth0

$ ip -6 route show fc00::18
fc00::18  encap seg6local action End.BPF my_bpf.o:[my_func] dev eth0
metric 1024 pref medium

Signed-off-by: Mathieu Xhonneux <m.xhonneux@gmail.com>
---
 ip/iproute_lwtunnel.c | 122 +++++++++++++++++++++++++++++---------------------
 lib/bpf.c             |   5 +++
 2 files changed, 77 insertions(+), 50 deletions(-)

Comments

Mathieu Xhonneux July 16, 2018, 12:51 p.m. UTC | #1
This patch corresponds to a new feature that is now available in the
net tree. I hence assumed that this patch had to be sent to iproute2
and not iproute2-next, please tell me if this is not OK, I'll then
send a v2 towards iproute2-next.

Thanks.

2018-07-16 14:47 GMT+00:00 Mathieu Xhonneux <m.xhonneux@gmail.com>:
> 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 obj my_bpf.o
> sec my_func dev eth0
>
> $ ip -6 route show fc00::18
> fc00::18  encap seg6local action End.BPF my_bpf.o:[my_func] dev eth0
> metric 1024 pref medium
>
> Signed-off-by: Mathieu Xhonneux <m.xhonneux@gmail.com>
> ---
>  ip/iproute_lwtunnel.c | 122 +++++++++++++++++++++++++++++---------------------
>  lib/bpf.c             |   5 +++
>  2 files changed, 77 insertions(+), 50 deletions(-)
>
> diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c
> index 46a212c8..71c3d8a4 100644
> --- a/ip/iproute_lwtunnel.c
> +++ b/ip/iproute_lwtunnel.c
> @@ -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)
> @@ -250,6 +251,15 @@ 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]) {
> +               struct rtattr *tb_bpf[LWT_BPF_PROG_MAX+1];
> +
> +               parse_rtattr_nested(tb_bpf, LWT_BPF_PROG_MAX, tb[SEG6_LOCAL_BPF]);
> +
> +               if (tb_bpf[LWT_BPF_PROG_NAME])
> +                       fprintf(fp, "%s ", rta_getattr_str(tb_bpf[LWT_BPF_PROG_NAME]));
> +       }
>  }
>
>  static void print_encap_mpls(FILE *fp, struct rtattr *encap)
> @@ -546,11 +556,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 +686,18 @@ static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp,
>                         } else {
>                                 continue;
>                         }
> +               } else if (strcmp(*argv, "object-file") == 0 ||
> +                          strcmp(*argv, "obj") == 0 ||
> +                          strcmp(*argv, "object-pinned") == 0 ||
> +                          strcmp(*argv, "pinned") == 0 ||
> +                          strcmp(*argv, "fd") == 0) {
> +                       if (bpf_ok++) {
> +                               NEXT_ARG();
> +                               duparg2(*(argv-1), *argv);
> +                       }
> +                       if (lwt_parse_bpf(rta, len, &argc, &argv, SEG6_LOCAL_BPF,
> +                           BPF_PROG_TYPE_LWT_SEG6LOCAL) < 0)
> +                               exit(-1);
>                 } else {
>                         break;
>                 }
> @@ -896,55 +967,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");
> diff --git a/lib/bpf.c b/lib/bpf.c
> index 4e26c0df..65e26989 100644
> --- 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)
> --
> 2.16.1
>
Stephen Hemminger July 16, 2018, 2:48 p.m. UTC | #2
On Mon, 16 Jul 2018 14:47:41 +0000
Mathieu Xhonneux <m.xhonneux@gmail.com> wrote:

> 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 obj my_bpf.o
> sec my_func dev eth0
> 
> $ ip -6 route show fc00::18
> fc00::18  encap seg6local action End.BPF my_bpf.o:[my_func] dev eth0
> metric 1024 pref medium
> 
> Signed-off-by: Mathieu Xhonneux <m.xhonneux@gmail.com>

> ---
>  ip/iproute_lwtunnel.c | 122 +++++++++++++++++++++++++++++---------------------
>  lib/bpf.c             |   5 +++
>  2 files changed, 77 insertions(+), 50 deletions(-)
> 
> diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c
> index 46a212c8..71c3d8a4 100644
> --- a/ip/iproute_lwtunnel.c
> +++ b/ip/iproute_lwtunnel.c
> @@ -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)
> @@ -250,6 +251,15 @@ 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]) {
> +		struct rtattr *tb_bpf[LWT_BPF_PROG_MAX+1];
> +
> +		parse_rtattr_nested(tb_bpf, LWT_BPF_PROG_MAX, tb[SEG6_LOCAL_BPF]);
> +
> +		if (tb_bpf[LWT_BPF_PROG_NAME])
> +			fprintf(fp, "%s ", rta_getattr_str(tb_bpf[LWT_BPF_PROG_NAME]));
> +	}
>  }

Please use print_string to support JSON output.
diff mbox series

Patch

diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c
index 46a212c8..71c3d8a4 100644
--- a/ip/iproute_lwtunnel.c
+++ b/ip/iproute_lwtunnel.c
@@ -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)
@@ -250,6 +251,15 @@  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]) {
+		struct rtattr *tb_bpf[LWT_BPF_PROG_MAX+1];
+
+		parse_rtattr_nested(tb_bpf, LWT_BPF_PROG_MAX, tb[SEG6_LOCAL_BPF]);
+
+		if (tb_bpf[LWT_BPF_PROG_NAME])
+			fprintf(fp, "%s ", rta_getattr_str(tb_bpf[LWT_BPF_PROG_NAME]));
+	}
 }
 
 static void print_encap_mpls(FILE *fp, struct rtattr *encap)
@@ -546,11 +556,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 +686,18 @@  static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp,
 			} else {
 				continue;
 			}
+		} else if (strcmp(*argv, "object-file") == 0 ||
+			   strcmp(*argv, "obj") == 0 ||
+			   strcmp(*argv, "object-pinned") == 0 ||
+			   strcmp(*argv, "pinned") == 0 ||
+			   strcmp(*argv, "fd") == 0) {
+			if (bpf_ok++) {
+				NEXT_ARG();
+				duparg2(*(argv-1), *argv);
+			}
+			if (lwt_parse_bpf(rta, len, &argc, &argv, SEG6_LOCAL_BPF,
+			    BPF_PROG_TYPE_LWT_SEG6LOCAL) < 0)
+				exit(-1);
 		} else {
 			break;
 		}
@@ -896,55 +967,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");
diff --git a/lib/bpf.c b/lib/bpf.c
index 4e26c0df..65e26989 100644
--- 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)