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