Line data Source code
1 : /* SPDX-License-Identifier: GPL-2.0-only */
2 : /*
3 : * Copyright (c) 2023 Meta Platforms, Inc. and affiliates.
4 : */
5 :
6 : #include "bpfilter/opts.h"
7 :
8 : #include <argp.h>
9 : #include <errno.h>
10 : #include <limits.h>
11 : #include <stdbool.h>
12 : #include <stddef.h>
13 : #include <stdint.h>
14 : #include <stdlib.h>
15 :
16 : #include "core/front.h"
17 : #include "core/helper.h"
18 : #include "core/logger.h"
19 :
20 : #define BF_DEFAULT_BPFFS_PATH "/sys/fs/bpf"
21 :
22 : enum
23 : {
24 : BF_OPT_NO_IPTABLES_KEY,
25 : BF_OPT_NO_NFTABLES_KEY,
26 : BF_OPT_NO_CLI_KEY,
27 : BF_OPT_WITH_BPF_TOKEN,
28 : BF_OPT_BPFFS_PATH,
29 : BF_OPT_VERSION,
30 : };
31 :
32 : static const char *_bf_verbose_strs[] = {
33 : [BF_VERBOSE_DEBUG] = "debug",
34 : [BF_VERBOSE_BPF] = "bpf",
35 : [BF_VERBOSE_BYTECODE] = "bytecode",
36 : };
37 :
38 : static_assert(ARRAY_SIZE(_bf_verbose_strs) == _BF_VERBOSE_MAX,
39 : "missing entries in _bf_verbose_strs array");
40 :
41 0 : enum bf_verbose bf_verbose_from_str(const char *str)
42 : {
43 0 : bf_assert(str);
44 :
45 0 : for (enum bf_verbose verbose = 0; verbose < _BF_VERBOSE_MAX; ++verbose) {
46 0 : if (bf_streq(_bf_verbose_strs[verbose], str))
47 : return verbose;
48 : }
49 :
50 : return -EINVAL;
51 : }
52 :
53 : /**
54 : * bpfilter runtime configuration
55 : */
56 : static struct bf_options
57 : {
58 : /** If true, bpfilter won't load or save its state to the filesystem, and
59 : * all the loaded BPF programs will be unloaded before shuting down. Hence,
60 : * as long as bpfilter is running, filtering rules will be applied. When
61 : * bpfilter is stopped, everything is cleaned up. */
62 : bool transient;
63 :
64 : /** Pass a token to BPF system calls, obtained from bpffs. */
65 : bool with_bpf_token;
66 :
67 : /** Path to the bpffs to pin the BPF objects into. */
68 : const char *bpffs_path;
69 :
70 : /** Bit flags for enabled fronts. */
71 : uint16_t fronts;
72 :
73 : /** Verbose flags. Supported flags are:
74 : * - @c debug Print all the debug logs.
75 : * - @c bpf Add debug log messages in the generated BPF programs. */
76 : uint16_t verbose;
77 : } _bf_opts = {
78 : .transient = false,
79 : .with_bpf_token = false,
80 : .bpffs_path = BF_DEFAULT_BPFFS_PATH,
81 : .fronts = 0xffff,
82 : .verbose = 0,
83 : };
84 :
85 : static struct argp_option options[] = {
86 : {"transient", 't', 0, 0,
87 : "Do not load or save runtime context and remove all BPF programs on shutdown",
88 : 0},
89 : {"buffer-len", 'b', "BUF_LEN_POW", 0,
90 : "DEPRECATED. Size of the BPF log buffer as a power of 2 (only used when --verbose is used). Default: 16.",
91 : 0},
92 : {"no-iptables", BF_OPT_NO_IPTABLES_KEY, 0, 0, "Disable iptables support",
93 : 0},
94 : {"no-nftables", BF_OPT_NO_NFTABLES_KEY, 0, 0, "Disable nftables support",
95 : 0},
96 : {"no-cli", BF_OPT_NO_CLI_KEY, 0, 0, "Disable CLI support", 0},
97 : {"with-bpf-token", BF_OPT_WITH_BPF_TOKEN, NULL, 0,
98 : "Use a BPF token with the bpf() system calls. The token is created from the bpffs instance mounted at /sys/fs/bpf.",
99 : 0},
100 : {"bpffs-path", BF_OPT_BPFFS_PATH, "BPFFS_PATH", 0,
101 : "Path to the bpffs to pin the BPF objects into. Defaults to " BF_DEFAULT_BPFFS_PATH
102 : ".",
103 : 0},
104 : {"verbose", 'v', "VERBOSE_FLAG", 0,
105 : "Verbose flags to enable. Can be used more than once.", 0},
106 : {0},
107 : };
108 :
109 : /**
110 : * argp callback to process command line arguments.
111 : *
112 : * @return 0 on succcess, non-zero on failure.
113 : */
114 12 : static error_t _bf_opts_parser(int key, char *arg, struct argp_state *state)
115 : {
116 : UNUSED(arg);
117 :
118 12 : struct bf_options *args = state->input;
119 : enum bf_verbose opt;
120 :
121 12 : switch (key) {
122 1 : case 't':
123 1 : args->transient = true;
124 1 : break;
125 0 : case 'b':
126 0 : bf_warn(
127 : "--buffer-len is deprecated, buffer size is defined automatically");
128 : break;
129 0 : case BF_OPT_NO_IPTABLES_KEY:
130 0 : bf_info("disabling iptables support");
131 0 : args->fronts &= ~BF_FLAG(BF_FRONT_IPT);
132 0 : break;
133 1 : case BF_OPT_NO_NFTABLES_KEY:
134 1 : bf_info("disabling nftables support");
135 1 : args->fronts &= ~BF_FLAG(BF_FRONT_NFT);
136 1 : break;
137 0 : case BF_OPT_NO_CLI_KEY:
138 0 : bf_info("disabling CLI support");
139 0 : args->fronts &= ~BF_FLAG(BF_FRONT_CLI);
140 0 : break;
141 0 : case BF_OPT_WITH_BPF_TOKEN:
142 0 : args->with_bpf_token = true;
143 0 : bf_info("using a BPF token");
144 : break;
145 0 : case BF_OPT_BPFFS_PATH:
146 0 : args->bpffs_path = arg;
147 0 : bf_info("using bpffs at %s", args->bpffs_path);
148 : break;
149 0 : case 'v':
150 0 : opt = bf_verbose_from_str(arg);
151 0 : if ((int)opt < 0) {
152 0 : return bf_err_r(
153 : (int)opt,
154 : "unknown --verbose option '%s', valid --verbose options: [debug, bpf, bytecode]",
155 : arg);
156 : }
157 0 : bf_info("enabling verbose for '%s'", arg);
158 0 : if (opt == BF_VERBOSE_DEBUG)
159 0 : bf_log_set_level(BF_LOG_DBG);
160 0 : args->verbose |= BF_FLAG(opt);
161 0 : break;
162 : default:
163 : return ARGP_ERR_UNKNOWN;
164 : }
165 :
166 : return 0;
167 : }
168 :
169 2 : int bf_opts_init(int argc, char *argv[])
170 : {
171 2 : struct argp argp = {options, _bf_opts_parser, NULL, NULL, 0, NULL, NULL};
172 :
173 2 : return argp_parse(&argp, argc, argv, 0, 0, &_bf_opts);
174 : }
175 :
176 0 : bool bf_opts_transient(void)
177 : {
178 0 : return _bf_opts.transient;
179 : }
180 :
181 8 : bool bf_opts_persist(void)
182 : {
183 8 : return !_bf_opts.transient;
184 : }
185 :
186 0 : bool bf_opts_is_front_enabled(enum bf_front front)
187 : {
188 0 : return _bf_opts.fronts & BF_FLAG(front);
189 : }
190 :
191 4 : bool bf_opts_with_bpf_token(void)
192 : {
193 4 : return _bf_opts.with_bpf_token;
194 : }
195 :
196 0 : const char *bf_opts_bpffs_path(void)
197 : {
198 0 : return _bf_opts.bpffs_path;
199 : }
200 :
201 0 : bool bf_opts_is_verbose(enum bf_verbose opt)
202 : {
203 0 : return _bf_opts.verbose & BF_FLAG(opt);
204 : }
205 :
206 0 : void bf_opts_set_verbose(enum bf_verbose opt)
207 : {
208 0 : _bf_opts.verbose |= BF_FLAG(opt);
209 0 : }
|