From: Thomas Graf
Adds support to configure BPF programs as nexthop actions via the LWT
framework.
Example:
ip route add 192.168.253.2/32 \
encap bpf out obj lwt_len_hist_kern.o section len_hist \
dev veth0
Signed-off-by: Thomas Graf
---
include/bpf_api.h | 5 ++
ip/iproute_lwtunnel.c | 186 +
lib/bpf.c | 18 +
man/man8/ip-route.8.in | 41 ++-
4 files changed, 235 insertions(+), 15 deletions(-)
diff --git a/include/bpf_api.h b/include/bpf_api.h
index 72578c9..d132471 100644
--- a/include/bpf_api.h
+++ b/include/bpf_api.h
@@ -87,6 +87,11 @@
__section(ELF_SECTION_ACTION)
#endif
+#ifndef __section_lwt_entry
+# define __section_lwt_entry \
+ __section(ELF_SECTION_PROG)
+#endif
+
#ifndef __section_license
# define __section_license \
__section(ELF_SECTION_LICENSE)
diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c
index b656143..6c1f8fb 100644
--- a/ip/iproute_lwtunnel.c
+++ b/ip/iproute_lwtunnel.c
@@ -24,20 +24,7 @@
#include "rt_names.h"
#include "utils.h"
#include "iproute_lwtunnel.h"
-
-static int read_encap_type(const char *name)
-{
- if (strcmp(name, "mpls") == 0)
- return LWTUNNEL_ENCAP_MPLS;
- else if (strcmp(name, "ip") == 0)
- return LWTUNNEL_ENCAP_IP;
- else if (strcmp(name, "ip6") == 0)
- return LWTUNNEL_ENCAP_IP6;
- else if (strcmp(name, "ila") == 0)
- return LWTUNNEL_ENCAP_ILA;
- else
- return LWTUNNEL_ENCAP_NONE;
-}
+#include "bpf_util.h"
static const char *format_encap_type(int type)
{
@@ -50,11 +37,44 @@ static const char *format_encap_type(int type)
return "ip6";
case LWTUNNEL_ENCAP_ILA:
return "ila";
+ case LWTUNNEL_ENCAP_BPF:
+ return "bpf";
default:
return "unknown";
}
}
+static void encap_type_usage(void)
+{
+ int i;
+
+ fprintf(stderr, "Usage: ip route ... encap TYPE [ OPTIONS ] [...]\n");
+
+ for (i = 1; i <= LWTUNNEL_ENCAP_MAX; i++)
+ fprintf(stderr, "%s %s\n", format_encap_type(i),
+ i == 1 ? "TYPE := " : " ");
+
+ exit(-1);
+}
+
+static int read_encap_type(const char *name)
+{
+ if (strcmp(name, "mpls") == 0)
+ return LWTUNNEL_ENCAP_MPLS;
+ else if (strcmp(name, "ip") == 0)
+ return LWTUNNEL_ENCAP_IP;
+ else if (strcmp(name, "ip6") == 0)
+ return LWTUNNEL_ENCAP_IP6;
+ else if (strcmp(name, "ila") == 0)
+ return LWTUNNEL_ENCAP_ILA;
+ else if (strcmp(name, "bpf") == 0)
+ return LWTUNNEL_ENCAP_BPF;
+ else if (strcmp(name, "help") == 0)
+ encap_type_usage();
+
+ return LWTUNNEL_ENCAP_NONE;
+}
+
static void print_encap_mpls(FILE *fp, struct rtattr *encap)
{
struct rtattr *tb[MPLS_IPTUNNEL_MAX+1];
@@ -159,6 +179,34 @@ static void print_encap_ip6(FILE *fp, struct rtattr *encap)
fprintf(fp, "tc %d ", 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];
+
+ parse_rtattr_nested(tb, LWT_BPF_PROG_MAX, encap);
+ fprintf(fp, "%s ", str);
+
+ if (tb[LWT_BPF_PROG_NAME])
+ fprintf(fp, "%s ", rta_getattr_str(tb[LWT_BPF_PROG_NAME]));
+}
+
+static void print_encap_bpf(FILE *fp, struct rtattr *encap)
+{
+ struct rtattr *tb[LWT_BPF_MAX+1];
+
+ parse_rtattr_nested(tb, LWT_BPF_MAX, encap);
+
+ if (tb[LWT_BPF_IN])
+ print_encap_bpf_prog(fp, tb[LWT_BPF_IN], "in");
+ if (tb[LWT_BPF_OUT])
+ print_encap_bpf_prog(fp, tb[LWT_BPF_OUT], "out");
+ if (tb[LWT_BPF_XMIT])
+ print_encap_bpf_prog(fp, tb[LWT_BPF_XMIT], "xmit");
+ if (tb[LWT_BPF_XMIT_HEADROOM])
+ fprintf(fp, "%d ", rta_getattr_u32(tb[LWT_BPF_XMIT_HEADROOM]));
+}
+
void lwt_print_encap(FILE *fp, struct rtattr *encap_type,
struct rtattr *encap)
{
@@ -184,6 +232,9 @@ void lwt_print_encap(FILE *fp, struct rtattr *encap_type,
case LWTUNNEL_ENCAP_IP6:
print_encap_ip6(fp, encap);
break;
+ case LWTUNNEL_ENCAP_BPF:
+ print_encap_bpf(fp, encap);
+ break;
}
}
@@ -365,6 +416,109 @@ static int parse_encap_ip6(struct rtattr *rta, size_t
len, int *argcp, char ***a
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->l