From 0b477491fb95c04d908ef83d683c42db9102cf40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 4 Mar 2025 22:12:42 -0800 Subject: [PATCH] bpf: switch to mainline netbpfload on Android S/SV2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Test: TreeHugger, manually installing tethering apex (with and without dnsresolver apex) on pixel 6 running S incl. 'atest bpf_existence_test' Signed-off-by: Maciej Żenczykowski Change-Id: I63d4b84287e9c98dc0d2a517ac58d3f3ce9d7760 --- Tethering/apex/Android.bp | 3 +- bpf/dns_helper/DnsBpfHelper.cpp | 36 ++++++++++++++++++++-- bpf/loader/Android.bp | 13 +++++++- bpf/loader/NetBpfLoad.cpp | 46 +++++++++++++++++++--------- bpf/loader/netbpfload.31rc | 13 ++++++++ bpf/progs/Android.bp | 20 ++---------- bpf/progs/offload.c | 12 ++------ bpf/progs/test.c | 12 ++------ bpf/tests/mts/bpf_existence_test.cpp | 7 ++++- 9 files changed, 103 insertions(+), 59 deletions(-) create mode 100644 bpf/loader/netbpfload.31rc diff --git a/Tethering/apex/Android.bp b/Tethering/apex/Android.bp index 19dd492b67..2878f79458 100644 --- a/Tethering/apex/Android.bp +++ b/Tethering/apex/Android.bp @@ -102,15 +102,14 @@ apex { "dscpPolicy.o", "netd.o", "offload.o", - "offload@mainline.o", "test.o", - "test@mainline.o", ], apps: [ "ServiceConnectivityResources", ], prebuilts: [ "current_sdkinfo", + "netbpfload.31rc", "netbpfload.33rc", "netbpfload.35rc", "ot-daemon.34rc", diff --git a/bpf/dns_helper/DnsBpfHelper.cpp b/bpf/dns_helper/DnsBpfHelper.cpp index 0719ade395..cf2fa2b736 100644 --- a/bpf/dns_helper/DnsBpfHelper.cpp +++ b/bpf/dns_helper/DnsBpfHelper.cpp @@ -32,12 +32,44 @@ namespace net { } \ } while (0) +// copied from BpfHandler.cpp +static bool mainlineNetBpfLoadDone() { + return !access("/sys/fs/bpf/netd_shared/mainline_done", F_OK); +} + +// copied from BpfHandler.cpp +static inline void waitForNetProgsLoaded() { + // 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 (base::WaitForProperty("init.svc.mdnsd_netbpfload", "stopped", std::chrono::seconds(delay)) + && mainlineNetBpfLoadDone()) return; + LOG(WARNING) << "Waited " << delay << "s for init.svc.mdnsd_netbpfload=stopped, still waiting."; + } +} + base::Result DnsBpfHelper::init() { - if (!android::modules::sdklevel::IsAtLeastT()) { - LOG(ERROR) << __func__ << ": Unsupported before Android T."; + if (!android::modules::sdklevel::IsAtLeastS()) { + LOG(ERROR) << __func__ << ": Unsupported before Android S."; return base::Error(EOPNOTSUPP); } + if (!android::modules::sdklevel::IsAtLeastT()) { + LOG(INFO) << "performing Android S mainline NetBpfload magic!"; + if (!mainlineNetBpfLoadDone()) { + // We're on S/Sv2 & it's the first time netd is starting up (unless crashlooping) + if (!base::SetProperty("ctl.start", "mdnsd_netbpfload")) { + LOG(ERROR) << "Failed to set property ctl.start=mdnsd_netbpfload, see dmesg for reason."; + return base::Error(ENOEXEC); + } + + LOG(INFO) << "Waiting for Networking BPF programs"; + waitForNetProgsLoaded(); + LOG(INFO) << "Networking BPF programs are loaded"; + } + return {}; + } + RETURN_IF_RESULT_NOT_OK(mConfigurationMap.init(CONFIGURATION_MAP_PATH)); RETURN_IF_RESULT_NOT_OK(mUidOwnerMap.init(UID_OWNER_MAP_PATH)); RETURN_IF_RESULT_NOT_OK(mDataSaverEnabledMap.init(DATA_SAVER_ENABLED_MAP_PATH)); diff --git a/bpf/loader/Android.bp b/bpf/loader/Android.bp index b08913a2c5..780fe20d84 100644 --- a/bpf/loader/Android.bp +++ b/bpf/loader/Android.bp @@ -56,11 +56,22 @@ cc_binary { installable: false, } -// Versioned netbpfload init rc: init system will process it only on api T/33+ devices +// Versioned netbpfload init rc: init system will process it only on api R/30 S/31 Sv2/32 devices // Note: R[30] S[31] Sv2[32] T[33] U[34] V[35]) // // For details of versioned rc files see: // https://android.googlesource.com/platform/system/core/+/HEAD/init/README.md#versioned-rc-files-within-apexs +// +// However, .Xrc versioning doesn't work on S, so we use unversioned, and thus *do* trigger on R, +// luckily nothing ever uses the new service on R, so you can think of it as being S/Sv2 only +prebuilt_etc { + name: "netbpfload.31rc", + src: "netbpfload.31rc", + filename: "netbpfload.rc", // intentional: .31rc wouldn't take effect on S + installable: false, +} + +// Versioned netbpfload init rc: init system will process it only on api T/33+ devices prebuilt_etc { name: "netbpfload.33rc", src: "netbpfload.33rc", diff --git a/bpf/loader/NetBpfLoad.cpp b/bpf/loader/NetBpfLoad.cpp index 9c62e7440f..bad506f7c0 100644 --- a/bpf/loader/NetBpfLoad.cpp +++ b/bpf/loader/NetBpfLoad.cpp @@ -122,6 +122,7 @@ static constexpr bool specified(domain d) { struct Location { const char* const dir = ""; const char* const prefix = ""; + const bool t_plus = true; }; // Returns the build type string (from ro.build.type). @@ -1216,8 +1217,9 @@ static bool exists(const char* const path) { const Location locations[] = { // S+ Tethering mainline module (network_stack): tether offload { - .dir = BPFROOT "/", + .dir = BPFROOT "/tethering/", .prefix = "tethering/", + .t_plus = false, }, // T+ Tethering mainline module (shared with netd & system server) // netutils_wrapper (for iptables xt_bpf) has access to programs @@ -1412,6 +1414,13 @@ static bool isWear() { } static int doLoad(char** argv, char * const envp[]) { + if (!isAtLeastS) { + ALOGE("Impossible - not reachable on Android