BpfLoader: split legacy bpfloader into 3 phases, simplify arguments

Should make integration with BpfLoader written in rust easier.

While at it add simple wrappers around ALOG{V,D,I,W,E}(),
which may come in handy as bpfloader runs early enough that
logging must be to the kernel dmesg ringbuffer instead...

Test: TreeHugger
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: Ia49c605bae63241b74d04e2e0f58fd089c23993d
This commit is contained in:
Maciej Żenczykowski 2024-08-07 12:27:18 -07:00 • committed by Neill Kapron
commit dd4bd2d655
3 changed files with 69 additions and 14 deletions

View file

@ -16,6 +16,9 @@
#include <libbpf_android.h>
int main(int argc, char** argv, char * const envp[]) {
return android::bpf::legacyBpfLoader(argc, argv, envp);
__noreturn int main() {
initLogging();
legacyBpfLoader();
execNetBpfLoadDone();
// unreachable
}

View file

@ -975,27 +975,58 @@ int createSysFsBpfSubDir(const char* const prefix) {
return 0;
}
int legacyBpfLoader(int __unused argc, char** argv, char * const envp[]) {
base::InitLogging(argv, &base::KernelLogger);
} // namespace bpf
} // namespace android
// ----- extern C stuff for rust below here -----
void initLogging() {
// since we only ever get called from mainline NetBpfLoad
// (see packages/modules/Connectivity/netbpfload/NetBpfLoad.cpp around line 516)
// and there no arguments, so we can just pretend/assume this is the case.
const char* argv[] = {"/system/bin/bpfloader", NULL};
android::base::InitLogging(const_cast<char**>(argv), &android::base::KernelLogger);
}
void legacyBpfLoader() {
// Load all ELF objects, create programs and maps, and pin them
for (const auto& location : locations) {
if (createSysFsBpfSubDir(location.prefix) || loadAllElfObjects(location)) {
for (const auto& location : android::bpf::locations) {
if (android::bpf::createSysFsBpfSubDir(location.prefix) ||
android::bpf::loadAllElfObjects(location)) {
ALOGE("=== CRITICAL FAILURE LOADING BPF PROGRAMS FROM %s ===", location.dir);
ALOGE("If this triggers reliably, you're probably missing kernel options or patches.");
ALOGE("If this triggers randomly, you might be hitting some memory allocation "
"problems or startup script race.");
ALOGE("--- DO NOT EXPECT SYSTEM TO BOOT SUCCESSFULLY ---");
sleep(20);
return 120;
exit(120);
}
}
const char * args[] = { "/apex/com.android.tethering/bin/netbpfload", "done", NULL, };
execve(args[0], (char**)args, envp);
ALOGE("FATAL: execve(): %d[%s]", errno, strerror(errno));
return 121;
}
} // namespace bpf
} // namespace android
void execNetBpfLoadDone() {
const char* args[] = {"/apex/com.android.tethering/bin/netbpfload", "done", NULL};
execve(args[0], (char**)args, environ);
ALOGE("FATAL: execve(): %d[%s]", errno, strerror(errno));
exit(121);
}
void logVerbose(const char* msg) {
ALOGV("%s", msg);
}
void logDebug(const char* msg) {
ALOGD("%s", msg);
}
void logInfo(const char* msg) {
ALOGI("%s", msg);
}
void logWarn(const char* msg) {
ALOGW("%s", msg);
}
void logError(const char* msg) {
ALOGE("%s", msg);
}

View file

@ -17,6 +17,8 @@
#pragma once
#ifdef __cplusplus
#include <linux/bpf.h>
#include <fstream>
@ -37,7 +39,26 @@ int loadProg(const char* elfPath, bool* isCritical, const Location &location = {
// Exposed for testing
unsigned int readSectionUint(const char* name, std::ifstream& elfFile, unsigned int defVal);
int legacyBpfLoader(int argc, char** argv, char * const envp[]);
} // namespace bpf
} // namespace android
extern "C" {
#else // __cplusplus
#define __noreturn
#endif // __cplusplus
// The C++ portion of the BpfLoader is exposed as 3 functions to be called in order.
void initLogging();
void legacyBpfLoader();
__noreturn void execNetBpfLoadDone();
// For logging from rust
void logVerbose(const char* msg);
void logDebug(const char* msg);
void logInfo(const char* msg);
void logWarn(const char* msg);
void logError(const char* msg);
#ifdef __cplusplus
} // extern C
#endif