^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /* Copyright (c) 2016 PLUMgrid
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) #include <linux/bpf.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) #include <linux/if_link.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) #include <assert.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #include <errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include <signal.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <stdio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <stdlib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <libgen.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <sys/resource.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <net/if.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include "bpf_util.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <bpf/bpf.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <bpf/libbpf.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) static int ifindex;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) static __u32 xdp_flags = XDP_FLAGS_UPDATE_IF_NOEXIST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) static __u32 prog_id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static void int_exit(int sig)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) __u32 curr_prog_id = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) if (bpf_get_link_xdp_id(ifindex, &curr_prog_id, xdp_flags)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) printf("bpf_get_link_xdp_id failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) exit(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) if (prog_id == curr_prog_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) bpf_set_link_xdp_fd(ifindex, -1, xdp_flags);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) else if (!curr_prog_id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) printf("couldn't find a prog id on a given interface\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) printf("program on interface changed, not removing\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) exit(0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) /* simple per-protocol drop counter
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) static void poll_stats(int map_fd, int interval)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) unsigned int nr_cpus = bpf_num_possible_cpus();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) __u64 values[nr_cpus], prev[UINT8_MAX] = { 0 };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) while (1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) __u32 key = UINT32_MAX;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) sleep(interval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) while (bpf_map_get_next_key(map_fd, &key, &key) != -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) __u64 sum = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) assert(bpf_map_lookup_elem(map_fd, &key, values) == 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) for (i = 0; i < nr_cpus; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) sum += values[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) if (sum > prev[key])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) printf("proto %u: %10llu pkt/s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) key, (sum - prev[key]) / interval);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) prev[key] = sum;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) static void usage(const char *prog)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) fprintf(stderr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) "usage: %s [OPTS] IFACE\n\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) "OPTS:\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) " -S use skb-mode\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) " -N enforce native mode\n"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) " -F force loading prog\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) prog);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) int main(int argc, char **argv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) struct rlimit r = {RLIM_INFINITY, RLIM_INFINITY};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) struct bpf_prog_load_attr prog_load_attr = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) .prog_type = BPF_PROG_TYPE_XDP,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) struct bpf_prog_info info = {};
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) __u32 info_len = sizeof(info);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) const char *optstr = "FSN";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) int prog_fd, map_fd, opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) struct bpf_object *obj;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) struct bpf_map *map;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) char filename[256];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) while ((opt = getopt(argc, argv, optstr)) != -1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) switch (opt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) case 'S':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) xdp_flags |= XDP_FLAGS_SKB_MODE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) case 'N':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) /* default, set below */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) case 'F':
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) xdp_flags &= ~XDP_FLAGS_UPDATE_IF_NOEXIST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) usage(basename(argv[0]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) if (!(xdp_flags & XDP_FLAGS_SKB_MODE))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) xdp_flags |= XDP_FLAGS_DRV_MODE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) if (optind == argc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) usage(basename(argv[0]));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) if (setrlimit(RLIMIT_MEMLOCK, &r)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) perror("setrlimit(RLIMIT_MEMLOCK)");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) ifindex = if_nametoindex(argv[optind]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) if (!ifindex) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) perror("if_nametoindex");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) prog_load_attr.file = filename;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) if (bpf_prog_load_xattr(&prog_load_attr, &obj, &prog_fd))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) map = bpf_map__next(NULL, obj);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) if (!map) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) printf("finding a map in obj file failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) map_fd = bpf_map__fd(map);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) if (!prog_fd) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) printf("bpf_prog_load_xattr: %s\n", strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) signal(SIGINT, int_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) signal(SIGTERM, int_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) if (bpf_set_link_xdp_fd(ifindex, prog_fd, xdp_flags) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) printf("link set xdp fd failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) err = bpf_obj_get_info_by_fd(prog_fd, &info, &info_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) printf("can't get prog info - %s\n", strerror(errno));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) prog_id = info.id;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) poll_stats(map_fd, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) }