Mark ab/7061308 as merged in stage.
Bug: 180401296
Merged-In: I29e012cafcbadea5f0ce8f5b0348581afdd78339
Change-Id: Ie4bdf948f4c3a6e3758fdaf5a39091573b316fac
diff --git a/Android.bp b/Android.bp
index a1d6d9a..c8c1681 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,3 +1,20 @@
+package {
+ default_applicable_licenses: ["system_bpf_license"],
+}
+
+// Added automatically by a large-scale-change
+// http://go/android-license-faq
+license {
+ name: "system_bpf_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
+
cc_defaults {
name: "bpf_defaults",
cflags: [
diff --git a/bpfloader/Android.bp b/bpfloader/Android.bp
index 0b4bbd4..7a6a4c4 100644
--- a/bpfloader/Android.bp
+++ b/bpfloader/Android.bp
@@ -17,6 +17,14 @@
//
// bpfLoad binary
//
+package {
+ // http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // the below license kinds from "system_bpf_license":
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["system_bpf_license"],
+}
+
cc_binary {
name: "bpfloader",
diff --git a/bpfloader/BpfLoader.cpp b/bpfloader/BpfLoader.cpp
index 33208d1..7a68894 100644
--- a/bpfloader/BpfLoader.cpp
+++ b/bpfloader/BpfLoader.cpp
@@ -51,10 +51,23 @@
using android::base::EndsWith;
using std::string;
-#define BPF_PROG_PATH_MAINLINE_TETHERING "/apex/com.android.tethering/etc/bpf/"
-#define BPF_PROG_PATH_SYSTEM "/system/etc/bpf/"
+struct {
+ const char* const dir;
+ const char* const prefix;
+} locations[] = {
+ // Tethering mainline module
+ {
+ .dir = "/apex/com.android.tethering/etc/bpf/",
+ .prefix = "tethering/",
+ },
+ // Core operating system
+ {
+ .dir = "/system/etc/bpf/",
+ .prefix = "",
+ },
+};
-int loadAllElfObjects(const char* progDir) {
+int loadAllElfObjects(const char* const progDir, const char* const prefix) {
int retVal = 0;
DIR* dir;
struct dirent* ent;
@@ -68,7 +81,7 @@
progPath += s;
bool critical;
- int ret = android::bpf::loadProg(progPath.c_str(), &critical);
+ int ret = android::bpf::loadProg(progPath.c_str(), &critical, prefix);
if (ret) {
if (critical) retVal = ret;
ALOGE("Failed to load object: %s, ret: %s", progPath.c_str(), std::strerror(-ret));
@@ -81,13 +94,29 @@
return retVal;
}
-int main() {
- if (!android::bpf::isBpfSupported()) return 0;
+void createSysFsBpfSubDir(const char* const prefix) {
+ if (*prefix) {
+ mode_t prevUmask = umask(0);
+ string s = "/sys/fs/bpf/";
+ s += prefix;
+
+ errno = 0;
+ int ret = mkdir(s.c_str(), S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO);
+ if (ret && errno != EEXIST) {
+ ALOGW("Failed to create directory: %s, ret: %s", s.c_str(), std::strerror(errno));
+ }
+
+ umask(prevUmask);
+ }
+}
+
+int main() {
// Load all ELF objects, create programs and maps, and pin them
- for (const auto dir : {BPF_PROG_PATH_MAINLINE_TETHERING, BPF_PROG_PATH_SYSTEM}) {
- if (loadAllElfObjects(dir) != 0) {
- ALOGE("=== CRITICAL FAILURE LOADING BPF PROGRAMS FROM %s ===", dir);
+ for (const auto location : locations) {
+ createSysFsBpfSubDir(location.prefix);
+ if (loadAllElfObjects(location.dir, location.prefix) != 0) {
+ 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.");
diff --git a/bpfloader/bpfloader.rc b/bpfloader/bpfloader.rc
index fec7530..9a9482c 100644
--- a/bpfloader/bpfloader.rc
+++ b/bpfloader/bpfloader.rc
@@ -7,9 +7,6 @@
# - /sys/fs/bpf is already mounted,
# - apex (incl. rollback) is initialized (so that in the future we can load bpf
# programs shipped as part of apex mainline modules)
-# - system properties have been set, this is because isBpfSupported() calls
-# getUncachedBpfSupportLevel() which depends on
-# ro.kernel.ebpf.supported, ro.product.first_api_level & ro.build.version.sdk
# - logd is ready for us to log stuff
#
# At the same time we want to be as early as possible to reduce races and thus
diff --git a/libbpf_android/Android.bp b/libbpf_android/Android.bp
index 507ca18..06528c8 100644
--- a/libbpf_android/Android.bp
+++ b/libbpf_android/Android.bp
@@ -14,6 +14,14 @@
// limitations under the License.
//
+package {
+ // http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // the below license kinds from "system_bpf_license":
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["system_bpf_license"],
+}
+
cc_library_headers {
name: "libbpf_android_headers",
vendor_available: false,
@@ -25,6 +33,9 @@
enabled: true,
},
},
+ sdk_version: "30",
+ header_libs: ["bpf_syscall_wrappers"],
+ export_header_lib_headers: ["bpf_syscall_wrappers"],
}
cc_library {
diff --git a/libbpf_android/BpfLoadTest.cpp b/libbpf_android/BpfLoadTest.cpp
index b384c11..09cd36c 100644
--- a/libbpf_android/BpfLoadTest.cpp
+++ b/libbpf_android/BpfLoadTest.cpp
@@ -38,8 +38,6 @@
int mProgFd;
void SetUp() {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
unlink(tp_prog_path);
unlink(tp_map_path);
@@ -55,8 +53,6 @@
}
void TearDown() {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
close(mProgFd);
unlink(tp_prog_path);
unlink(tp_map_path);
@@ -88,8 +84,6 @@
};
TEST_F(BpfLoadTest, bpfCheckMap) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
checkMapNonZero();
}
diff --git a/libbpf_android/BpfMapTest.cpp b/libbpf_android/BpfMapTest.cpp
index 91b9bf3..d0737b0 100644
--- a/libbpf_android/BpfMapTest.cpp
+++ b/libbpf_android/BpfMapTest.cpp
@@ -54,8 +54,6 @@
BpfMapTest() {}
void SetUp() {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
EXPECT_EQ(0, setrlimitForTest());
if (!access(PINNED_MAP_PATH, R_OK)) {
EXPECT_EQ(0, remove(PINNED_MAP_PATH));
@@ -63,8 +61,6 @@
}
void TearDown() {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
if (!access(PINNED_MAP_PATH, R_OK)) {
EXPECT_EQ(0, remove(PINNED_MAP_PATH));
}
@@ -107,8 +103,6 @@
};
TEST_F(BpfMapTest, constructor) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
BpfMap<uint32_t, uint32_t> testMap1;
checkMapInvalid(testMap1);
@@ -117,8 +111,6 @@
}
TEST_F(BpfMapTest, basicHelpers) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
BpfMap<uint32_t, uint32_t> testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
uint32_t key = TEST_KEY1;
uint32_t value_write = TEST_VALUE1;
@@ -133,8 +125,6 @@
}
TEST_F(BpfMapTest, reset) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
BpfMap<uint32_t, uint32_t> testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
uint32_t key = TEST_KEY1;
uint32_t value_write = TEST_VALUE1;
@@ -147,8 +137,6 @@
}
TEST_F(BpfMapTest, moveConstructor) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
BpfMap<uint32_t, uint32_t> testMap1(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
BpfMap<uint32_t, uint32_t> testMap2;
testMap2 = std::move(testMap1);
@@ -159,8 +147,6 @@
}
TEST_F(BpfMapTest, SetUpMap) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
EXPECT_NE(0, access(PINNED_MAP_PATH, R_OK));
BpfMap<uint32_t, uint32_t> testMap1(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
ASSERT_EQ(0, bpfFdPin(testMap1.getMap(), PINNED_MAP_PATH));
@@ -177,8 +163,6 @@
}
TEST_F(BpfMapTest, iterate) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
BpfMap<uint32_t, uint32_t> testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
populateMap(TEST_MAP_SIZE, testMap);
int totalCount = 0;
@@ -197,8 +181,6 @@
}
TEST_F(BpfMapTest, iterateWithValue) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
BpfMap<uint32_t, uint32_t> testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
populateMap(TEST_MAP_SIZE, testMap);
int totalCount = 0;
@@ -219,8 +201,6 @@
}
TEST_F(BpfMapTest, mapIsEmpty) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
BpfMap<uint32_t, uint32_t> testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
expectMapEmpty(testMap);
uint32_t key = TEST_KEY1;
@@ -251,8 +231,6 @@
}
TEST_F(BpfMapTest, mapClear) {
- SKIP_IF_BPF_NOT_SUPPORTED;
-
BpfMap<uint32_t, uint32_t> testMap(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, BPF_F_NO_PREALLOC);
populateMap(TEST_MAP_SIZE, testMap);
Result<bool> isEmpty = testMap.isEmpty();
diff --git a/libbpf_android/BpfUtils.cpp b/libbpf_android/BpfUtils.cpp
index 3b6c764..8689192 100644
--- a/libbpf_android/BpfUtils.cpp
+++ b/libbpf_android/BpfUtils.cpp
@@ -34,7 +34,6 @@
#include <sstream>
#include <string>
-#include <android-base/properties.h>
#include <android-base/unique_fd.h>
#include <log/log.h>
#include <processgroup/processgroup.h>
@@ -95,8 +94,6 @@
return res;
}
-#define KVER(a, b, c) ((a)*65536 + (b)*256 + (c))
-
unsigned kernelVersion() {
struct utsname buf;
int ret = uname(&buf);
@@ -113,52 +110,5 @@
return KVER(kver_major, kver_minor, kver_sub);
}
-std::string BpfLevelToString(BpfLevel bpfLevel) {
- switch (bpfLevel) {
- case BpfLevel::NONE:
- return "None [pre-4.9 or pre-P]";
- case BpfLevel::BASIC_4_9:
- return "Basic [4.9 P+]";
- case BpfLevel::EXTENDED_4_14:
- return "Extended [4.14]";
- case BpfLevel::EXTENDED_4_19:
- return "Extended [4.19]";
- case BpfLevel::EXTENDED_5_4:
- return "Extended [5.4+]";
- // No default statement. We want to see errors of the form:
- // "enumeration value 'BPF_LEVEL_xxx' not handled in switch [-Werror,-Wswitch]".
- }
-}
-
-static BpfLevel getUncachedBpfSupportLevel() {
- unsigned kver = kernelVersion();
-
- 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;
-
- // Override for devices launched with O but now on a 4.9-P+ kernel.
- bool ebpf_supported = base::GetBoolProperty("ro.kernel.ebpf.supported", false);
- if (ebpf_supported) return BpfLevel::BASIC_4_9;
-
- uint64_t api_level = base::GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
- if (api_level == 0) {
- ALOGE("Cannot determine initial API level of the device");
- api_level = base::GetUintProperty<uint64_t>("ro.build.version.sdk", 0);
- }
-
- // Check if the device is shipped originally with android P.
- if (api_level < MINIMUM_API_REQUIRED) return BpfLevel::NONE;
-
- if (kver >= KVER(4, 9, 0)) return BpfLevel::BASIC_4_9;
-
- return BpfLevel::NONE;
-}
-
-BpfLevel getBpfSupportLevel() {
- static BpfLevel cache = getUncachedBpfSupportLevel();
- return cache;
-}
-
} // namespace bpf
} // namespace android
diff --git a/libbpf_android/Loader.cpp b/libbpf_android/Loader.cpp
index 47e6c67..01f8964 100644
--- a/libbpf_android/Loader.cpp
+++ b/libbpf_android/Loader.cpp
@@ -29,7 +29,6 @@
#include <unistd.h>
#include "../progs/include/bpf_map_def.h"
-#include "LoaderUtils.h"
#include "bpf/BpfUtils.h"
#include "include/libbpf_android.h"
@@ -40,7 +39,6 @@
#include <string>
#include <vector>
-#include <android-base/properties.h>
#include <android-base/strings.h>
#include <android-base/unique_fd.h>
@@ -60,6 +58,17 @@
namespace android {
namespace bpf {
+static string pathToFilename(const string& path, bool noext = false) {
+ vector<string> spath = android::base::Split(path, "/");
+ string ret = spath.back();
+
+ if (noext) {
+ size_t lastindex = ret.find_last_of('.');
+ return ret.substr(0, lastindex);
+ }
+ return ret;
+}
+
typedef struct {
const char* name;
enum bpf_prog_type type;
@@ -73,15 +82,16 @@
* is the name of the program, and tracepoint is the type.
*/
sectionType sectionNameTypes[] = {
- {"kprobe", BPF_PROG_TYPE_KPROBE},
- {"tracepoint", BPF_PROG_TYPE_TRACEPOINT},
- {"skfilter", BPF_PROG_TYPE_SOCKET_FILTER},
- {"cgroupskb", BPF_PROG_TYPE_CGROUP_SKB},
- {"schedcls", BPF_PROG_TYPE_SCHED_CLS},
- {"cgroupsock", BPF_PROG_TYPE_CGROUP_SOCK},
+ {"kprobe", BPF_PROG_TYPE_KPROBE},
+ {"tracepoint", BPF_PROG_TYPE_TRACEPOINT},
+ {"skfilter", BPF_PROG_TYPE_SOCKET_FILTER},
+ {"cgroupskb", BPF_PROG_TYPE_CGROUP_SKB},
+ {"schedcls", BPF_PROG_TYPE_SCHED_CLS},
+ {"cgroupsock", BPF_PROG_TYPE_CGROUP_SOCK},
+ {"xdp", BPF_PROG_TYPE_XDP},
- /* End of table */
- {"END", BPF_PROG_TYPE_UNSPEC},
+ /* End of table */
+ {"END", BPF_PROG_TYPE_UNSPEC},
};
typedef struct {
@@ -125,11 +135,8 @@
/* Read a section by its index - for ex to get sec hdr strtab blob */
static int readSectionByIdx(ifstream& elfFile, int id, vector<char>& sec) {
vector<Elf64_Shdr> shTable;
- int entries, ret = 0;
-
- ret = readSectionHeadersAll(elfFile, shTable);
+ int ret = readSectionHeadersAll(elfFile, shTable);
if (ret) return ret;
- entries = shTable.size();
elfFile.seekg(shTable[id].sh_offset);
if (elfFile.fail()) return -1;
@@ -143,9 +150,7 @@
/* Read whole section header string table */
static int readSectionHeaderStrtab(ifstream& elfFile, vector<char>& strtab) {
Elf64_Ehdr eh;
- int ret = 0;
-
- ret = readElfHeader(elfFile, &eh);
+ int ret = readElfHeader(elfFile, &eh);
if (ret) return ret;
ret = readSectionByIdx(elfFile, eh.e_shstrndx, strtab);
@@ -256,7 +261,7 @@
{
for (int i = 0; sectionNameTypes[i].type != BPF_PROG_TYPE_UNSPEC; i++)
if (sectionNameTypes[i].type == type)
- return std::string(sectionNameTypes[i].name);
+ return string(sectionNameTypes[i].name);
return NULL;
}
@@ -268,7 +273,7 @@
if (st.type != cs.type) continue;
- if (StartsWith(name, std::string(".rel") + st.name + "/"))
+ if (StartsWith(name, string(".rel") + st.name + "/"))
return true;
else
return false;
@@ -356,7 +361,10 @@
enum bpf_prog_type ptype = getSectionType(name);
if (ptype != BPF_PROG_TYPE_UNSPEC) {
string oldName = name;
- deslash(name);
+
+ // convert all slashes to underscores
+ std::replace(name.begin(), name.end(), '/', '_');
+
cs_temp.type = ptype;
cs_temp.name = name;
@@ -407,7 +415,8 @@
return getSymName(elfFile, symtab[index].st_name, name);
}
-static int createMaps(const char* elfPath, ifstream& elfFile, vector<unique_fd>& mapFds) {
+static int createMaps(const char* elfPath, ifstream& elfFile, vector<unique_fd>& mapFds,
+ const char* prefix) {
int ret;
vector<char> mdData;
vector<struct bpf_map_def> md;
@@ -425,11 +434,11 @@
for (int i = 0; i < (int)mapNames.size(); i++) {
unique_fd fd;
- // Format of pin location is /sys/fs/bpf/map_<filename>_<mapname>
+ // Format of pin location is /sys/fs/bpf/<prefix>map_<filename>_<mapname>
string mapPinLoc;
bool reuse = false;
- mapPinLoc = string(BPF_FS_PATH) + "map_" + fname + "_" + string(mapNames[i]);
+ mapPinLoc = string(BPF_FS_PATH) + prefix + "map_" + fname + "_" + string(mapNames[i]);
if (access(mapPinLoc.c_str(), F_OK) == 0) {
fd.reset(bpf_obj_get(mapPinLoc.c_str()));
ALOGD("bpf_create_map reusing map %s, ret: %d\n", mapNames[i].c_str(), fd.get());
@@ -531,7 +540,8 @@
}
}
-static int loadCodeSections(const char* elfPath, vector<codeSection>& cs, const string& license) {
+static int loadCodeSections(const char* elfPath, vector<codeSection>& cs, const string& license,
+ const char* prefix) {
unsigned kvers = kernelVersion();
int ret, fd;
@@ -558,8 +568,10 @@
bool reuse = false;
// Format of pin location is
- // /sys/fs/bpf/prog_<filename>_<mapname>
- string progPinLoc = BPF_FS_PATH "prog_";
+ // /sys/fs/bpf/<prefix>prog_<filename>_<mapname>
+ string progPinLoc = BPF_FS_PATH;
+ progPinLoc += prefix;
+ progPinLoc += "prog_";
progPinLoc += fname;
progPinLoc += '_';
progPinLoc += name;
@@ -578,7 +590,7 @@
cs[i].name.c_str(), fd, (fd < 0 ? std::strerror(errno) : "no error"));
if (fd < 0) {
- std::vector<std::string> lines = android::base::Split(log_buf.data(), "\n");
+ vector<string> lines = android::base::Split(log_buf.data(), "\n");
ALOGW("bpf_prog_load - BEGIN log_buf contents:");
for (const auto& line : lines) ALOGW("%s", line.c_str());
@@ -613,7 +625,7 @@
return 0;
}
-int loadProg(const char* elfPath, bool* isCritical) {
+int loadProg(const char* elfPath, bool* isCritical, const char* prefix) {
vector<char> license;
vector<char> critical;
vector<codeSection> cs;
@@ -648,7 +660,7 @@
/* Just for future debugging */
if (0) dumpAllCs(cs);
- ret = createMaps(elfPath, elfFile, mapFds);
+ ret = createMaps(elfPath, elfFile, mapFds, prefix);
if (ret) {
ALOGE("Failed to create maps: (ret=%d) in %s\n", ret, elfPath);
return ret;
@@ -659,28 +671,11 @@
applyMapRelo(elfFile, mapFds, cs);
- ret = loadCodeSections(elfPath, cs, string(license.data()));
+ ret = loadCodeSections(elfPath, cs, string(license.data()), prefix);
if (ret) ALOGE("Failed to load programs, loadCodeSections ret=%d\n", ret);
return ret;
}
-static bool waitSecondsForProgsLoaded(int seconds) {
- bool ok =
- android::base::WaitForProperty("bpf.progs_loaded", "1", std::chrono::seconds(seconds));
- if (!ok) ALOGW("Waited %ds for bpf.progs_loaded, still waiting...", seconds);
- return ok;
-}
-
-void waitForProgsLoaded() {
- if (!android::bpf::isBpfSupported()) return;
-
- if (waitSecondsForProgsLoaded(5)) return;
- if (waitSecondsForProgsLoaded(10)) return;
- if (waitSecondsForProgsLoaded(20)) return;
- while (!waitSecondsForProgsLoaded(60))
- ; // loop until success
-}
-
} // namespace bpf
} // namespace android
diff --git a/libbpf_android/LoaderUtils.h b/libbpf_android/LoaderUtils.h
deleted file mode 100644
index a5ff7fc..0000000
--- a/libbpf_android/LoaderUtils.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <stdio.h>
-#include <iostream>
-#include <string>
-#include <vector>
-
-#include <android-base/strings.h>
-
-static std::string pathToFilename(const std::string& path, bool noext = false) {
- std::vector<std::string> spath = android::base::Split(path, "/");
- std::string ret = spath.back();
-
- if (noext) {
- size_t lastindex = ret.find_last_of('.');
- return ret.substr(0, lastindex);
- }
- return ret;
-}
-
-static void deslash(std::string& s) {
- std::replace(s.begin(), s.end(), '/', '_');
-}
diff --git a/libbpf_android/include/bpf/BpfMap.h b/libbpf_android/include/bpf/BpfMap.h
index 3e7413e..bdffc0f 100644
--- a/libbpf_android/include/bpf/BpfMap.h
+++ b/libbpf_android/include/bpf/BpfMap.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef BPF_BPFMAP_H
-#define BPF_BPFMAP_H
+#pragma once
#include <linux/bpf.h>
@@ -134,10 +133,11 @@
return *this;
}
- // Move constructor
- void operator=(BpfMap<Key, Value>&& other) noexcept {
+ // Move assignment operator
+ BpfMap<Key, Value>& operator=(BpfMap<Key, Value>&& other) noexcept {
mMapFd = std::move(other.mMapFd);
other.reset(-1);
+ return *this;
}
void reset(base::unique_fd fd) = delete;
@@ -258,5 +258,3 @@
} // namespace bpf
} // namespace android
-
-#endif
diff --git a/libbpf_android/include/bpf/BpfUtils.h b/libbpf_android/include/bpf/BpfUtils.h
index 046d80f..9671b8a 100644
--- a/libbpf_android/include/bpf/BpfUtils.h
+++ b/libbpf_android/include/bpf/BpfUtils.h
@@ -14,12 +14,9 @@
* limitations under the License.
*/
-#ifndef BPF_BPFUTILS_H
-#define BPF_BPFUTILS_H
+#pragma once
-#include <linux/bpf.h>
#include <linux/if_ether.h>
-#include <linux/unistd.h>
#include <net/if.h>
#include <stdlib.h>
#include <string.h>
@@ -27,181 +24,44 @@
#include <string>
-#ifdef BPF_FD_JUST_USE_INT
- #define BPF_FD_TYPE int
- #define BPF_FD_TO_U32(x) static_cast<__u32>(x)
-#else
- #include <android-base/unique_fd.h>
- #define BPF_FD_TYPE base::unique_fd&
- #define BPF_FD_TO_U32(x) static_cast<__u32>((x).get())
-#endif
-
-#define ptr_to_u64(x) ((uint64_t)(uintptr_t)(x))
+#include "BpfSyscallWrappers.h"
namespace android {
namespace bpf {
-enum class BpfLevel {
- // Devices shipped before P or kernel version is lower than 4.9 do not
- // have eBPF enabled.
- NONE,
- // Devices shipped in P with android 4.9 kernel only have the basic eBPF
- // functionalities such as xt_bpf and cgroup skb filter.
- BASIC_4_9,
- // For devices that have 4.14 kernel. It supports advanced features like
- // map_in_map and cgroup socket filter.
- EXTENDED_4_14,
- EXTENDED_4_19,
- EXTENDED_5_4,
-};
-
constexpr const int OVERFLOW_COUNTERSET = 2;
constexpr const uint64_t NONEXISTENT_COOKIE = 0;
-constexpr const int MINIMUM_API_REQUIRED = 28;
-
-/* Note: bpf_attr is a union which might have a much larger size then the anonymous struct portion
- * of it that we are using. The kernel's bpf() system call will perform a strict check to ensure
- * all unused portions are zero. It will fail with E2BIG if we don't fully zero bpf_attr.
- */
-
-inline int bpf(int cmd, const bpf_attr& attr) {
- return syscall(__NR_bpf, cmd, &attr, sizeof(attr));
-}
-
-inline int createMap(bpf_map_type map_type, uint32_t key_size, uint32_t value_size,
- uint32_t max_entries, uint32_t map_flags) {
- return bpf(BPF_MAP_CREATE, {
- .map_type = map_type,
- .key_size = key_size,
- .value_size = value_size,
- .max_entries = max_entries,
- .map_flags = map_flags,
- });
-}
-
-inline int writeToMapEntry(const BPF_FD_TYPE map_fd, const void* key, const void* value,
- uint64_t flags) {
- return bpf(BPF_MAP_UPDATE_ELEM, {
- .map_fd = BPF_FD_TO_U32(map_fd),
- .key = ptr_to_u64(key),
- .value = ptr_to_u64(value),
- .flags = flags,
- });
-}
-
-inline int findMapEntry(const BPF_FD_TYPE map_fd, const void* key, void* value) {
- return bpf(BPF_MAP_LOOKUP_ELEM, {
- .map_fd = BPF_FD_TO_U32(map_fd),
- .key = ptr_to_u64(key),
- .value = ptr_to_u64(value),
- });
-}
-
-inline int deleteMapEntry(const BPF_FD_TYPE map_fd, const void* key) {
- return bpf(BPF_MAP_DELETE_ELEM, {
- .map_fd = BPF_FD_TO_U32(map_fd),
- .key = ptr_to_u64(key),
- });
-}
-
-inline int getNextMapKey(const BPF_FD_TYPE map_fd, const void* key, void* next_key) {
- return bpf(BPF_MAP_GET_NEXT_KEY, {
- .map_fd = BPF_FD_TO_U32(map_fd),
- .key = ptr_to_u64(key),
- .next_key = ptr_to_u64(next_key),
- });
-}
-
-inline int getFirstMapKey(const BPF_FD_TYPE map_fd, void* firstKey) {
- return getNextMapKey(map_fd, NULL, firstKey);
-}
-
-inline int bpfFdPin(const BPF_FD_TYPE map_fd, const char* pathname) {
- return bpf(BPF_OBJ_PIN, {
- .pathname = ptr_to_u64(pathname),
- .bpf_fd = BPF_FD_TO_U32(map_fd),
- });
-}
-
-inline int bpfFdGet(const char* pathname, uint32_t flag) {
- return bpf(BPF_OBJ_GET, {
- .pathname = ptr_to_u64(pathname),
- .file_flags = flag,
- });
-}
-
-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 BPF_FD_TYPE prog_fd,
- const BPF_FD_TYPE cg_fd) {
- return bpf(BPF_PROG_ATTACH, {
- .target_fd = BPF_FD_TO_U32(cg_fd),
- .attach_bpf_fd = BPF_FD_TO_U32(prog_fd),
- .attach_type = type,
- });
-}
-
-inline int detachProgram(bpf_attach_type type, const BPF_FD_TYPE cg_fd) {
- return bpf(BPF_PROG_DETACH, {
- .target_fd = BPF_FD_TO_U32(cg_fd),
- .attach_type = type,
- });
-}
-
uint64_t getSocketCookie(int sockFd);
int synchronizeKernelRCU();
int setrlimitForTest();
-unsigned kernelVersion();
-std::string BpfLevelToString(BpfLevel BpfLevel);
-BpfLevel getBpfSupportLevel();
-inline bool isBpfSupported() {
- return getBpfSupportLevel() != BpfLevel::NONE;
+#define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c))
+
+unsigned kernelVersion();
+
+static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsigned sub) {
+ return kernelVersion() >= KVER(major, minor, sub);
}
-#define SKIP_IF_BPF_NOT_SUPPORTED \
- do { \
- if (!android::bpf::isBpfSupported()) { \
- GTEST_LOG_(INFO) << "This test is skipped since bpf is not available\n"; \
- return; \
- } \
+#define SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED \
+ do { \
+ if (!android::bpf::isAtLeastKernelVersion(4, 14, 0)) { \
+ GTEST_LOG_(INFO) << "This test is skipped since extended bpf feature" \
+ << "not supported\n"; \
+ return; \
+ } \
} while (0)
-#define SKIP_IF_BPF_SUPPORTED \
- do { \
- if (android::bpf::isBpfSupported()) return; \
- } while (0)
-
-#define SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED \
- do { \
- if (android::bpf::getBpfSupportLevel() < android::bpf::BpfLevel::EXTENDED_4_14) { \
- GTEST_LOG_(INFO) << "This test is skipped since extended bpf feature" \
- << "not supported\n"; \
- return; \
- } \
+#define SKIP_IF_XDP_NOT_SUPPORTED \
+ do { \
+ if (!android::bpf::isAtLeastKernelVersion(5, 9, 0)) { \
+ GTEST_LOG_(INFO) << "This test is skipped since xdp" \
+ << "not supported\n"; \
+ return; \
+ } \
} while (0)
} // namespace bpf
} // namespace android
-
-#endif
diff --git a/libbpf_android/include/libbpf_android.h b/libbpf_android/include/libbpf_android.h
index 3810d07..90c9906 100644
--- a/libbpf_android/include/libbpf_android.h
+++ b/libbpf_android/include/libbpf_android.h
@@ -15,22 +15,30 @@
* limitations under the License.
*/
-#ifndef LIBBPF_SYSTEM_H
-#define LIBBPF_SYSTEM_H
+#pragma once
#include <libbpf.h>
#include <linux/bpf.h>
+#include <log/log.h>
+
+#include <android-base/properties.h>
namespace android {
namespace bpf {
// BPF loader implementation. Loads an eBPF ELF object
-int loadProg(const char* elfPath, bool* isCritical);
+int loadProg(const char* elfPath, bool* isCritical, const char* prefix = "");
// Wait for bpfloader to load BPF programs.
-void waitForProgsLoaded();
+static inline void waitForProgsLoaded() {
+ // infinite loop until success with 5/10/20/40/60/60/60... delay
+ for (int delay = 5;; delay *= 2) {
+ if (delay > 60) delay = 60;
+ if (android::base::WaitForProperty("bpf.progs_loaded", "1", std::chrono::seconds(delay)))
+ return;
+ ALOGW("Waited %ds for bpf.progs_loaded, still waiting...", delay);
+ }
+}
} // namespace bpf
} // namespace android
-
-#endif
diff --git a/progs/Android.bp b/progs/Android.bp
index 37feafd..aeb04a7 100644
--- a/progs/Android.bp
+++ b/progs/Android.bp
@@ -14,6 +14,14 @@
// limitations under the License.
//
+package {
+ // http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // the below license kinds from "system_bpf_license":
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["system_bpf_license"],
+}
+
cc_library_headers {
name: "bpf_prog_headers",
export_include_dirs: ["include"],
diff --git a/progs/include/bpf_helpers.h b/progs/include/bpf_helpers.h
index 9d22584..075ea94 100644
--- a/progs/include/bpf_helpers.h
+++ b/progs/include/bpf_helpers.h
@@ -47,18 +47,18 @@
* This will make sure that if you change the type of a map you'll get compile
* errors at any spots you forget to update with the new type.
*
- * Note: these all take 'const void* map' because from the C/eBPF point of view
+ * Note: these all take pointers to const map because from the C/eBPF point of view
* the map struct is really just a readonly map definition of the in kernel object.
* Runtime modification of the map defining struct is meaningless, since
* the contents is only ever used during bpf program loading & map creation
* by the bpf loader, and not by the eBPF program itself.
*/
-static void* (*bpf_map_lookup_elem_unsafe)(const void* map,
+static void* (*bpf_map_lookup_elem_unsafe)(const struct bpf_map_def* map,
const void* key) = (void*)BPF_FUNC_map_lookup_elem;
-static int (*bpf_map_update_elem_unsafe)(const void* map, const void* key, const void* value,
- unsigned long long flags) = (void*)
+static int (*bpf_map_update_elem_unsafe)(const struct bpf_map_def* map, const void* key,
+ const void* value, unsigned long long flags) = (void*)
BPF_FUNC_map_update_elem;
-static int (*bpf_map_delete_elem_unsafe)(const void* map,
+static int (*bpf_map_delete_elem_unsafe)(const struct bpf_map_def* map,
const void* key) = (void*)BPF_FUNC_map_delete_elem;
/* type safe macro to declare a map and related accessor functions */
@@ -102,13 +102,14 @@
static int (*bpf_probe_read)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read;
static int (*bpf_probe_read_str)(void* dst, int size, void* unsafe_ptr) = (void*) BPF_FUNC_probe_read_str;
static unsigned long long (*bpf_ktime_get_ns)(void) = (void*) BPF_FUNC_ktime_get_ns;
+static unsigned long long (*bpf_ktime_get_boot_ns)(void) = (void*)BPF_FUNC_ktime_get_boot_ns;
static int (*bpf_trace_printk)(const char* fmt, int fmt_size, ...) = (void*) BPF_FUNC_trace_printk;
static unsigned long long (*bpf_get_current_pid_tgid)(void) = (void*) BPF_FUNC_get_current_pid_tgid;
static unsigned long long (*bpf_get_current_uid_gid)(void) = (void*) BPF_FUNC_get_current_uid_gid;
static unsigned long long (*bpf_get_smp_processor_id)(void) = (void*) BPF_FUNC_get_smp_processor_id;
#define KVER_NONE 0
-#define KVER(a, b, c) ((a)*65536 + (b)*256 + (c))
+#define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c))
#define KVER_INF 0xFFFFFFFF
#define DEFINE_BPF_PROG_KVER_RANGE_OPT(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, max_kv, \
diff --git a/progs/include/bpf_timeinstate.h b/progs/include/bpf_timeinstate.h
index 7cb7baa..1065b6e 100644
--- a/progs/include/bpf_timeinstate.h
+++ b/progs/include/bpf_timeinstate.h
@@ -19,6 +19,10 @@
#define BPF_FS_PATH "/sys/fs/bpf/"
+// Number of frequencies tracked in the array with total time. If some CPUs have
+// more than 64 freqs
+// // available, the overflow is stored in the last entry.
+#define MAX_FREQS_FOR_TOTAL 64
// Number of frequencies for which a UID's times can be tracked in a single map entry. If some CPUs
// have more than 32 freqs available, a single UID is tracked using 2 or more entries.
#define FREQS_PER_ENTRY 32