bpf - struct bpf_map_def - add min/max kernel version.

This is also bpfloader v0.2.
Some newer map types (for example DEVMAP) are unusable
on older kernel versions.

Bug: 190519702
Test: atest, TreeHugger
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I085cc723ff1c19d8acc8972a391f894e16dd1875
diff --git a/libbpf_android/Loader.cpp b/libbpf_android/Loader.cpp
index b1af34f..aa1f3c0 100644
--- a/libbpf_android/Loader.cpp
+++ b/libbpf_android/Loader.cpp
@@ -28,10 +28,9 @@
 #include <sys/utsname.h>
 #include <unistd.h>
 
-// This is BpfLoader 0.1, we need to define this prior to including bpf_map_def.h
-// to get the 0.1 struct definitions
+// This is BpfLoader v0.2
 #define BPFLOADER_VERSION_MAJOR 0u
-#define BPFLOADER_VERSION_MINOR 1u
+#define BPFLOADER_VERSION_MINOR 2u
 #define BPFLOADER_VERSION ((BPFLOADER_VERSION_MAJOR << 16) | BPFLOADER_VERSION_MINOR)
 
 #include "../progs/include/bpf_map_def.h"
@@ -494,6 +493,7 @@
         memset(&m, 0, sizeof(m));
         // Then we set non-zero defaults
         m.bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER;  // v1.0
+        m.max_kver = 0xFFFFFFFFu;                         // matches KVER_INF from bpf_helpers.h
         // Then we copy over the structure prefix from the ELF file.
         memcpy(&m, dataPtr, trimmedSize);
         // Move to next struct in the ELF file
@@ -503,14 +503,9 @@
     ret = getSectionSymNames(elfFile, "maps", mapNames);
     if (ret) return ret;
 
-    for (int i = 0; i < (int)mapNames.size(); i++) {
-        unique_fd fd;
-        int saved_errno;
-        // Format of pin location is /sys/fs/bpf/<prefix>map_<filename>_<mapname>
-        string mapPinLoc =
-                string(BPF_FS_PATH) + prefix + "map_" + fname + "_" + string(mapNames[i]);
-        bool reuse = false;
+    unsigned kvers = kernelVersion();
 
+    for (int i = 0; i < (int)mapNames.size(); i++) {
         if (BPFLOADER_VERSION < md[i].bpfloader_min_ver) {
             ALOGI("skipping map %s which requires bpfloader min ver 0x%05x\n", mapNames[i].c_str(),
                   md[i].bpfloader_min_ver);
@@ -525,6 +520,27 @@
             continue;
         }
 
+        if (kvers < md[i].min_kver) {
+            ALOGI("skipping map %s which requires kernel version 0x%x >= 0x%x\n",
+                  mapNames[i].c_str(), kvers, md[i].min_kver);
+            mapFds.push_back(unique_fd());
+            continue;
+        }
+
+        if (kvers >= md[i].max_kver) {
+            ALOGI("skipping map %s which requires kernel version 0x%x < 0x%x\n",
+                  mapNames[i].c_str(), kvers, md[i].max_kver);
+            mapFds.push_back(unique_fd());
+            continue;
+        }
+
+        // Format of pin location is /sys/fs/bpf/<prefix>map_<filename>_<mapname>
+        string mapPinLoc =
+                string(BPF_FS_PATH) + prefix + "map_" + fname + "_" + string(mapNames[i]);
+        bool reuse = false;
+        unique_fd fd;
+        int saved_errno;
+
         if (access(mapPinLoc.c_str(), F_OK) == 0) {
             fd.reset(bpf_obj_get(mapPinLoc.c_str()));
             saved_errno = errno;
diff --git a/progs/include/bpf_helpers.h b/progs/include/bpf_helpers.h
index 6e5fe69..abd19c6 100644
--- a/progs/include/bpf_helpers.h
+++ b/progs/include/bpf_helpers.h
@@ -59,6 +59,10 @@
  * implemented in the kernel sources.
  */
 
+#define KVER_NONE 0
+#define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c))
+#define KVER_INF 0xFFFFFFFFu
+
 /* generic functions */
 
 /*
@@ -110,6 +114,8 @@
             .mode = (md),                                                                        \
             .bpfloader_min_ver = DEFAULT_BPFLOADER_MIN_VER,                                      \
             .bpfloader_max_ver = DEFAULT_BPFLOADER_MAX_VER,                                      \
+            .min_kver = KVER_NONE,                                                               \
+            .max_kver = KVER_INF,                                                                \
     };                                                                                           \
                                                                                                  \
     static inline __always_inline __unused TypeOfValue* bpf_##the_map##_lookup_elem(             \
@@ -147,10 +153,6 @@
 static unsigned long long (*bpf_get_current_uid_gid)(void) = (void*) BPF_FUNC_get_current_uid_gid;
 static unsigned long long (*bpf_get_smp_processor_id)(void) = (void*) BPF_FUNC_get_smp_processor_id;
 
-#define KVER_NONE 0
-#define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c))
-#define KVER_INF 0xFFFFFFFF
-
 #define DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, \
                                        opt)                                                        \
     const struct bpf_prog_def SEC("progs") the_prog##_def = {                                      \
diff --git a/progs/include/bpf_map_def.h b/progs/include/bpf_map_def.h
index f51b1c4..647c813 100644
--- a/progs/include/bpf_map_def.h
+++ b/progs/include/bpf_map_def.h
@@ -141,10 +141,15 @@
     // The following fields were added in version 0.1
     unsigned int bpfloader_min_ver;  // if missing, defaults to 0, ie. v0.0
     unsigned int bpfloader_max_ver;  // if missing, defaults to 0x10000, ie. v1.0
+
+    // The following fields were added in version 0.2
+    // kernelVersion() must be >= min_kver and < max_kver
+    unsigned int min_kver;
+    unsigned int max_kver;
 };
 
 // This needs to be updated whenever the above structure definition is expanded.
-_Static_assert(sizeof(struct bpf_map_def) == 40, "sizeof struct bpf_map_def != 40");
+_Static_assert(sizeof(struct bpf_map_def) == 48, "sizeof struct bpf_map_def != 48");
 _Static_assert(__alignof__(struct bpf_map_def) == 4, "__alignof__ struct bpf_map_def != 4");
 _Static_assert(_Alignof(struct bpf_map_def) == 4, "_Alignof struct bpf_map_def != 4");
 
@@ -162,6 +167,8 @@
     // The following fields were added in version 0.1
     unsigned int bpfloader_min_ver;  // if missing, defaults to 0, ie. v0.0
     unsigned int bpfloader_max_ver;  // if missing, defaults to 0x10000, ie. v1.0
+
+    // No new fields in version 0.2
 };
 
 // This needs to be updated whenever the above structure definition is expanded.