|  | /* eBPF example program: | 
|  | * | 
|  | * - Creates arraymap in kernel with 4 bytes keys and 8 byte values | 
|  | * | 
|  | * - Loads eBPF program | 
|  | * | 
|  | *   The eBPF program accesses the map passed in to store two pieces of | 
|  | *   information. The number of invocations of the program, which maps | 
|  | *   to the number of packets received, is stored to key 0. Key 1 is | 
|  | *   incremented on each iteration by the number of bytes stored in | 
|  | *   the skb. | 
|  | * | 
|  | * - Attaches the new program to a cgroup using BPF_PROG_ATTACH | 
|  | * | 
|  | * - Every second, reads map[0] and map[1] to see how many bytes and | 
|  | *   packets were seen on any socket of tasks in the given cgroup. | 
|  | */ | 
|  |  | 
|  | #define _GNU_SOURCE | 
|  |  | 
|  | #include <stdio.h> | 
|  | #include <stdlib.h> | 
|  | #include <assert.h> | 
|  | #include <unistd.h> | 
|  |  | 
|  | #include <linux/bpf.h> | 
|  |  | 
|  | #include "libbpf.h" | 
|  | #include "cgroup_helpers.h" | 
|  |  | 
|  | #define FOO		"/foo" | 
|  | #define BAR		"/foo/bar/" | 
|  | #define PING_CMD	"ping -c1 -w1 127.0.0.1" | 
|  |  | 
|  | char bpf_log_buf[BPF_LOG_BUF_SIZE]; | 
|  |  | 
|  | static int prog_load(int verdict) | 
|  | { | 
|  | int ret; | 
|  | struct bpf_insn prog[] = { | 
|  | BPF_MOV64_IMM(BPF_REG_0, verdict), /* r0 = verdict */ | 
|  | BPF_EXIT_INSN(), | 
|  | }; | 
|  | size_t insns_cnt = sizeof(prog) / sizeof(struct bpf_insn); | 
|  |  | 
|  | ret = bpf_load_program(BPF_PROG_TYPE_CGROUP_SKB, | 
|  | prog, insns_cnt, "GPL", 0, | 
|  | bpf_log_buf, BPF_LOG_BUF_SIZE); | 
|  |  | 
|  | if (ret < 0) { | 
|  | log_err("Loading program"); | 
|  | printf("Output from verifier:\n%s\n-------\n", bpf_log_buf); | 
|  | return 0; | 
|  | } | 
|  | return ret; | 
|  | } | 
|  |  | 
|  |  | 
|  | int main(int argc, char **argv) | 
|  | { | 
|  | int drop_prog, allow_prog, foo = 0, bar = 0, rc = 0; | 
|  |  | 
|  | allow_prog = prog_load(1); | 
|  | if (!allow_prog) | 
|  | goto err; | 
|  |  | 
|  | drop_prog = prog_load(0); | 
|  | if (!drop_prog) | 
|  | goto err; | 
|  |  | 
|  | if (setup_cgroup_environment()) | 
|  | goto err; | 
|  |  | 
|  | /* Create cgroup /foo, get fd, and join it */ | 
|  | foo = create_and_get_cgroup(FOO); | 
|  | if (!foo) | 
|  | goto err; | 
|  |  | 
|  | if (join_cgroup(FOO)) | 
|  | goto err; | 
|  |  | 
|  | if (bpf_prog_attach(drop_prog, foo, BPF_CGROUP_INET_EGRESS)) { | 
|  | log_err("Attaching prog to /foo"); | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | assert(system(PING_CMD) != 0); | 
|  |  | 
|  | /* Create cgroup /foo/bar, get fd, and join it */ | 
|  | bar = create_and_get_cgroup(BAR); | 
|  | if (!bar) | 
|  | goto err; | 
|  |  | 
|  | if (join_cgroup(BAR)) | 
|  | goto err; | 
|  |  | 
|  | assert(system(PING_CMD) != 0); | 
|  |  | 
|  | if (bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS)) { | 
|  | log_err("Attaching prog to /foo/bar"); | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | assert(system(PING_CMD) == 0); | 
|  |  | 
|  |  | 
|  | if (bpf_prog_detach(bar, BPF_CGROUP_INET_EGRESS)) { | 
|  | log_err("Detaching program from /foo/bar"); | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | assert(system(PING_CMD) != 0); | 
|  |  | 
|  | if (bpf_prog_attach(allow_prog, bar, BPF_CGROUP_INET_EGRESS)) { | 
|  | log_err("Attaching prog to /foo/bar"); | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | if (bpf_prog_detach(foo, BPF_CGROUP_INET_EGRESS)) { | 
|  | log_err("Detaching program from /foo"); | 
|  | goto err; | 
|  | } | 
|  |  | 
|  | assert(system(PING_CMD) == 0); | 
|  |  | 
|  | goto out; | 
|  |  | 
|  | err: | 
|  | rc = 1; | 
|  |  | 
|  | out: | 
|  | close(foo); | 
|  | close(bar); | 
|  | cleanup_cgroup_environment(); | 
|  | return rc; | 
|  | } |