]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
selftests/bpf: Utility functions to capture libbpf log in test_progs
authorEduard Zingerman <eddyz87@gmail.com>
Wed, 6 Mar 2024 10:45:19 +0000 (12:45 +0200)
committerAndrii Nakryiko <andrii@kernel.org>
Wed, 6 Mar 2024 23:18:15 +0000 (15:18 -0800)
Several test_progs tests already capture libbpf log in order to check
for some expected output, e.g bpf_tcp_ca.c, kfunc_dynptr_param.c,
log_buf.c and a few others.

This commit provides a, hopefully, simple API to capture libbpf log
w/o necessity to define new print callback in each test:

    /* Creates a global memstream capturing INFO and WARN level output
     * passed to libbpf_print_fn.
     * Returns 0 on success, negative value on failure.
     * On failure the description is printed using PRINT_FAIL and
     * current test case is marked as fail.
     */
    int start_libbpf_log_capture(void)

    /* Destroys global memstream created by start_libbpf_log_capture().
     * Returns a pointer to captured data which has to be freed.
     * Returned buffer is null terminated.
     */
    char *stop_libbpf_log_capture(void)

The intended usage is as follows:

    if (start_libbpf_log_capture())
            return;
    use_libbpf();
    char *log = stop_libbpf_log_capture();
    ASSERT_HAS_SUBSTR(log, "... expected ...", "expected some message");
    free(log);

As a safety measure, free(start_libbpf_log_capture()) is invoked in the
epilogue of the test_progs.c:run_one_test().

Signed-off-by: Eduard Zingerman <eddyz87@gmail.com>
Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Link: https://lore.kernel.org/bpf/20240306104529.6453-6-eddyz87@gmail.com
tools/testing/selftests/bpf/test_progs.c
tools/testing/selftests/bpf/test_progs.h

index 808550986f306530be2010f7e417ced77d7ba3a3..89ff704e9dad5eabfe35047616f109f6f133a27e 100644 (file)
@@ -683,11 +683,69 @@ static const struct argp_option opts[] = {
        {},
 };
 
+static FILE *libbpf_capture_stream;
+
+static struct {
+       char *buf;
+       size_t buf_sz;
+} libbpf_output_capture;
+
+/* Creates a global memstream capturing INFO and WARN level output
+ * passed to libbpf_print_fn.
+ * Returns 0 on success, negative value on failure.
+ * On failure the description is printed using PRINT_FAIL and
+ * current test case is marked as fail.
+ */
+int start_libbpf_log_capture(void)
+{
+       if (libbpf_capture_stream) {
+               PRINT_FAIL("%s: libbpf_capture_stream != NULL\n", __func__);
+               return -EINVAL;
+       }
+
+       libbpf_capture_stream = open_memstream(&libbpf_output_capture.buf,
+                                              &libbpf_output_capture.buf_sz);
+       if (!libbpf_capture_stream) {
+               PRINT_FAIL("%s: open_memstream failed errno=%d\n", __func__, errno);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* Destroys global memstream created by start_libbpf_log_capture().
+ * Returns a pointer to captured data which has to be freed.
+ * Returned buffer is null terminated.
+ */
+char *stop_libbpf_log_capture(void)
+{
+       char *buf;
+
+       if (!libbpf_capture_stream)
+               return NULL;
+
+       fputc(0, libbpf_capture_stream);
+       fclose(libbpf_capture_stream);
+       libbpf_capture_stream = NULL;
+       /* get 'buf' after fclose(), see open_memstream() documentation */
+       buf = libbpf_output_capture.buf;
+       memset(&libbpf_output_capture, 0, sizeof(libbpf_output_capture));
+       return buf;
+}
+
 static int libbpf_print_fn(enum libbpf_print_level level,
                           const char *format, va_list args)
 {
+       if (libbpf_capture_stream && level != LIBBPF_DEBUG) {
+               va_list args2;
+
+               va_copy(args2, args);
+               vfprintf(libbpf_capture_stream, format, args2);
+       }
+
        if (env.verbosity < VERBOSE_VERY && level == LIBBPF_DEBUG)
                return 0;
+
        vfprintf(stdout, format, args);
        return 0;
 }
@@ -1081,6 +1139,7 @@ static void run_one_test(int test_num)
                cleanup_cgroup_environment();
 
        stdio_restore();
+       free(stop_libbpf_log_capture());
 
        dump_test_log(test, state, false, false, NULL);
 }
index 80df5124488667ece3bbe157bbf7df04c0bd0d73..0ba5a20b19ba8e8e0ec3f7ca774ba847c1cb3320 100644 (file)
@@ -397,6 +397,9 @@ int test__join_cgroup(const char *path);
                system(cmd);                                            \
        })
 
+int start_libbpf_log_capture(void);
+char *stop_libbpf_log_capture(void);
+
 static inline __u64 ptr_to_u64(const void *ptr)
 {
        return (__u64) (unsigned long) ptr;