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