add support for marking ebpf programs as being only for some kernel versions
Some ebpf code cannot be loaded on too old kernels.
Sometimes we want a different - more advanced - version of an ebpf program
to be loaded on a newer kernel.
Test: build, atest
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I9e93e7246951916e6d60544575337a7a19c82886
diff --git a/libbpf_android/BpfUtils.cpp b/libbpf_android/BpfUtils.cpp
index f8ed6d5..c7c56d5 100644
--- a/libbpf_android/BpfUtils.cpp
+++ b/libbpf_android/BpfUtils.cpp
@@ -96,6 +96,24 @@
return res;
}
+#define KVER(a, b, c) ((a)*65536 + (b)*256 + (c))
+
+unsigned kernelVersion() {
+ struct utsname buf;
+ int ret = uname(&buf);
+ if (ret) return 0;
+
+ unsigned kver_major;
+ unsigned kver_minor;
+ unsigned kver_sub;
+ char dummy;
+ ret = sscanf(buf.release, "%u.%u.%u%c", &kver_major, &kver_minor, &kver_sub, &dummy);
+ // Check the device kernel version
+ if (ret < 3) return 0;
+
+ return KVER(kver_major, kver_minor, kver_sub);
+}
+
std::string BpfLevelToString(BpfLevel bpfLevel) {
switch (bpfLevel) {
case BpfLevel::NONE:
@@ -123,23 +141,12 @@
// Check if the device is shipped originally with android P.
if (api_level < MINIMUM_API_REQUIRED) return BpfLevel::NONE;
- struct utsname buf;
- int ret = uname(&buf);
- if (ret) return BpfLevel::NONE;
+ unsigned kver = kernelVersion();
- int kernel_version_major;
- int kernel_version_minor;
- char dummy;
- ret = sscanf(buf.release, "%d.%d%c", &kernel_version_major, &kernel_version_minor, &dummy);
- // Check the device kernel version
- if (ret < 2) return BpfLevel::NONE;
-
- if (kernel_version_major > 5) return BpfLevel::EXTENDED_5_4;
- if (kernel_version_major == 5 && kernel_version_minor >= 4) return BpfLevel::EXTENDED_5_4;
- if (kernel_version_major == 5) return BpfLevel::EXTENDED_4_19;
- if (kernel_version_major == 4 && kernel_version_minor >= 19) return BpfLevel::EXTENDED_4_19;
- if (kernel_version_major == 4 && kernel_version_minor >= 14) return BpfLevel::EXTENDED_4_14;
- if (kernel_version_major == 4 && kernel_version_minor >= 9) return BpfLevel::BASIC_4_9;
+ if (kver >= KVER(5, 4, 0)) return BpfLevel::EXTENDED_5_4;
+ if (kver >= KVER(4, 19, 0)) return BpfLevel::EXTENDED_4_19;
+ if (kver >= KVER(4, 14, 0)) return BpfLevel::EXTENDED_4_14;
+ if (kver >= KVER(4, 9, 0)) return BpfLevel::BASIC_4_9;
return BpfLevel::NONE;
}
diff --git a/libbpf_android/Loader.cpp b/libbpf_android/Loader.cpp
index 8f139a3..ce710a4 100644
--- a/libbpf_android/Loader.cpp
+++ b/libbpf_android/Loader.cpp
@@ -30,6 +30,7 @@
#include "../progs/include/bpf_map_def.h"
#include "LoaderUtils.h"
+#include "bpf/BpfUtils.h"
#include "include/libbpf_android.h"
#include <cstdlib>
@@ -531,9 +532,10 @@
}
static int loadCodeSections(const char* elfPath, vector<codeSection>& cs, const string& license) {
- int ret, fd, kvers;
+ unsigned kvers = kernelVersion();
+ int ret, fd;
- if ((kvers = getMachineKvers()) < 0) return -1;
+ if (!kvers) return -1;
string fname = pathToFilename(string(elfPath), true);
@@ -541,6 +543,11 @@
string progPinLoc;
bool reuse = false;
+ if (cs[i].prog_def.has_value()) {
+ if (kvers < cs[i].prog_def->min_kver) continue;
+ if (kvers >= cs[i].prog_def->max_kver) continue;
+ }
+
// Format of pin location is
// /sys/fs/bpf/prog_<filename>_<mapname>
progPinLoc = string(BPF_FS_PATH) + "prog_" + fname + "_" + cs[i].name;
diff --git a/libbpf_android/LoaderUtils.h b/libbpf_android/LoaderUtils.h
index 9eda833..a5ff7fc 100644
--- a/libbpf_android/LoaderUtils.h
+++ b/libbpf_android/LoaderUtils.h
@@ -32,43 +32,6 @@
return ret;
}
-static int getMachineKvers(void) {
- struct utsname un;
- char* unameOut;
- int nums[3]; // maj, min, sub
-
- if (uname(&un)) return -1;
- unameOut = un.release;
-
- std::string s = unameOut;
- std::string token;
- size_t pos = 0;
- int cur_num = 0;
-
- while ((pos = s.find('.')) != std::string::npos && cur_num < 3) {
- token = s.substr(0, pos);
- s.erase(0, pos + 1);
-
- if ((pos = token.find('-')) != std::string::npos) token = token.substr(0, pos);
-
- nums[cur_num++] = stoi(token);
- }
-
- if ((pos = s.find('-')) != std::string::npos)
- token = s.substr(0, pos);
- else
- token = s;
-
- if (token.length() > 0 && cur_num < 3) {
- nums[cur_num++] = stoi(token);
- }
-
- if (cur_num != 3)
- return -1;
- else
- return (65536 * nums[0] + 256 * nums[1] + nums[2]);
-}
-
static void deslash(std::string& s) {
std::replace(s.begin(), s.end(), '/', '_');
}
diff --git a/libbpf_android/include/bpf/BpfUtils.h b/libbpf_android/include/bpf/BpfUtils.h
index 06dcc47..f724f3b 100644
--- a/libbpf_android/include/bpf/BpfUtils.h
+++ b/libbpf_android/include/bpf/BpfUtils.h
@@ -148,6 +148,7 @@
uint64_t getSocketCookie(int sockFd);
int synchronizeKernelRCU();
int setrlimitForTest();
+unsigned kernelVersion();
std::string BpfLevelToString(BpfLevel BpfLevel);
BpfLevel getBpfSupportLevel();