Pull bpf updates from Alexei Starovoitov: - Add BPF uprobe session support (Jiri Olsa) - Optimize uprobe performance (Andrii Nakryiko) - Add bpf_fastcall support to helpers and kfuncs (Eduard Zingerman) - Avoid calling free_htab_elem() under hash map bucket lock (Hou Tao) - Prevent tailcall infinite loop caused by freplace (Leon Hwang) - Mark raw_tracepoint arguments as nullable (Kumar Kartikeya Dwivedi) - Introduce uptr support in the task local storage map (Martin KaFai Lau) - Stringify errno log messages in libbpf (Mykyta Yatsenko) - Add kmem_cache BPF iterator for perf's lock profiling (Namhyung Kim) - Support BPF objects of either endianness in libbpf (Tony Ambardar) - Add ksym to struct_ops trampoline to fix stack trace (Xu Kuohai) - Introduce private stack for eligible BPF programs (Yonghong Song) - Migrate samples/bpf tests to selftests/bpf test_progs (Daniel T. Lee) - Migrate test_sock to selftests/bpf test_progs (Jordan Rife) * tag 'bpf-next-6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/bpf/bpf-next: (152 commits) libbpf: Change hash_combine parameters from long to unsigned long selftests/bpf: Fix build error with llvm 19 libbpf: Fix memory leak in bpf_program__attach_uprobe_multi bpf: use common instruction history across all states bpf: Add necessary migrate_disable to range_tree. bpf: Do not alloc arena on unsupported arches selftests/bpf: Set test path for token/obj_priv_implicit_token_envvar selftests/bpf: Add a test for arena range tree algorithm bpf: Introduce range_tree data structure and use it in bpf arena samples/bpf: Remove unused variable in xdp2skb_meta_kern.c samples/bpf: Remove unused variables in tc_l2_redirect_kern.c bpftool: Cast variable `var` to long long bpf, x86: Propagate tailcall info only for subprogs bpf: Add kernel symbol for struct_ops trampoline bpf: Use function pointers count as struct_ops links count bpf: Remove unused member rcu from bpf_struct_ops_map selftests/bpf: Add struct_ops prog private stack tests bpf: Support private stack for struct_ops progs selftests/bpf: Add tracing prog private stack tests bpf, x86: Support private stack in jit ...
Showing the changes to samples (25 of 211 files). Show all
Unified · Split
| @@ -17,20 +17,12 @@ tprogs-y += tracex3 · 16 unmodified lines | |||
| 17 | tprogs-y += tracex4 | 17 | tprogs-y += tracex4 |
| 18 | tprogs-y += tracex5 | 18 | tprogs-y += tracex5 |
| 19 | tprogs-y += tracex6 | 19 | tprogs-y += tracex6 |
| 20 | tprogs-y += tracex7 | ||
| 21 | tprogs-y += test_probe_write_user | ||
| 22 | tprogs-y += trace_output | 20 | tprogs-y += trace_output |
| 23 | tprogs-y += lathist | 21 | tprogs-y += lathist |
| 24 | tprogs-y += offwaketime | 22 | tprogs-y += offwaketime |
| 25 | tprogs-y += spintest | 23 | tprogs-y += spintest |
| 26 | tprogs-y += map_perf_test | 24 | tprogs-y += map_perf_test |
| 27 | tprogs-y += test_overhead | ||
| 28 | tprogs-y += test_cgrp2_array_pin | ||
| 29 | tprogs-y += test_cgrp2_attach | ||
| 30 | tprogs-y += test_cgrp2_sock | ||
| 31 | tprogs-y += test_cgrp2_sock2 | ||
| 32 | tprogs-y += xdp_router_ipv4 | 25 | tprogs-y += xdp_router_ipv4 |
| 33 | tprogs-y += test_current_task_under_cgroup | ||
| 34 | tprogs-y += trace_event | 26 | tprogs-y += trace_event |
| 35 | tprogs-y += sampleip | 27 | tprogs-y += sampleip |
| 36 | tprogs-y += tc_l2_redirect | 28 | tprogs-y += tc_l2_redirect |
| @@ -66,20 +58,12 @@ tracex3-objs := tracex3_user.o · 29 unmodified lines | |||
| 66 | tracex4-objs := tracex4_user.o | 58 | tracex4-objs := tracex4_user.o |
| 67 | tracex5-objs := tracex5_user.o $(TRACE_HELPERS) | 59 | tracex5-objs := tracex5_user.o $(TRACE_HELPERS) |
| 68 | tracex6-objs := tracex6_user.o | 60 | tracex6-objs := tracex6_user.o |
| 69 | tracex7-objs := tracex7_user.o | ||
| 70 | test_probe_write_user-objs := test_probe_write_user_user.o | ||
| 71 | trace_output-objs := trace_output_user.o | 61 | trace_output-objs := trace_output_user.o |
| 72 | lathist-objs := lathist_user.o | 62 | lathist-objs := lathist_user.o |
| 73 | offwaketime-objs := offwaketime_user.o $(TRACE_HELPERS) | 63 | offwaketime-objs := offwaketime_user.o $(TRACE_HELPERS) |
| 74 | spintest-objs := spintest_user.o $(TRACE_HELPERS) | 64 | spintest-objs := spintest_user.o $(TRACE_HELPERS) |
| 75 | map_perf_test-objs := map_perf_test_user.o | 65 | map_perf_test-objs := map_perf_test_user.o |
| 76 | test_overhead-objs := test_overhead_user.o | 66 | test_overhead-objs := test_overhead_user.o |
| 77 | test_cgrp2_array_pin-objs := test_cgrp2_array_pin.o | ||
| 78 | test_cgrp2_attach-objs := test_cgrp2_attach.o | ||
| 79 | test_cgrp2_sock-objs := test_cgrp2_sock.o | ||
| 80 | test_cgrp2_sock2-objs := test_cgrp2_sock2.o | ||
| 81 | test_current_task_under_cgroup-objs := $(CGROUP_HELPERS) \ | ||
| 82 | test_current_task_under_cgroup_user.o | ||
| 83 | trace_event-objs := trace_event_user.o $(TRACE_HELPERS) | 67 | trace_event-objs := trace_event_user.o $(TRACE_HELPERS) |
| 84 | sampleip-objs := sampleip_user.o $(TRACE_HELPERS) | 68 | sampleip-objs := sampleip_user.o $(TRACE_HELPERS) |
| 85 | tc_l2_redirect-objs := tc_l2_redirect_user.o | 69 | tc_l2_redirect-objs := tc_l2_redirect_user.o |
| @@ -107,9 +91,6 @@ always-y += tracex3.bpf.o · 21 unmodified lines | |||
| 107 | always-y += tracex4.bpf.o | 91 | always-y += tracex4.bpf.o |
| 108 | always-y += tracex5.bpf.o | 92 | always-y += tracex5.bpf.o |
| 109 | always-y += tracex6.bpf.o | 93 | always-y += tracex6.bpf.o |
| 110 | always-y += tracex7.bpf.o | ||
| 111 | always-y += sock_flags.bpf.o | ||
| 112 | always-y += test_probe_write_user.bpf.o | ||
| 113 | always-y += trace_output.bpf.o | 94 | always-y += trace_output.bpf.o |
| 114 | always-y += tcbpf1_kern.o | 95 | always-y += tcbpf1_kern.o |
| 115 | always-y += tc_l2_redirect_kern.o | 96 | always-y += tc_l2_redirect_kern.o |
| @@ -117,12 +98,7 @@ always-y += lathist_kern.o · 1 unmodified line | |||
| 117 | always-y += offwaketime.bpf.o | 98 | always-y += offwaketime.bpf.o |
| 118 | always-y += spintest.bpf.o | 99 | always-y += spintest.bpf.o |
| 119 | always-y += map_perf_test.bpf.o | 100 | always-y += map_perf_test.bpf.o |
| 120 | always-y += test_overhead_tp.bpf.o | ||
| 121 | always-y += test_overhead_raw_tp.bpf.o | ||
| 122 | always-y += test_overhead_kprobe.bpf.o | ||
| 123 | always-y += parse_varlen.o parse_simple.o parse_ldabs.o | 101 | always-y += parse_varlen.o parse_simple.o parse_ldabs.o |
| 124 | always-y += test_cgrp2_tc.bpf.o | ||
| 125 | always-y += test_current_task_under_cgroup.bpf.o | ||
| 126 | always-y += trace_event_kern.o | 102 | always-y += trace_event_kern.o |
| 127 | always-y += sampleip_kern.o | 103 | always-y += sampleip_kern.o |
| 128 | always-y += lwt_len_hist.bpf.o | 104 | always-y += lwt_len_hist.bpf.o |
| @@ -195,7 +171,6 @@ TPROGLDLIBS_xdp_router_ipv4 += -lm -pthread · 66 unmodified lines | |||
| 195 | TPROGLDLIBS_tracex4 += -lrt | 171 | TPROGLDLIBS_tracex4 += -lrt |
| 196 | TPROGLDLIBS_trace_output += -lrt | 172 | TPROGLDLIBS_trace_output += -lrt |
| 197 | TPROGLDLIBS_map_perf_test += -lrt | 173 | TPROGLDLIBS_map_perf_test += -lrt |
| 198 | TPROGLDLIBS_test_overhead += -lrt | ||
| 199 | 174 | ||
| 200 | # Allows pointing LLC/CLANG to a LLVM backend with bpf support, redefine on cmdline: | 175 | # Allows pointing LLC/CLANG to a LLVM backend with bpf support, redefine on cmdline: |
| 201 | # make M=samples/bpf LLC=~/git/llvm-project/llvm/build/bin/llc CLANG=~/git/llvm-project/llvm/build/bin/clang | 176 | # make M=samples/bpf LLC=~/git/llvm-project/llvm/build/bin/llc CLANG=~/git/llvm-project/llvm/build/bin/clang |
| @@ -1,47 +0,0 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | #include "vmlinux.h" | ||
| 3 | #include "net_shared.h" | ||
| 4 | #include <bpf/bpf_helpers.h> | ||
| 5 | |||
| 6 | SEC("cgroup/sock") | ||
| 7 | int bpf_prog1(struct bpf_sock *sk) | ||
| 8 | { | ||
| 9 | char fmt[] = "socket: family %d type %d protocol %d\n"; | ||
| 10 | char fmt2[] = "socket: uid %u gid %u\n"; | ||
| 11 | __u64 gid_uid = bpf_get_current_uid_gid(); | ||
| 12 | __u32 uid = gid_uid & 0xffffffff; | ||
| 13 | __u32 gid = gid_uid >> 32; | ||
| 14 | |||
| 15 | bpf_trace_printk(fmt, sizeof(fmt), sk->family, sk->type, sk->protocol); | ||
| 16 | bpf_trace_printk(fmt2, sizeof(fmt2), uid, gid); | ||
| 17 | |||
| 18 | /* block AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6 sockets | ||
| 19 | * ie., make ping6 fail | ||
| 20 | */ | ||
| 21 | if (sk->family == AF_INET6 && | ||
| 22 | sk->type == SOCK_DGRAM && | ||
| 23 | sk->protocol == IPPROTO_ICMPV6) | ||
| 24 | return 0; | ||
| 25 | |||
| 26 | return 1; | ||
| 27 | } | ||
| 28 | |||
| 29 | SEC("cgroup/sock") | ||
| 30 | int bpf_prog2(struct bpf_sock *sk) | ||
| 31 | { | ||
| 32 | char fmt[] = "socket: family %d type %d protocol %d\n"; | ||
| 33 | |||
| 34 | bpf_trace_printk(fmt, sizeof(fmt), sk->family, sk->type, sk->protocol); | ||
| 35 | |||
| 36 | /* block AF_INET, SOCK_DGRAM, IPPROTO_ICMP sockets | ||
| 37 | * ie., make ping fail | ||
| 38 | */ | ||
| 39 | if (sk->family == AF_INET && | ||
| 40 | sk->type == SOCK_DGRAM && | ||
| 41 | sk->protocol == IPPROTO_ICMP) | ||
| 42 | return 0; | ||
| 43 | |||
| 44 | return 1; | ||
| 45 | } | ||
| 46 | |||
| 47 | char _license[] SEC("license") = "GPL"; | ||
| @@ -2,6 +2,9 @@ · 1 unmodified line | |||
| 2 | #include <uapi/linux/unistd.h> | 2 | #include <uapi/linux/unistd.h> |
| 3 | #include <linux/kbuild.h> | 3 | #include <linux/kbuild.h> |
| 4 | 4 | ||
| 5 | #pragma GCC diagnostic push | ||
| 6 | #pragma GCC diagnostic ignored "-Wmissing-prototypes" | ||
| 7 | |||
| 5 | #define SYSNR(_NR) DEFINE(SYS ## _NR, _NR) | 8 | #define SYSNR(_NR) DEFINE(SYS ## _NR, _NR) |
| 6 | 9 | ||
| 7 | void syscall_defines(void) | 10 | void syscall_defines(void) |
| @@ -17,3 +20,5 @@ void syscall_defines(void) · 9 unmodified lines | |||
| 17 | #endif | 20 | #endif |
| 18 | 21 | ||
| 19 | } | 22 | } |
| 23 | |||
| 24 | #pragma GCC diagnostic pop | ||
| @@ -58,14 +58,11 @@ static __always_inline bool is_vip_addr(__be16 eth_proto, __be32 daddr) · 57 unmodified lines | |||
| 58 | SEC("l2_to_iptun_ingress_forward") | 58 | SEC("l2_to_iptun_ingress_forward") |
| 59 | int _l2_to_iptun_ingress_forward(struct __sk_buff *skb) | 59 | int _l2_to_iptun_ingress_forward(struct __sk_buff *skb) |
| 60 | { | 60 | { |
| 61 | struct bpf_tunnel_key tkey = {}; | ||
| 62 | void *data = (void *)(long)skb->data; | 61 | void *data = (void *)(long)skb->data; |
| 63 | struct eth_hdr *eth = data; | 62 | struct eth_hdr *eth = data; |
| 64 | void *data_end = (void *)(long)skb->data_end; | 63 | void *data_end = (void *)(long)skb->data_end; |
| 65 | int key = 0, *ifindex; | 64 | int key = 0, *ifindex; |
| 66 | 65 | ||
| 67 | int ret; | ||
| 68 | |||
| 69 | if (data + sizeof(*eth) > data_end) | 66 | if (data + sizeof(*eth) > data_end) |
| 70 | return TC_ACT_OK; | 67 | return TC_ACT_OK; |
| 71 | 68 | ||
| @@ -115,8 +112,6 @@ int _l2_to_iptun_ingress_redirect(struct __sk_buff *skb) · 43 unmodified lines | |||
| 115 | void *data_end = (void *)(long)skb->data_end; | 112 | void *data_end = (void *)(long)skb->data_end; |
| 116 | int key = 0, *ifindex; | 113 | int key = 0, *ifindex; |
| 117 | 114 | ||
| 118 | int ret; | ||
| 119 | |||
| 120 | if (data + sizeof(*eth) > data_end) | 115 | if (data + sizeof(*eth) > data_end) |
| 121 | return TC_ACT_OK; | 116 | return TC_ACT_OK; |
| 122 | 117 | ||
| @@ -205,7 +200,6 @@ int _l2_to_ip6tun_ingress_redirect(struct __sk_buff *skb) · 82 unmodified lines | |||
| 205 | SEC("drop_non_tun_vip") | 200 | SEC("drop_non_tun_vip") |
| 206 | int _drop_non_tun_vip(struct __sk_buff *skb) | 201 | int _drop_non_tun_vip(struct __sk_buff *skb) |
| 207 | { | 202 | { |
| 208 | struct bpf_tunnel_key tkey = {}; | ||
| 209 | void *data = (void *)(long)skb->data; | 203 | void *data = (void *)(long)skb->data; |
| 210 | struct eth_hdr *eth = data; | 204 | struct eth_hdr *eth = data; |
| 211 | void *data_end = (void *)(long)skb->data_end; | 205 | void *data_end = (void *)(long)skb->data_end; |
| @@ -1,106 +0,0 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | ||
| 2 | /* Copyright (c) 2016 Facebook | ||
| 3 | */ | ||
| 4 | #include <linux/unistd.h> | ||
| 5 | #include <linux/bpf.h> | ||
| 6 | |||
| 7 | #include <stdio.h> | ||
| 8 | #include <stdint.h> | ||
| 9 | #include <unistd.h> | ||
| 10 | #include <string.h> | ||
| 11 | #include <errno.h> | ||
| 12 | #include <fcntl.h> | ||
| 13 | |||
| 14 | #include <bpf/bpf.h> | ||
| 15 | |||
| 16 | static void usage(void) | ||
| 17 | { | ||
| 18 | printf("Usage: test_cgrp2_array_pin [...]\n"); | ||
| 19 | printf(" -F <file> File to pin an BPF cgroup array\n"); | ||
| 20 | printf(" -U <file> Update an already pinned BPF cgroup array\n"); | ||
| 21 | printf(" -v <value> Full path of the cgroup2\n"); | ||
| 22 | printf(" -h Display this help\n"); | ||
| 23 | } | ||
| 24 | |||
| 25 | int main(int argc, char **argv) | ||
| 26 | { | ||
| 27 | const char *pinned_file = NULL, *cg2 = NULL; | ||
| 28 | int create_array = 1; | ||
| 29 | int array_key = 0; | ||
| 30 | int array_fd = -1; | ||
| 31 | int cg2_fd = -1; | ||
| 32 | int ret = -1; | ||
| 33 | int opt; | ||
| 34 | |||
| 35 | while ((opt = getopt(argc, argv, "F:U:v:")) != -1) { | ||
| 36 | switch (opt) { | ||
| 37 | /* General args */ | ||
| 38 | case 'F': | ||
| 39 | pinned_file = optarg; | ||
| 40 | break; | ||
| 41 | case 'U': | ||
| 42 | pinned_file = optarg; | ||
| 43 | create_array = 0; | ||
| 44 | break; | ||
| 45 | case 'v': | ||
| 46 | cg2 = optarg; | ||
| 47 | break; | ||
| 48 | default: | ||
| 49 | usage(); | ||
| 50 | goto out; | ||
| 51 | } | ||
| 52 | } | ||
| 53 | |||
| 54 | if (!cg2 || !pinned_file) { | ||
| 55 | usage(); | ||
| 56 | goto out; | ||
| 57 | } | ||
| 58 | |||
| 59 | cg2_fd = open(cg2, O_RDONLY); | ||
| 60 | if (cg2_fd < 0) { | ||
| 61 | fprintf(stderr, "open(%s,...): %s(%d)\n", | ||
| 62 | cg2, strerror(errno), errno); | ||
| 63 | goto out; | ||
| 64 | } | ||
| 65 | |||
| 66 | if (create_array) { | ||
| 67 | array_fd = bpf_map_create(BPF_MAP_TYPE_CGROUP_ARRAY, NULL, | ||
| 68 | sizeof(uint32_t), sizeof(uint32_t), | ||
| 69 | 1, NULL); | ||
| 70 | if (array_fd < 0) { | ||
| 71 | fprintf(stderr, | ||
| 72 | "bpf_create_map(BPF_MAP_TYPE_CGROUP_ARRAY,...): %s(%d)\n", | ||
| 73 | strerror(errno), errno); | ||
| 74 | goto out; | ||
| 75 | } | ||
| 76 | } else { | ||
| 77 | array_fd = bpf_obj_get(pinned_file); | ||
| 78 | if (array_fd < 0) { | ||
| 79 | fprintf(stderr, "bpf_obj_get(%s): %s(%d)\n", | ||
| 80 | pinned_file, strerror(errno), errno); | ||
| 81 | goto out; | ||
| 82 | } | ||
| 83 | } | ||
| 84 | |||
| 85 | ret = bpf_map_update_elem(array_fd, &array_key, &cg2_fd, 0); | ||
| 86 | if (ret) { | ||
| 87 | perror("bpf_map_update_elem"); | ||
| 88 | goto out; | ||
| 89 | } | ||
| 90 | |||
| 91 | if (create_array) { | ||
| 92 | ret = bpf_obj_pin(array_fd, pinned_file); | ||
| 93 | if (ret) { | ||
| 94 | fprintf(stderr, "bpf_obj_pin(..., %s): %s(%d)\n", | ||
| 95 | pinned_file, strerror(errno), errno); | ||
| 96 | goto out; | ||
| 97 | } | ||
| 98 | } | ||
| 99 | |||
| 100 | out: | ||
| 101 | if (array_fd != -1) | ||
| 102 | close(array_fd); | ||
| 103 | if (cg2_fd != -1) | ||
| 104 | close(cg2_fd); | ||
| 105 | return ret; | ||
| 106 | } | ||
| @@ -1,177 +0,0 @@ | |||
| 1 | /* eBPF example program: | ||
| 2 | * | ||
| 3 | * - Creates arraymap in kernel with 4 bytes keys and 8 byte values | ||
| 4 | * | ||
| 5 | * - Loads eBPF program | ||
| 6 | * | ||
| 7 | * The eBPF program accesses the map passed in to store two pieces of | ||
| 8 | * information. The number of invocations of the program, which maps | ||
| 9 | * to the number of packets received, is stored to key 0. Key 1 is | ||
| 10 | * incremented on each iteration by the number of bytes stored in | ||
| 11 | * the skb. | ||
| 12 | * | ||
| 13 | * - Attaches the new program to a cgroup using BPF_PROG_ATTACH | ||
| 14 | * | ||
| 15 | * - Every second, reads map[0] and map[1] to see how many bytes and | ||
| 16 | * packets were seen on any socket of tasks in the given cgroup. | ||
| 17 | */ | ||
| 18 | |||
| 19 | #define _GNU_SOURCE | ||
| 20 | |||
| 21 | #include <stdio.h> | ||
| 22 | #include <stdlib.h> | ||
| 23 | #include <stddef.h> | ||
| 24 | #include <string.h> | ||
| 25 | #include <unistd.h> | ||
| 26 | #include <assert.h> | ||
| 27 | #include <errno.h> | ||
| 28 | #include <fcntl.h> | ||
| 29 | |||
| 30 | #include <linux/bpf.h> | ||
| 31 | #include <bpf/bpf.h> | ||
| 32 | |||
| 33 | #include "bpf_insn.h" | ||
| 34 | #include "bpf_util.h" | ||
| 35 | |||
| 36 | enum { | ||
| 37 | MAP_KEY_PACKETS, | ||
| 38 | MAP_KEY_BYTES, | ||
| 39 | }; | ||
| 40 | |||
| 41 | char bpf_log_buf[BPF_LOG_BUF_SIZE]; | ||
| 42 | |||
| 43 | static int prog_load(int map_fd, int verdict) | ||
| 44 | { | ||
| 45 | struct bpf_insn prog[] = { | ||
| 46 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), /* save r6 so it's not clobbered by BPF_CALL */ | ||
| 47 | |||
| 48 | /* Count packets */ | ||
| 49 | BPF_MOV64_IMM(BPF_REG_0, MAP_KEY_PACKETS), /* r0 = 0 */ | ||
| 50 | BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4), /* *(u32 *)(fp - 4) = r0 */ | ||
| 51 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
| 52 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4), /* r2 = fp - 4 */ | ||
| 53 | BPF_LD_MAP_FD(BPF_REG_1, map_fd), /* load map fd to r1 */ | ||
| 54 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), | ||
| 55 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), | ||
| 56 | BPF_MOV64_IMM(BPF_REG_1, 1), /* r1 = 1 */ | ||
| 57 | BPF_ATOMIC_OP(BPF_DW, BPF_ADD, BPF_REG_0, BPF_REG_1, 0), | ||
| 58 | |||
| 59 | /* Count bytes */ | ||
| 60 | BPF_MOV64_IMM(BPF_REG_0, MAP_KEY_BYTES), /* r0 = 1 */ | ||
| 61 | BPF_STX_MEM(BPF_W, BPF_REG_10, BPF_REG_0, -4), /* *(u32 *)(fp - 4) = r0 */ | ||
| 62 | BPF_MOV64_REG(BPF_REG_2, BPF_REG_10), | ||
| 63 | BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -4), /* r2 = fp - 4 */ | ||
| 64 | BPF_LD_MAP_FD(BPF_REG_1, map_fd), | ||
| 65 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, BPF_FUNC_map_lookup_elem), | ||
| 66 | BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 2), | ||
| 67 | BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_6, offsetof(struct __sk_buff, len)), /* r1 = skb->len */ | ||
| 68 | |||
| 69 | BPF_ATOMIC_OP(BPF_DW, BPF_ADD, BPF_REG_0, BPF_REG_1, 0), | ||
| 70 | |||
| 71 | BPF_MOV64_IMM(BPF_REG_0, verdict), /* r0 = verdict */ | ||
| 72 | BPF_EXIT_INSN(), | ||
| 73 | }; | ||
| 74 | size_t insns_cnt = ARRAY_SIZE(prog); | ||
| 75 | LIBBPF_OPTS(bpf_prog_load_opts, opts, | ||
| 76 | .log_buf = bpf_log_buf, | ||
| 77 | .log_size = BPF_LOG_BUF_SIZE, | ||
| 78 | ); | ||
| 79 | |||
| 80 | return bpf_prog_load(BPF_PROG_TYPE_CGROUP_SKB, NULL, "GPL", | ||
| 81 | prog, insns_cnt, &opts); | ||
| 82 | } | ||
| 83 | |||
| 84 | static int usage(const char *argv0) | ||
| 85 | { | ||
| 86 | printf("Usage: %s [-d] [-D] <cg-path> <egress|ingress>\n", argv0); | ||
| 87 | printf(" -d Drop Traffic\n"); | ||
| 88 | printf(" -D Detach filter, and exit\n"); | ||
| 89 | return EXIT_FAILURE; | ||
| 90 | } | ||
| 91 | |||
| 92 | static int attach_filter(int cg_fd, int type, int verdict) | ||
| 93 | { | ||
| 94 | int prog_fd, map_fd, ret, key; | ||
| 95 | long long pkt_cnt, byte_cnt; | ||
| 96 | |||
| 97 | map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, NULL, | ||
| 98 | sizeof(key), sizeof(byte_cnt), | ||
| 99 | 256, NULL); | ||
| 100 | if (map_fd < 0) { | ||
| 101 | printf("Failed to create map: '%s'\n", strerror(errno)); | ||
| 102 | return EXIT_FAILURE; | ||
| 103 | } | ||
| 104 | |||
| 105 | prog_fd = prog_load(map_fd, verdict); | ||
| 106 | printf("Output from kernel verifier:\n%s\n-------\n", bpf_log_buf); | ||
| 107 | |||
| 108 | if (prog_fd < 0) { | ||
| 109 | printf("Failed to load prog: '%s'\n", strerror(errno)); | ||
| 110 | return EXIT_FAILURE; | ||
| 111 | } | ||
| 112 | |||
| 113 | ret = bpf_prog_attach(prog_fd, cg_fd, type, 0); | ||
| 114 | if (ret < 0) { | ||
| 115 | printf("Failed to attach prog to cgroup: '%s'\n", | ||
| 116 | strerror(errno)); | ||
| 117 | return EXIT_FAILURE; | ||
| 118 | } | ||
| 119 | while (1) { | ||
| 120 | key = MAP_KEY_PACKETS; | ||
| 121 | assert(bpf_map_lookup_elem(map_fd, &key, &pkt_cnt) == 0); | ||
| 122 | |||
| 123 | key = MAP_KEY_BYTES; | ||
| 124 | assert(bpf_map_lookup_elem(map_fd, &key, &byte_cnt) == 0); | ||
| 125 | |||
| 126 | printf("cgroup received %lld packets, %lld bytes\n", | ||
| 127 | pkt_cnt, byte_cnt); | ||
| 128 | sleep(1); | ||
| 129 | } | ||
| 130 | |||
| 131 | return EXIT_SUCCESS; | ||
| 132 | } | ||
| 133 | |||
| 134 | int main(int argc, char **argv) | ||
| 135 | { | ||
| 136 | int detach_only = 0, verdict = 1; | ||
| 137 | enum bpf_attach_type type; | ||
| 138 | int opt, cg_fd, ret; | ||
| 139 | |||
| 140 | while ((opt = getopt(argc, argv, "Dd")) != -1) { | ||
| 141 | switch (opt) { | ||
| 142 | case 'd': | ||
| 143 | verdict = 0; | ||
| 144 | break; | ||
| 145 | case 'D': | ||
| 146 | detach_only = 1; | ||
| 147 | break; | ||
| 148 | default: | ||
| 149 | return usage(argv[0]); | ||
| 150 | } | ||
| 151 | } | ||
| 152 | |||
| 153 | if (argc - optind < 2) | ||
| 154 | return usage(argv[0]); | ||
| 155 | |||
| 156 | if (strcmp(argv[optind + 1], "ingress") == 0) | ||
| 157 | type = BPF_CGROUP_INET_INGRESS; | ||
| 158 | else if (strcmp(argv[optind + 1], "egress") == 0) | ||
| 159 | type = BPF_CGROUP_INET_EGRESS; | ||
| 160 | else | ||
| 161 | return usage(argv[0]); | ||
| 162 | |||
| 163 | cg_fd = open(argv[optind], O_DIRECTORY | O_RDONLY); | ||
| 164 | if (cg_fd < 0) { | ||
| 165 | printf("Failed to open cgroup path: '%s'\n", strerror(errno)); | ||
| 166 | return EXIT_FAILURE; | ||
| 167 | } | ||
| 168 | |||
| 169 | if (detach_only) { | ||
| 170 | ret = bpf_prog_detach(cg_fd, type); | ||
| 171 | printf("bpf_prog_detach() returned '%s' (%d)\n", | ||
| 172 | strerror(errno), errno); | ||
| 173 | } else | ||
| 174 | ret = attach_filter(cg_fd, type, verdict); | ||
| 175 | |||
| 176 | return ret; | ||
| 177 | } | ||
| @@ -1,294 +0,0 @@ | |||
| 1 | /* eBPF example program: | ||
| 2 | * | ||
| 3 | * - Loads eBPF program | ||
| 4 | * | ||
| 5 | * The eBPF program sets the sk_bound_dev_if index in new AF_INET{6} | ||
| 6 | * sockets opened by processes in the cgroup. | ||
| 7 | * | ||
| 8 | * - Attaches the new program to a cgroup using BPF_PROG_ATTACH | ||
| 9 | */ | ||
| 10 | |||
| 11 | #define _GNU_SOURCE | ||
| 12 | |||
| 13 | #include <stdio.h> | ||
| 14 | #include <stdlib.h> | ||
| 15 | #include <stddef.h> | ||
| 16 | #include <string.h> | ||
| 17 | #include <unistd.h> | ||
| 18 | #include <assert.h> | ||
| 19 | #include <errno.h> | ||
| 20 | #include <fcntl.h> | ||
| 21 | #include <net/if.h> | ||
| 22 | #include <inttypes.h> | ||
| 23 | #include <linux/bpf.h> | ||
| 24 | #include <bpf/bpf.h> | ||
| 25 | |||
| 26 | #include "bpf_insn.h" | ||
| 27 | |||
| 28 | char bpf_log_buf[BPF_LOG_BUF_SIZE]; | ||
| 29 | |||
| 30 | static int prog_load(__u32 idx, __u32 mark, __u32 prio) | ||
| 31 | { | ||
| 32 | /* save pointer to context */ | ||
| 33 | struct bpf_insn prog_start[] = { | ||
| 34 | BPF_MOV64_REG(BPF_REG_6, BPF_REG_1), | ||
| 35 | }; | ||
| 36 | struct bpf_insn prog_end[] = { | ||
| 37 | BPF_MOV64_IMM(BPF_REG_0, 1), /* r0 = verdict */ | ||
| 38 | BPF_EXIT_INSN(), | ||
| 39 | }; | ||
| 40 | |||
| 41 | /* set sk_bound_dev_if on socket */ | ||
| 42 | struct bpf_insn prog_dev[] = { | ||
| 43 | BPF_MOV64_IMM(BPF_REG_3, idx), | ||
| 44 | BPF_MOV64_IMM(BPF_REG_2, offsetof(struct bpf_sock, bound_dev_if)), | ||
| 45 | BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3, offsetof(struct bpf_sock, bound_dev_if)), | ||
| 46 | }; | ||
| 47 | |||
| 48 | /* set mark on socket */ | ||
| 49 | struct bpf_insn prog_mark[] = { | ||
| 50 | /* get uid of process */ | ||
| 51 | BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, | ||
| 52 | BPF_FUNC_get_current_uid_gid), | ||
| 53 | BPF_ALU64_IMM(BPF_AND, BPF_REG_0, 0xffffffff), | ||
| 54 | |||
| 55 | /* if uid is 0, use given mark, else use the uid as the mark */ | ||
| 56 | BPF_MOV64_REG(BPF_REG_3, BPF_REG_0), | ||
| 57 | BPF_JMP_IMM(BPF_JNE, BPF_REG_0, 0, 1), | ||
| 58 | BPF_MOV64_IMM(BPF_REG_3, mark), | ||
| 59 | |||
| 60 | /* set the mark on the new socket */ | ||
| 61 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), | ||
| 62 | BPF_MOV64_IMM(BPF_REG_2, offsetof(struct bpf_sock, mark)), | ||
| 63 | BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3, offsetof(struct bpf_sock, mark)), | ||
| 64 | }; | ||
| 65 | |||
| 66 | /* set priority on socket */ | ||
| 67 | struct bpf_insn prog_prio[] = { | ||
| 68 | BPF_MOV64_REG(BPF_REG_1, BPF_REG_6), | ||
| 69 | BPF_MOV64_IMM(BPF_REG_3, prio), | ||
| 70 | BPF_MOV64_IMM(BPF_REG_2, offsetof(struct bpf_sock, priority)), | ||
| 71 | BPF_STX_MEM(BPF_W, BPF_REG_1, BPF_REG_3, offsetof(struct bpf_sock, priority)), | ||
| 72 | }; | ||
| 73 | LIBBPF_OPTS(bpf_prog_load_opts, opts, | ||
| 74 | .log_buf = bpf_log_buf, | ||
| 75 | .log_size = BPF_LOG_BUF_SIZE, | ||
| 76 | ); | ||
| 77 | |||
| 78 | struct bpf_insn *prog; | ||
| 79 | size_t insns_cnt; | ||
| 80 | void *p; | ||
| 81 | int ret; | ||
| 82 | |||
| 83 | insns_cnt = sizeof(prog_start) + sizeof(prog_end); | ||
| 84 | if (idx) | ||
| 85 | insns_cnt += sizeof(prog_dev); | ||
| 86 | |||
| 87 | if (mark) | ||
| 88 | insns_cnt += sizeof(prog_mark); | ||
| 89 | |||
| 90 | if (prio) | ||
| 91 | insns_cnt += sizeof(prog_prio); | ||
| 92 | |||
| 93 | p = prog = malloc(insns_cnt); | ||
| 94 | if (!prog) { | ||
| 95 | fprintf(stderr, "Failed to allocate memory for instructions\n"); | ||
| 96 | return EXIT_FAILURE; | ||
| 97 | } | ||
| 98 | |||
| 99 | memcpy(p, prog_start, sizeof(prog_start)); | ||
| 100 | p += sizeof(prog_start); | ||
| 101 | |||
| 102 | if (idx) { | ||
| 103 | memcpy(p, prog_dev, sizeof(prog_dev)); | ||
| 104 | p += sizeof(prog_dev); | ||
| 105 | } | ||
| 106 | |||
| 107 | if (mark) { | ||
| 108 | memcpy(p, prog_mark, sizeof(prog_mark)); | ||
| 109 | p += sizeof(prog_mark); | ||
| 110 | } | ||
| 111 | |||
| 112 | if (prio) { | ||
| 113 | memcpy(p, prog_prio, sizeof(prog_prio)); | ||
| 114 | p += sizeof(prog_prio); | ||
| 115 | } | ||
| 116 | |||
| 117 | memcpy(p, prog_end, sizeof(prog_end)); | ||
| 118 | p += sizeof(prog_end); | ||
| 119 | |||
| 120 | insns_cnt /= sizeof(struct bpf_insn); | ||
| 121 | |||
| 122 | ret = bpf_prog_load(BPF_PROG_TYPE_CGROUP_SOCK, NULL, "GPL", | ||
| 123 | prog, insns_cnt, &opts); | ||
| 124 | |||
| 125 | free(prog); | ||
| 126 | |||
| 127 | return ret; | ||
| 128 | } | ||
| 129 | |||
| 130 | static int get_bind_to_device(int sd, char *name, size_t len) | ||
| 131 | { | ||
| 132 | socklen_t optlen = len; | ||
| 133 | int rc; | ||
| 134 | |||
| 135 | name[0] = '\0'; | ||
| 136 | rc = getsockopt(sd, SOL_SOCKET, SO_BINDTODEVICE, name, &optlen); | ||
| 137 | if (rc < 0) | ||
| 138 | perror("setsockopt(SO_BINDTODEVICE)"); | ||
| 139 | |||
| 140 | return rc; | ||
| 141 | } | ||
| 142 | |||
| 143 | static unsigned int get_somark(int sd) | ||
| 144 | { | ||
| 145 | unsigned int mark = 0; | ||
| 146 | socklen_t optlen = sizeof(mark); | ||
| 147 | int rc; | ||
| 148 | |||
| 149 | rc = getsockopt(sd, SOL_SOCKET, SO_MARK, &mark, &optlen); | ||
| 150 | if (rc < 0) | ||
| 151 | perror("getsockopt(SO_MARK)"); | ||
| 152 | |||
| 153 | return mark; | ||
| 154 | } | ||
| 155 | |||
| 156 | static unsigned int get_priority(int sd) | ||
| 157 | { | ||
| 158 | unsigned int prio = 0; | ||
| 159 | socklen_t optlen = sizeof(prio); | ||
| 160 | int rc; | ||
| 161 | |||
| 162 | rc = getsockopt(sd, SOL_SOCKET, SO_PRIORITY, &prio, &optlen); | ||
| 163 | if (rc < 0) | ||
| 164 | perror("getsockopt(SO_PRIORITY)"); | ||
| 165 | |||
| 166 | return prio; | ||
| 167 | } | ||
| 168 | |||
| 169 | static int show_sockopts(int family) | ||
| 170 | { | ||
| 171 | unsigned int mark, prio; | ||
| 172 | char name[16]; | ||
| 173 | int sd; | ||
| 174 | |||
| 175 | sd = socket(family, SOCK_DGRAM, 17); | ||
| 176 | if (sd < 0) { | ||
| 177 | perror("socket"); | ||
| 178 | return 1; | ||
| 179 | } | ||
| 180 | |||
| 181 | if (get_bind_to_device(sd, name, sizeof(name)) < 0) | ||
| 182 | return 1; | ||
| 183 | |||
| 184 | mark = get_somark(sd); | ||
| 185 | prio = get_priority(sd); | ||
| 186 | |||
| 187 | close(sd); | ||
| 188 | |||
| 189 | printf("sd %d: dev %s, mark %u, priority %u\n", sd, name, mark, prio); | ||
| 190 | |||
| 191 | return 0; | ||
| 192 | } | ||
| 193 | |||
| 194 | static int usage(const char *argv0) | ||
| 195 | { | ||
| 196 | printf("Usage:\n"); | ||
| 197 | printf(" Attach a program\n"); | ||
| 198 | printf(" %s -b bind-to-dev -m mark -p prio cg-path\n", argv0); | ||
| 199 | printf("\n"); | ||
| 200 | printf(" Detach a program\n"); | ||
| 201 | printf(" %s -d cg-path\n", argv0); | ||
| 202 | printf("\n"); | ||
| 203 | printf(" Show inherited socket settings (mark, priority, and device)\n"); | ||
| 204 | printf(" %s [-6]\n", argv0); | ||
| 205 | return EXIT_FAILURE; | ||
| 206 | } | ||
| 207 | |||
| 208 | int main(int argc, char **argv) | ||
| 209 | { | ||
| 210 | __u32 idx = 0, mark = 0, prio = 0; | ||
| 211 | const char *cgrp_path = NULL; | ||
| 212 | int cg_fd, prog_fd, ret; | ||
| 213 | int family = PF_INET; | ||
| 214 | int do_attach = 1; | ||
| 215 | int rc; | ||
| 216 | |||
| 217 | while ((rc = getopt(argc, argv, "db:m:p:6")) != -1) { | ||
| 218 | switch (rc) { | ||
| 219 | case 'd': | ||
| 220 | do_attach = 0; | ||
| 221 | break; | ||
| 222 | case 'b': | ||
| 223 | idx = if_nametoindex(optarg); | ||
| 224 | if (!idx) { | ||
| 225 | idx = strtoumax(optarg, NULL, 0); | ||
| 226 | if (!idx) { | ||
| 227 | printf("Invalid device name\n"); | ||
| 228 | return EXIT_FAILURE; | ||
| 229 | } | ||
| 230 | } | ||
| 231 | break; | ||
| 232 | case 'm': | ||
| 233 | mark = strtoumax(optarg, NULL, 0); | ||
| 234 | break; | ||
| 235 | case 'p': | ||
| 236 | prio = strtoumax(optarg, NULL, 0); | ||
| 237 | break; | ||
| 238 | case '6': | ||
| 239 | family = PF_INET6; | ||
| 240 | break; | ||
| 241 | default: | ||
| 242 | return usage(argv[0]); | ||
| 243 | } | ||
| 244 | } | ||
| 245 | |||
| 246 | if (optind == argc) | ||
| 247 | return show_sockopts(family); | ||
| 248 | |||
| 249 | cgrp_path = argv[optind]; | ||
| 250 | if (!cgrp_path) { | ||
| 251 | fprintf(stderr, "cgroup path not given\n"); | ||
| 252 | return EXIT_FAILURE; | ||
| 253 | } | ||
| 254 | |||
| 255 | if (do_attach && !idx && !mark && !prio) { | ||
| 256 | fprintf(stderr, | ||
| 257 | "One of device, mark or priority must be given\n"); | ||
| 258 | return EXIT_FAILURE; | ||
| 259 | } | ||
| 260 | |||
| 261 | cg_fd = open(cgrp_path, O_DIRECTORY | O_RDONLY); | ||
| 262 | if (cg_fd < 0) { | ||
| 263 | printf("Failed to open cgroup path: '%s'\n", strerror(errno)); | ||
| 264 | return EXIT_FAILURE; | ||
| 265 | } | ||
| 266 | |||
| 267 | if (do_attach) { | ||
| 268 | prog_fd = prog_load(idx, mark, prio); | ||
| 269 | if (prog_fd < 0) { | ||
| 270 | printf("Failed to load prog: '%s'\n", strerror(errno)); | ||
| 271 | printf("Output from kernel verifier:\n%s\n-------\n", | ||
| 272 | bpf_log_buf); | ||
| 273 | return EXIT_FAILURE; | ||
| 274 | } | ||
| 275 | |||
| 276 | ret = bpf_prog_attach(prog_fd, cg_fd, | ||
| 277 | BPF_CGROUP_INET_SOCK_CREATE, 0); | ||
| 278 | if (ret < 0) { | ||
| 279 | printf("Failed to attach prog to cgroup: '%s'\n", | ||
| 280 | strerror(errno)); | ||
| 281 | return EXIT_FAILURE; | ||
| 282 | } | ||
| 283 | } else { | ||
| 284 | ret = bpf_prog_detach(cg_fd, BPF_CGROUP_INET_SOCK_CREATE); | ||
| 285 | if (ret < 0) { | ||
| 286 | printf("Failed to detach prog from cgroup: '%s'\n", | ||
| 287 | strerror(errno)); | ||
| 288 | return EXIT_FAILURE; | ||
| 289 | } | ||
| 290 | } | ||
| 291 | |||
| 292 | close(cg_fd); | ||
| 293 | return EXIT_SUCCESS; | ||
| 294 | } | ||
| @@ -1,137 +0,0 @@ | |||
| 1 | #!/bin/sh | ||
| 2 | # SPDX-License-Identifier: GPL-2.0 | ||
| 3 | |||
| 4 | # Test various socket options that can be set by attaching programs to cgroups. | ||
| 5 | |||
| 6 | MY_DIR=$(dirname $0) | ||
| 7 | TEST=$MY_DIR/test_cgrp2_sock | ||
| 8 | CGRP_MNT="/tmp/cgroupv2-test_cgrp2_sock" | ||
| 9 | |||
| 10 | ################################################################################ | ||
| 11 | # | ||
| 12 | print_result() | ||
| 13 | { | ||
| 14 | local rc=$1 | ||
| 15 | local status=" OK " | ||
| 16 | |||
| 17 | [ $rc -ne 0 ] && status="FAIL" | ||
| 18 | |||
| 19 | printf "%-50s [%4s]\n" "$2" "$status" | ||
| 20 | } | ||
| 21 | |||
| 22 | check_sock() | ||
| 23 | { | ||
| 24 | out=$($TEST) | ||
| 25 | echo $out | grep -q "$1" | ||
| 26 | if [ $? -ne 0 ]; then | ||
| 27 | print_result 1 "IPv4: $2" | ||
| 28 | echo " expected: $1" | ||
| 29 | echo " have: $out" | ||
| 30 | rc=1 | ||
| 31 | else | ||
| 32 | print_result 0 "IPv4: $2" | ||
| 33 | fi | ||
| 34 | } | ||
| 35 | |||
| 36 | check_sock6() | ||
| 37 | { | ||
| 38 | out=$($TEST -6) | ||
| 39 | echo $out | grep -q "$1" | ||
| 40 | if [ $? -ne 0 ]; then | ||
| 41 | print_result 1 "IPv6: $2" | ||
| 42 | echo " expected: $1" | ||
| 43 | echo " have: $out" | ||
| 44 | rc=1 | ||
| 45 | else | ||
| 46 | print_result 0 "IPv6: $2" | ||
| 47 | fi | ||
| 48 | } | ||
| 49 | |||
| 50 | ################################################################################ | ||
| 51 | # | ||
| 52 | |||
| 53 | cleanup() | ||
| 54 | { | ||
| 55 | echo $$ >> ${CGRP_MNT}/cgroup.procs | ||
| 56 | rmdir ${CGRP_MNT}/sockopts | ||
| 57 | } | ||
| 58 | |||
| 59 | cleanup_and_exit() | ||
| 60 | { | ||
| 61 | local rc=$1 | ||
| 62 | local msg="$2" | ||
| 63 | |||
| 64 | [ -n "$msg" ] && echo "ERROR: $msg" | ||
| 65 | |||
| 66 | $TEST -d ${CGRP_MNT}/sockopts | ||
| 67 | ip li del cgrp2_sock | ||
| 68 | umount ${CGRP_MNT} | ||
| 69 | |||
| 70 | exit $rc | ||
| 71 | } | ||
| 72 | |||
| 73 | |||
| 74 | ################################################################################ | ||
| 75 | # main | ||
| 76 | |||
| 77 | rc=0 | ||
| 78 | |||
| 79 | ip li add cgrp2_sock type dummy 2>/dev/null | ||
| 80 | |||
| 81 | set -e | ||
| 82 | mkdir -p ${CGRP_MNT} | ||
| 83 | mount -t cgroup2 none ${CGRP_MNT} | ||
| 84 | set +e | ||
| 85 | |||
| 86 | |||
| 87 | # make sure we have a known start point | ||
| 88 | cleanup 2>/dev/null | ||
| 89 | |||
| 90 | mkdir -p ${CGRP_MNT}/sockopts | ||
| 91 | [ $? -ne 0 ] && cleanup_and_exit 1 "Failed to create cgroup hierarchy" | ||
| 92 | |||
| 93 | |||
| 94 | # set pid into cgroup | ||
| 95 | echo $$ > ${CGRP_MNT}/sockopts/cgroup.procs | ||
| 96 | |||
| 97 | # no bpf program attached, so socket should show no settings | ||
| 98 | check_sock "dev , mark 0, priority 0" "No programs attached" | ||
| 99 | check_sock6 "dev , mark 0, priority 0" "No programs attached" | ||
| 100 | |||
| 101 | # verify device is set | ||
| 102 | # | ||
| 103 | $TEST -b cgrp2_sock ${CGRP_MNT}/sockopts | ||
| 104 | if [ $? -ne 0 ]; then | ||
| 105 | cleanup_and_exit 1 "Failed to install program to set device" | ||
| 106 | fi | ||
| 107 | check_sock "dev cgrp2_sock, mark 0, priority 0" "Device set" | ||
| 108 | check_sock6 "dev cgrp2_sock, mark 0, priority 0" "Device set" | ||
| 109 | |||
| 110 | # verify mark is set | ||
| 111 | # | ||
| 112 | $TEST -m 666 ${CGRP_MNT}/sockopts | ||
| 113 | if [ $? -ne 0 ]; then | ||
| 114 | cleanup_and_exit 1 "Failed to install program to set mark" | ||
| 115 | fi | ||
| 116 | check_sock "dev , mark 666, priority 0" "Mark set" | ||
| 117 | check_sock6 "dev , mark 666, priority 0" "Mark set" | ||
| 118 | |||
| 119 | # verify priority is set | ||
| 120 | # | ||
| 121 | $TEST -p 123 ${CGRP_MNT}/sockopts | ||
| 122 | if [ $? -ne 0 ]; then | ||
| 123 | cleanup_and_exit 1 "Failed to install program to set priority" | ||
| 124 | fi | ||
| 125 | check_sock "dev , mark 0, priority 123" "Priority set" | ||
| 126 | check_sock6 "dev , mark 0, priority 123" "Priority set" | ||
| 127 | |||
| 128 | # all 3 at once | ||
| 129 | # | ||
| 130 | $TEST -b cgrp2_sock -m 666 -p 123 ${CGRP_MNT}/sockopts | ||
| 131 | if [ $? -ne 0 ]; then | ||
| 132 | cleanup_and_exit 1 "Failed to install program to set device, mark and priority" | ||
| 133 | fi | ||
| 134 | check_sock "dev cgrp2_sock, mark 666, priority 123" "Priority set" | ||
| 135 | check_sock6 "dev cgrp2_sock, mark 666, priority 123" "Priority set" | ||
| 136 | |||
| 137 | cleanup_and_exit $rc | ||
| @@ -1,95 +0,0 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* eBPF example program: | ||
| 3 | * | ||
| 4 | * - Loads eBPF program | ||
| 5 | * | ||
| 6 | * The eBPF program loads a filter from file and attaches the | ||
| 7 | * program to a cgroup using BPF_PROG_ATTACH | ||
| 8 | */ | ||
| 9 | |||
| 10 | #define _GNU_SOURCE | ||
| 11 | |||
| 12 | #include <stdio.h> | ||
| 13 | #include <stdlib.h> | ||
| 14 | #include <stddef.h> | ||
| 15 | #include <string.h> | ||
| 16 | #include <unistd.h> | ||
| 17 | #include <assert.h> | ||
| 18 | #include <errno.h> | ||
| 19 | #include <fcntl.h> | ||
| 20 | #include <net/if.h> | ||
| 21 | #include <linux/bpf.h> | ||
| 22 | #include <bpf/bpf.h> | ||
| 23 | #include <bpf/libbpf.h> | ||
| 24 | |||
| 25 | #include "bpf_insn.h" | ||
| 26 | |||
| 27 | static int usage(const char *argv0) | ||
| 28 | { | ||
| 29 | printf("Usage: %s cg-path filter-path [filter-id]\n", argv0); | ||
| 30 | return EXIT_FAILURE; | ||
| 31 | } | ||
| 32 | |||
| 33 | int main(int argc, char **argv) | ||
| 34 | { | ||
| 35 | int cg_fd, err, ret = EXIT_FAILURE, filter_id = 0, prog_cnt = 0; | ||
| 36 | const char *link_pin_path = "/sys/fs/bpf/test_cgrp2_sock2"; | ||
| 37 | struct bpf_link *link = NULL; | ||
| 38 | struct bpf_program *progs[2]; | ||
| 39 | struct bpf_program *prog; | ||
| 40 | struct bpf_object *obj; | ||
| 41 | |||
| 42 | if (argc < 3) | ||
| 43 | return usage(argv[0]); | ||
| 44 | |||
| 45 | if (argc > 3) | ||
| 46 | filter_id = atoi(argv[3]); | ||
| 47 | |||
| 48 | cg_fd = open(argv[1], O_DIRECTORY | O_RDONLY); | ||
| 49 | if (cg_fd < 0) { | ||
| 50 | printf("Failed to open cgroup path: '%s'\n", strerror(errno)); | ||
| 51 | return ret; | ||
| 52 | } | ||
| 53 | |||
| 54 | obj = bpf_object__open_file(argv[2], NULL); | ||
| 55 | if (libbpf_get_error(obj)) { | ||
| 56 | printf("ERROR: opening BPF object file failed\n"); | ||
| 57 | return ret; | ||
| 58 | } | ||
| 59 | |||
| 60 | bpf_object__for_each_program(prog, obj) { | ||
| 61 | progs[prog_cnt] = prog; | ||
| 62 | prog_cnt++; | ||
| 63 | } | ||
| 64 | |||
| 65 | if (filter_id >= prog_cnt) { | ||
| 66 | printf("Invalid program id; program not found in file\n"); | ||
| 67 | goto cleanup; | ||
| 68 | } | ||
| 69 | |||
| 70 | /* load BPF program */ | ||
| 71 | if (bpf_object__load(obj)) { | ||
| 72 | printf("ERROR: loading BPF object file failed\n"); | ||
| 73 | goto cleanup; | ||
| 74 | } | ||
| 75 | |||
| 76 | link = bpf_program__attach_cgroup(progs[filter_id], cg_fd); | ||
| 77 | if (libbpf_get_error(link)) { | ||
| 78 | printf("ERROR: bpf_program__attach failed\n"); | ||
| 79 | link = NULL; | ||
| 80 | goto cleanup; | ||
| 81 | } | ||
| 82 | |||
| 83 | err = bpf_link__pin(link, link_pin_path); | ||
| 84 | if (err < 0) { | ||
| 85 | printf("ERROR: bpf_link__pin failed: %d\n", err); | ||
| 86 | goto cleanup; | ||
| 87 | } | ||
| 88 | |||
| 89 | ret = EXIT_SUCCESS; | ||
| 90 | |||
| 91 | cleanup: | ||
| 92 | bpf_link__destroy(link); | ||
| 93 | bpf_object__close(obj); | ||
| 94 | return ret; | ||
| 95 | } | ||
| @@ -1,103 +0,0 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | # SPDX-License-Identifier: GPL-2.0 | ||
| 3 | |||
| 4 | BPFFS=/sys/fs/bpf | ||
| 5 | MY_DIR=$(dirname $0) | ||
| 6 | TEST=$MY_DIR/test_cgrp2_sock2 | ||
| 7 | LINK_PIN=$BPFFS/test_cgrp2_sock2 | ||
| 8 | BPF_PROG=$MY_DIR/sock_flags.bpf.o | ||
| 9 | |||
| 10 | function config_device { | ||
| 11 | ip netns add at_ns0 | ||
| 12 | ip link add veth0 type veth peer name veth0b | ||
| 13 | ip link set veth0 netns at_ns0 | ||
| 14 | ip netns exec at_ns0 sysctl -q net.ipv6.conf.veth0.disable_ipv6=0 | ||
| 15 | ip netns exec at_ns0 ip addr add 172.16.1.100/24 dev veth0 | ||
| 16 | ip netns exec at_ns0 ip addr add 2401:db00::1/64 dev veth0 nodad | ||
| 17 | ip netns exec at_ns0 ip link set dev veth0 up | ||
| 18 | sysctl -q net.ipv6.conf.veth0b.disable_ipv6=0 | ||
| 19 | ip addr add 172.16.1.101/24 dev veth0b | ||
| 20 | ip addr add 2401:db00::2/64 dev veth0b nodad | ||
| 21 | ip link set veth0b up | ||
| 22 | } | ||
| 23 | |||
| 24 | function config_cgroup { | ||
| 25 | rm -rf /tmp/cgroupv2 | ||
| 26 | mkdir -p /tmp/cgroupv2 | ||
| 27 | mount -t cgroup2 none /tmp/cgroupv2 | ||
| 28 | mkdir -p /tmp/cgroupv2/foo | ||
| 29 | echo $$ >> /tmp/cgroupv2/foo/cgroup.procs | ||
| 30 | } | ||
| 31 | |||
| 32 | function config_bpffs { | ||
| 33 | if mount | grep $BPFFS > /dev/null; then | ||
| 34 | echo "bpffs already mounted" | ||
| 35 | else | ||
| 36 | echo "bpffs not mounted. Mounting..." | ||
| 37 | mount -t bpf none $BPFFS | ||
| 38 | fi | ||
| 39 | } | ||
| 40 | |||
| 41 | function attach_bpf { | ||
| 42 | $TEST /tmp/cgroupv2/foo $BPF_PROG $1 | ||
| 43 | [ $? -ne 0 ] && exit 1 | ||
| 44 | } | ||
| 45 | |||
| 46 | function cleanup { | ||
| 47 | rm -rf $LINK_PIN | ||
| 48 | ip link del veth0b | ||
| 49 | ip netns delete at_ns0 | ||
| 50 | umount /tmp/cgroupv2 | ||
| 51 | rm -rf /tmp/cgroupv2 | ||
| 52 | } | ||
| 53 | |||
| 54 | cleanup 2>/dev/null | ||
| 55 | |||
| 56 | set -e | ||
| 57 | config_device | ||
| 58 | config_cgroup | ||
| 59 | config_bpffs | ||
| 60 | set +e | ||
| 61 | |||
| 62 | # | ||
| 63 | # Test 1 - fail ping6 | ||
| 64 | # | ||
| 65 | attach_bpf 0 | ||
| 66 | ping -c1 -w1 172.16.1.100 | ||
| 67 | if [ $? -ne 0 ]; then | ||
| 68 | echo "ping failed when it should succeed" | ||
| 69 | cleanup | ||
| 70 | exit 1 | ||
| 71 | fi | ||
| 72 | |||
| 73 | ping6 -c1 -w1 2401:db00::1 | ||
| 74 | if [ $? -eq 0 ]; then | ||
| 75 | echo "ping6 succeeded when it should not" | ||
| 76 | cleanup | ||
| 77 | exit 1 | ||
| 78 | fi | ||
| 79 | |||
| 80 | rm -rf $LINK_PIN | ||
| 81 | sleep 1 # Wait for link detach | ||
| 82 | |||
| 83 | # | ||
| 84 | # Test 2 - fail ping | ||
| 85 | # | ||
| 86 | attach_bpf 1 | ||
| 87 | ping6 -c1 -w1 2401:db00::1 | ||
| 88 | if [ $? -ne 0 ]; then | ||
| 89 | echo "ping6 failed when it should succeed" | ||
| 90 | cleanup | ||
| 91 | exit 1 | ||
| 92 | fi | ||
| 93 | |||
| 94 | ping -c1 -w1 172.16.1.100 | ||
| 95 | if [ $? -eq 0 ]; then | ||
| 96 | echo "ping succeeded when it should not" | ||
| 97 | cleanup | ||
| 98 | exit 1 | ||
| 99 | fi | ||
| 100 | |||
| 101 | cleanup | ||
| 102 | echo | ||
| 103 | echo "*** PASS ***" | ||
| @@ -1,56 +0,0 @@ | |||
| 1 | /* Copyright (c) 2016 Facebook | ||
| 2 | * | ||
| 3 | * This program is free software; you can redistribute it and/or | ||
| 4 | * modify it under the terms of version 2 of the GNU General Public | ||
| 5 | * License as published by the Free Software Foundation. | ||
| 6 | */ | ||
| 7 | #define KBUILD_MODNAME "foo" | ||
| 8 | #include "vmlinux.h" | ||
| 9 | #include "net_shared.h" | ||
| 10 | #include <bpf/bpf_helpers.h> | ||
| 11 | |||
| 12 | /* copy of 'struct ethhdr' without __packed */ | ||
| 13 | struct eth_hdr { | ||
| 14 | unsigned char h_dest[ETH_ALEN]; | ||
| 15 | unsigned char h_source[ETH_ALEN]; | ||
| 16 | unsigned short h_proto; | ||
| 17 | }; | ||
| 18 | |||
| 19 | struct { | ||
| 20 | __uint(type, BPF_MAP_TYPE_CGROUP_ARRAY); | ||
| 21 | __type(key, u32); | ||
| 22 | __type(value, u32); | ||
| 23 | __uint(pinning, LIBBPF_PIN_BY_NAME); | ||
| 24 | __uint(max_entries, 1); | ||
| 25 | } test_cgrp2_array_pin SEC(".maps"); | ||
| 26 | |||
| 27 | SEC("filter") | ||
| 28 | int handle_egress(struct __sk_buff *skb) | ||
| 29 | { | ||
| 30 | void *data = (void *)(long)skb->data; | ||
| 31 | struct eth_hdr *eth = data; | ||
| 32 | struct ipv6hdr *ip6h = data + sizeof(*eth); | ||
| 33 | void *data_end = (void *)(long)skb->data_end; | ||
| 34 | char dont_care_msg[] = "dont care %04x %d\n"; | ||
| 35 | char pass_msg[] = "pass\n"; | ||
| 36 | char reject_msg[] = "reject\n"; | ||
| 37 | |||
| 38 | /* single length check */ | ||
| 39 | if (data + sizeof(*eth) + sizeof(*ip6h) > data_end) | ||
| 40 | return TC_ACT_OK; | ||
| 41 | |||
| 42 | if (eth->h_proto != bpf_htons(ETH_P_IPV6) || | ||
| 43 | ip6h->nexthdr != IPPROTO_ICMPV6) { | ||
| 44 | bpf_trace_printk(dont_care_msg, sizeof(dont_care_msg), | ||
| 45 | eth->h_proto, ip6h->nexthdr); | ||
| 46 | return TC_ACT_OK; | ||
| 47 | } else if (bpf_skb_under_cgroup(skb, &test_cgrp2_array_pin, 0) != 1) { | ||
| 48 | bpf_trace_printk(pass_msg, sizeof(pass_msg)); | ||
| 49 | return TC_ACT_OK; | ||
| 50 | } else { | ||
| 51 | bpf_trace_printk(reject_msg, sizeof(reject_msg)); | ||
| 52 | return TC_ACT_SHOT; | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | char _license[] SEC("license") = "GPL"; | ||
| @@ -1,187 +0,0 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | # SPDX-License-Identifier: GPL-2.0 | ||
| 3 | |||
| 4 | MY_DIR=$(dirname $0) | ||
| 5 | # Details on the bpf prog | ||
| 6 | BPF_CGRP2_ARRAY_NAME='test_cgrp2_array_pin' | ||
| 7 | BPF_PROG="$MY_DIR/test_cgrp2_tc.bpf.o" | ||
| 8 | BPF_SECTION='filter' | ||
| 9 | |||
| 10 | [ -z "$TC" ] && TC='tc' | ||
| 11 | [ -z "$IP" ] && IP='ip' | ||
| 12 | |||
| 13 | # Names of the veth interface, net namespace...etc. | ||
| 14 | HOST_IFC='ve' | ||
| 15 | NS_IFC='vens' | ||
| 16 | NS='ns' | ||
| 17 | |||
| 18 | find_mnt() { | ||
| 19 | cat /proc/mounts | \ | ||
| 20 | awk '{ if ($3 == "'$1'" && mnt == "") { mnt = $2 }} END { print mnt }' | ||
| 21 | } | ||
| 22 | |||
| 23 | # Init cgroup2 vars | ||
| 24 | init_cgrp2_vars() { | ||
| 25 | CGRP2_ROOT=$(find_mnt cgroup2) | ||
| 26 | if [ -z "$CGRP2_ROOT" ] | ||
| 27 | then | ||
| 28 | CGRP2_ROOT='/mnt/cgroup2' | ||
| 29 | MOUNT_CGRP2="yes" | ||
| 30 | fi | ||
| 31 | CGRP2_TC="$CGRP2_ROOT/tc" | ||
| 32 | CGRP2_TC_LEAF="$CGRP2_TC/leaf" | ||
| 33 | } | ||
| 34 | |||
| 35 | # Init bpf fs vars | ||
| 36 | init_bpf_fs_vars() { | ||
| 37 | local bpf_fs_root=$(find_mnt bpf) | ||
| 38 | [ -n "$bpf_fs_root" ] || return -1 | ||
| 39 | BPF_FS_TC_SHARE="$bpf_fs_root/tc/globals" | ||
| 40 | } | ||
| 41 | |||
| 42 | setup_cgrp2() { | ||
| 43 | case $1 in | ||
| 44 | start) | ||
| 45 | if [ "$MOUNT_CGRP2" == 'yes' ] | ||
| 46 | then | ||
| 47 | [ -d $CGRP2_ROOT ] || mkdir -p $CGRP2_ROOT | ||
| 48 | mount -t cgroup2 none $CGRP2_ROOT || return $? | ||
| 49 | fi | ||
| 50 | mkdir -p $CGRP2_TC_LEAF | ||
| 51 | ;; | ||
| 52 | *) | ||
| 53 | rmdir $CGRP2_TC_LEAF && rmdir $CGRP2_TC | ||
| 54 | [ "$MOUNT_CGRP2" == 'yes' ] && umount $CGRP2_ROOT | ||
| 55 | ;; | ||
| 56 | esac | ||
| 57 | } | ||
| 58 | |||
| 59 | setup_bpf_cgrp2_array() { | ||
| 60 | local bpf_cgrp2_array="$BPF_FS_TC_SHARE/$BPF_CGRP2_ARRAY_NAME" | ||
| 61 | case $1 in | ||
| 62 | start) | ||
| 63 | $MY_DIR/test_cgrp2_array_pin -U $bpf_cgrp2_array -v $CGRP2_TC | ||
| 64 | ;; | ||
| 65 | *) | ||
| 66 | [ -d "$BPF_FS_TC_SHARE" ] && rm -f $bpf_cgrp2_array | ||
| 67 | ;; | ||
| 68 | esac | ||
| 69 | } | ||
| 70 | |||
| 71 | setup_net() { | ||
| 72 | case $1 in | ||
| 73 | start) | ||
| 74 | $IP link add $HOST_IFC type veth peer name $NS_IFC || return $? | ||
| 75 | $IP link set dev $HOST_IFC up || return $? | ||
| 76 | sysctl -q net.ipv6.conf.$HOST_IFC.disable_ipv6=0 | ||
| 77 | sysctl -q net.ipv6.conf.$HOST_IFC.accept_dad=0 | ||
| 78 | |||
| 79 | $IP netns add $NS || return $? | ||
| 80 | $IP link set dev $NS_IFC netns $NS || return $? | ||
| 81 | $IP -n $NS link set dev $NS_IFC up || return $? | ||
| 82 | $IP netns exec $NS sysctl -q net.ipv6.conf.$NS_IFC.disable_ipv6=0 | ||
| 83 | $IP netns exec $NS sysctl -q net.ipv6.conf.$NS_IFC.accept_dad=0 | ||
| 84 | $TC qdisc add dev $HOST_IFC clsact || return $? | ||
| 85 | $TC filter add dev $HOST_IFC egress bpf da obj $BPF_PROG sec $BPF_SECTION || return $? | ||
| 86 | ;; | ||
| 87 | *) | ||
| 88 | $IP netns del $NS | ||
| 89 | $IP link del $HOST_IFC | ||
| 90 | ;; | ||
| 91 | esac | ||
| 92 | } | ||
| 93 | |||
| 94 | run_in_cgrp() { | ||
| 95 | # Fork another bash and move it under the specified cgroup. | ||
| 96 | # It makes the cgroup cleanup easier at the end of the test. | ||
| 97 | cmd='echo $$ > ' | ||
| 98 | cmd="$cmd $1/cgroup.procs; exec $2" | ||
| 99 | bash -c "$cmd" | ||
| 100 | } | ||
| 101 | |||
| 102 | do_test() { | ||
| 103 | run_in_cgrp $CGRP2_TC_LEAF "ping -6 -c3 ff02::1%$HOST_IFC >& /dev/null" | ||
| 104 | local dropped=$($TC -s qdisc show dev $HOST_IFC | tail -3 | \ | ||
| 105 | awk '/drop/{print substr($7, 0, index($7, ",")-1)}') | ||
| 106 | if [[ $dropped -eq 0 ]] | ||
| 107 | then | ||
| 108 | echo "FAIL" | ||
| 109 | return 1 | ||
| 110 | else | ||
| 111 | echo "Successfully filtered $dropped packets" | ||
| 112 | return 0 | ||
| 113 | fi | ||
| 114 | } | ||
| 115 | |||
| 116 | do_exit() { | ||
| 117 | if [ "$DEBUG" == "yes" ] && [ "$MODE" != 'cleanuponly' ] | ||
| 118 | then | ||
| 119 | echo "------ DEBUG ------" | ||
| 120 | echo "mount: "; mount | grep -E '(cgroup2|bpf)'; echo | ||
| 121 | echo "$CGRP2_TC_LEAF: "; ls -l $CGRP2_TC_LEAF; echo | ||
| 122 | if [ -d "$BPF_FS_TC_SHARE" ] | ||
| 123 | then | ||
| 124 | echo "$BPF_FS_TC_SHARE: "; ls -l $BPF_FS_TC_SHARE; echo | ||
| 125 | fi | ||
| 126 | echo "Host net:" | ||
| 127 | $IP netns | ||
| 128 | $IP link show dev $HOST_IFC | ||
| 129 | $IP -6 a show dev $HOST_IFC | ||
| 130 | $TC -s qdisc show dev $HOST_IFC | ||
| 131 | echo | ||
| 132 | echo "$NS net:" | ||
| 133 | $IP -n $NS link show dev $NS_IFC | ||
| 134 | $IP -n $NS -6 link show dev $NS_IFC | ||
| 135 | echo "------ DEBUG ------" | ||
| 136 | echo | ||
| 137 | fi | ||
| 138 | |||
| 139 | if [ "$MODE" != 'nocleanup' ] | ||
| 140 | then | ||
| 141 | setup_net stop | ||
| 142 | setup_bpf_cgrp2_array stop | ||
| 143 | setup_cgrp2 stop | ||
| 144 | fi | ||
| 145 | } | ||
| 146 | |||
| 147 | init_cgrp2_vars | ||
| 148 | init_bpf_fs_vars | ||
| 149 | |||
| 150 | while [[ $# -ge 1 ]] | ||
| 151 | do | ||
| 152 | a="$1" | ||
| 153 | case $a in | ||
| 154 | debug) | ||
| 155 | DEBUG='yes' | ||
| 156 | shift 1 | ||
| 157 | ;; | ||
| 158 | cleanup-only) | ||
| 159 | MODE='cleanuponly' | ||
| 160 | shift 1 | ||
| 161 | ;; | ||
| 162 | no-cleanup) | ||
| 163 | MODE='nocleanup' | ||
| 164 | shift 1 | ||
| 165 | ;; | ||
| 166 | *) | ||
| 167 | echo "test_cgrp2_tc [debug] [cleanup-only | no-cleanup]" | ||
| 168 | echo " debug: Print cgrp and network setup details at the end of the test" | ||
| 169 | echo " cleanup-only: Try to cleanup things from last test. No test will be run" | ||
| 170 | echo " no-cleanup: Run the test but don't do cleanup at the end" | ||
| 171 | echo "[Note: If no arg is given, it will run the test and do cleanup at the end]" | ||
| 172 | echo | ||
| 173 | exit -1 | ||
| 174 | ;; | ||
| 175 | esac | ||
| 176 | done | ||
| 177 | |||
| 178 | trap do_exit 0 | ||
| 179 | |||
| 180 | [ "$MODE" == 'cleanuponly' ] && exit | ||
| 181 | |||
| 182 | setup_cgrp2 start || exit $? | ||
| 183 | setup_net start || exit $? | ||
| 184 | init_bpf_fs_vars || exit $? | ||
| 185 | setup_bpf_cgrp2_array start || exit $? | ||
| 186 | do_test | ||
| 187 | echo | ||
| @@ -1,43 +0,0 @@ | |||
| 1 | /* Copyright (c) 2016 Sargun Dhillon <sargun@sargun.me> | ||
| 2 | * | ||
| 3 | * This program is free software; you can redistribute it and/or | ||
| 4 | * modify it under the terms of version 2 of the GNU General Public | ||
| 5 | * License as published by the Free Software Foundation. | ||
| 6 | */ | ||
| 7 | |||
| 8 | #include "vmlinux.h" | ||
| 9 | #include <linux/version.h> | ||
| 10 | #include <bpf/bpf_helpers.h> | ||
| 11 | #include <bpf/bpf_tracing.h> | ||
| 12 | #include <bpf/bpf_core_read.h> | ||
| 13 | |||
| 14 | struct { | ||
| 15 | __uint(type, BPF_MAP_TYPE_CGROUP_ARRAY); | ||
| 16 | __uint(key_size, sizeof(u32)); | ||
| 17 | __uint(value_size, sizeof(u32)); | ||
| 18 | __uint(max_entries, 1); | ||
| 19 | } cgroup_map SEC(".maps"); | ||
| 20 | |||
| 21 | struct { | ||
| 22 | __uint(type, BPF_MAP_TYPE_ARRAY); | ||
| 23 | __type(key, u32); | ||
| 24 | __type(value, u64); | ||
| 25 | __uint(max_entries, 1); | ||
| 26 | } perf_map SEC(".maps"); | ||
| 27 | |||
| 28 | /* Writes the last PID that called sync to a map at index 0 */ | ||
| 29 | SEC("ksyscall/sync") | ||
| 30 | int BPF_KSYSCALL(bpf_prog1) | ||
| 31 | { | ||
| 32 | u64 pid = bpf_get_current_pid_tgid(); | ||
| 33 | int idx = 0; | ||
| 34 | |||
| 35 | if (!bpf_current_task_under_cgroup(&cgroup_map, 0)) | ||
| 36 | return 0; | ||
| 37 | |||
| 38 | bpf_map_update_elem(&perf_map, &idx, &pid, BPF_ANY); | ||
| 39 | return 0; | ||
| 40 | } | ||
| 41 | |||
| 42 | char _license[] SEC("license") = "GPL"; | ||
| 43 | u32 _version SEC("version") = LINUX_VERSION_CODE; | ||
| @@ -1,115 +0,0 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | ||
| 2 | /* Copyright (c) 2016 Sargun Dhillon <sargun@sargun.me> | ||
| 3 | */ | ||
| 4 | |||
| 5 | #define _GNU_SOURCE | ||
| 6 | #include <stdio.h> | ||
| 7 | #include <unistd.h> | ||
| 8 | #include <bpf/bpf.h> | ||
| 9 | #include <bpf/libbpf.h> | ||
| 10 | #include "cgroup_helpers.h" | ||
| 11 | |||
| 12 | #define CGROUP_PATH "/my-cgroup" | ||
| 13 | |||
| 14 | int main(int argc, char **argv) | ||
| 15 | { | ||
| 16 | pid_t remote_pid, local_pid = getpid(); | ||
| 17 | int cg2 = -1, idx = 0, rc = 1; | ||
| 18 | struct bpf_link *link = NULL; | ||
| 19 | struct bpf_program *prog; | ||
| 20 | struct bpf_object *obj; | ||
| 21 | char filename[256]; | ||
| 22 | int map_fd[2]; | ||
| 23 | |||
| 24 | snprintf(filename, sizeof(filename), "%s.bpf.o", argv[0]); | ||
| 25 | obj = bpf_object__open_file(filename, NULL); | ||
| 26 | if (libbpf_get_error(obj)) { | ||
| 27 | fprintf(stderr, "ERROR: opening BPF object file failed\n"); | ||
| 28 | return 0; | ||
| 29 | } | ||
| 30 | |||
| 31 | prog = bpf_object__find_program_by_name(obj, "bpf_prog1"); | ||
| 32 | if (!prog) { | ||
| 33 | printf("finding a prog in obj file failed\n"); | ||
| 34 | goto cleanup; | ||
| 35 | } | ||
| 36 | |||
| 37 | /* load BPF program */ | ||
| 38 | if (bpf_object__load(obj)) { | ||
| 39 | fprintf(stderr, "ERROR: loading BPF object file failed\n"); | ||
| 40 | goto cleanup; | ||
| 41 | } | ||
| 42 | |||
| 43 | map_fd[0] = bpf_object__find_map_fd_by_name(obj, "cgroup_map"); | ||
| 44 | map_fd[1] = bpf_object__find_map_fd_by_name(obj, "perf_map"); | ||
| 45 | if (map_fd[0] < 0 || map_fd[1] < 0) { | ||
| 46 | fprintf(stderr, "ERROR: finding a map in obj file failed\n"); | ||
| 47 | goto cleanup; | ||
| 48 | } | ||
| 49 | |||
| 50 | link = bpf_program__attach(prog); | ||
| 51 | if (libbpf_get_error(link)) { | ||
| 52 | fprintf(stderr, "ERROR: bpf_program__attach failed\n"); | ||
| 53 | link = NULL; | ||
| 54 | goto cleanup; | ||
| 55 | } | ||
| 56 | |||
| 57 | if (setup_cgroup_environment()) | ||
| 58 | goto err; | ||
| 59 | |||
| 60 | cg2 = create_and_get_cgroup(CGROUP_PATH); | ||
| 61 | |||
| 62 | if (cg2 < 0) | ||
| 63 | goto err; | ||
| 64 | |||
| 65 | if (bpf_map_update_elem(map_fd[0], &idx, &cg2, BPF_ANY)) { | ||
| 66 | log_err("Adding target cgroup to map"); | ||
| 67 | goto err; | ||
| 68 | } | ||
| 69 | |||
| 70 | if (join_cgroup(CGROUP_PATH)) | ||
| 71 | goto err; | ||
| 72 | |||
| 73 | /* | ||
| 74 | * The installed helper program catched the sync call, and should | ||
| 75 | * write it to the map. | ||
| 76 | */ | ||
| 77 | |||
| 78 | sync(); | ||
| 79 | bpf_map_lookup_elem(map_fd[1], &idx, &remote_pid); | ||
| 80 | |||
| 81 | if (local_pid != remote_pid) { | ||
| 82 | fprintf(stderr, | ||
| 83 | "BPF Helper didn't write correct PID to map, but: %d\n", | ||
| 84 | remote_pid); | ||
| 85 | goto err; | ||
| 86 | } | ||
| 87 | |||
| 88 | /* Verify the negative scenario; leave the cgroup */ | ||
| 89 | if (join_cgroup("/")) | ||
| 90 | goto err; | ||
| 91 | |||
| 92 | remote_pid = 0; | ||
| 93 | bpf_map_update_elem(map_fd[1], &idx, &remote_pid, BPF_ANY); | ||
| 94 | |||
| 95 | sync(); | ||
| 96 | bpf_map_lookup_elem(map_fd[1], &idx, &remote_pid); | ||
| 97 | |||
| 98 | if (local_pid == remote_pid) { | ||
| 99 | fprintf(stderr, "BPF cgroup negative test did not work\n"); | ||
| 100 | goto err; | ||
| 101 | } | ||
| 102 | |||
| 103 | rc = 0; | ||
| 104 | |||
| 105 | err: | ||
| 106 | if (cg2 != -1) | ||
| 107 | close(cg2); | ||
| 108 | |||
| 109 | cleanup_cgroup_environment(); | ||
| 110 | |||
| 111 | cleanup: | ||
| 112 | bpf_link__destroy(link); | ||
| 113 | bpf_object__close(obj); | ||
| 114 | return rc; | ||
| 115 | } | ||
| @@ -1,41 +0,0 @@ | |||
| 1 | /* Copyright (c) 2016 Facebook | ||
| 2 | * | ||
| 3 | * This program is free software; you can redistribute it and/or | ||
| 4 | * modify it under the terms of version 2 of the GNU General Public | ||
| 5 | * License as published by the Free Software Foundation. | ||
| 6 | */ | ||
| 7 | #include "vmlinux.h" | ||
| 8 | #include <linux/version.h> | ||
| 9 | #include <bpf/bpf_helpers.h> | ||
| 10 | #include <bpf/bpf_tracing.h> | ||
| 11 | #include <bpf/bpf_core_read.h> | ||
| 12 | |||
| 13 | SEC("kprobe/__set_task_comm") | ||
| 14 | int prog(struct pt_regs *ctx) | ||
| 15 | { | ||
| 16 | struct signal_struct *signal; | ||
| 17 | struct task_struct *tsk; | ||
| 18 | char oldcomm[TASK_COMM_LEN] = {}; | ||
| 19 | char newcomm[TASK_COMM_LEN] = {}; | ||
| 20 | u16 oom_score_adj; | ||
| 21 | u32 pid; | ||
| 22 | |||
| 23 | tsk = (void *)PT_REGS_PARM1_CORE(ctx); | ||
| 24 | |||
| 25 | pid = BPF_CORE_READ(tsk, pid); | ||
| 26 | bpf_core_read_str(oldcomm, sizeof(oldcomm), &tsk->comm); | ||
| 27 | bpf_core_read_str(newcomm, sizeof(newcomm), | ||
| 28 | (void *)PT_REGS_PARM2(ctx)); | ||
| 29 | signal = BPF_CORE_READ(tsk, signal); | ||
| 30 | oom_score_adj = BPF_CORE_READ(signal, oom_score_adj); | ||
| 31 | return 0; | ||
| 32 | } | ||
| 33 | |||
| 34 | SEC("kprobe/fib_table_lookup") | ||
| 35 | int prog2(struct pt_regs *ctx) | ||
| 36 | { | ||
| 37 | return 0; | ||
| 38 | } | ||
| 39 | |||
| 40 | char _license[] SEC("license") = "GPL"; | ||
| 41 | u32 _version SEC("version") = LINUX_VERSION_CODE; | ||
| @@ -1,17 +0,0 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | /* Copyright (c) 2018 Facebook */ | ||
| 3 | #include "vmlinux.h" | ||
| 4 | #include <bpf/bpf_helpers.h> | ||
| 5 | |||
| 6 | SEC("raw_tracepoint/task_rename") | ||
| 7 | int prog(struct bpf_raw_tracepoint_args *ctx) | ||
| 8 | { | ||
| 9 | return 0; | ||
| 10 | } | ||
| 11 | |||
| 12 | SEC("raw_tracepoint/fib_table_lookup") | ||
| 13 | int prog2(struct bpf_raw_tracepoint_args *ctx) | ||
| 14 | { | ||
| 15 | return 0; | ||
| 16 | } | ||
| 17 | char _license[] SEC("license") = "GPL"; | ||
| @@ -1,23 +0,0 @@ | |||
| 1 | /* Copyright (c) 2016 Facebook | ||
| 2 | * | ||
| 3 | * This program is free software; you can redistribute it and/or | ||
| 4 | * modify it under the terms of version 2 of the GNU General Public | ||
| 5 | * License as published by the Free Software Foundation. | ||
| 6 | */ | ||
| 7 | #include "vmlinux.h" | ||
| 8 | #include <bpf/bpf_helpers.h> | ||
| 9 | |||
| 10 | /* from /sys/kernel/tracing/events/task/task_rename/format */ | ||
| 11 | SEC("tracepoint/task/task_rename") | ||
| 12 | int prog(struct trace_event_raw_task_rename *ctx) | ||
| 13 | { | ||
| 14 | return 0; | ||
| 15 | } | ||
| 16 | |||
| 17 | /* from /sys/kernel/tracing/events/fib/fib_table_lookup/format */ | ||
| 18 | SEC("tracepoint/fib/fib_table_lookup") | ||
| 19 | int prog2(struct trace_event_raw_fib_table_lookup *ctx) | ||
| 20 | { | ||
| 21 | return 0; | ||
| 22 | } | ||
| 23 | char _license[] SEC("license") = "GPL"; | ||
| @@ -1,225 +0,0 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-only | ||
| 2 | /* Copyright (c) 2016 Facebook | ||
| 3 | */ | ||
| 4 | #define _GNU_SOURCE | ||
| 5 | #include <sched.h> | ||
| 6 | #include <errno.h> | ||
| 7 | #include <stdio.h> | ||
| 8 | #include <sys/types.h> | ||
| 9 | #include <asm/unistd.h> | ||
| 10 | #include <fcntl.h> | ||
| 11 | #include <unistd.h> | ||
| 12 | #include <assert.h> | ||
| 13 | #include <sys/wait.h> | ||
| 14 | #include <sys/socket.h> | ||
| 15 | #include <arpa/inet.h> | ||
| 16 | #include <stdlib.h> | ||
| 17 | #include <signal.h> | ||
| 18 | #include <linux/bpf.h> | ||
| 19 | #include <string.h> | ||
| 20 | #include <time.h> | ||
| 21 | #include <bpf/bpf.h> | ||
| 22 | #include <bpf/libbpf.h> | ||
| 23 | |||
| 24 | #define MAX_CNT 1000000 | ||
| 25 | #define DUMMY_IP "127.0.0.1" | ||
| 26 | #define DUMMY_PORT 80 | ||
| 27 | |||
| 28 | static struct bpf_link *links[2]; | ||
| 29 | static struct bpf_object *obj; | ||
| 30 | static int cnt; | ||
| 31 | |||
| 32 | static __u64 time_get_ns(void) | ||
| 33 | { | ||
| 34 | struct timespec ts; | ||
| 35 | |||
| 36 | clock_gettime(CLOCK_MONOTONIC, &ts); | ||
| 37 | return ts.tv_sec * 1000000000ull + ts.tv_nsec; | ||
| 38 | } | ||
| 39 | |||
| 40 | static void test_task_rename(int cpu) | ||
| 41 | { | ||
| 42 | char buf[] = "test\n"; | ||
| 43 | __u64 start_time; | ||
| 44 | int i, fd; | ||
| 45 | |||
| 46 | fd = open("/proc/self/comm", O_WRONLY|O_TRUNC); | ||
| 47 | if (fd < 0) { | ||
| 48 | printf("couldn't open /proc\n"); | ||
| 49 | exit(1); | ||
| 50 | } | ||
| 51 | start_time = time_get_ns(); | ||
| 52 | for (i = 0; i < MAX_CNT; i++) { | ||
| 53 | if (write(fd, buf, sizeof(buf)) < 0) { | ||
| 54 | printf("task rename failed: %s\n", strerror(errno)); | ||
| 55 | close(fd); | ||
| 56 | return; | ||
| 57 | } | ||
| 58 | } | ||
| 59 | printf("task_rename:%d: %lld events per sec\n", | ||
| 60 | cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time)); | ||
| 61 | close(fd); | ||
| 62 | } | ||
| 63 | |||
| 64 | static void test_fib_table_lookup(int cpu) | ||
| 65 | { | ||
| 66 | struct sockaddr_in addr; | ||
| 67 | char buf[] = "test\n"; | ||
| 68 | __u64 start_time; | ||
| 69 | int i, fd; | ||
| 70 | |||
| 71 | fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); | ||
| 72 | if (fd < 0) { | ||
| 73 | printf("couldn't open socket\n"); | ||
| 74 | exit(1); | ||
| 75 | } | ||
| 76 | memset((char *)&addr, 0, sizeof(addr)); | ||
| 77 | addr.sin_addr.s_addr = inet_addr(DUMMY_IP); | ||
| 78 | addr.sin_port = htons(DUMMY_PORT); | ||
| 79 | addr.sin_family = AF_INET; | ||
| 80 | start_time = time_get_ns(); | ||
| 81 | for (i = 0; i < MAX_CNT; i++) { | ||
| 82 | if (sendto(fd, buf, strlen(buf), 0, | ||
| 83 | (struct sockaddr *)&addr, sizeof(addr)) < 0) { | ||
| 84 | printf("failed to start ping: %s\n", strerror(errno)); | ||
| 85 | close(fd); | ||
| 86 | return; | ||
| 87 | } | ||
| 88 | } | ||
| 89 | printf("fib_table_lookup:%d: %lld events per sec\n", | ||
| 90 | cpu, MAX_CNT * 1000000000ll / (time_get_ns() - start_time)); | ||
| 91 | close(fd); | ||
| 92 | } | ||
| 93 | |||
| 94 | static void loop(int cpu, int flags) | ||
| 95 | { | ||
| 96 | cpu_set_t cpuset; | ||
| 97 | |||
| 98 | CPU_ZERO(&cpuset); | ||
| 99 | CPU_SET(cpu, &cpuset); | ||
| 100 | sched_setaffinity(0, sizeof(cpuset), &cpuset); | ||
| 101 | |||
| 102 | if (flags & 1) | ||
| 103 | test_task_rename(cpu); | ||
| 104 | if (flags & 2) | ||
| 105 | test_fib_table_lookup(cpu); | ||
| 106 | } | ||
| 107 | |||
| 108 | static void run_perf_test(int tasks, int flags) | ||
| 109 | { | ||
| 110 | pid_t pid[tasks]; | ||
| 111 | int i; | ||
| 112 | |||
| 113 | for (i = 0; i < tasks; i++) { | ||
| 114 | pid[i] = fork(); | ||
| 115 | if (pid[i] == 0) { | ||
| 116 | loop(i, flags); | ||
| 117 | exit(0); | ||
| 118 | } else if (pid[i] == -1) { | ||
| 119 | printf("couldn't spawn #%d process\n", i); | ||
| 120 | exit(1); | ||
| 121 | } | ||
| 122 | } | ||
| 123 | for (i = 0; i < tasks; i++) { | ||
| 124 | int status; | ||
| 125 | |||
| 126 | assert(waitpid(pid[i], &status, 0) == pid[i]); | ||
| 127 | assert(status == 0); | ||
| 128 | } | ||
| 129 | } | ||
| 130 | |||
| 131 | static int load_progs(char *filename) | ||
| 132 | { | ||
| 133 | struct bpf_program *prog; | ||
| 134 | int err = 0; | ||
| 135 | |||
| 136 | obj = bpf_object__open_file(filename, NULL); | ||
| 137 | err = libbpf_get_error(obj); | ||
| 138 | if (err < 0) { | ||
| 139 | fprintf(stderr, "ERROR: opening BPF object file failed\n"); | ||
| 140 | return err; | ||
| 141 | } | ||
| 142 | |||
| 143 | /* load BPF program */ | ||
| 144 | err = bpf_object__load(obj); | ||
| 145 | if (err < 0) { | ||
| 146 | fprintf(stderr, "ERROR: loading BPF object file failed\n"); | ||
| 147 | return err; | ||
| 148 | } | ||
| 149 | |||
| 150 | bpf_object__for_each_program(prog, obj) { | ||
| 151 | links[cnt] = bpf_program__attach(prog); | ||
| 152 | err = libbpf_get_error(links[cnt]); | ||
| 153 | if (err < 0) { | ||
| 154 | fprintf(stderr, "ERROR: bpf_program__attach failed\n"); | ||
| 155 | links[cnt] = NULL; | ||
| 156 | return err; | ||
| 157 | } | ||
| 158 | cnt++; | ||
| 159 | } | ||
| 160 | |||
| 161 | return err; | ||
| 162 | } | ||
| 163 | |||
| 164 | static void unload_progs(void) | ||
| 165 | { | ||
| 166 | while (cnt) | ||
| 167 | bpf_link__destroy(links[--cnt]); | ||
| 168 | |||
| 169 | bpf_object__close(obj); | ||
| 170 | } | ||
| 171 | |||
| 172 | int main(int argc, char **argv) | ||
| 173 | { | ||
| 174 | int num_cpu = sysconf(_SC_NPROCESSORS_ONLN); | ||
| 175 | int test_flags = ~0; | ||
| 176 | char filename[256]; | ||
| 177 | int err = 0; | ||
| 178 | |||
| 179 | |||
| 180 | if (argc > 1) | ||
| 181 | test_flags = atoi(argv[1]) ? : test_flags; | ||
| 182 | if (argc > 2) | ||
| 183 | num_cpu = atoi(argv[2]) ? : num_cpu; | ||
| 184 | |||
| 185 | if (test_flags & 0x3) { | ||
| 186 | printf("BASE\n"); | ||
| 187 | run_perf_test(num_cpu, test_flags); | ||
| 188 | } | ||
| 189 | |||
| 190 | if (test_flags & 0xC) { | ||
| 191 | snprintf(filename, sizeof(filename), | ||
| 192 | "%s_kprobe.bpf.o", argv[0]); | ||
| 193 | |||
| 194 | printf("w/KPROBE\n"); | ||
| 195 | err = load_progs(filename); | ||
| 196 | if (!err) | ||
| 197 | run_perf_test(num_cpu, test_flags >> 2); | ||
| 198 | |||
| 199 | unload_progs(); | ||
| 200 | } | ||
| 201 | |||
| 202 | if (test_flags & 0x30) { | ||
| 203 | snprintf(filename, sizeof(filename), | ||
| 204 | "%s_tp.bpf.o", argv[0]); | ||
| 205 | printf("w/TRACEPOINT\n"); | ||
| 206 | err = load_progs(filename); | ||
| 207 | if (!err) | ||
| 208 | run_perf_test(num_cpu, test_flags >> 4); | ||
| 209 | |||
| 210 | unload_progs(); | ||
| 211 | } | ||
| 212 | |||
| 213 | if (test_flags & 0xC0) { | ||
| 214 | snprintf(filename, sizeof(filename), | ||
| 215 | "%s_raw_tp.bpf.o", argv[0]); | ||
| 216 | printf("w/RAW_TRACEPOINT\n"); | ||
| 217 | err = load_progs(filename); | ||
| 218 | if (!err) | ||
| 219 | run_perf_test(num_cpu, test_flags >> 6); | ||
| 220 | |||
| 221 | unload_progs(); | ||
| 222 | } | ||
| 223 | |||
| 224 | return err; | ||
| 225 | } | ||
| @@ -1,16 +0,0 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | |||
| 3 | rm -r tmpmnt | ||
| 4 | rm -f testfile.img | ||
| 5 | dd if=/dev/zero of=testfile.img bs=1M seek=1000 count=1 | ||
| 6 | DEVICE=$(losetup --show -f testfile.img) | ||
| 7 | mkfs.btrfs -f $DEVICE | ||
| 8 | mkdir tmpmnt | ||
| 9 | ./tracex7 $DEVICE | ||
| 10 | if [ $? -eq 0 ] | ||
| 11 | then | ||
| 12 | echo "SUCCESS!" | ||
| 13 | else | ||
| 14 | echo "FAILED!" | ||
| 15 | fi | ||
| 16 | losetup -d $DEVICE | ||
| @@ -1,52 +0,0 @@ | |||
| 1 | /* Copyright (c) 2016 Sargun Dhillon <sargun@sargun.me> | ||
| 2 | * | ||
| 3 | * This program is free software; you can redistribute it and/or | ||
| 4 | * modify it under the terms of version 2 of the GNU General Public | ||
| 5 | * License as published by the Free Software Foundation. | ||
| 6 | */ | ||
| 7 | #include "vmlinux.h" | ||
| 8 | #include <string.h> | ||
| 9 | #include <linux/version.h> | ||
| 10 | #include <bpf/bpf_helpers.h> | ||
| 11 | #include <bpf/bpf_tracing.h> | ||
| 12 | #include <bpf/bpf_core_read.h> | ||
| 13 | |||
| 14 | struct { | ||
| 15 | __uint(type, BPF_MAP_TYPE_HASH); | ||
| 16 | __type(key, struct sockaddr_in); | ||
| 17 | __type(value, struct sockaddr_in); | ||
| 18 | __uint(max_entries, 256); | ||
| 19 | } dnat_map SEC(".maps"); | ||
| 20 | |||
| 21 | /* kprobe is NOT a stable ABI | ||
| 22 | * kernel functions can be removed, renamed or completely change semantics. | ||
| 23 | * Number of arguments and their positions can change, etc. | ||
| 24 | * In such case this bpf+kprobe example will no longer be meaningful | ||
| 25 | * | ||
| 26 | * This example sits on a syscall, and the syscall ABI is relatively stable | ||
| 27 | * of course, across platforms, and over time, the ABI may change. | ||
| 28 | */ | ||
| 29 | SEC("ksyscall/connect") | ||
| 30 | int BPF_KSYSCALL(bpf_prog1, int fd, struct sockaddr_in *uservaddr, | ||
| 31 | int addrlen) | ||
| 32 | { | ||
| 33 | struct sockaddr_in new_addr, orig_addr = {}; | ||
| 34 | struct sockaddr_in *mapped_addr; | ||
| 35 | |||
| 36 | if (addrlen > sizeof(orig_addr)) | ||
| 37 | return 0; | ||
| 38 | |||
| 39 | if (bpf_probe_read_user(&orig_addr, sizeof(orig_addr), uservaddr) != 0) | ||
| 40 | return 0; | ||
| 41 | |||
| 42 | mapped_addr = bpf_map_lookup_elem(&dnat_map, &orig_addr); | ||
| 43 | if (mapped_addr != NULL) { | ||
| 44 | memcpy(&new_addr, mapped_addr, sizeof(new_addr)); | ||
| 45 | bpf_probe_write_user(uservaddr, &new_addr, | ||
| 46 | sizeof(new_addr)); | ||
| 47 | } | ||
| 48 | return 0; | ||
| 49 | } | ||
| 50 | |||
| 51 | char _license[] SEC("license") = "GPL"; | ||
| 52 | u32 _version SEC("version") = LINUX_VERSION_CODE; | ||
| @@ -1,108 +0,0 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0 | ||
| 2 | #include <stdio.h> | ||
| 3 | #include <assert.h> | ||
| 4 | #include <unistd.h> | ||
| 5 | #include <bpf/bpf.h> | ||
| 6 | #include <bpf/libbpf.h> | ||
| 7 | #include <sys/socket.h> | ||
| 8 | #include <netinet/in.h> | ||
| 9 | #include <arpa/inet.h> | ||
| 10 | |||
| 11 | int main(int ac, char **argv) | ||
| 12 | { | ||
| 13 | struct sockaddr_in *serv_addr_in, *mapped_addr_in, *tmp_addr_in; | ||
| 14 | struct sockaddr serv_addr, mapped_addr, tmp_addr; | ||
| 15 | int serverfd, serverconnfd, clientfd, map_fd; | ||
| 16 | struct bpf_link *link = NULL; | ||
| 17 | struct bpf_program *prog; | ||
| 18 | struct bpf_object *obj; | ||
| 19 | socklen_t sockaddr_len; | ||
| 20 | char filename[256]; | ||
| 21 | char *ip; | ||
| 22 | |||
| 23 | serv_addr_in = (struct sockaddr_in *)&serv_addr; | ||
| 24 | mapped_addr_in = (struct sockaddr_in *)&mapped_addr; | ||
| 25 | tmp_addr_in = (struct sockaddr_in *)&tmp_addr; | ||
| 26 | |||
| 27 | snprintf(filename, sizeof(filename), "%s.bpf.o", argv[0]); | ||
| 28 | obj = bpf_object__open_file(filename, NULL); | ||
| 29 | if (libbpf_get_error(obj)) { | ||
| 30 | fprintf(stderr, "ERROR: opening BPF object file failed\n"); | ||
| 31 | return 0; | ||
| 32 | } | ||
| 33 | |||
| 34 | prog = bpf_object__find_program_by_name(obj, "bpf_prog1"); | ||
| 35 | if (libbpf_get_error(prog)) { | ||
| 36 | fprintf(stderr, "ERROR: finding a prog in obj file failed\n"); | ||
| 37 | goto cleanup; | ||
| 38 | } | ||
| 39 | |||
| 40 | /* load BPF program */ | ||
| 41 | if (bpf_object__load(obj)) { | ||
| 42 | fprintf(stderr, "ERROR: loading BPF object file failed\n"); | ||
| 43 | goto cleanup; | ||
| 44 | } | ||
| 45 | |||
| 46 | map_fd = bpf_object__find_map_fd_by_name(obj, "dnat_map"); | ||
| 47 | if (map_fd < 0) { | ||
| 48 | fprintf(stderr, "ERROR: finding a map in obj file failed\n"); | ||
| 49 | goto cleanup; | ||
| 50 | } | ||
| 51 | |||
| 52 | link = bpf_program__attach(prog); | ||
| 53 | if (libbpf_get_error(link)) { | ||
| 54 | fprintf(stderr, "ERROR: bpf_program__attach failed\n"); | ||
| 55 | link = NULL; | ||
| 56 | goto cleanup; | ||
| 57 | } | ||
| 58 | |||
| 59 | assert((serverfd = socket(AF_INET, SOCK_STREAM, 0)) > 0); | ||
| 60 | assert((clientfd = socket(AF_INET, SOCK_STREAM, 0)) > 0); | ||
| 61 | |||
| 62 | /* Bind server to ephemeral port on lo */ | ||
| 63 | memset(&serv_addr, 0, sizeof(serv_addr)); | ||
| 64 | serv_addr_in->sin_family = AF_INET; | ||
| 65 | serv_addr_in->sin_port = 0; | ||
| 66 | serv_addr_in->sin_addr.s_addr = htonl(INADDR_LOOPBACK); | ||
| 67 | |||
| 68 | assert(bind(serverfd, &serv_addr, sizeof(serv_addr)) == 0); | ||
| 69 | |||
| 70 | sockaddr_len = sizeof(serv_addr); | ||
| 71 | assert(getsockname(serverfd, &serv_addr, &sockaddr_len) == 0); | ||
| 72 | ip = inet_ntoa(serv_addr_in->sin_addr); | ||
| 73 | printf("Server bound to: %s:%d\n", ip, ntohs(serv_addr_in->sin_port)); | ||
| 74 | |||
| 75 | memset(&mapped_addr, 0, sizeof(mapped_addr)); | ||
| 76 | mapped_addr_in->sin_family = AF_INET; | ||
| 77 | mapped_addr_in->sin_port = htons(5555); | ||
| 78 | mapped_addr_in->sin_addr.s_addr = inet_addr("255.255.255.255"); | ||
| 79 | |||
| 80 | assert(!bpf_map_update_elem(map_fd, &mapped_addr, &serv_addr, BPF_ANY)); | ||
| 81 | |||
| 82 | assert(listen(serverfd, 5) == 0); | ||
| 83 | |||
| 84 | ip = inet_ntoa(mapped_addr_in->sin_addr); | ||
| 85 | printf("Client connecting to: %s:%d\n", | ||
| 86 | ip, ntohs(mapped_addr_in->sin_port)); | ||
| 87 | assert(connect(clientfd, &mapped_addr, sizeof(mapped_addr)) == 0); | ||
| 88 | |||
| 89 | sockaddr_len = sizeof(tmp_addr); | ||
| 90 | ip = inet_ntoa(tmp_addr_in->sin_addr); | ||
| 91 | assert((serverconnfd = accept(serverfd, &tmp_addr, &sockaddr_len)) > 0); | ||
| 92 | printf("Server received connection from: %s:%d\n", | ||
| 93 | ip, ntohs(tmp_addr_in->sin_port)); | ||
| 94 | |||
| 95 | sockaddr_len = sizeof(tmp_addr); | ||
| 96 | assert(getpeername(clientfd, &tmp_addr, &sockaddr_len) == 0); | ||
| 97 | ip = inet_ntoa(tmp_addr_in->sin_addr); | ||
| 98 | printf("Client's peer address: %s:%d\n", | ||
| 99 | ip, ntohs(tmp_addr_in->sin_port)); | ||
| 100 | |||
| 101 | /* Is the server's getsockname = the socket getpeername */ | ||
| 102 | assert(memcmp(&serv_addr, &tmp_addr, sizeof(struct sockaddr_in)) == 0); | ||
| 103 | |||
| 104 | cleanup: | ||
| 105 | bpf_link__destroy(link); | ||
| 106 | bpf_object__close(obj); | ||
| 107 | return 0; | ||
| 108 | } | ||
| @@ -1,15 +0,0 @@ | |||
| 1 | #include "vmlinux.h" | ||
| 2 | #include <linux/version.h> | ||
| 3 | #include <bpf/bpf_helpers.h> | ||
| 4 | |||
| 5 | SEC("kprobe/open_ctree") | ||
| 6 | int bpf_prog1(struct pt_regs *ctx) | ||
| 7 | { | ||
| 8 | unsigned long rc = -12; | ||
| 9 | |||
| 10 | bpf_override_return(ctx, rc); | ||
| 11 | return 0; | ||
| 12 | } | ||
| 13 | |||
| 14 | char _license[] SEC("license") = "GPL"; | ||
| 15 | u32 _version SEC("version") = LINUX_VERSION_CODE; | ||
| @@ -1,56 +0,0 @@ | |||
| 1 | #define _GNU_SOURCE | ||
| 2 | |||
| 3 | #include <stdio.h> | ||
| 4 | #include <unistd.h> | ||
| 5 | #include <bpf/libbpf.h> | ||
| 6 | |||
| 7 | int main(int argc, char **argv) | ||
| 8 | { | ||
| 9 | struct bpf_link *link = NULL; | ||
| 10 | struct bpf_program *prog; | ||
| 11 | struct bpf_object *obj; | ||
| 12 | char filename[256]; | ||
| 13 | char command[256]; | ||
| 14 | int ret = 0; | ||
| 15 | FILE *f; | ||
| 16 | |||
| 17 | if (!argv[1]) { | ||
| 18 | fprintf(stderr, "ERROR: Run with the btrfs device argument!\n"); | ||
| 19 | return 0; | ||
| 20 | } | ||
| 21 | |||
| 22 | snprintf(filename, sizeof(filename), "%s.bpf.o", argv[0]); | ||
| 23 | obj = bpf_object__open_file(filename, NULL); | ||
| 24 | if (libbpf_get_error(obj)) { | ||
| 25 | fprintf(stderr, "ERROR: opening BPF object file failed\n"); | ||
| 26 | return 0; | ||
| 27 | } | ||
| 28 | |||
| 29 | prog = bpf_object__find_program_by_name(obj, "bpf_prog1"); | ||
| 30 | if (!prog) { | ||
| 31 | fprintf(stderr, "ERROR: finding a prog in obj file failed\n"); | ||
| 32 | goto cleanup; | ||
| 33 | } | ||
| 34 | |||
| 35 | /* load BPF program */ | ||
| 36 | if (bpf_object__load(obj)) { | ||
| 37 | fprintf(stderr, "ERROR: loading BPF object file failed\n"); | ||
| 38 | goto cleanup; | ||
| 39 | } | ||
| 40 | |||
| 41 | link = bpf_program__attach(prog); | ||
| 42 | if (libbpf_get_error(link)) { | ||
| 43 | fprintf(stderr, "ERROR: bpf_program__attach failed\n"); | ||
| 44 | link = NULL; | ||
| 45 | goto cleanup; | ||
| 46 | } | ||
| 47 | |||
| 48 | snprintf(command, 256, "mount %s tmpmnt/", argv[1]); | ||
| 49 | f = popen(command, "r"); | ||
| 50 | ret = pclose(f); | ||
| 51 | |||
| 52 | cleanup: | ||
| 53 | bpf_link__destroy(link); | ||
| 54 | bpf_object__close(obj); | ||
| 55 | return ret ? 0 : 1; | ||
| 56 | } | ||
| @@ -32,7 +32,7 @@ SEC("xdp_mark") · 31 unmodified lines | |||
| 32 | int _xdp_mark(struct xdp_md *ctx) | 32 | int _xdp_mark(struct xdp_md *ctx) |
| 33 | { | 33 | { |
| 34 | struct meta_info *meta; | 34 | struct meta_info *meta; |
| 35 | void *data, *data_end; | 35 | void *data; |
| 36 | int ret; | 36 | int ret; |
| 37 | 37 | ||
| 38 | /* Reserve space in-front of data pointer for our meta info. | 38 | /* Reserve space in-front of data pointer for our meta info. |
| @@ -57,6 +57,7 @@ static __always_inline void swap_mac(void *data, struct ethhdr *orig_eth) · 56 unmodified lines | |||
| 57 | 57 | ||
| 58 | static __always_inline __u16 csum_fold_helper(__u32 csum) | 58 | static __always_inline __u16 csum_fold_helper(__u32 csum) |
| 59 | { | 59 | { |
| 60 | csum = (csum & 0xffff) + (csum >> 16); | ||
| 60 | return ~((csum & 0xffff) + (csum >> 16)); | 61 | return ~((csum & 0xffff) + (csum >> 16)); |
| 61 | } | 62 | } |
| 62 | 63 | ||