summaryrefslogtreecommitdiff
path: root/libbpf_android
diff options
context:
space:
mode:
authorMaciej Żenczykowski <maze@google.com>2022-01-25 02:31:59 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2022-01-25 02:31:59 +0000
commit102f93a5dac0199f13bf629513eb95459e4dbf95 (patch)
tree69fc0e9a6b13bb2f42aa5e9d494bf35fa8cb6f76 /libbpf_android
parent5ffd6bb828e69f2aea4a4bcc819d8221f6f52c3a (diff)
parent35425e5a884342b6b3ce50d990080288e3b3140b (diff)
downloadbpf-102f93a5dac0199f13bf629513eb95459e4dbf95.tar.gz
Merge "bpfloader: load map BTF via btfloader"
Diffstat (limited to 'libbpf_android')
-rw-r--r--libbpf_android/BpfLoadTest.cpp15
-rw-r--r--libbpf_android/Loader.cpp106
2 files changed, 118 insertions, 3 deletions
diff --git a/libbpf_android/BpfLoadTest.cpp b/libbpf_android/BpfLoadTest.cpp
index 2560890..72c0fc1 100644
--- a/libbpf_android/BpfLoadTest.cpp
+++ b/libbpf_android/BpfLoadTest.cpp
@@ -85,6 +85,17 @@ class BpfLoadTest : public TestWithParam<std::string> {
EXPECT_RESULT_OK(m.iterateWithValue(iterFunc));
EXPECT_EQ(non_zero, 1);
}
+
+ void checkMapBtf() {
+ // Earlier kernels lack BPF_BTF_LOAD support
+ if (!isAtLeastKernelVersion(4, 19, 0)) GTEST_SKIP() << "pre-4.19 kernel does not support BTF";
+
+ const bool haveBtf = GetParam().find("btf") != std::string::npos;
+
+ std::string str;
+ EXPECT_EQ(android::base::ReadFileToString(mTpMapPath, &str), haveBtf);
+ if (haveBtf) EXPECT_FALSE(str.empty());
+ }
};
INSTANTIATE_TEST_SUITE_P(BpfLoadTests, BpfLoadTest,
@@ -94,5 +105,9 @@ TEST_P(BpfLoadTest, bpfCheckMap) {
checkMapNonZero();
}
+TEST_P(BpfLoadTest, bpfCheckBtf) {
+ checkMapBtf();
+}
+
} // namespace bpf
} // namespace android
diff --git a/libbpf_android/Loader.cpp b/libbpf_android/Loader.cpp
index ec251fb..cad5950 100644
--- a/libbpf_android/Loader.cpp
+++ b/libbpf_android/Loader.cpp
@@ -24,8 +24,10 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sysexits.h>
#include <sys/stat.h>
#include <sys/utsname.h>
+#include <sys/wait.h>
#include <unistd.h>
// This is BpfLoader v0.9
@@ -37,13 +39,18 @@
#include "bpf/bpf_map_def.h"
#include "include/libbpf_android.h"
+#include <bpf/bpf.h>
+
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <optional>
#include <string>
+#include <unordered_map>
#include <vector>
+#include <android-base/cmsg.h>
+#include <android-base/file.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
@@ -472,12 +479,88 @@ static int getSymNameByIdx(ifstream& elfFile, int index, string& name) {
return getSymName(elfFile, symtab[index].st_name, name);
}
+static bool waitpidTimeout(pid_t pid, int timeoutMs) {
+ // Add SIGCHLD to the signal set.
+ sigset_t child_mask, original_mask;
+ sigemptyset(&child_mask);
+ sigaddset(&child_mask, SIGCHLD);
+ if (sigprocmask(SIG_BLOCK, &child_mask, &original_mask) == -1) return false;
+
+ // Wait for a SIGCHLD notification.
+ errno = 0;
+ timespec ts = {0, timeoutMs * 1000000};
+ int wait_result = TEMP_FAILURE_RETRY(sigtimedwait(&child_mask, nullptr, &ts));
+
+ // Restore the original signal set.
+ sigprocmask(SIG_SETMASK, &original_mask, nullptr);
+
+ if (wait_result == -1) return false;
+
+ int status;
+ return TEMP_FAILURE_RETRY(waitpid(pid, &status, WNOHANG)) == pid;
+}
+
+static std::optional<unique_fd> getMapBtfInfo(const char* elfPath,
+ std::unordered_map<string, std::pair<uint32_t, uint32_t>> &btfTypeIds) {
+ unique_fd bpfloaderSocket, btfloaderSocket;
+ if (!android::base::Socketpair(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK, 0, &bpfloaderSocket,
+ &btfloaderSocket)) {
+ return {};
+ }
+
+ unique_fd pipeRead, pipeWrite;
+ if (!android::base::Pipe(&pipeRead, &pipeWrite, O_NONBLOCK)) {
+ return {};
+ }
+
+ pid_t pid = fork();
+ if (pid < 0) return {};
+ if (!pid) {
+ bpfloaderSocket.reset();
+ pipeRead.reset();
+ auto socketFdStr = std::to_string(btfloaderSocket.release());
+ auto pipeFdStr = std::to_string(pipeWrite.release());
+
+ if (execl("/system/bin/btfloader", "/system/bin/btfloader", socketFdStr.c_str(),
+ pipeFdStr.c_str(), elfPath, NULL) == -1) {
+ ALOGW("exec btfloader failed with errno %d (%s)\n", errno, strerror(errno));
+ exit(EX_UNAVAILABLE);
+ }
+ }
+ btfloaderSocket.reset();
+ pipeWrite.reset();
+ if (!waitpidTimeout(pid, 100)) {
+ kill(pid, SIGKILL);
+ return {};
+ }
+
+ unique_fd btfFd;
+ if (android::base::ReceiveFileDescriptors(bpfloaderSocket, nullptr, 0, &btfFd)) return {};
+
+ std::string btfTypeIdStr;
+ if (!android::base::ReadFdToString(pipeRead, &btfTypeIdStr)) return {};
+ if (btfFd.get() < 0) return {};
+
+ const auto mapTypeIdLines = android::base::Split(btfTypeIdStr, "\n");
+ for (const auto &line : mapTypeIdLines) {
+ const auto vec = android::base::Split(line, " ");
+ // Splitting on newline will give us one empty line
+ if (vec.size() != 3) continue;
+ const int kTid = atoi(vec[1].c_str());
+ const int vTid = atoi(vec[2].c_str());
+ if (!kTid || !vTid) return {};
+ btfTypeIds[vec[0]] = std::make_pair(kTid, vTid);
+ }
+ return btfFd;
+}
+
static int createMaps(const char* elfPath, ifstream& elfFile, vector<unique_fd>& mapFds,
const char* prefix, size_t sizeOfBpfMapDef) {
int ret;
- vector<char> mdData;
+ vector<char> mdData, btfData;
vector<struct bpf_map_def> md;
vector<string> mapNames;
+ std::unordered_map<string, std::pair<uint32_t, uint32_t>> btfTypeIdMap;
string fname = pathToFilename(string(elfPath), true);
ret = readSectionByName("maps", elfFile, mdData);
@@ -510,6 +593,11 @@ static int createMaps(const char* elfPath, ifstream& elfFile, vector<unique_fd>&
ret = getSectionSymNames(elfFile, "maps", mapNames);
if (ret) return ret;
+ std::optional<unique_fd> btfFd;
+ if (!readSectionByName(".BTF", elfFile, btfData)) {
+ btfFd = getMapBtfInfo(elfPath, btfTypeIdMap);
+ }
+
unsigned kvers = kernelVersion();
for (int i = 0; i < (int)mapNames.size(); i++) {
@@ -575,8 +663,20 @@ static int createMaps(const char* elfPath, ifstream& elfFile, vector<unique_fd>&
// programs as being 5.4+...
type = BPF_MAP_TYPE_HASH;
}
- fd.reset(bcc_create_map(type, mapNames[i].c_str(), md[i].key_size, md[i].value_size,
- md[i].max_entries, md[i].map_flags));
+ struct bpf_create_map_attr attr = {
+ .name = mapNames[i].c_str(),
+ .map_type = type,
+ .map_flags = md[i].map_flags,
+ .key_size = md[i].key_size,
+ .value_size = md[i].value_size,
+ .max_entries = md[i].max_entries,
+ };
+ if (btfFd.has_value() && btfTypeIdMap.find(mapNames[i]) != btfTypeIdMap.end()) {
+ attr.btf_fd = btfFd->get();
+ attr.btf_key_type_id = btfTypeIdMap.at(mapNames[i]).first;
+ attr.btf_value_type_id = btfTypeIdMap.at(mapNames[i]).second;
+ }
+ fd.reset(bcc_create_map_xattr(&attr, true));
saved_errno = errno;
ALOGD("bpf_create_map name %s, ret: %d\n", mapNames[i].c_str(), fd.get());
}