libbpf: Wire through log_true_size returned from kernel for BPF_PROG_LOAD
authorAndrii Nakryiko <andrii@kernel.org>
Thu, 6 Apr 2023 23:42:01 +0000 (16:42 -0700)
committerDaniel Borkmann <daniel@iogearbox.net>
Tue, 11 Apr 2023 16:05:44 +0000 (18:05 +0200)
Add output-only log_true_size field to bpf_prog_load_opts to return
bpf_attr->log_true_size value back from bpf() syscall.

Note, that we have to drop const modifier from opts in bpf_prog_load().
This could potentially cause compilation error for some users. But
the usual practice is to define bpf_prog_load_ops
as a local variable next to bpf_prog_load() call and pass pointer to it,
so const vs non-const makes no difference and won't even come up in most
(if not all) cases.

There are no runtime and ABI backwards/forward compatibility issues at all.
If user provides old struct bpf_prog_load_opts, libbpf won't set new
fields. If old libbpf is provided new bpf_prog_load_opts, nothing will
happen either as old libbpf doesn't yet know about this new field.

Adding a new variant of bpf_prog_load() just for this seems like a big
and unnecessary overkill. As a corroborating evidence is the fact that
entire selftests/bpf code base required not adjustment whatsoever.

Signed-off-by: Andrii Nakryiko <andrii@kernel.org>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/20230406234205.323208-16-andrii@kernel.org
tools/lib/bpf/bpf.c
tools/lib/bpf/bpf.h

index f1d04ee..a031de0 100644 (file)
@@ -230,9 +230,9 @@ alloc_zero_tailing_info(const void *orecord, __u32 cnt,
 int bpf_prog_load(enum bpf_prog_type prog_type,
                  const char *prog_name, const char *license,
                  const struct bpf_insn *insns, size_t insn_cnt,
-                 const struct bpf_prog_load_opts *opts)
+                 struct bpf_prog_load_opts *opts)
 {
-       const size_t attr_sz = offsetofend(union bpf_attr, fd_array);
+       const size_t attr_sz = offsetofend(union bpf_attr, log_true_size);
        void *finfo = NULL, *linfo = NULL;
        const char *func_info, *line_info;
        __u32 log_size, log_level, attach_prog_fd, attach_btf_obj_fd;
@@ -312,6 +312,7 @@ int bpf_prog_load(enum bpf_prog_type prog_type,
        }
 
        fd = sys_bpf_prog_load(&attr, attr_sz, attempts);
+       OPTS_SET(opts, log_true_size, attr.log_true_size);
        if (fd >= 0)
                return fd;
 
@@ -352,6 +353,7 @@ int bpf_prog_load(enum bpf_prog_type prog_type,
                }
 
                fd = sys_bpf_prog_load(&attr, attr_sz, attempts);
+               OPTS_SET(opts, log_true_size, attr.log_true_size);
                if (fd >= 0)
                        goto done;
        }
@@ -366,6 +368,7 @@ int bpf_prog_load(enum bpf_prog_type prog_type,
                attr.log_level = 1;
 
                fd = sys_bpf_prog_load(&attr, attr_sz, attempts);
+               OPTS_SET(opts, log_true_size, attr.log_true_size);
        }
 done:
        /* free() doesn't affect errno, so we don't need to restore it */
index b073e73..cfa0cdf 100644 (file)
@@ -96,13 +96,20 @@ struct bpf_prog_load_opts {
        __u32 log_level;
        __u32 log_size;
        char *log_buf;
+       /* output: actual total log contents size (including termintaing zero).
+        * It could be both larger than original log_size (if log was
+        * truncated), or smaller (if log buffer wasn't filled completely).
+        * If kernel doesn't support this feature, log_size is left unchanged.
+        */
+       __u32 log_true_size;
+       size_t :0;
 };
-#define bpf_prog_load_opts__last_field log_buf
+#define bpf_prog_load_opts__last_field log_true_size
 
 LIBBPF_API int bpf_prog_load(enum bpf_prog_type prog_type,
                             const char *prog_name, const char *license,
                             const struct bpf_insn *insns, size_t insn_cnt,
-                            const struct bpf_prog_load_opts *opts);
+                            struct bpf_prog_load_opts *opts);
 
 /* Flags to direct loading requirements */
 #define MAPS_RELAX_COMPAT      0x01