Revert "bpftool: Use libbpf 1.0 API mode instead of RLIMIT_MEMLOCK"
authorQuentin Monnet <quentin@isovalent.com>
Fri, 10 Jun 2022 11:26:47 +0000 (12:26 +0100)
committerDaniel Borkmann <daniel@iogearbox.net>
Tue, 14 Jun 2022 20:18:06 +0000 (22:18 +0200)
This reverts commit a777e18f1bcd32528ff5dfd10a6629b655b05eb8.

In commit a777e18f1bcd ("bpftool: Use libbpf 1.0 API mode instead of
RLIMIT_MEMLOCK"), we removed the rlimit bump in bpftool, because the
kernel has switched to memcg-based memory accounting. Thanks to the
LIBBPF_STRICT_AUTO_RLIMIT_MEMLOCK, we attempted to keep compatibility
with other systems and ask libbpf to raise the limit for us if
necessary.

How do we know if memcg-based accounting is supported? There is a probe
in libbpf to check this. But this probe currently relies on the
availability of a given BPF helper, bpf_ktime_get_coarse_ns(), which
landed in the same kernel version as the memory accounting change. This
works in the generic case, but it may fail, for example, if the helper
function has been backported to an older kernel. This has been observed
for Google Cloud's Container-Optimized OS (COS), where the helper is
available but rlimit is still in use. The probe succeeds, the rlimit is
not raised, and probing features with bpftool, for example, fails.

A patch was submitted [0] to update this probe in libbpf, based on what
the cilium/ebpf Go library does [1]. It would lower the soft rlimit to
0, attempt to load a BPF object, and reset the rlimit. But it may induce
some hard-to-debug flakiness if another process starts, or the current
application is killed, while the rlimit is reduced, and the approach was
discarded.

As a workaround to ensure that the rlimit bump does not depend on the
availability of a given helper, we restore the unconditional rlimit bump
in bpftool for now.

  [0] https://lore.kernel.org/bpf/20220609143614.97837-1-quentin@isovalent.com/
  [1] https://github.com/cilium/ebpf/blob/v0.9.0/rlimit/rlimit.go#L39

Signed-off-by: Quentin Monnet <quentin@isovalent.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Cc: Yafang Shao <laoar.shao@gmail.com>
Cc: Stanislav Fomichev <sdf@google.com>
Link: https://lore.kernel.org/bpf/20220610112648.29695-2-quentin@isovalent.com
tools/bpf/bpftool/common.c
tools/bpf/bpftool/feature.c
tools/bpf/bpftool/main.c
tools/bpf/bpftool/main.h
tools/bpf/bpftool/map.c
tools/bpf/bpftool/pids.c
tools/bpf/bpftool/prog.c
tools/bpf/bpftool/struct_ops.c

index a45b42ee8ab0888695d5857441fa742a5555ccb0..a0d4acd7c54aea06279b82af26364f89696baed9 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/magic.h>
 #include <net/if.h>
 #include <sys/mount.h>
+#include <sys/resource.h>
 #include <sys/stat.h>
 #include <sys/vfs.h>
 
@@ -72,6 +73,13 @@ static bool is_bpffs(char *path)
        return (unsigned long)st_fs.f_type == BPF_FS_MAGIC;
 }
 
+void set_max_rlimit(void)
+{
+       struct rlimit rinf = { RLIM_INFINITY, RLIM_INFINITY };
+
+       setrlimit(RLIMIT_MEMLOCK, &rinf);
+}
+
 static int
 mnt_fs(const char *target, const char *type, char *buff, size_t bufflen)
 {
index cc9e4df8c58ef2ecf9145f7c39c07fc49963a1d4..bac4ef428a02592deefe47e9cdf572b08e590d1d 100644 (file)
@@ -1167,6 +1167,8 @@ static int do_probe(int argc, char **argv)
        __u32 ifindex = 0;
        char *ifname;
 
+       set_max_rlimit();
+
        while (argc) {
                if (is_prefix(*argv, "kernel")) {
                        if (target != COMPONENT_UNSPEC) {
index 9062ef2b87670197e21f960fb005a4e631048672..e81227761f5d1be3b57bd720465384cfbefd36db 100644 (file)
@@ -507,9 +507,9 @@ int main(int argc, char **argv)
                 * It will still be rejected if users use LIBBPF_STRICT_ALL
                 * mode for loading generated skeleton.
                 */
-               libbpf_set_strict_mode(LIBBPF_STRICT_ALL & ~LIBBPF_STRICT_MAP_DEFINITIONS);
-       } else {
-               libbpf_set_strict_mode(LIBBPF_STRICT_AUTO_RLIMIT_MEMLOCK);
+               ret = libbpf_set_strict_mode(LIBBPF_STRICT_ALL & ~LIBBPF_STRICT_MAP_DEFINITIONS);
+               if (ret)
+                       p_err("failed to enable libbpf strict mode: %d", ret);
        }
 
        argc -= optind;
index 6c311f47147e7742e3d29157565188e86aa30fd0..589cb76b227ade760a785a6e8b81e12165dbfc3a 100644 (file)
@@ -96,6 +96,8 @@ int detect_common_prefix(const char *arg, ...);
 void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep);
 void usage(void) __noreturn;
 
+void set_max_rlimit(void);
+
 int mount_tracefs(const char *target);
 
 struct obj_ref {
index 800834be1bcb1673e6b1c6be9d892a9da13e1795..38b6bc9c26c3bb0d95ec6ceb4c791f54998039c5 100644 (file)
@@ -1326,6 +1326,8 @@ static int do_create(int argc, char **argv)
                goto exit;
        }
 
+       set_max_rlimit();
+
        fd = bpf_map_create(map_type, map_name, key_size, value_size, max_entries, &attr);
        if (fd < 0) {
                p_err("map create failed: %s", strerror(errno));
index e2d00d3cd868478eb0aa91c4d73ab9c6d24ac8ad..bb6c969a114a33b0e50e5b8924550d95f41496af 100644 (file)
@@ -108,6 +108,7 @@ int build_obj_refs_table(struct hashmap **map, enum bpf_obj_type type)
                p_err("failed to create hashmap for PID references");
                return -1;
        }
+       set_max_rlimit();
 
        skel = pid_iter_bpf__open();
        if (!skel) {
index e71f0b2da50b76b1ce1fa0b04849f10e03c0e606..f081de398b60cb69d89b4924eceff1a1f6cd79fe 100644 (file)
@@ -1590,6 +1590,8 @@ static int load_with_options(int argc, char **argv, bool first_prog_only)
                }
        }
 
+       set_max_rlimit();
+
        if (verifier_logs)
                /* log_level1 + log_level2 + stats, but not stable UAPI */
                open_opts.kernel_log_level = 1 + 2 + 4;
@@ -2287,6 +2289,7 @@ static int do_profile(int argc, char **argv)
                }
        }
 
+       set_max_rlimit();
        err = profiler_bpf__load(profile_obj);
        if (err) {
                p_err("failed to load profile_obj");
index 2535f079ed6743342cb2fcfe498e98f105d88b17..e08a6ff2866c36be9db62e75f5ea8059c94b438d 100644 (file)
@@ -501,6 +501,8 @@ static int do_register(int argc, char **argv)
        if (libbpf_get_error(obj))
                return -1;
 
+       set_max_rlimit();
+
        if (bpf_object__load(obj)) {
                bpf_object__close(obj);
                return -1;