qosify: add support for keeping stats
[project/qosify.git] / loader.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * Copyright (C) 2021 Felix Fietkau <nbd@nbd.name>
4 */
5 #include <sys/resource.h>
6 #include <sys/stat.h>
7 #include <arpa/inet.h>
8 #include <glob.h>
9 #include <unistd.h>
10
11 #include "qosify.h"
12
13 static struct {
14 const char *suffix;
15 uint32_t flags;
16 int fd;
17 } bpf_progs[] = {
18 { "egress_eth", 0 },
19 { "egress_ip", QOSIFY_IP_ONLY },
20 { "ingress_eth", QOSIFY_INGRESS },
21 { "ingress_ip", QOSIFY_INGRESS | QOSIFY_IP_ONLY },
22 };
23
24 static int qosify_bpf_pr(enum libbpf_print_level level, const char *format,
25 va_list args)
26 {
27 return vfprintf(stderr, format, args);
28 }
29
30 static void qosify_init_env(void)
31 {
32 struct rlimit limit = {
33 .rlim_cur = RLIM_INFINITY,
34 .rlim_max = RLIM_INFINITY,
35 };
36
37 setrlimit(RLIMIT_MEMLOCK, &limit);
38 }
39
40 static void qosify_fill_rodata(struct bpf_object *obj, uint32_t flags)
41 {
42 struct bpf_map *map = NULL;
43
44 while ((map = bpf_object__next_map(obj, map)) != NULL) {
45 if (!strstr(bpf_map__name(map), ".rodata"))
46 continue;
47
48 bpf_map__set_initial_value(map, &flags, sizeof(flags));
49 }
50 }
51
52 const char *qosify_get_program(uint32_t flags, int *fd)
53 {
54 int i;
55
56 for (i = 0; i < ARRAY_SIZE(bpf_progs); i++) {
57 if (bpf_progs[i].flags != flags)
58 continue;
59
60 *fd = bpf_progs[i].fd;
61 return bpf_progs[i].suffix;
62 }
63
64 return NULL;
65 }
66
67
68 static int
69 qosify_create_program(int idx)
70 {
71 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts,
72 .pin_root_path = CLASSIFY_DATA_PATH,
73 );
74 struct bpf_program *prog;
75 struct bpf_object *obj;
76 char path[256];
77 int err;
78
79 snprintf(path, sizeof(path), CLASSIFY_PIN_PATH "_" "%s", bpf_progs[idx].suffix);
80
81 obj = bpf_object__open_file(CLASSIFY_PROG_PATH, &opts);
82 err = libbpf_get_error(obj);
83 if (err) {
84 perror("bpf_object__open_file");
85 return -1;
86 }
87
88 prog = bpf_object__find_program_by_name(obj, "classify");
89 if (!prog) {
90 fprintf(stderr, "Can't find classifier prog\n");
91 return -1;
92 }
93
94 bpf_program__set_type(prog, BPF_PROG_TYPE_SCHED_CLS);
95
96 qosify_fill_rodata(obj, bpf_progs[idx].flags);
97
98 err = bpf_object__load(obj);
99 if (err) {
100 perror("bpf_object__load");
101 return -1;
102 }
103
104 libbpf_set_print(NULL);
105
106 unlink(path);
107 err = bpf_program__pin(prog, path);
108 if (err) {
109 fprintf(stderr, "Failed to pin program to %s: %s\n",
110 path, strerror(-err));
111 return -1;
112 }
113
114 bpf_object__close(obj);
115
116 err = bpf_obj_get(path);
117 if (err < 0) {
118 fprintf(stderr, "Failed to load pinned program %s: %s\n",
119 path, strerror(errno));
120 }
121 bpf_progs[idx].fd = err;
122
123 return 0;
124 }
125
126 int qosify_loader_init(void)
127 {
128 glob_t g;
129 int i;
130
131 if (glob(CLASSIFY_DATA_PATH "/*", 0, NULL, &g) == 0) {
132 for (i = 0; i < g.gl_pathc; i++)
133 unlink(g.gl_pathv[i]);
134 }
135
136 libbpf_set_print(qosify_bpf_pr);
137
138 qosify_init_env();
139
140 for (i = 0; i < ARRAY_SIZE(bpf_progs); i++) {
141 if (qosify_create_program(i))
142 return -1;
143 }
144
145 return 0;
146 }