]> sourceware.org Git - systemtap.git/commitdiff
stapbpf maps, PR23407: increase BPF_MAXMAP_ENTRIES, ensure space with setrlimit
authorSerhei Makarov <smakarov@redhat.com>
Thu, 16 Aug 2018 15:38:27 +0000 (11:38 -0400)
committerSerhei Makarov <smakarov@redhat.com>
Thu, 16 Aug 2018 15:50:12 +0000 (11:50 -0400)
eBPF maps can be arbitrarily large, but they live in memlocked memory
which has a very low default maximum per-process.

This patch increases RLIMIT_MEMLOCK to allow larger maps, and
increases BPF_MAX_MAPENTRIES to 2048.

Since the rlimit is set separately for each process, impact on the
system should not be significant.

TODO: The exact amount by which to increase the rlimit is a matter for
some experimentation. In addition to the space for keys and values,
there is a per-entry overhead that may need to be tweaked upwards
based on further testing.

* bpf-internal.h (BPF_MAXMAPENTRIES): now bigger.
* stapbpf.cxx (instantiate_maps): increase RLIMIT_MEMLOCK before
  allocating maps, add diagnostic printfs.

bpf-internal.h
stapbpf/stapbpf.cxx

index 9d787c9ad3ca93bb38d4f619b0528f88c511d5d8..8ec5453703f0f579c37871df2a37bc4f9f829203 100644 (file)
@@ -28,14 +28,13 @@ struct vardecl;
 namespace bpf {
 
 #define MAX_BPF_STACK 512
+#define BPF_REG_SIZE 8
 #define BPF_MAXSTRINGLEN 64
 #define BPF_MAXFORMATLEN 256
-#define BPF_MAXMAPENTRIES 16
-//#define BPF_MAXMAPENTRIES 2048 // TODO requires setrlimit
+#define BPF_MAXMAPENTRIES 2048
 // TODO: add BPF_MAXSPRINTFLEN
-#define BPF_REG_SIZE 8
-// TODO: BPF_MAX{STRING,FORMAT}LEN,BPF_MAXMAPSIZE should be user-configurable.
-// TODO: BPF_MAXMAPSIZE may depend on kernel version and rlimit. May need to setrlimit to create a bigger map (would like to default to 2048).
+// TODO: BPF_MAX{STRING,FORMAT}LEN,BPF_MAXMAPENTRIES,BPF_MAXSPRINTFLEN should be user-configurable.
+// XXX: BPF_MAXMAPENTRIES may depend on kernel version. May need to experiment with rlimit in instantiate_maps().
 
 typedef unsigned short regno;
 static const regno max_regno = BPF_MAXINSNS;
index 89e00ece77074f4590a02eadbab43b507d2431c1..ddb268756554236a287007d341f45ee6d39675e1 100644 (file)
@@ -37,6 +37,7 @@
 #include <sys/ioctl.h>
 #include <sys/syscall.h>
 #include <sys/utsname.h>
+#include <sys/resource.h>
 #include "bpfinterp.h"
 
 extern "C" {
@@ -225,8 +226,55 @@ instantiate_maps (Elf64_Shdr *shdr, Elf_Data *data)
   map_attrs = attrs;
   map_fds.assign(n, -1);
 
+  /* First, make room for the maps in this process' RLIMIT_MEMLOCK: */
+  size_t rlimit_increase = 0;
   for (i = 0; i < n; ++i)
     {
+      // TODO: The 58 bytes of overhead space per entry has been
+      // decided by trial and error, and may require further tweaking:
+      rlimit_increase += (58 + attrs[i].key_size + attrs[i].value_size) * attrs[i].max_entries;
+    }
+
+  struct rlimit curr_rlimit;
+  int rc;
+
+  rc = getrlimit(RLIMIT_MEMLOCK, &curr_rlimit);
+  if (rc < 0)
+    fatal("could not get map resource limit: %s\n",
+          strerror(errno));
+
+  size_t rlim_orig = curr_rlimit.rlim_cur;
+  size_t rlim_max_orig = curr_rlimit.rlim_max;
+  curr_rlimit.rlim_cur += rlimit_increase;
+  curr_rlimit.rlim_max += rlimit_increase;
+  if (curr_rlimit.rlim_cur < rlim_orig) // handle overflow
+    curr_rlimit.rlim_cur = rlim_orig;
+  if (curr_rlimit.rlim_max < rlim_max_orig) // handle overflow
+    curr_rlimit.rlim_max = rlim_max_orig;
+
+  rc = setrlimit(RLIMIT_MEMLOCK, &curr_rlimit);
+  if (rc < 0)
+    fatal("could not increase map resource limit -- "
+          "cur from %lu to %lu, max from %lu to %lu: %s\n",
+          rlim_orig, curr_rlimit.rlim_cur,
+          rlim_max_orig, curr_rlimit.rlim_max,
+          strerror(errno));
+  if (log_level > 1)
+    {
+      fprintf(stderr, "increasing map cur resource limit from %lu to %lu\n",
+              rlim_orig, curr_rlimit.rlim_cur);
+      fprintf(stderr, "increasing map max resource limit from %lu to %lu\n",
+              rlim_max_orig, curr_rlimit.rlim_max);
+    }
+
+  /* Now create the maps: */
+  for (i = 0; i < n; ++i)
+    {
+      if (log_level > 2)
+        fprintf(stderr, "creating map entry %zu: key_size %u, value_size %u, "
+                "max_entries %u, map_flags %u\n", i,
+                attrs[i].key_size, attrs[i].value_size,
+                attrs[i].max_entries, attrs[i].map_flags);
       int fd = bpf_create_map(static_cast<bpf_map_type>(attrs[i].type),
                              attrs[i].key_size, attrs[i].value_size,
                              attrs[i].max_entries, attrs[i].map_flags);
This page took 0.061407 seconds and 5 git commands to generate.