BpfLoader v0.25 - add support for obj@ver.o
This allows for 2 different versions of obj.o to be
shipped simultaneously (via mainline module),
with different bpfloader version limitations.
For example a obj.o for bpfloader < 0.25 and a
obj@25.o for bpfloader 0.25+. These can provide
for different implementations of maps/programs,
while still being pinned into the same ultimate
destination in /sys/fs/bpf/.../{map,prog}_obj_...
so as to not require special selection of appropriate
program/map path names in higher level code
(at least for common functionality).
When using this functionality one does have to be
careful to not end up with unintentional duplication
(ie. an obj@1.o and obj@2.o that both load on bpfloader
version X), and to make sure that the defined
bpf maps and programs with identical names
are also sufficiently identical in behaviour.
In practice it is likely that all versions of obj@ver.o
will be built from the same source code, with compilation
controlled by appropriate preprocessor conditional macros,
to hide certain parts of obj.c while building the version
for older bpfloader...
However, exactly how to use this is ultimately
left up to the future...
Multiple viable mechanisms exist:
(a) each obj@ver.o is standalone, only one should be loaded,
bpfloader min/max version annotations would be used
to guarantee this, making sure that programs/maps that
exist in multiple versions of obj.o should have matching
types and behaviours, but nothing guarantees this
(although key/value size checks will certainly help)
(b) obj.o is baseline and always loaded,
while obj@25.o is an extension with extra maps/programs
and is loaded on only newer bpfloaders,
it may have duplicate defines of shared maps
(likely via #include of some shared header file)
if some of the extra programs also need some of
the data from maps from the 'older' obj.o
(c) variously complex combinations of (a) and (b) are also possible
Bug: 218408035
Test: TreeHugger, manually with offload@1.o in p/m/C
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: Ib60d07b18fd6617d456c2c469f8e8ed166aadffd
diff --git a/libbpf_android/Loader.cpp b/libbpf_android/Loader.cpp
index c49a65b..bb816fd 100644
--- a/libbpf_android/Loader.cpp
+++ b/libbpf_android/Loader.cpp
@@ -30,9 +30,9 @@
#include <sys/wait.h>
#include <unistd.h>
-// This is BpfLoader v0.24
+// This is BpfLoader v0.25
#define BPFLOADER_VERSION_MAJOR 0u
-#define BPFLOADER_VERSION_MINOR 24u
+#define BPFLOADER_VERSION_MINOR 25u
#define BPFLOADER_VERSION ((BPFLOADER_VERSION_MAJOR << 16) | BPFLOADER_VERSION_MINOR)
#include "bpf/BpfUtils.h"
@@ -135,15 +135,14 @@
return domain::unrecognized;
}
-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;
+static string pathToObjName(const string& path) {
+ // extract everything after the final slash, ie. this is the filename 'foo@1.o' or 'bar.o'
+ string filename = android::base::Split(path, "/").back();
+ // strip off everything from the final period onwards (strip '.o' suffix), ie. 'foo@1' or 'bar'
+ string name = filename.substr(0, filename.find_last_of('.'));
+ // strip any potential @1 suffix, this will leave us with just 'foo' or 'bar'
+ // this can be used to provide duplicate programs (mux based on the bpfloader version)
+ return name.substr(0, name.find_last_of('@'));
}
typedef struct {
@@ -695,7 +694,7 @@
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);
+ string objName = pathToObjName(string(elfPath));
ret = readSectionByName("maps", elfFile, mdData);
if (ret == -2) return 0; // no maps to read
@@ -812,11 +811,11 @@
pin_subdir, lookupPinSubdir(pin_subdir));
}
- // Format of pin location is /sys/fs/bpf/<pin_subdir|prefix>map_<filename>_<mapname>
- // except that maps shared across .o's have empty <filename>
- // Note: <filename> refers to the extension-less basename of the .o file.
+ // Format of pin location is /sys/fs/bpf/<pin_subdir|prefix>map_<objName>_<mapName>
+ // except that maps shared across .o's have empty <objName>
+ // Note: <objName> refers to the extension-less basename of the .o file (without @ suffix).
string mapPinLoc = string(BPF_FS_PATH) + lookupPinSubdir(pin_subdir, prefix) + "map_" +
- (md[i].shared ? "" : fname) + "_" + mapNames[i];
+ (md[i].shared ? "" : objName) + "_" + mapNames[i];
bool reuse = false;
unique_fd fd;
int saved_errno;
@@ -855,7 +854,7 @@
if (!reuse) {
if (specified(selinux_context)) {
string createLoc = string(BPF_FS_PATH) + lookupPinSubdir(selinux_context) +
- "tmp_map_" + fname + "_" + mapNames[i];
+ "tmp_map_" + objName + "_" + mapNames[i];
ret = bpf_obj_pin(fd, createLoc.c_str());
if (ret) {
int err = errno;
@@ -988,7 +987,7 @@
if (!kvers) return -1;
- string fname = pathToFilename(string(elfPath), true);
+ string objName = pathToObjName(string(elfPath));
for (int i = 0; i < (int)cs.size(); i++) {
string name = cs[i].name;
@@ -1047,9 +1046,9 @@
bool reuse = false;
// Format of pin location is
- // /sys/fs/bpf/<prefix>prog_<filename>_<mapname>
+ // /sys/fs/bpf/<prefix>prog_<objName>_<progName>
string progPinLoc = string(BPF_FS_PATH) + lookupPinSubdir(pin_subdir, prefix) + "prog_" +
- fname + '_' + string(name);
+ objName + '_' + string(name);
if (access(progPinLoc.c_str(), F_OK) == 0) {
fd = retrieveProgram(progPinLoc.c_str());
ALOGD("New bpf prog load reusing prog %s, ret: %d (%s)", progPinLoc.c_str(), fd,
@@ -1094,7 +1093,7 @@
if (!reuse) {
if (specified(selinux_context)) {
string createLoc = string(BPF_FS_PATH) + lookupPinSubdir(selinux_context) +
- "tmp_prog_" + fname + '_' + string(name);
+ "tmp_prog_" + objName + '_' + string(name);
ret = bpf_obj_pin(fd, createLoc.c_str());
if (ret) {
int err = errno;