allow eBPF programs to be attached to sockets
Subsystems (15)
v2 cover allow eBPF programs to be attached to sockets
V1->V2:
fixed comments in sample code to state clearly that packet data is accessed with LD_ABS instructions and not internal skb fields.
Also replaced constants in:BPF_LD_ABS(BPF_B, 14 + 9 /* R0 = ip->proto */),
with:BPF_LD_ABS(BPF_B, ETH_HLEN + offsetof(struct iphdr, protocol) /* R0 = ip->proto */),
V1 cover:
Introduce BPF_PROG_TYPE_SOCKET_FILTER type of eBPF programs that can be attached to sockets with setsockopt().
Allow such programs to access maps via lookup/update/delete helpers.
This feature was previewed by bpf manpage in commit b4fc1a460f30("Merge branch 'bpf-next'") Now it can actually run.
1st patch adds LD_ABS/LD_IND instruction verification and 2nd patch adds new setsockopt() flag.
Patches 3-6 are examples in assembler and in C.
Though native eBPF programs are way more powerful than classic filters (attachable through similar setsockopt() call), they don't have skb field accessors yet. Like skb->pkt_type, skb->dev->ifindex are not accessible. There are sevaral ways to achieve that. That will be in the next set of patches. So in this set native eBPF programs can only read data from packet and access maps.
The most powerful example is sockex2_kern.c from patch 6 where ~200 lines of C are compiled into ~300 of eBPF instructions.
It shows how quite complex packet parsing can be done.
LLVM used to build examples is at https://github.com/iovisor/llvm
which is fork of llvm trunk that I'm cleaning up for upstreaming.
Alexei Starovoitov (6):
bpf: verifier: add checks for BPF_ABS | BPF_IND instructions
net: sock: allow eBPF programs to be attached to sockets
samples: bpf: example of stateful socket filtering
samples: bpf: elf_bpf file loader
samples: bpf: trivial eBPF program in C
samples: bpf: large eBPF program in C
arch/alpha/include/uapi/asm/socket.h | 3 + arch/avr32/include/uapi/asm/socket.h | 3 + arch/cris/include/uapi/asm/socket.h | 3 + arch/frv/include/uapi/asm/socket.h | 3 + arch/ia64/include/uapi/asm/socket.h | 3 + arch/m32r/include/uapi/asm/socket.h | 3 + arch/mips/include/uapi/asm/socket.h | 3 + arch/mn10300/include/uapi/asm/socket.h | 3 + arch/parisc/include/uapi/asm/socket.h | 3 + arch/powerpc/include/uapi/asm/socket.h | 3 + arch/s390/include/uapi/asm/socket.h | 3 + arch/sparc/include/uapi/asm/socket.h | 3 + arch/xtensa/include/uapi/asm/socket.h | 3 + include/linux/bpf.h | 4 + include/linux/filter.h | 1 + include/uapi/asm-generic/socket.h | 3 + include/uapi/linux/bpf.h | 1 + kernel/bpf/verifier.c | 70 ++++++++++- net/core/filter.c | 97 +++++++++++++- net/core/sock.c | 13 ++ samples/bpf/Makefile | 20 +++ samples/bpf/bpf_helpers.h | 40 ++++++ samples/bpf/bpf_load.c | 203 ++++++++++++++++++++++++++++++ samples/bpf/bpf_load.h | 24 ++++ samples/bpf/libbpf.c | 28 +++++ samples/bpf/libbpf.h | 15 ++- samples/bpf/sock_example.c | 101 +++++++++++++++ samples/bpf/sockex1_kern.c | 25 ++++ samples/bpf/sockex1_user.c | 49 ++++++++ samples/bpf/sockex2_kern.c | 215 ++++++++++++++++++++++++++++++++ samples/bpf/sockex2_user.c | 44 +++++++ 31 files changed, 987 insertions(+), 5 deletions(-) create mode 100644 samples/bpf/bpf_helpers.h create mode 100644 samples/bpf/bpf_load.c create mode 100644 samples/bpf/bpf_load.h create mode 100644 samples/bpf/sock_example.c create mode 100644 samples/bpf/sockex1_kern.c create mode 100644 samples/bpf/sockex1_user.c create mode 100644 samples/bpf/sockex2_kern.c create mode 100644 samples/bpf/sockex2_user.c
Signature · 1 line
1.7.9.5
PATCH v2 1/6 bpf: verifier: add checks for BPF_ABS | BPF_IND instructions
introduce program type BPF_PROG_TYPE_SOCKET_FILTER that is used for attaching programs to sockets where ctx == skb.
add verifier checks for ABS/IND instructions which can only be seen in socket filters, therefore the check:
if (env->prog->aux->prog_type != BPF_PROG_TYPE_SOCKET_FILTER)
verbose("BPF_LD_ABS|IND instructions are only allowed in socket filters\n");---
v2: no changes
include/uapi/linux/bpf.h | 1 + kernel/bpf/verifier.c | 70 ++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 69 insertions(+), 2 deletions(-)
include/uapi/linux/bpf.h +1 -0
@@ -117,6 +117,7 @@ enum bpf_map_type {enum bpf_prog_type {BPF_PROG_TYPE_UNSPEC , +BPF_PROG_TYPE_SOCKET_FILTER , };/* flags for BPF_MAP_UPDATE_ELEM command */
kernel/bpf/verifier.c +68 -2
82 lines not on this page · raw message
Signature · 1 line
1.7.9.5
PATCH v2 2/6 net: sock: allow eBPF programs to be attached to sockets
In reply to Alexei Starovoitovintroduce new setsockopt() command:
setsockopt(sock, SOL_SOCKET, SO_ATTACH_BPF, &prog_fd, sizeof(prog_fd))
where prog_fd was received from syscall bpf(BPF_PROG_LOAD, attr, ...) and attr->prog_type == BPF_PROG_TYPE_SOCKET_FILTER
setsockopt() calls bpf_prog_get() which increments refcnt of the program, so it doesn't get unloaded while socket is using the program.
The same eBPF program can be attached to multiple sockets.
User task exit automatically closes socket which calls sk_filter_uncharge() which decrements refcnt of eBPF program
---
v2: no changes
Note, I'm not happy about 'ifdef', but 'select or depend BPF_SYSCALL' will make tinification folks cringe, so use ifdef until native eBPF use cases become widespread.
arch/alpha/include/uapi/asm/socket.h | 3 + arch/avr32/include/uapi/asm/socket.h | 3 + arch/cris/include/uapi/asm/socket.h | 3 + arch/frv/include/uapi/asm/socket.h | 3 + arch/ia64/include/uapi/asm/socket.h | 3 + arch/m32r/include/uapi/asm/socket.h | 3 + arch/mips/include/uapi/asm/socket.h | 3 + arch/mn10300/include/uapi/asm/socket.h | 3 + arch/parisc/include/uapi/asm/socket.h | 3 + arch/powerpc/include/uapi/asm/socket.h | 3 + arch/s390/include/uapi/asm/socket.h | 3 + arch/sparc/include/uapi/asm/socket.h | 3 + arch/xtensa/include/uapi/asm/socket.h | 3 + include/linux/bpf.h | 4 ++ include/linux/filter.h | 1 + include/uapi/asm-generic/socket.h | 3 + net/core/filter.c | 97 +++++++++++++++++++++++++++++++- net/core/sock.c | 13 +++++ 18 files changed, 155 insertions(+), 2 deletions(-)
arch/alpha/include/uapi/asm/socket.h +3 -0
@@ -89,4 +89,7 @@#define SO_INCOMING_CPU 49 +#define SO_ATTACH_BPF 50 +#define SO_DETACH_BPF SO_DETACH_FILTER +#endif /* _UAPI_ASM_SOCKET_H */
arch/avr32/include/uapi/asm/socket.h +3 -0
@@ -82,4 +82,7 @@#define SO_INCOMING_CPU 49 +#define SO_ATTACH_BPF 50 +#define SO_DETACH_BPF SO_DETACH_FILTER +#endif /* _UAPI__ASM_AVR32_SOCKET_H */
arch/cris/include/uapi/asm/socket.h +3 -0
@@ -84,6 +84,9 @@#define SO_INCOMING_CPU 49 +#define SO_ATTACH_BPF 50 +#define SO_DETACH_BPF SO_DETACH_FILTER +#endif /* _ASM_SOCKET_H */
arch/frv/include/uapi/asm/socket.h +3 -0
@@ -82,5 +82,8 @@#define SO_INCOMING_CPU 49 +#define SO_ATTACH_BPF 50 +#define SO_DETACH_BPF SO_DETACH_FILTER +#endif /* _ASM_SOCKET_H */
arch/ia64/include/uapi/asm/socket.h +3 -0
@@ -91,4 +91,7 @@#define SO_INCOMING_CPU 49 +#define SO_ATTACH_BPF 50 +#define SO_DETACH_BPF SO_DETACH_FILTER +#endif /* _ASM_IA64_SOCKET_H */
arch/m32r/include/uapi/asm/socket.h +3 -0
@@ -82,4 +82,7 @@#define SO_INCOMING_CPU 49 +#define SO_ATTACH_BPF 50 +#define SO_DETACH_BPF SO_DETACH_FILTER +#endif /* _ASM_M32R_SOCKET_H */
arch/mips/include/uapi/asm/socket.h +3 -0
@@ -100,4 +100,7 @@#define SO_INCOMING_CPU 49 +#define SO_ATTACH_BPF 50 +#define SO_DETACH_BPF SO_DETACH_FILTER +#endif /* _UAPI_ASM_SOCKET_H */
arch/mn10300/include/uapi/asm/socket.h +3 -0
@@ -82,4 +82,7 @@#define SO_INCOMING_CPU 49 +#define SO_ATTACH_BPF 50 +#define SO_DETACH_BPF SO_DETACH_FILTER +#endif /* _ASM_SOCKET_H */
arch/parisc/include/uapi/asm/socket.h +3 -0
@@ -81,4 +81,7 @@#define SO_INCOMING_CPU 0x402A +#define SO_ATTACH_BPF 0x402B +#define SO_DETACH_BPF SO_DETACH_FILTER +#endif /* _UAPI_ASM_SOCKET_H */
arch/powerpc/include/uapi/asm/socket.h +3 -0
@@ -89,4 +89,7 @@#define SO_INCOMING_CPU 49 +#define SO_ATTACH_BPF 50 +#define SO_DETACH_BPF SO_DETACH_FILTER +#endif /* _ASM_POWERPC_SOCKET_H */
arch/s390/include/uapi/asm/socket.h +3 -0
@@ -88,4 +88,7 @@#define SO_INCOMING_CPU 49 +#define SO_ATTACH_BPF 50 +#define SO_DETACH_BPF SO_DETACH_FILTER +#endif /* _ASM_SOCKET_H */
arch/sparc/include/uapi/asm/socket.h +3 -0
@@ -78,6 +78,9 @@#define SO_INCOMING_CPU 0x0033 +#define SO_ATTACH_BPF 0x0034 +#define SO_DETACH_BPF SO_DETACH_FILTER +/* Security levels - as per NRL IPv6 - don't actually do anything */ #define SO_SECURITY_AUTHENTICATION 0x5001#define SO_SECURITY_ENCRYPTION_TRANSPORT 0x5002
arch/xtensa/include/uapi/asm/socket.h +3 -0
@@ -93,4 +93,7 @@#define SO_INCOMING_CPU 49 +#define SO_ATTACH_BPF 50 +#define SO_DETACH_BPF SO_DETACH_FILTER +#endif /* _XTENSA_SOCKET_H */
include/linux/bpf.h +4 -0
@@ -128,7 +128,11 @@ struct bpf_prog_aux {struct work_struct work; }; +#ifdef CONFIG_BPF_SYSCALL void bpf_prog_put (struct bpf_prog *prog); +#else +static inline void bpf_prog_put (struct bpf_prog *prog) {} +#endif struct bpf_prog *bpf_prog_get (u32 ufd);/* verify correctness of eBPF program */ int bpf_check (struct bpf_prog *fp,union bpf_attr *attr);
include/linux/filter.h +1 -0
@@ -381,6 +381,7 @@ int bpf_prog_create(struct bpf_prog **pfp, struct sock_fprog_kern *fprog);void bpf_prog_destroy (struct bpf_prog *fp);int sk_attach_filter (struct sock_fprog *fprog,struct sock *sk); +int sk_attach_bpf (u32 ufd,struct sock *sk);int sk_detach_filter (struct sock *sk);int bpf_check_classic (const struct sock_filter *filter,unsigned int flen);
include/uapi/asm-generic/socket.h +3 -0
@@ -84,4 +84,7 @@#define SO_INCOMING_CPU 49 +#define SO_ATTACH_BPF 50 +#define SO_DETACH_BPF SO_DETACH_FILTER +#endif /* __ASM_GENERIC_SOCKET_H */
net/core/filter.c +95 -2
115 lines not on this page · raw message
net/core/sock.c +13 -0
@@ -888,6 +888,19 @@ set_rcvbuf: }break ; +case SO_ATTACH_BPF : + ret = -EINVAL ; +if (optlen ==sizeof (u32)) { +u32 ufd; + + ret = -EFAULT ; +if (copy_from_user (&ufd, optval,sizeof (ufd))) +break ; + + ret =sk_attach_bpf (ufd, sk); + } +break ; +case SO_DETACH_FILTER : ret =sk_detach_filter (sk);break ;
Signature · 1 line
1.7.9.5
PATCH v2 3/6 samples: bpf: example of stateful socket filtering
In reply to Alexei Starovoitovthis socket filter example does:
- creates arraymap in kernel with key 4 bytes and value 8 bytes
- loads eBPF program which assumes that packet is IPv4 and loads one byte of IP->proto from the packet and uses it as a key in a map
r0 = skb->data[ETH_HLEN + offsetof(struct iphdr, protocol)];
*(u32*)(fp - 4) = r0;
value = bpf_map_lookup_elem(map_fd, fp - 4);
if (value)
(*(u64*)value) += 1;- attaches this program to raw socket
- every second user space reads map[IPPROTO_TCP], map[IPPROTO_UDP], map[IPPROTO_ICMP] to see how many packets of given protocol were seen on loopback interface
Usage:
$sudo samples/bpf/sock_example
TCP 0 UDP 0 ICMP 0 packets
TCP 187600 UDP 0 ICMP 4 packets
TCP 376504 UDP 0 ICMP 8 packets
TCP 563116 UDP 0 ICMP 12 packets
TCP 753144 UDP 0 ICMP 16 packets
---V1->V2:
fixed comments and replaced constants in:BPF_LD_ABS(BPF_B, 14 + 9 /* R0 = ip->proto */),
with:BPF_LD_ABS(BPF_B, ETH_HLEN + offsetof(struct iphdr, protocol) /* R0 = ip->proto */),
samples/bpf/Makefile | 2 + samples/bpf/libbpf.c | 28 ++++++++++++ samples/bpf/libbpf.h | 13 ++++++ samples/bpf/sock_example.c | 101 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 144 insertions(+) create mode 100644 samples/bpf/sock_example.c
samples/bpf/Makefile +2 -0
@@ -3,9 +3,11 @@ obj- := dummy.o # List of programs to build hostprogs-y := test_verifier test_maps +hostprogs-y += sock_example test_verifier-objs := test_verifier.o libbpf.o test_maps-objs := test_maps.o libbpf.o +sock_example-objs := sock_example.o libbpf.o # Tell kbuild to always build the programs always := $(hostprogs-y)
samples/bpf/libbpf.c +28 -0
@@ -7,6 +7,10 @@#include <linux/netlink.h> #include <linux/bpf.h> #include <errno.h> +#include <net/ethernet.h> +#include <net/if.h> +#include <linux/if_packet.h> +#include <arpa/inet.h> #include "libbpf.h" static __u64 ptr_to_u64 (void *ptr)
@@ -93,3 +97,27 @@ int bpf_prog_load(enum bpf_prog_type prog_type,return syscall (__NR_bpf,BPF_PROG_LOAD , &attr,sizeof (attr)); } + +int open_raw_sock (const char *name) +{ +struct sockaddr_ll sll; +int sock; + + sock =socket (PF_PACKET ,SOCK_RAW |SOCK_NONBLOCK |SOCK_CLOEXEC ,htons (ETH_P_ALL )); +if (sock <0 ) { +printf ("cannot create raw socket\n" ); +return -1 ; + } + +memset (&sll,0 ,sizeof (sll)); + sll.sll_family =AF_PACKET ; + sll.sll_ifindex =if_nametoindex (name); + sll.sll_protocol =htons (ETH_P_ALL ); +if (bind (sock, (struct sockaddr *)&sll,sizeof (sll)) <0 ) { +printf ("bind to %s: %s\n" , name,strerror (errno)); +close (sock); +return -1 ; + } + +return sock; +}
samples/bpf/libbpf.h +13 -0
@@ -99,6 +99,16 @@ extern char bpf_log_buf[LOG_BUF_SIZE];BPF_LD_IMM64_RAW (DST ,BPF_PSEUDO_MAP_FD ,MAP_FD ) +/* Direct packet access, R0 = *(uint *) (skb->data + imm32) */ + +#define BPF_LD_ABS (SIZE ,IMM ) \ + ((struct bpf_insn) { \ + .code = BPF_LD | BPF_SIZE(SIZE) | BPF_ABS, \ + .dst_reg = 0, \ + .src_reg = 0, \ + .off = 0, \ + .imm = IMM }) +/* Memory load, dst_reg = *(uint *) (src_reg + off16) */ #define BPF_LDX_MEM (SIZE ,DST ,SRC ,OFF ) \
@@ -169,4 +179,7 @@ extern char bpf_log_buf[LOG_BUF_SIZE]; .off = 0, \ .imm = 0 }) +/* create RAW socket and bind to interface 'name' */ +int open_raw_sock (const char *name); +#endif
samples/bpf/sock_example.c new file +101 -0
101 lines not on this page · raw message
Signature · 1 line
1.7.9.5
PATCH v2 4/6 samples: bpf: elf_bpf file loader
In reply to Alexei Starovoitovsimple .o parser and loader using BPF syscall.
.o is a standard ELF generated by LLVM backend
It parses elf file compiled by llvm .c->.o
- parses 'maps' section and creates maps via BPF syscall
- parses 'license' section and passes it to syscall
- parses elf relocations for BPF maps and adjusts BPF_LD_IMM64 insns by storing map_fd into insn->imm and marking such insns as BPF_PSEUDO_MAP_FD
- loads eBPF programs via BPF syscall
One ELF file can contain multiple BPF programs.
int load_bpf_file(char *path);
populates prog_fd[] and map_fd[] with FDs received from bpf syscall
bpf_helpers.h - helper functions available to eBPF programs written in C
---
v2: no changes
These helpers and loader are done as separate patch to make eBPF C examples (that follow in the next patches) to focus on demonstrating programming of eBPF in restricted C.
samples/bpf/bpf_helpers.h | 40 +++++++++ samples/bpf/bpf_load.c | 203 +++++++++++++++++++++++++++++++++++++++++++++ samples/bpf/bpf_load.h | 24 ++++++ 3 files changed, 267 insertions(+) create mode 100644 samples/bpf/bpf_helpers.h create mode 100644 samples/bpf/bpf_load.c create mode 100644 samples/bpf/bpf_load.h
samples/bpf/bpf_helpers.h new file +40 -0
@@ -0,0 +1,40 @@ +#ifndef __BPF_HELPERS_H +#define __BPF_HELPERS_H + +/* helper macro to place programs, maps, license in +* different sections in elf_bpf file. Section names +* are interpreted by elf_bpf loader +*/ +#define SEC (NAME ) __attribute__((section(NAME), used)) + +/* helper functions called from eBPF programs written in C */ +static void *(*bpf_map_lookup_elem)(void *map,void *key) = + (void *) BPF_FUNC_map_lookup_elem; +static int (*bpf_map_update_elem)(void *map,void *key,void *value, +unsigned long long flags) = + (void *) BPF_FUNC_map_update_elem; +static int (*bpf_map_delete_elem)(void *map,void *key) = + (void *) BPF_FUNC_map_delete_elem; + +/* llvm builtin functions that eBPF C program may use to +* emit BPF_LD_ABS and BPF_LD_IND instructions +*/ +struct sk_buff ; +unsigned long long load_byte (void *skb, +unsigned long long off) asm("llvm.bpf.load.byte" ); +unsigned long long load_half (void *skb, +unsigned long long off) asm("llvm.bpf.load.half" ); +unsigned long long load_word (void *skb, +unsigned long long off) asm("llvm.bpf.load.word" ); + +/* a helper structure used by eBPF C program +* to describe map attributes to elf_bpf loader +*/ +struct bpf_map_def { +unsigned int type; +unsigned int key_size; +unsigned int value_size; +unsigned int max_entries; +}; + +#endif
samples/bpf/bpf_load.c new file +203 -0
203 lines not on this page · raw message
samples/bpf/bpf_load.h new file +24 -0
@@ -0,0 +1,24 @@ +#ifndef __BPF_LOAD_H +#define __BPF_LOAD_H + +#define MAX_MAPS 32 +#define MAX_PROGS 32 + +extern int map_fd[MAX_MAPS ]; +extern int prog_fd[MAX_PROGS ]; + +/* parses elf file compiled by llvm .c->.o +* . parses 'maps' section and creates maps via BPF syscall +* . parses 'license' section and passes it to syscall +* . parses elf relocations for BPF maps and adjusts BPF_LD_IMM64 insns by +* storing map_fd into insn->imm and marking such insns as BPF_PSEUDO_MAP_FD +* . loads eBPF programs via BPF syscall +* +* One ELF file can contain multiple BPF programs which will be loaded +* and their FDs stored stored in prog_fd array +* +* returns zero on success +*/ +int load_bpf_file (char *path); + +#endif
Signature · 1 line
1.7.9.5
PATCH v2 5/6 samples: bpf: trivial eBPF program in C
In reply to Alexei Starovoitovthis example does the same task as previous socket example in assembler, but this one does it in C.
eBPF program in kernel does:
/* assume that packet is IPv4, load one byte of IP->proto */
int index = load_byte(skb, ETH_HLEN + offsetof(struct iphdr, protocol));
long *value;
value = bpf_map_lookup_elem(&my_map, &index);
if (value)
__sync_fetch_and_add(value, 1);Corresponding user space reads map[tcp], map[udp], map[icmp] and prints protocol stats every second
---V1->V2:
replaced constants in:load_byte(skb, 14 + 9)
with:load_byte(skb, ETH_HLEN + offsetof(struct iphdr, protocol))
samples/bpf/Makefile | 14 +++++++++++++ samples/bpf/libbpf.h | 2 +- samples/bpf/sockex1_kern.c | 25 ++++++++++++++++++++++ samples/bpf/sockex1_user.c | 49 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 samples/bpf/sockex1_kern.c create mode 100644 samples/bpf/sockex1_user.c
samples/bpf/Makefile +14 -0
@@ -4,12 +4,26 @@ obj- := dummy.o # List of programs to build hostprogs-y := test_verifier test_maps hostprogs-y += sock_example +hostprogs-y += sockex1 test_verifier-objs := test_verifier.o libbpf.o test_maps-objs := test_maps.o libbpf.o sock_example-objs := sock_example.o libbpf.o +sockex1-objs := bpf_load.o libbpf.o sockex1_user.o # Tell kbuild to always build the programs always := $(hostprogs-y) +always += sockex1_kern.o HOSTCFLAGS += -I$(objtree)/usr/include + +HOSTCFLAGS_bpf_load.o += -I$(objtree)/usr/include -Wno-unused-variable +HOSTLOADLIBES_sockex1 += -lelf + +# point this to your LLVM backend with bpf support +LLC=$(srctree)/tools/bpf/llvm/bld/Debug+Asserts/bin/llc + +%.o: %.c + clang $(NOSTDINC_FLAGS) $(LINUXINCLUDE) $(EXTRA_CFLAGS) \ + -D__KERNEL__ -Wno-unused-value -Wno-pointer-sign \ + -O2 -emit-llvm -c $< -o -| $(LLC) -march=bpf -filetype=obj -o $@
samples/bpf/libbpf.h +1 -1
@@ -15,7 +15,7 @@ int bpf_prog_load(enum bpf_prog_type prog_type, const struct bpf_insn *insns, int insn_len, const char *license); -#define LOG_BUF_SIZE 8192 +#define LOG_BUF_SIZE 65536extern char bpf_log_buf[LOG_BUF_SIZE ];/* ALU ops on registers, bpf_add|sub|...: dst_reg += src_reg */
samples/bpf/sockex1_kern.c new file +25 -0
@@ -0,0 +1,25 @@ +#include <uapi/linux/bpf.h> +#include <uapi/linux/if_ether.h> +#include <uapi/linux/ip.h> +#include "bpf_helpers.h" + +struct bpf_map_def SEC("maps") my_map = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(u32), + .value_size = sizeof(long), + .max_entries = 256, +}; + +SEC("socket1") +int bpf_prog1 (struct sk_buff *skb) +{ +int index =load_byte (skb,ETH_HLEN + offsetof(struct iphdr , protocol)); +long *value; + + value =bpf_map_lookup_elem (&my_map, &index); +if (value) +__sync_fetch_and_add (value,1 ); + +return 0 ; +} +char _license[] SEC("license") = "GPL";
samples/bpf/sockex1_user.c new file +49 -0
49 lines not on this page · raw message
Signature · 1 line
1.7.9.5
PATCH v2 6/6 samples: bpf: large eBPF program in C
In reply to Alexei Starovoitovsockex2_kern.c is purposefully large eBPF program in C. llvm compiles ~200 lines of C code into ~300 eBPF instructions.
It's similar to __skb_flow_dissect() to demonstrate that complex packet parsing can be done by eBPF.
Then it uses (struct flow_keys)->dst IP address (or hash of ipv6 dst) to keep stats of number of packets per IP.
User space loads eBPF program, attaches it to loopback interface and prints dest_ip->#packets stats every second.
Usage:
$sudo samples/bpf/sockex2
ip 127.0.0.1 count 19
ip 127.0.0.1 count 178115
ip 127.0.0.1 count 369437
ip 127.0.0.1 count 559841
ip 127.0.0.1 count 750539
---
v2: no changes
samples/bpf/Makefile | 4 + samples/bpf/sockex2_kern.c | 215 ++++++++++++++++++++++++++++++++++++++++++++ samples/bpf/sockex2_user.c | 44 +++++++++ 3 files changed, 263 insertions(+) create mode 100644 samples/bpf/sockex2_kern.c create mode 100644 samples/bpf/sockex2_user.c
samples/bpf/Makefile +4 -0
@@ -5,20 +5,24 @@ obj- := dummy.o hostprogs-y := test_verifier test_maps hostprogs-y += sock_example hostprogs-y += sockex1 +hostprogs-y += sockex2 test_verifier-objs := test_verifier.o libbpf.o test_maps-objs := test_maps.o libbpf.o sock_example-objs := sock_example.o libbpf.o sockex1-objs := bpf_load.o libbpf.o sockex1_user.o +sockex2-objs := bpf_load.o libbpf.o sockex2_user.o # Tell kbuild to always build the programs always := $(hostprogs-y) always += sockex1_kern.o +always += sockex2_kern.o HOSTCFLAGS += -I$(objtree)/usr/include HOSTCFLAGS_bpf_load.o += -I$(objtree)/usr/include -Wno-unused-variable HOSTLOADLIBES_sockex1 += -lelf +HOSTLOADLIBES_sockex2 += -lelf # point this to your LLVM backend with bpf support LLC=$(srctree)/tools/bpf/llvm/bld/Debug+Asserts/bin/llc
samples/bpf/sockex2_kern.c new file +215 -0
215 lines not on this page · raw message
samples/bpf/sockex2_user.c new file +44 -0
44 lines not on this page · raw message
Signature · 1 line
1.7.9.5
David Miller
maintainerFrom: Alexei Starovoitov <[email protected]>
Date: Mon, 1 Dec 2014 15:06:33 -0800
Quoted 29 lines
V1->V2:fixed comments in sample code to state clearly that packet data is accessed with
LD_ABSinstructions and not internal skb fields.
Also replaced constants in:BPF_LD_ABS(BPF_B, 14 + 9 /* R0 = ip->proto */),
with:BPF_LD_ABS(BPF_B, ETH_HLEN + offsetof(struct iphdr, protocol) /* R0 = ip->proto */),V1 cover:
Introduce
BPF_PROG_TYPE_SOCKET_FILTERtype of eBPF programs that can be attached to sockets withsetsockopt().
Allow such programs to access maps via lookup/update/delete helpers.This feature was previewed by bpf manpage in commit
b4fc1a460f30("Merge branch 'bpf-next'")Now it can actually run.1st patch adds LD_ABS/LD_IND instruction verification and 2nd patch adds new
setsockopt()flag.
Patches 3-6 are examples in assembler and in C.Though native eBPF programs are way more powerful than classic filters (attachable through similar
setsockopt()call), they don't have skb field accessors yet. Likeskb->pkt_type,skb->dev->ifindexare not accessible. There are sevaral ways to achieve that. That will be in the next set of patches. So in this set native eBPF programs can only read data from packet and access maps.
Quoted 6 lines
The most powerful example is
sockex2_kern.cfrom patch 6 where ~200 lines of C are compiled into ~300 of eBPF instructions.
It shows how quite complex packet parsing can be done.LLVM used to build examples is at https://github.com/iovisor/llvm
which is fork of llvm trunk that I'm cleaning up for upstreaming.
Series applied, thanks.