Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

bpftool: Refactor kernel config reading into common helper

Extract the kernel configuration file parsing logic from feature.c into
a new read_kernel_config() function in common.c. This includes:

1. Moving the config file handling and option parsing code
2. Adding required headers and struct definition
3. Keeping all existing functionality

The refactoring enables sharing this logic with other components while
maintaining current behavior. This will be used by subsequent patches
that need to check kernel config options.

Signed-off-by: Yuan Chen <chenyuan@kylinos.cn>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Acked-by: Quentin Monnet <qmo@kernel.org>
Acked-by: Yonghong Song <yonghong.song@linux.dev>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Link: https://lore.kernel.org/bpf/20250829061107.23905-2-chenyuan_fl@163.com

authored by

Yuan Chen and committed by
Daniel Borkmann
70f32a10 98857d11

+106 -82
+93
tools/bpf/bpftool/common.c
··· 21 21 #include <sys/resource.h> 22 22 #include <sys/stat.h> 23 23 #include <sys/vfs.h> 24 + #include <sys/utsname.h> 24 25 25 26 #include <linux/filter.h> 26 27 #include <linux/limits.h> ··· 32 31 #include <bpf/hashmap.h> 33 32 #include <bpf/libbpf.h> /* libbpf_num_possible_cpus */ 34 33 #include <bpf/btf.h> 34 + #include <zlib.h> 35 35 36 36 #include "main.h" 37 37 ··· 1209 1207 return -ENAMETOOLONG; 1210 1208 1211 1209 return 0; 1210 + } 1211 + 1212 + static bool read_next_kernel_config_option(gzFile file, char *buf, size_t n, 1213 + char **value) 1214 + { 1215 + char *sep; 1216 + 1217 + while (gzgets(file, buf, n)) { 1218 + if (strncmp(buf, "CONFIG_", 7)) 1219 + continue; 1220 + 1221 + sep = strchr(buf, '='); 1222 + if (!sep) 1223 + continue; 1224 + 1225 + /* Trim ending '\n' */ 1226 + buf[strlen(buf) - 1] = '\0'; 1227 + 1228 + /* Split on '=' and ensure that a value is present. */ 1229 + *sep = '\0'; 1230 + if (!sep[1]) 1231 + continue; 1232 + 1233 + *value = sep + 1; 1234 + return true; 1235 + } 1236 + 1237 + return false; 1238 + } 1239 + 1240 + int read_kernel_config(const struct kernel_config_option *requested_options, 1241 + size_t num_options, char **out_values, 1242 + const char *define_prefix) 1243 + { 1244 + struct utsname utsn; 1245 + char path[PATH_MAX]; 1246 + gzFile file = NULL; 1247 + char buf[4096]; 1248 + char *value; 1249 + size_t i; 1250 + int ret = 0; 1251 + 1252 + if (!requested_options || !out_values || num_options == 0) 1253 + return -1; 1254 + 1255 + if (!uname(&utsn)) { 1256 + snprintf(path, sizeof(path), "/boot/config-%s", utsn.release); 1257 + 1258 + /* gzopen also accepts uncompressed files. */ 1259 + file = gzopen(path, "r"); 1260 + } 1261 + 1262 + if (!file) { 1263 + /* Some distributions build with CONFIG_IKCONFIG=y and put the 1264 + * config file at /proc/config.gz. 1265 + */ 1266 + file = gzopen("/proc/config.gz", "r"); 1267 + } 1268 + 1269 + if (!file) { 1270 + p_info("skipping kernel config, can't open file: %s", 1271 + strerror(errno)); 1272 + return -1; 1273 + } 1274 + 1275 + if (!gzgets(file, buf, sizeof(buf)) || !gzgets(file, buf, sizeof(buf))) { 1276 + p_info("skipping kernel config, can't read from file: %s", 1277 + strerror(errno)); 1278 + ret = -1; 1279 + goto end_parse; 1280 + } 1281 + 1282 + if (strcmp(buf, "# Automatically generated file; DO NOT EDIT.\n")) { 1283 + p_info("skipping kernel config, can't find correct file"); 1284 + ret = -1; 1285 + goto end_parse; 1286 + } 1287 + 1288 + while (read_next_kernel_config_option(file, buf, sizeof(buf), &value)) { 1289 + for (i = 0; i < num_options; i++) { 1290 + if ((define_prefix && !requested_options[i].macro_dump) || 1291 + out_values[i] || strcmp(buf, requested_options[i].name)) 1292 + continue; 1293 + 1294 + out_values[i] = strdup(value); 1295 + } 1296 + } 1297 + 1298 + end_parse: 1299 + gzclose(file); 1300 + return ret; 1212 1301 }
+4 -82
tools/bpf/bpftool/feature.c
··· 10 10 #ifdef USE_LIBCAP 11 11 #include <sys/capability.h> 12 12 #endif 13 - #include <sys/utsname.h> 14 13 #include <sys/vfs.h> 15 14 16 15 #include <linux/filter.h> ··· 17 18 18 19 #include <bpf/bpf.h> 19 20 #include <bpf/libbpf.h> 20 - #include <zlib.h> 21 21 22 22 #include "main.h" 23 23 ··· 325 327 } 326 328 } 327 329 328 - static bool read_next_kernel_config_option(gzFile file, char *buf, size_t n, 329 - char **value) 330 - { 331 - char *sep; 332 - 333 - while (gzgets(file, buf, n)) { 334 - if (strncmp(buf, "CONFIG_", 7)) 335 - continue; 336 - 337 - sep = strchr(buf, '='); 338 - if (!sep) 339 - continue; 340 - 341 - /* Trim ending '\n' */ 342 - buf[strlen(buf) - 1] = '\0'; 343 - 344 - /* Split on '=' and ensure that a value is present. */ 345 - *sep = '\0'; 346 - if (!sep[1]) 347 - continue; 348 - 349 - *value = sep + 1; 350 - return true; 351 - } 352 - 353 - return false; 354 - } 355 - 356 330 static void probe_kernel_image_config(const char *define_prefix) 357 331 { 358 - static const struct { 359 - const char * const name; 360 - bool macro_dump; 361 - } options[] = { 332 + struct kernel_config_option options[] = { 362 333 /* Enable BPF */ 363 334 { "CONFIG_BPF", }, 364 335 /* Enable bpf() syscall */ ··· 402 435 { "CONFIG_HZ", true, } 403 436 }; 404 437 char *values[ARRAY_SIZE(options)] = { }; 405 - struct utsname utsn; 406 - char path[PATH_MAX]; 407 - gzFile file = NULL; 408 - char buf[4096]; 409 - char *value; 410 438 size_t i; 411 439 412 - if (!uname(&utsn)) { 413 - snprintf(path, sizeof(path), "/boot/config-%s", utsn.release); 414 - 415 - /* gzopen also accepts uncompressed files. */ 416 - file = gzopen(path, "r"); 417 - } 418 - 419 - if (!file) { 420 - /* Some distributions build with CONFIG_IKCONFIG=y and put the 421 - * config file at /proc/config.gz. 422 - */ 423 - file = gzopen("/proc/config.gz", "r"); 424 - } 425 - if (!file) { 426 - p_info("skipping kernel config, can't open file: %s", 427 - strerror(errno)); 428 - goto end_parse; 429 - } 430 - /* Sanity checks */ 431 - if (!gzgets(file, buf, sizeof(buf)) || 432 - !gzgets(file, buf, sizeof(buf))) { 433 - p_info("skipping kernel config, can't read from file: %s", 434 - strerror(errno)); 435 - goto end_parse; 436 - } 437 - if (strcmp(buf, "# Automatically generated file; DO NOT EDIT.\n")) { 438 - p_info("skipping kernel config, can't find correct file"); 439 - goto end_parse; 440 - } 441 - 442 - while (read_next_kernel_config_option(file, buf, sizeof(buf), &value)) { 443 - for (i = 0; i < ARRAY_SIZE(options); i++) { 444 - if ((define_prefix && !options[i].macro_dump) || 445 - values[i] || strcmp(buf, options[i].name)) 446 - continue; 447 - 448 - values[i] = strdup(value); 449 - } 450 - } 440 + if (read_kernel_config(options, ARRAY_SIZE(options), values, 441 + define_prefix)) 442 + return; 451 443 452 444 for (i = 0; i < ARRAY_SIZE(options); i++) { 453 445 if (define_prefix && !options[i].macro_dump) ··· 414 488 print_kernel_option(options[i].name, values[i], define_prefix); 415 489 free(values[i]); 416 490 } 417 - 418 - end_parse: 419 - if (file) 420 - gzclose(file); 421 491 } 422 492 423 493 static bool probe_bpf_syscall(const char *define_prefix)
+9
tools/bpf/bpftool/main.h
··· 275 275 /* print netfilter bpf_link info */ 276 276 void netfilter_dump_plain(const struct bpf_link_info *info); 277 277 void netfilter_dump_json(const struct bpf_link_info *info, json_writer_t *wtr); 278 + 279 + struct kernel_config_option { 280 + const char *name; 281 + bool macro_dump; 282 + }; 283 + 284 + int read_kernel_config(const struct kernel_config_option *requested_options, 285 + size_t num_options, char **out_values, 286 + const char *define_prefix); 278 287 #endif