diff options
author | Maciej Żenczykowski <maze@google.com> | 2020-06-17 17:21:06 +0000 |
---|---|---|
committer | Maciej Zenczykowski <maze@google.com> | 2020-06-18 04:19:15 +0000 |
commit | 2464ddb0dfbe86771f371d545139dd47db36bb44 (patch) | |
tree | 5009769ace4840970df3fd372922e8956da93d05 | |
parent | 45f5ffd167b6fd172866fc8f6e9fa0895fbd6528 (diff) | |
download | platform_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.cpp | 17 | ||||
-rw-r--r-- | libbpf_android/include/bpf/BpfMap.h | 2 | ||||
-rw-r--r-- | libbpf_android/include/bpf/BpfUtils.h | 16 | ||||
-rw-r--r-- | progs/include/bpf_helpers.h | 48 | ||||
-rw-r--r-- | progs/include/bpf_map_def.h | 2 |
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. }; |