1 | #include <linux/unistd.h> |
2 | #include <linux/bpf.h> |
3 | |
4 | #include <stdio.h> |
5 | #include <stdlib.h> |
6 | #include <stdint.h> |
7 | #include <unistd.h> |
8 | #include <string.h> |
9 | #include <assert.h> |
10 | #include <errno.h> |
11 | |
12 | #include <sys/types.h> |
13 | #include <sys/socket.h> |
14 | |
15 | #include <bpf/bpf.h> |
16 | |
17 | #include <bpf/libbpf.h> |
18 | #include "bpf_insn.h" |
19 | #include "sock_example.h" |
20 | #include "bpf_util.h" |
21 | |
22 | #define BPF_F_PIN (1 << 0) |
23 | #define BPF_F_GET (1 << 1) |
24 | #define BPF_F_PIN_GET (BPF_F_PIN | BPF_F_GET) |
25 | |
26 | #define BPF_F_KEY (1 << 2) |
27 | #define BPF_F_VAL (1 << 3) |
28 | #define BPF_F_KEY_VAL (BPF_F_KEY | BPF_F_VAL) |
29 | |
30 | #define BPF_M_UNSPEC 0 |
31 | #define BPF_M_MAP 1 |
32 | #define BPF_M_PROG 2 |
33 | |
34 | char bpf_log_buf[BPF_LOG_BUF_SIZE]; |
35 | |
36 | static void usage(void) |
37 | { |
38 | printf(format: "Usage: fds_example [...]\n" ); |
39 | printf(format: " -F <file> File to pin/get object\n" ); |
40 | printf(format: " -P |- pin object\n" ); |
41 | printf(format: " -G `- get object\n" ); |
42 | printf(format: " -m eBPF map mode\n" ); |
43 | printf(format: " -k <key> |- map key\n" ); |
44 | printf(format: " -v <value> `- map value\n" ); |
45 | printf(format: " -p eBPF prog mode\n" ); |
46 | printf(format: " -o <object> `- object file\n" ); |
47 | printf(format: " -h Display this help.\n" ); |
48 | } |
49 | |
50 | static int bpf_prog_create(const char *object) |
51 | { |
52 | static struct bpf_insn insns[] = { |
53 | BPF_MOV64_IMM(BPF_REG_0, 1), |
54 | BPF_EXIT_INSN(), |
55 | }; |
56 | size_t insns_cnt = ARRAY_SIZE(insns); |
57 | struct bpf_object *obj; |
58 | int err; |
59 | |
60 | if (object) { |
61 | obj = bpf_object__open_file(object, NULL); |
62 | assert(!libbpf_get_error(obj)); |
63 | err = bpf_object__load(obj); |
64 | assert(!err); |
65 | return bpf_program__fd(bpf_object__next_program(obj, NULL)); |
66 | } else { |
67 | LIBBPF_OPTS(bpf_prog_load_opts, opts, |
68 | .log_buf = bpf_log_buf, |
69 | .log_size = BPF_LOG_BUF_SIZE, |
70 | ); |
71 | |
72 | return bpf_prog_load(BPF_PROG_TYPE_SOCKET_FILTER, NULL, "GPL" , |
73 | insns, insns_cnt, &opts); |
74 | } |
75 | } |
76 | |
77 | static int bpf_do_map(const char *file, uint32_t flags, uint32_t key, |
78 | uint32_t value) |
79 | { |
80 | int fd, ret; |
81 | |
82 | if (flags & BPF_F_PIN) { |
83 | fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, NULL, sizeof(uint32_t), |
84 | sizeof(uint32_t), 1024, NULL); |
85 | printf(format: "bpf: map fd:%d (%s)\n" , fd, strerror(errno)); |
86 | assert(fd > 0); |
87 | |
88 | ret = bpf_obj_pin(fd, file); |
89 | printf(format: "bpf: pin ret:(%d,%s)\n" , ret, strerror(errno)); |
90 | assert(ret == 0); |
91 | } else { |
92 | fd = bpf_obj_get(file); |
93 | printf(format: "bpf: get fd:%d (%s)\n" , fd, strerror(errno)); |
94 | assert(fd > 0); |
95 | } |
96 | |
97 | if ((flags & BPF_F_KEY_VAL) == BPF_F_KEY_VAL) { |
98 | ret = bpf_map_update_elem(fd, &key, &value, 0); |
99 | printf(format: "bpf: fd:%d u->(%u:%u) ret:(%d,%s)\n" , fd, key, value, |
100 | ret, strerror(errno)); |
101 | assert(ret == 0); |
102 | } else if (flags & BPF_F_KEY) { |
103 | ret = bpf_map_lookup_elem(fd, &key, &value); |
104 | printf(format: "bpf: fd:%d l->(%u):%u ret:(%d,%s)\n" , fd, key, value, |
105 | ret, strerror(errno)); |
106 | assert(ret == 0); |
107 | } |
108 | |
109 | return 0; |
110 | } |
111 | |
112 | static int bpf_do_prog(const char *file, uint32_t flags, const char *object) |
113 | { |
114 | int fd, sock, ret; |
115 | |
116 | if (flags & BPF_F_PIN) { |
117 | fd = bpf_prog_create(object); |
118 | printf(format: "bpf: prog fd:%d (%s)\n" , fd, strerror(errno)); |
119 | assert(fd > 0); |
120 | |
121 | ret = bpf_obj_pin(fd, file); |
122 | printf(format: "bpf: pin ret:(%d,%s)\n" , ret, strerror(errno)); |
123 | assert(ret == 0); |
124 | } else { |
125 | fd = bpf_obj_get(file); |
126 | printf(format: "bpf: get fd:%d (%s)\n" , fd, strerror(errno)); |
127 | assert(fd > 0); |
128 | } |
129 | |
130 | sock = open_raw_sock(name: "lo" ); |
131 | assert(sock > 0); |
132 | |
133 | ret = setsockopt(fd: sock, SOL_SOCKET, SO_ATTACH_BPF, optval: &fd, optlen: sizeof(fd)); |
134 | printf(format: "bpf: sock:%d <- fd:%d attached ret:(%d,%s)\n" , sock, fd, |
135 | ret, strerror(errno)); |
136 | assert(ret == 0); |
137 | |
138 | return 0; |
139 | } |
140 | |
141 | int main(int argc, char **argv) |
142 | { |
143 | const char *file = NULL, *object = NULL; |
144 | uint32_t key = 0, value = 0, flags = 0; |
145 | int opt, mode = BPF_M_UNSPEC; |
146 | |
147 | while ((opt = getopt(argc: argc, argv: argv, shortopts: "F:PGmk:v:po:" )) != -1) { |
148 | switch (opt) { |
149 | /* General args */ |
150 | case 'F': |
151 | file = optarg; |
152 | break; |
153 | case 'P': |
154 | flags |= BPF_F_PIN; |
155 | break; |
156 | case 'G': |
157 | flags |= BPF_F_GET; |
158 | break; |
159 | /* Map-related args */ |
160 | case 'm': |
161 | mode = BPF_M_MAP; |
162 | break; |
163 | case 'k': |
164 | key = strtoul(nptr: optarg, NULL, base: 0); |
165 | flags |= BPF_F_KEY; |
166 | break; |
167 | case 'v': |
168 | value = strtoul(nptr: optarg, NULL, base: 0); |
169 | flags |= BPF_F_VAL; |
170 | break; |
171 | /* Prog-related args */ |
172 | case 'p': |
173 | mode = BPF_M_PROG; |
174 | break; |
175 | case 'o': |
176 | object = optarg; |
177 | break; |
178 | default: |
179 | goto out; |
180 | } |
181 | } |
182 | |
183 | if (!(flags & BPF_F_PIN_GET) || !file) |
184 | goto out; |
185 | |
186 | switch (mode) { |
187 | case BPF_M_MAP: |
188 | return bpf_do_map(file, flags, key, value); |
189 | case BPF_M_PROG: |
190 | return bpf_do_prog(file, flags, object); |
191 | } |
192 | out: |
193 | usage(); |
194 | return -1; |
195 | } |
196 | |