summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaciej Żenczykowski <maze@google.com>2020-06-17 17:21:06 +0000
committerMaciej Zenczykowski <maze@google.com>2020-06-18 04:19:15 +0000
commit2464ddb0dfbe86771f371d545139dd47db36bb44 (patch)
tree5009769ace4840970df3fd372922e8956da93d05
parent45f5ffd167b6fd172866fc8f6e9fa0895fbd6528 (diff)
downloadplatform_system_bpf-2464ddb0dfbe86771f371d545139dd47db36bb44.tar.gz
platform_system_bpf-2464ddb0dfbe86771f371d545139dd47db36bb44.tar.bz2
platform_system_bpf-2464ddb0dfbe86771f371d545139dd47db36bb44.zip
implement support for functions which may optionally fail to load
This is useful for critical functions with fallbacks, but may even be useful for non-critical functions, where a function in the middle of the file may fail to load, but you still want other (later) functions to be attempted. Critical applies to the entire .c file (or to be more correct to the entire resulting .o). Optional applies to a specific section of that .o (ie. a specific individual function). This new optional attribute is necessary to be able to declare a .c/.o file critical even if *some* of the individual functions might fail to load due to missing kernel patches. (Note: we currently have no way to specify a map as optional) Critical guarantees that all non-optional programs, and all maps, have been created, pinned, chowned, and chmoded successfully (or that they already existed). For an example of use see: system/netd/bpf_progs/offload.c (while at it also add retrieveProgram() and mapRetrieve{RW,RO,WO}() helpers to BpfUtils.h) Test: builds, atest, see paired netd change for extra details Bug: 150040815 Signed-off-by: Maciej Żenczykowski <maze@google.com> Original-Change: https://android-review.googlesource.com/1336225 Merged-In: I50b292c061b05fc8f4b4b8574f128345c45c78db Change-Id: I50b292c061b05fc8f4b4b8574f128345c45c78db
-rw-r--r--libbpf_android/Loader.cpp17
-rw-r--r--libbpf_android/include/bpf/BpfMap.h2
-rw-r--r--libbpf_android/include/bpf/BpfUtils.h16
-rw-r--r--progs/include/bpf_helpers.h48
-rw-r--r--progs/include/bpf_map_def.h2
5 files changed, 68 insertions, 17 deletions
diff --git a/libbpf_android/Loader.cpp b/libbpf_android/Loader.cpp
index 8f5318d..5a65c1b 100644
--- a/libbpf_android/Loader.cpp
+++ b/libbpf_android/Loader.cpp
@@ -564,8 +564,9 @@ static int loadCodeSections(const char* elfPath, vector<codeSection>& cs, const
progPinLoc += '_';
progPinLoc += name;
if (access(progPinLoc.c_str(), F_OK) == 0) {
- fd = bpf_obj_get(progPinLoc.c_str());
- ALOGD("New bpf prog load reusing prog %s, ret: %d\n", progPinLoc.c_str(), fd);
+ fd = retrieveProgram(progPinLoc.c_str());
+ ALOGD("New bpf prog load reusing prog %s, ret: %d (%s)\n", progPinLoc.c_str(), fd,
+ (fd < 0 ? std::strerror(errno) : "no error"));
reuse = true;
} else {
vector<char> log_buf(BPF_LOAD_LOG_SZ, 0);
@@ -579,9 +580,15 @@ static int loadCodeSections(const char* elfPath, vector<codeSection>& cs, const
if (fd < 0) {
std::vector<std::string> lines = android::base::Split(log_buf.data(), "\n");
- ALOGE("bpf_prog_load - BEGIN log_buf contents:");
- for (const auto& line : lines) ALOGE("%s", line.c_str());
- ALOGE("bpf_prog_load - END log_buf contents.");
+ ALOGW("bpf_prog_load - BEGIN log_buf contents:");
+ for (const auto& line : lines) ALOGW("%s", line.c_str());
+ ALOGW("bpf_prog_load - END log_buf contents.");
+
+ if (cs[i].prog_def->optional) {
+ ALOGW("failed program is marked optional - continuing...");
+ continue;
+ }
+ ALOGE("non-optional program failed to load.");
}
}
diff --git a/libbpf_android/include/bpf/BpfMap.h b/libbpf_android/include/bpf/BpfMap.h
index c92f989..3e7413e 100644
--- a/libbpf_android/include/bpf/BpfMap.h
+++ b/libbpf_android/include/bpf/BpfMap.h
@@ -179,7 +179,7 @@ class BpfMap {
template <class Key, class Value>
base::Result<void> BpfMap<Key, Value>::init(const char* path) {
- mMapFd = base::unique_fd(mapRetrieve(path, 0));
+ mMapFd = base::unique_fd(mapRetrieveRW(path));
if (mMapFd == -1) {
return ErrnoErrorf("Pinned map not accessible or does not exist: ({})", path);
}
diff --git a/libbpf_android/include/bpf/BpfUtils.h b/libbpf_android/include/bpf/BpfUtils.h
index f724f3b..6814f94 100644
--- a/libbpf_android/include/bpf/BpfUtils.h
+++ b/libbpf_android/include/bpf/BpfUtils.h
@@ -129,6 +129,22 @@ inline int mapRetrieve(const char* pathname, uint32_t flag) {
return bpfFdGet(pathname, flag);
}
+inline int mapRetrieveRW(const char* pathname) {
+ return mapRetrieve(pathname, 0);
+}
+
+inline int mapRetrieveRO(const char* pathname) {
+ return mapRetrieve(pathname, BPF_F_RDONLY);
+}
+
+inline int mapRetrieveWO(const char* pathname) {
+ return mapRetrieve(pathname, BPF_F_WRONLY);
+}
+
+inline int retrieveProgram(const char* pathname) {
+ return bpfFdGet(pathname, BPF_F_RDONLY);
+}
+
inline int attachProgram(bpf_attach_type type, const base::unique_fd& prog_fd,
const base::unique_fd& cg_fd) {
return bpf(BPF_PROG_ATTACH, {
diff --git a/progs/include/bpf_helpers.h b/progs/include/bpf_helpers.h
index f76b382..9d22584 100644
--- a/progs/include/bpf_helpers.h
+++ b/progs/include/bpf_helpers.h
@@ -111,21 +111,47 @@ static unsigned long long (*bpf_get_smp_processor_id)(void) = (void*) BPF_FUNC_g
#define KVER(a, b, c) ((a)*65536 + (b)*256 + (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 = { \
+ .uid = (prog_uid), \
+ .gid = (prog_gid), \
+ .min_kver = (min_kv), \
+ .max_kver = (max_kv), \
+ .optional = (opt), \
+ }; \
+ SEC(SECTION_NAME) \
+ int the_prog
+
+// Programs (here used in the sense of functions/sections) marked optional are allowed to fail
+// to load (for example due to missing kernel patches).
+// The bpfloader will just ignore these failures and continue processing the next section.
+//
+// A non-optional program (function/section) failing to load causes a failure and aborts
+// processing of the entire .o, if the .o is additionally marked critical, this will result
+// in the entire bpfloader process terminating with a failure and not setting the bpf.progs_loaded
+// system property. This in turn results in waitForProgsLoaded() never finishing.
+//
+// ie. a non-optional program in a critical .o is mandatory for kernels matching the min/max kver.
+
// programs requiring a kernel version >= min_kv && < max_kv
#define DEFINE_BPF_PROG_KVER_RANGE(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv) \
- const struct bpf_prog_def SEC("progs") the_prog##_def = { \
- .uid = (prog_uid), \
- .gid = (prog_gid), \
- .min_kver = (min_kv), \
- .max_kver = (max_kv), \
- }; \
- SEC(SECTION_NAME) \
- int the_prog
+ DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, \
+ false)
+#define DEFINE_OPTIONAL_BPF_PROG_KVER_RANGE(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, \
+ max_kv) \
+ DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, true)
// programs requiring a kernel version >= min_kv
-#define DEFINE_BPF_PROG_KVER(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv) \
- DEFINE_BPF_PROG_KVER_RANGE(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, KVER_INF)
+#define DEFINE_BPF_PROG_KVER(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv) \
+ DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, KVER_INF, \
+ false)
+#define DEFINE_OPTIONAL_BPF_PROG_KVER(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv) \
+ DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, KVER_INF, \
+ true)
// programs with no kernel version requirements
#define DEFINE_BPF_PROG(SECTION_NAME, prog_uid, prog_gid, the_prog) \
- DEFINE_BPF_PROG_KVER_RANGE(SECTION_NAME, prog_uid, prog_gid, the_prog, 0, KVER_INF)
+ DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, 0, KVER_INF, false)
+#define DEFINE_OPTIONAL_BPF_PROG(SECTION_NAME, prog_uid, prog_gid, the_prog) \
+ DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, 0, KVER_INF, true)
diff --git a/progs/include/bpf_map_def.h b/progs/include/bpf_map_def.h
index 01d9b8e..452b682 100644
--- a/progs/include/bpf_map_def.h
+++ b/progs/include/bpf_map_def.h
@@ -60,4 +60,6 @@ struct bpf_prog_def {
unsigned int min_kver; // KERNEL_MAJOR * 65536 + KERNEL_MINOR * 256 + KERNEL_SUB
unsigned int max_kver; // ie. 0x40900 for Linux 4.9 - but beware of hexadecimal for >= 10
+
+ bool optional; // program section (ie. function) may fail to load, continue onto next func.
};