Merge "Merge Android 14 QPR3 to AOSP main" into main
diff --git a/Tethering/apex/Android.bp b/Tethering/apex/Android.bp
index 8ed5ac0..8a5d249 100644
--- a/Tethering/apex/Android.bp
+++ b/Tethering/apex/Android.bp
@@ -101,6 +101,7 @@
"block.o",
"clatd.o",
"dscpPolicy.o",
+ "gentle.o",
"netd.o",
"offload.o",
"offload@mainline.o",
diff --git a/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java b/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java
index f8aa69f..47aebe8 100644
--- a/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java
+++ b/Tethering/tests/privileged/src/com/android/networkstack/tethering/BpfMapTest.java
@@ -69,6 +69,10 @@
private static final int TEST_MAP_SIZE = 16;
private static final String TETHER_DOWNSTREAM6_FS_PATH =
"/sys/fs/bpf/tethering/map_test_tether_downstream6_map";
+ private static final String TETHER2_DOWNSTREAM6_FS_PATH =
+ "/sys/fs/bpf/tethering/map_test_tether2_downstream6_map";
+ private static final String TETHER3_DOWNSTREAM6_FS_PATH =
+ "/sys/fs/bpf/tethering/map_test_tether3_downstream6_map";
private ArrayMap<TetherDownstream6Key, Tether6Value> mTestData;
@@ -108,8 +112,8 @@
private BpfMap<TetherDownstream6Key, Tether6Value> openTestMap() throws Exception {
return mShouldTestSingleWriterMap
- ? new SingleWriterBpfMap<>(TETHER_DOWNSTREAM6_FS_PATH, TetherDownstream6Key.class,
- Tether6Value.class)
+ ? SingleWriterBpfMap.getSingleton(TETHER2_DOWNSTREAM6_FS_PATH,
+ TetherDownstream6Key.class, Tether6Value.class)
: new BpfMap<>(TETHER_DOWNSTREAM6_FS_PATH, TetherDownstream6Key.class,
Tether6Value.class);
}
@@ -154,7 +158,7 @@
assertEquals(OsConstants.EPERM, expected.errno);
}
}
- try (BpfMap writeOnlyMap = new BpfMap<>(TETHER_DOWNSTREAM6_FS_PATH, BpfMap.BPF_F_WRONLY,
+ try (BpfMap writeOnlyMap = new BpfMap<>(TETHER3_DOWNSTREAM6_FS_PATH, BpfMap.BPF_F_WRONLY,
TetherDownstream6Key.class, Tether6Value.class)) {
assertNotNull(writeOnlyMap);
try {
@@ -506,12 +510,6 @@
@Test
public void testSingleWriterCacheEffectiveness() throws Exception {
assumeTrue(mShouldTestSingleWriterMap);
-
- // Ensure the map is not empty.
- for (int i = 0; i < mTestData.size(); i++) {
- mTestMap.insertEntry(mTestData.keyAt(i), mTestData.valueAt(i));
- }
-
// Benchmark parameters.
final int timeoutMs = 5_000; // Only hit if threads don't complete.
final int benchmarkTimeMs = 2_000;
@@ -520,11 +518,17 @@
// Only require 3x to reduce test flakiness.
final int expectedSpeedup = 3;
- final BpfMap cachedMap = new SingleWriterBpfMap(TETHER_DOWNSTREAM6_FS_PATH,
+ final BpfMap cachedMap = SingleWriterBpfMap.getSingleton(TETHER2_DOWNSTREAM6_FS_PATH,
TetherDownstream6Key.class, Tether6Value.class);
final BpfMap uncachedMap = new BpfMap(TETHER_DOWNSTREAM6_FS_PATH,
TetherDownstream6Key.class, Tether6Value.class);
+ // Ensure the maps are not empty.
+ for (int i = 0; i < mTestData.size(); i++) {
+ cachedMap.insertEntry(mTestData.keyAt(i), mTestData.valueAt(i));
+ uncachedMap.insertEntry(mTestData.keyAt(i), mTestData.valueAt(i));
+ }
+
final CompletableFuture<Integer> cachedResult = new CompletableFuture<>();
final CompletableFuture<Integer> uncachedResult = new CompletableFuture<>();
diff --git a/bpf_progs/Android.bp b/bpf_progs/Android.bp
index 1958aa8..9e67415 100644
--- a/bpf_progs/Android.bp
+++ b/bpf_progs/Android.bp
@@ -85,6 +85,16 @@
}
bpf {
+ name: "gentle.o",
+ srcs: ["gentle.c"],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
+ sub_dir: "net_shared",
+}
+
+bpf {
name: "offload.o",
srcs: ["offload.c"],
cflags: [
diff --git a/bpf_progs/block.c b/bpf_progs/block.c
index 152dda6..353525e 100644
--- a/bpf_progs/block.c
+++ b/bpf_progs/block.c
@@ -20,7 +20,7 @@
#include <stdint.h>
// The resulting .o needs to load on Android T+
-#define BPFLOADER_MIN_VER BPFLOADER_MAINLINE_T_VERSION
+#define BPFLOADER_MIN_VER BPFLOADER_T_VERSION
#include "bpf_helpers.h"
@@ -76,3 +76,4 @@
LICENSE("Apache 2.0");
CRITICAL("ConnectivityNative");
DISABLE_BTF_ON_USER_BUILDS();
+DISABLE_ON_MAINLINE_BEFORE_U_QPR3();
diff --git a/bpf_progs/bpf_net_helpers.h b/bpf_progs/bpf_net_helpers.h
index f3c7de5..1511ee5 100644
--- a/bpf_progs/bpf_net_helpers.h
+++ b/bpf_progs/bpf_net_helpers.h
@@ -35,6 +35,7 @@
// this returns 0 iff skb->sk is NULL
static uint64_t (*bpf_get_socket_cookie)(struct __sk_buff* skb) = (void*)BPF_FUNC_get_socket_cookie;
+static uint64_t (*bpf_get_sk_cookie)(struct bpf_sock* sk) = (void*)BPF_FUNC_get_socket_cookie;
static uint32_t (*bpf_get_socket_uid)(struct __sk_buff* skb) = (void*)BPF_FUNC_get_socket_uid;
diff --git a/bpf_progs/clatd.c b/bpf_progs/clatd.c
index f83e5ae..95e9a4c 100644
--- a/bpf_progs/clatd.c
+++ b/bpf_progs/clatd.c
@@ -31,7 +31,7 @@
#include <linux/udp.h>
// The resulting .o needs to load on Android T+
-#define BPFLOADER_MIN_VER BPFLOADER_MAINLINE_T_VERSION
+#define BPFLOADER_MIN_VER BPFLOADER_T_VERSION
#include "bpf_helpers.h"
#include "bpf_net_helpers.h"
@@ -431,3 +431,4 @@
LICENSE("Apache 2.0");
CRITICAL("Connectivity");
DISABLE_BTF_ON_USER_BUILDS();
+DISABLE_ON_MAINLINE_BEFORE_U_QPR3();
diff --git a/bpf_progs/dscpPolicy.c b/bpf_progs/dscpPolicy.c
index ed114e4..8bb8ad5 100644
--- a/bpf_progs/dscpPolicy.c
+++ b/bpf_progs/dscpPolicy.c
@@ -28,7 +28,7 @@
#include <string.h>
// The resulting .o needs to load on Android T+
-#define BPFLOADER_MIN_VER BPFLOADER_MAINLINE_T_VERSION
+#define BPFLOADER_MIN_VER BPFLOADER_T_VERSION
#include "bpf_helpers.h"
#include "dscpPolicy.h"
@@ -239,3 +239,4 @@
LICENSE("Apache 2.0");
CRITICAL("Connectivity");
DISABLE_BTF_ON_USER_BUILDS();
+DISABLE_ON_MAINLINE_BEFORE_U_QPR3();
diff --git a/bpf_progs/gentle.c b/bpf_progs/gentle.c
new file mode 100644
index 0000000..ab9620e
--- /dev/null
+++ b/bpf_progs/gentle.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 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.
+ */
+
+#define BPFLOADER_MIN_VER BPFLOADER_MAINLINE_T_VERSION
+
+#include "bpf_helpers.h"
+#include "bpf_net_helpers.h"
+
+DEFINE_BPF_MAP_GRW(test, ARRAY, int, uint64_t, 1, AID_SYSTEM)
+
+DEFINE_BPF_PROG("skfilter/accept", AID_ROOT, AID_SYSTEM, accept)
+(struct __sk_buff *skb) {
+ return 1;
+}
+
+LICENSE("Apache 2.0");
+DISABLE_BTF_ON_USER_BUILDS();
diff --git a/bpf_progs/netd.c b/bpf_progs/netd.c
index c3acaad..c520c3c 100644
--- a/bpf_progs/netd.c
+++ b/bpf_progs/netd.c
@@ -15,7 +15,7 @@
*/
// The resulting .o needs to load on Android T+
-#define BPFLOADER_MIN_VER BPFLOADER_MAINLINE_T_VERSION
+#define BPFLOADER_MIN_VER BPFLOADER_T_VERSION
#include <bpf_helpers.h>
#include <linux/bpf.h>
@@ -97,19 +97,22 @@
DEFINE_BPF_MAP_NO_NETD(ingress_discard_map, HASH, IngressDiscardKey, IngressDiscardValue,
INGRESS_DISCARD_MAP_SIZE)
+DEFINE_BPF_MAP_RW_NETD(lock_array_test_map, ARRAY, uint32_t, bool, 1)
+DEFINE_BPF_MAP_RW_NETD(lock_hash_test_map, HASH, uint32_t, bool, 1)
+
/* never actually used from ebpf */
DEFINE_BPF_MAP_NO_NETD(iface_index_name_map, HASH, uint32_t, IfaceValue, IFACE_INDEX_NAME_MAP_SIZE)
// A single-element configuration array, packet tracing is enabled when 'true'.
DEFINE_BPF_MAP_EXT(packet_trace_enabled_map, ARRAY, uint32_t, bool, 1,
AID_ROOT, AID_SYSTEM, 0060, "fs_bpf_net_shared", "", PRIVATE,
- BPFLOADER_MAINLINE_U_VERSION, BPFLOADER_MAX_VER, LOAD_ON_ENG,
+ BPFLOADER_U_VERSION, BPFLOADER_MAX_VER, LOAD_ON_ENG,
LOAD_ON_USER, LOAD_ON_USERDEBUG)
// A ring buffer on which packet information is pushed.
DEFINE_BPF_RINGBUF_EXT(packet_trace_ringbuf, PacketTrace, PACKET_TRACE_BUF_SIZE,
AID_ROOT, AID_SYSTEM, 0060, "fs_bpf_net_shared", "", PRIVATE,
- BPFLOADER_MAINLINE_U_VERSION, BPFLOADER_MAX_VER, LOAD_ON_ENG,
+ BPFLOADER_U_VERSION, BPFLOADER_MAX_VER, LOAD_ON_ENG,
LOAD_ON_USER, LOAD_ON_USERDEBUG);
DEFINE_BPF_MAP_RO_NETD(data_saver_enabled_map, ARRAY, uint32_t, bool,
@@ -139,6 +142,11 @@
#define DEFINE_NETD_BPF_PROG(SECTION_NAME, prog_uid, prog_gid, the_prog) \
DEFINE_NETD_BPF_PROG_KVER(SECTION_NAME, prog_uid, prog_gid, the_prog, KVER_NONE)
+#define DEFINE_NETD_V_BPF_PROG_KVER(SECTION_NAME, prog_uid, prog_gid, the_prog, minKV) \
+ DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, minKV, \
+ KVER_INF, BPFLOADER_MAINLINE_V_VERSION, BPFLOADER_MAX_VER, MANDATORY, \
+ "fs_bpf_netd_readonly", "", LOAD_ON_ENG, LOAD_ON_USER, LOAD_ON_USERDEBUG)
+
// programs that only need to be usable by the system server
#define DEFINE_SYS_BPF_PROG(SECTION_NAME, prog_uid, prog_gid, the_prog) \
DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, KVER_NONE, KVER_INF, \
@@ -519,7 +527,7 @@
// This program is optional, and enables tracing on Android U+, 5.8+ on user builds.
DEFINE_BPF_PROG_EXT("cgroupskb/ingress/stats$trace_user", AID_ROOT, AID_SYSTEM,
bpf_cgroup_ingress_trace_user, KVER_5_8, KVER_INF,
- BPFLOADER_MAINLINE_U_VERSION, BPFLOADER_MAX_VER, OPTIONAL,
+ BPFLOADER_U_VERSION, BPFLOADER_MAX_VER, OPTIONAL,
"fs_bpf_netd_readonly", "",
IGNORE_ON_ENG, LOAD_ON_USER, IGNORE_ON_USERDEBUG)
(struct __sk_buff* skb) {
@@ -529,7 +537,7 @@
// This program is required, and enables tracing on Android U+, 5.8+, userdebug/eng.
DEFINE_BPF_PROG_EXT("cgroupskb/ingress/stats$trace", AID_ROOT, AID_SYSTEM,
bpf_cgroup_ingress_trace, KVER_5_8, KVER_INF,
- BPFLOADER_MAINLINE_U_VERSION, BPFLOADER_MAX_VER, MANDATORY,
+ BPFLOADER_U_VERSION, BPFLOADER_MAX_VER, MANDATORY,
"fs_bpf_netd_readonly", "",
LOAD_ON_ENG, IGNORE_ON_USER, LOAD_ON_USERDEBUG)
(struct __sk_buff* skb) {
@@ -551,7 +559,7 @@
// This program is optional, and enables tracing on Android U+, 5.8+ on user builds.
DEFINE_BPF_PROG_EXT("cgroupskb/egress/stats$trace_user", AID_ROOT, AID_SYSTEM,
bpf_cgroup_egress_trace_user, KVER_5_8, KVER_INF,
- BPFLOADER_MAINLINE_U_VERSION, BPFLOADER_MAX_VER, OPTIONAL,
+ BPFLOADER_U_VERSION, BPFLOADER_MAX_VER, OPTIONAL,
"fs_bpf_netd_readonly", "",
IGNORE_ON_ENG, LOAD_ON_USER, IGNORE_ON_USERDEBUG)
(struct __sk_buff* skb) {
@@ -561,7 +569,7 @@
// This program is required, and enables tracing on Android U+, 5.8+, userdebug/eng.
DEFINE_BPF_PROG_EXT("cgroupskb/egress/stats$trace", AID_ROOT, AID_SYSTEM,
bpf_cgroup_egress_trace, KVER_5_8, KVER_INF,
- BPFLOADER_MAINLINE_U_VERSION, BPFLOADER_MAX_VER, MANDATORY,
+ BPFLOADER_U_VERSION, BPFLOADER_MAX_VER, MANDATORY,
"fs_bpf_netd_readonly", "",
LOAD_ON_ENG, IGNORE_ON_USER, LOAD_ON_USERDEBUG)
(struct __sk_buff* skb) {
@@ -666,13 +674,81 @@
return permissions ? *permissions : BPF_PERMISSION_INTERNET;
}
-DEFINE_NETD_BPF_PROG_KVER("cgroupsock/inet/create", AID_ROOT, AID_ROOT, inet_socket_create,
+DEFINE_NETD_BPF_PROG_KVER("cgroupsock/inet_create", AID_ROOT, AID_ROOT, inet_socket_create,
KVER_4_14)
(struct bpf_sock* sk) {
// A return value of 1 means allow, everything else means deny.
return (get_app_permissions() & BPF_PERMISSION_INTERNET) ? 1 : 0;
}
+DEFINE_NETD_V_BPF_PROG_KVER("cgroupsockrelease/inet_release", AID_ROOT, AID_ROOT,
+ inet_socket_release, KVER_5_15)
+(struct bpf_sock* sk) {
+ uint64_t cookie = bpf_get_sk_cookie(sk);
+ if (cookie) bpf_cookie_tag_map_delete_elem(&cookie);
+
+ return 1;
+}
+
+static __always_inline inline int check_localhost(struct bpf_sock_addr *ctx) {
+ // See include/uapi/linux/bpf.h:
+ //
+ // struct bpf_sock_addr {
+ // __u32 user_family; // R: 4 byte
+ // __u32 user_ip4; // BE, R: 1,2,4-byte, W: 4-byte
+ // __u32 user_ip6[4]; // BE, R: 1,2,4,8-byte, W: 4,8-byte
+ // __u32 user_port; // BE, R: 1,2,4-byte, W: 4-byte
+ // __u32 family; // R: 4 byte
+ // __u32 type; // R: 4 byte
+ // __u32 protocol; // R: 4 byte
+ // __u32 msg_src_ip4; // BE, R: 1,2,4-byte, W: 4-byte
+ // __u32 msg_src_ip6[4]; // BE, R: 1,2,4,8-byte, W: 4,8-byte
+ // __bpf_md_ptr(struct bpf_sock *, sk);
+ // };
+ return 1;
+}
+
+DEFINE_NETD_V_BPF_PROG_KVER("connect4/inet4_connect", AID_ROOT, AID_ROOT, inet4_connect, KVER_5_15)
+(struct bpf_sock_addr *ctx) {
+ return check_localhost(ctx);
+}
+
+DEFINE_NETD_V_BPF_PROG_KVER("connect6/inet6_connect", AID_ROOT, AID_ROOT, inet6_connect, KVER_5_15)
+(struct bpf_sock_addr *ctx) {
+ return check_localhost(ctx);
+}
+
+DEFINE_NETD_V_BPF_PROG_KVER("recvmsg4/udp4_recvmsg", AID_ROOT, AID_ROOT, udp4_recvmsg, KVER_5_15)
+(struct bpf_sock_addr *ctx) {
+ return check_localhost(ctx);
+}
+
+DEFINE_NETD_V_BPF_PROG_KVER("recvmsg6/udp6_recvmsg", AID_ROOT, AID_ROOT, udp6_recvmsg, KVER_5_15)
+(struct bpf_sock_addr *ctx) {
+ return check_localhost(ctx);
+}
+
+DEFINE_NETD_V_BPF_PROG_KVER("sendmsg4/udp4_sendmsg", AID_ROOT, AID_ROOT, udp4_sendmsg, KVER_5_15)
+(struct bpf_sock_addr *ctx) {
+ return check_localhost(ctx);
+}
+
+DEFINE_NETD_V_BPF_PROG_KVER("sendmsg6/udp6_sendmsg", AID_ROOT, AID_ROOT, udp6_sendmsg, KVER_5_15)
+(struct bpf_sock_addr *ctx) {
+ return check_localhost(ctx);
+}
+
+DEFINE_NETD_V_BPF_PROG_KVER("getsockopt/prog", AID_ROOT, AID_ROOT, getsockopt_prog, KVER_5_15)
+(struct bpf_sockopt *ctx) {
+ return 1;
+}
+
+DEFINE_NETD_V_BPF_PROG_KVER("setsockopt/prog", AID_ROOT, AID_ROOT, setsockopt_prog, KVER_5_15)
+(struct bpf_sockopt *ctx) {
+ return 1;
+}
+
LICENSE("Apache 2.0");
CRITICAL("Connectivity and netd");
DISABLE_BTF_ON_USER_BUILDS();
+DISABLE_ON_MAINLINE_BEFORE_U_QPR3();
diff --git a/bpf_progs/netd.h b/bpf_progs/netd.h
index 8a56b4a..332979b 100644
--- a/bpf_progs/netd.h
+++ b/bpf_progs/netd.h
@@ -155,7 +155,16 @@
ASSERT_STRING_EQUAL(XT_BPF_ALLOWLIST_PROG_PATH, BPF_NETD_PATH "prog_netd_skfilter_allowlist_xtbpf");
ASSERT_STRING_EQUAL(XT_BPF_DENYLIST_PROG_PATH, BPF_NETD_PATH "prog_netd_skfilter_denylist_xtbpf");
-#define CGROUP_SOCKET_PROG_PATH BPF_NETD_PATH "prog_netd_cgroupsock_inet_create"
+#define CGROUP_INET_CREATE_PROG_PATH BPF_NETD_PATH "prog_netd_cgroupsock_inet_create"
+#define CGROUP_INET_RELEASE_PROG_PATH BPF_NETD_PATH "prog_netd_cgroupsockrelease_inet_release"
+#define CGROUP_CONNECT4_PROG_PATH BPF_NETD_PATH "prog_netd_connect4_inet4_connect"
+#define CGROUP_CONNECT6_PROG_PATH BPF_NETD_PATH "prog_netd_connect6_inet6_connect"
+#define CGROUP_UDP4_RECVMSG_PROG_PATH BPF_NETD_PATH "prog_netd_recvmsg4_udp4_recvmsg"
+#define CGROUP_UDP6_RECVMSG_PROG_PATH BPF_NETD_PATH "prog_netd_recvmsg6_udp6_recvmsg"
+#define CGROUP_UDP4_SENDMSG_PROG_PATH BPF_NETD_PATH "prog_netd_sendmsg4_udp4_sendmsg"
+#define CGROUP_UDP6_SENDMSG_PROG_PATH BPF_NETD_PATH "prog_netd_sendmsg6_udp6_sendmsg"
+#define CGROUP_GETSOCKOPT_PROG_PATH BPF_NETD_PATH "prog_netd_getsockopt_prog"
+#define CGROUP_SETSOCKOPT_PROG_PATH BPF_NETD_PATH "prog_netd_setsockopt_prog"
#define TC_BPF_INGRESS_ACCOUNT_PROG_NAME "prog_netd_schedact_ingress_account"
#define TC_BPF_INGRESS_ACCOUNT_PROG_PATH BPF_NETD_PATH TC_BPF_INGRESS_ACCOUNT_PROG_NAME
diff --git a/bpf_progs/offload.c b/bpf_progs/offload.c
index 4f152bf..c7ac059 100644
--- a/bpf_progs/offload.c
+++ b/bpf_progs/offload.c
@@ -28,11 +28,11 @@
// BTF is incompatible with bpfloaders < v0.10, hence for S (v0.2) we must
// ship a different file than for later versions, but we need bpfloader v0.25+
// for obj@ver.o support
-#define BPFLOADER_MIN_VER BPFLOADER_MAINLINE_T_VERSION
+#define BPFLOADER_MIN_VER BPFLOADER_OBJ_AT_VER_VERSION
#else /* MAINLINE */
-// The resulting .o needs to load on the Android S bpfloader
+// The resulting .o needs to load on the Android S & T bpfloaders
#define BPFLOADER_MIN_VER BPFLOADER_S_VERSION
-#define BPFLOADER_MAX_VER BPFLOADER_T_VERSION
+#define BPFLOADER_MAX_VER BPFLOADER_OBJ_AT_VER_VERSION
#endif /* MAINLINE */
// Warning: values other than AID_ROOT don't work for map uid on BpfLoader < v0.21
@@ -878,3 +878,4 @@
LICENSE("Apache 2.0");
CRITICAL("Connectivity (Tethering)");
DISABLE_BTF_ON_USER_BUILDS();
+DISABLE_ON_MAINLINE_BEFORE_U_QPR3();
diff --git a/bpf_progs/test.c b/bpf_progs/test.c
index fff3512..6a4471c 100644
--- a/bpf_progs/test.c
+++ b/bpf_progs/test.c
@@ -45,6 +45,10 @@
// Used only by TetheringPrivilegedTests, not by production code.
DEFINE_BPF_MAP_GRW(tether_downstream6_map, HASH, TetherDownstream6Key, Tether6Value, 16,
TETHERING_GID)
+DEFINE_BPF_MAP_GRW(tether2_downstream6_map, HASH, TetherDownstream6Key, Tether6Value, 16,
+ TETHERING_GID)
+DEFINE_BPF_MAP_GRW(tether3_downstream6_map, HASH, TetherDownstream6Key, Tether6Value, 16,
+ TETHERING_GID)
// Used only by BpfBitmapTest, not by production code.
DEFINE_BPF_MAP_GRW(bitmap, ARRAY, int, uint64_t, 2, TETHERING_GID)
diff --git a/netbpfload/NetBpfLoad.cpp b/netbpfload/NetBpfLoad.cpp
index e9f8e7c..e9c6d8a 100644
--- a/netbpfload/NetBpfLoad.cpp
+++ b/netbpfload/NetBpfLoad.cpp
@@ -224,11 +224,6 @@
return 0;
}
-static bool isGSI() {
- // From //system/gsid/libgsi.cpp IsGsiRunning()
- return !access("/metadata/gsi/dsu/booted", F_OK);
-}
-
static bool hasGSM() {
static string ph = base::GetProperty("gsm.current.phone-type", "");
static bool gsm = (ph != "");
@@ -255,10 +250,38 @@
static int doLoad(char** argv, char * const envp[]) {
const bool runningAsRoot = !getuid(); // true iff U QPR3 or V+
- const int device_api_level = android_get_device_api_level();
- const bool isAtLeastT = (device_api_level >= __ANDROID_API_T__);
- const bool isAtLeastU = (device_api_level >= __ANDROID_API_U__);
- const bool isAtLeastV = (device_api_level >= __ANDROID_API_V__);
+
+ // Any released device will have codename REL instead of a 'real' codename.
+ // For safety: default to 'REL' so we default to unreleased=false on failure.
+ const bool unreleased = (base::GetProperty("ro.build.version.codename", "REL") != "REL");
+
+ // goog/main device_api_level is bumped *way* before aosp/main api level
+ // (the latter only gets bumped during the push of goog/main to aosp/main)
+ //
+ // Since we develop in AOSP, we want it to behave as if it was bumped too.
+ //
+ // Note that AOSP doesn't really have a good api level (for example during
+ // early V dev cycle, it would have *all* of T, some but not all of U, and some V).
+ // One could argue that for our purposes AOSP api level should be infinite or 10000.
+ //
+ // This could also cause api to be increased in goog/main or other branches,
+ // but I can't imagine a case where this would be a problem: the problem
+ // is rather a too low api level, rather than some ill defined high value.
+ // For example as I write this aosp is 34/U, and goog is 35/V,
+ // we want to treat both goog & aosp as 35/V, but it's harmless if we
+ // treat goog as 36 because that value isn't yet defined to mean anything,
+ // and we thus never compare against it.
+ //
+ // Also note that 'android_get_device_api_level()' is what the
+ // //system/core/init/apex_init_util.cpp
+ // apex init .XXrc parsing code uses for XX filtering.
+ //
+ // That code has a hack to bump <35 to 35 (to force aosp/main to parse .35rc),
+ // but could (should?) perhaps be adjusted to match this.
+ const int effective_api_level = android_get_device_api_level() + (int)unreleased;
+ const bool isAtLeastT = (effective_api_level >= __ANDROID_API_T__);
+ const bool isAtLeastU = (effective_api_level >= __ANDROID_API_U__);
+ const bool isAtLeastV = (effective_api_level >= __ANDROID_API_V__);
// last in U QPR2 beta1
const bool has_platform_bpfloader_rc = exists("/system/etc/init/bpfloader.rc");
@@ -272,8 +295,9 @@
if (runningAsRoot) ++bpfloader_ver; // [45] BPFLOADER_MAINLINE_U_QPR3_VERSION
if (isAtLeastV) ++bpfloader_ver; // [46] BPFLOADER_MAINLINE_V_VERSION
- ALOGI("NetBpfLoad v0.%u (%s) api:%d kver:%07x (%s) uid:%d rc:%d%d",
- bpfloader_ver, argv[0], device_api_level, kernelVersion(), describeArch(), getuid(),
+ ALOGI("NetBpfLoad v0.%u (%s) api:%d/%d kver:%07x (%s) uid:%d rc:%d%d",
+ bpfloader_ver, argv[0], android_get_device_api_level(), effective_api_level,
+ kernelVersion(), describeArch(), getuid(),
has_platform_bpfloader_rc, has_platform_netbpfload_rc);
if (!has_platform_bpfloader_rc && !has_platform_netbpfload_rc) {
@@ -348,7 +372,7 @@
#undef REQUIRE
- if (bad && !isGSI()) {
+ if (bad) {
ALOGE("Unsupported kernel version (%07x).", kernelVersion());
}
}
diff --git a/netbpfload/loader.cpp b/netbpfload/loader.cpp
index 289b4d7..bb7c56f 100644
--- a/netbpfload/loader.cpp
+++ b/netbpfload/loader.cpp
@@ -165,32 +165,34 @@
* since they are less stable abi/api and may conflict with platform uses of bpf.
*/
sectionType sectionNameTypes[] = {
- {"bind4/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET4_BIND},
- {"bind6/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET6_BIND},
- {"cgroupskb/", BPF_PROG_TYPE_CGROUP_SKB, BPF_ATTACH_TYPE_UNSPEC},
- {"cgroupsock/", BPF_PROG_TYPE_CGROUP_SOCK, BPF_ATTACH_TYPE_UNSPEC},
- {"connect4/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET4_CONNECT},
- {"connect6/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET6_CONNECT},
- {"egress/", BPF_PROG_TYPE_CGROUP_SKB, BPF_CGROUP_INET_EGRESS},
- {"getsockopt/", BPF_PROG_TYPE_CGROUP_SOCKOPT, BPF_CGROUP_GETSOCKOPT},
- {"ingress/", BPF_PROG_TYPE_CGROUP_SKB, BPF_CGROUP_INET_INGRESS},
- {"lwt_in/", BPF_PROG_TYPE_LWT_IN, BPF_ATTACH_TYPE_UNSPEC},
- {"lwt_out/", BPF_PROG_TYPE_LWT_OUT, BPF_ATTACH_TYPE_UNSPEC},
- {"lwt_seg6local/", BPF_PROG_TYPE_LWT_SEG6LOCAL, BPF_ATTACH_TYPE_UNSPEC},
- {"lwt_xmit/", BPF_PROG_TYPE_LWT_XMIT, BPF_ATTACH_TYPE_UNSPEC},
- {"postbind4/", BPF_PROG_TYPE_CGROUP_SOCK, BPF_CGROUP_INET4_POST_BIND},
- {"postbind6/", BPF_PROG_TYPE_CGROUP_SOCK, BPF_CGROUP_INET6_POST_BIND},
- {"recvmsg4/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP4_RECVMSG},
- {"recvmsg6/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP6_RECVMSG},
- {"schedact/", BPF_PROG_TYPE_SCHED_ACT, BPF_ATTACH_TYPE_UNSPEC},
- {"schedcls/", BPF_PROG_TYPE_SCHED_CLS, BPF_ATTACH_TYPE_UNSPEC},
- {"sendmsg4/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP4_SENDMSG},
- {"sendmsg6/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP6_SENDMSG},
- {"setsockopt/", BPF_PROG_TYPE_CGROUP_SOCKOPT, BPF_CGROUP_SETSOCKOPT},
- {"skfilter/", BPF_PROG_TYPE_SOCKET_FILTER, BPF_ATTACH_TYPE_UNSPEC},
- {"sockops/", BPF_PROG_TYPE_SOCK_OPS, BPF_CGROUP_SOCK_OPS},
- {"sysctl", BPF_PROG_TYPE_CGROUP_SYSCTL, BPF_CGROUP_SYSCTL},
- {"xdp/", BPF_PROG_TYPE_XDP, BPF_ATTACH_TYPE_UNSPEC},
+ {"bind4/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET4_BIND},
+ {"bind6/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET6_BIND},
+ {"cgroupskb/", BPF_PROG_TYPE_CGROUP_SKB, BPF_ATTACH_TYPE_UNSPEC},
+ {"cgroupsock/", BPF_PROG_TYPE_CGROUP_SOCK, BPF_ATTACH_TYPE_UNSPEC},
+ {"cgroupsockcreate/", BPF_PROG_TYPE_CGROUP_SOCK, BPF_CGROUP_INET_SOCK_CREATE},
+ {"cgroupsockrelease/", BPF_PROG_TYPE_CGROUP_SOCK, BPF_CGROUP_INET_SOCK_RELEASE},
+ {"connect4/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET4_CONNECT},
+ {"connect6/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_INET6_CONNECT},
+ {"egress/", BPF_PROG_TYPE_CGROUP_SKB, BPF_CGROUP_INET_EGRESS},
+ {"getsockopt/", BPF_PROG_TYPE_CGROUP_SOCKOPT, BPF_CGROUP_GETSOCKOPT},
+ {"ingress/", BPF_PROG_TYPE_CGROUP_SKB, BPF_CGROUP_INET_INGRESS},
+ {"lwt_in/", BPF_PROG_TYPE_LWT_IN, BPF_ATTACH_TYPE_UNSPEC},
+ {"lwt_out/", BPF_PROG_TYPE_LWT_OUT, BPF_ATTACH_TYPE_UNSPEC},
+ {"lwt_seg6local/", BPF_PROG_TYPE_LWT_SEG6LOCAL, BPF_ATTACH_TYPE_UNSPEC},
+ {"lwt_xmit/", BPF_PROG_TYPE_LWT_XMIT, BPF_ATTACH_TYPE_UNSPEC},
+ {"postbind4/", BPF_PROG_TYPE_CGROUP_SOCK, BPF_CGROUP_INET4_POST_BIND},
+ {"postbind6/", BPF_PROG_TYPE_CGROUP_SOCK, BPF_CGROUP_INET6_POST_BIND},
+ {"recvmsg4/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP4_RECVMSG},
+ {"recvmsg6/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP6_RECVMSG},
+ {"schedact/", BPF_PROG_TYPE_SCHED_ACT, BPF_ATTACH_TYPE_UNSPEC},
+ {"schedcls/", BPF_PROG_TYPE_SCHED_CLS, BPF_ATTACH_TYPE_UNSPEC},
+ {"sendmsg4/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP4_SENDMSG},
+ {"sendmsg6/", BPF_PROG_TYPE_CGROUP_SOCK_ADDR, BPF_CGROUP_UDP6_SENDMSG},
+ {"setsockopt/", BPF_PROG_TYPE_CGROUP_SOCKOPT, BPF_CGROUP_SETSOCKOPT},
+ {"skfilter/", BPF_PROG_TYPE_SOCKET_FILTER, BPF_ATTACH_TYPE_UNSPEC},
+ {"sockops/", BPF_PROG_TYPE_SOCK_OPS, BPF_CGROUP_SOCK_OPS},
+ {"sysctl", BPF_PROG_TYPE_CGROUP_SYSCTL, BPF_CGROUP_SYSCTL},
+ {"xdp/", BPF_PROG_TYPE_XDP, BPF_ATTACH_TYPE_UNSPEC},
};
typedef struct {
@@ -1122,11 +1124,20 @@
readSectionUint("bpfloader_max_ver", elfFile, DEFAULT_BPFLOADER_MAX_VER);
unsigned int bpfLoaderMinRequiredVer =
readSectionUint("bpfloader_min_required_ver", elfFile, 0);
+ unsigned int netBpfLoadMinVer =
+ readSectionUint("netbpfload_min_ver", elfFile, 0);
size_t sizeOfBpfMapDef =
readSectionUint("size_of_bpf_map_def", elfFile, DEFAULT_SIZEOF_BPF_MAP_DEF);
size_t sizeOfBpfProgDef =
readSectionUint("size_of_bpf_prog_def", elfFile, DEFAULT_SIZEOF_BPF_PROG_DEF);
+ // temporary hack to enable gentle enablement of mainline NetBpfLoad
+ if (bpfloader_ver < netBpfLoadMinVer) {
+ ALOGI("NetBpfLoad version %d ignoring ELF object %s with netbpfload min ver %d",
+ bpfloader_ver, elfPath, netBpfLoadMinVer);
+ return 0;
+ }
+
// inclusive lower bound check
if (bpfloader_ver < bpfLoaderMinVer) {
ALOGI("BpfLoader version 0x%05x ignoring ELF object %s with min ver 0x%05x",
diff --git a/netbpfload/netbpfload.33rc b/netbpfload/netbpfload.33rc
index 05f566e..d269ce9 100644
--- a/netbpfload/netbpfload.33rc
+++ b/netbpfload/netbpfload.33rc
@@ -1,3 +1,15 @@
+# This file takes effect only on T and U (on V netbpfload.35rc takes priority).
+#
+# The service is started from netd's libnetd_updatable shared library
+# on initial (boot time) startup of netd.
+#
+# However we never start this service on U QPR3.
+#
+# This is due to lack of a need: U QPR2 split the previously single
+# platform bpfloader into platform netbpfload -> platform bpfloader.
+# U QPR3 made the platform netbpfload unconditionally exec apex netbpfload,
+# so by the time U QPR3's netd runs, apex netbpfload is already done.
+
service mdnsd_netbpfload /apex/com.android.tethering/bin/netbpfload
capabilities CHOWN SYS_ADMIN NET_ADMIN
group system root graphics network_stack net_admin net_bw_acct net_bw_stats net_raw
@@ -5,5 +17,5 @@
file /dev/kmsg w
rlimit memlock 1073741824 1073741824
oneshot
- reboot_on_failure reboot,bpfloader-failed
+ # TODO: reboot_on_failure reboot,netbpfload-failed
override
diff --git a/netd/BpfHandler.cpp b/netd/BpfHandler.cpp
index 15a4fef..fe25255 100644
--- a/netd/BpfHandler.cpp
+++ b/netd/BpfHandler.cpp
@@ -110,8 +110,31 @@
// TODO: delete the if statement once all devices should support cgroup
// socket filter (ie. the minimum kernel version required is 4.14).
if (bpf::isAtLeastKernelVersion(4, 14, 0)) {
- RETURN_IF_NOT_OK(
- attachProgramToCgroup(CGROUP_SOCKET_PROG_PATH, cg_fd, BPF_CGROUP_INET_SOCK_CREATE));
+ RETURN_IF_NOT_OK(attachProgramToCgroup(CGROUP_INET_CREATE_PROG_PATH,
+ cg_fd, BPF_CGROUP_INET_SOCK_CREATE));
+ }
+
+ if (modules::sdklevel::IsAtLeastV()) {
+ if (bpf::isAtLeastKernelVersion(5, 15, 0)) {
+ RETURN_IF_NOT_OK(attachProgramToCgroup(CGROUP_CONNECT4_PROG_PATH,
+ cg_fd, BPF_CGROUP_INET4_CONNECT));
+ RETURN_IF_NOT_OK(attachProgramToCgroup(CGROUP_CONNECT6_PROG_PATH,
+ cg_fd, BPF_CGROUP_INET6_CONNECT)) ;
+ RETURN_IF_NOT_OK(attachProgramToCgroup(CGROUP_UDP4_RECVMSG_PROG_PATH,
+ cg_fd, BPF_CGROUP_UDP4_RECVMSG));
+ RETURN_IF_NOT_OK(attachProgramToCgroup(CGROUP_UDP6_RECVMSG_PROG_PATH,
+ cg_fd, BPF_CGROUP_UDP6_RECVMSG));
+ RETURN_IF_NOT_OK(attachProgramToCgroup(CGROUP_UDP4_SENDMSG_PROG_PATH,
+ cg_fd, BPF_CGROUP_UDP4_SENDMSG));
+ RETURN_IF_NOT_OK(attachProgramToCgroup(CGROUP_UDP6_SENDMSG_PROG_PATH,
+ cg_fd, BPF_CGROUP_UDP6_SENDMSG));
+ RETURN_IF_NOT_OK(attachProgramToCgroup(CGROUP_GETSOCKOPT_PROG_PATH,
+ cg_fd, BPF_CGROUP_GETSOCKOPT));
+ RETURN_IF_NOT_OK(attachProgramToCgroup(CGROUP_SETSOCKOPT_PROG_PATH,
+ cg_fd, BPF_CGROUP_SETSOCKOPT));
+ RETURN_IF_NOT_OK(attachProgramToCgroup(CGROUP_INET_RELEASE_PROG_PATH,
+ cg_fd, BPF_CGROUP_INET_SOCK_RELEASE));
+ }
}
if (bpf::isAtLeastKernelVersion(4, 19, 0)) {
@@ -131,6 +154,20 @@
if (bpf::queryProgram(cg_fd, BPF_CGROUP_INET6_BIND) <= 0) abort();
}
+ if (modules::sdklevel::IsAtLeastV()) {
+ if (bpf::isAtLeastKernelVersion(5, 15, 0)) {
+ if (bpf::queryProgram(cg_fd, BPF_CGROUP_INET4_CONNECT) <= 0) abort();
+ if (bpf::queryProgram(cg_fd, BPF_CGROUP_INET6_CONNECT) <= 0) abort();
+ if (bpf::queryProgram(cg_fd, BPF_CGROUP_UDP4_RECVMSG) <= 0) abort();
+ if (bpf::queryProgram(cg_fd, BPF_CGROUP_UDP6_RECVMSG) <= 0) abort();
+ if (bpf::queryProgram(cg_fd, BPF_CGROUP_UDP4_SENDMSG) <= 0) abort();
+ if (bpf::queryProgram(cg_fd, BPF_CGROUP_UDP6_SENDMSG) <= 0) abort();
+ if (bpf::queryProgram(cg_fd, BPF_CGROUP_GETSOCKOPT) <= 0) abort();
+ if (bpf::queryProgram(cg_fd, BPF_CGROUP_SETSOCKOPT) <= 0) abort();
+ if (bpf::queryProgram(cg_fd, BPF_CGROUP_INET_SOCK_RELEASE) <= 0) abort();
+ }
+ }
+
return netdutils::status::ok;
}
@@ -171,15 +208,24 @@
}
if (!mainlineNetBpfLoadDone()) {
- // we're on < U QPR3 & it's the first time netd is starting up (unless crashlooping)
+ const bool enforce_mainline = false; // TODO: flip to true
+
+ // We're on < U QPR3 & it's the first time netd is starting up (unless crashlooping)
+ //
+ // On U QPR3+ netbpfload is guaranteed to run before the platform bpfloader,
+ // so waitForProgsLoaded() implies mainlineNetBpfLoadDone().
if (!base::SetProperty("ctl.start", "mdnsd_netbpfload")) {
ALOGE("Failed to set property ctl.start=mdnsd_netbpfload, see dmesg for reason.");
- abort();
+ if (enforce_mainline) abort();
}
- ALOGI("Waiting for Networking BPF programs");
- waitForNetProgsLoaded();
- ALOGI("Networking BPF programs are loaded");
+ if (enforce_mainline) {
+ ALOGI("Waiting for Networking BPF programs");
+ waitForNetProgsLoaded();
+ ALOGI("Networking BPF programs are loaded");
+ } else {
+ ALOGI("Started mdnsd_netbpfload asynchronously.");
+ }
}
ALOGI("BPF programs are loaded");
@@ -190,7 +236,30 @@
return netdutils::status::ok;
}
+static void mapLockTest(void) {
+ // The maps must be R/W, and as yet unopened (or more specifically not yet lock'ed).
+ const char * const m1 = BPF_NETD_PATH "map_netd_lock_array_test_map";
+ const char * const m2 = BPF_NETD_PATH "map_netd_lock_hash_test_map";
+
+ unique_fd fd0(bpf::mapRetrieveExclusiveRW(m1)); if (!fd0.ok()) abort(); // grabs exclusive lock
+
+ unique_fd fd1(bpf::mapRetrieveExclusiveRW(m2)); if (!fd1.ok()) abort(); // no conflict with fd0
+ unique_fd fd2(bpf::mapRetrieveExclusiveRW(m2)); if ( fd2.ok()) abort(); // busy due to fd1
+ unique_fd fd3(bpf::mapRetrieveRO(m2)); if (!fd3.ok()) abort(); // no lock taken
+ unique_fd fd4(bpf::mapRetrieveRW(m2)); if ( fd4.ok()) abort(); // busy due to fd1
+ fd1.reset(); // releases exclusive lock
+ unique_fd fd5(bpf::mapRetrieveRO(m2)); if (!fd5.ok()) abort(); // no lock taken
+ unique_fd fd6(bpf::mapRetrieveRW(m2)); if (!fd6.ok()) abort(); // now ok
+ unique_fd fd7(bpf::mapRetrieveRO(m2)); if (!fd7.ok()) abort(); // no lock taken
+ unique_fd fd8(bpf::mapRetrieveExclusiveRW(m2)); if ( fd8.ok()) abort(); // busy due to fd6
+
+ fd0.reset(); // releases exclusive lock
+ unique_fd fd9(bpf::mapRetrieveWO(m1)); if (!fd9.ok()) abort(); // grabs exclusive lock
+}
+
Status BpfHandler::initMaps() {
+ mapLockTest();
+
RETURN_IF_NOT_OK(mStatsMapA.init(STATS_MAP_A_PATH));
RETURN_IF_NOT_OK(mStatsMapB.init(STATS_MAP_B_PATH));
RETURN_IF_NOT_OK(mConfigurationMap.init(CONFIGURATION_MAP_PATH));
diff --git a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
index 18a274a..c0082bb 100644
--- a/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
+++ b/service/jni/com_android_server_connectivity_ClatCoordinator.cpp
@@ -80,7 +80,8 @@
case VERIFY_BIN: return;
case VERIFY_PROG: fd = bpf::retrieveProgram(path); break;
case VERIFY_MAP_RO: fd = bpf::mapRetrieveRO(path); break;
- case VERIFY_MAP_RW: fd = bpf::mapRetrieveRW(path); break;
+ // lockless: we're just checking access rights and will immediately close the fd
+ case VERIFY_MAP_RW: fd = bpf::mapRetrieveLocklessRW(path); break;
}
if (fd < 0) ALOGF("bpf_obj_get '%s' failed, errno=%d", path, errno);
diff --git a/service/src/com/android/server/BpfNetMaps.java b/service/src/com/android/server/BpfNetMaps.java
index a30735a..b3e7d8c 100644
--- a/service/src/com/android/server/BpfNetMaps.java
+++ b/service/src/com/android/server/BpfNetMaps.java
@@ -189,7 +189,7 @@
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private static IBpfMap<S32, U32> getConfigurationMap() {
try {
- return new SingleWriterBpfMap<>(
+ return SingleWriterBpfMap.getSingleton(
CONFIGURATION_MAP_PATH, S32.class, U32.class);
} catch (ErrnoException e) {
throw new IllegalStateException("Cannot open netd configuration map", e);
@@ -199,7 +199,7 @@
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private static IBpfMap<S32, UidOwnerValue> getUidOwnerMap() {
try {
- return new SingleWriterBpfMap<>(
+ return SingleWriterBpfMap.getSingleton(
UID_OWNER_MAP_PATH, S32.class, UidOwnerValue.class);
} catch (ErrnoException e) {
throw new IllegalStateException("Cannot open uid owner map", e);
@@ -209,7 +209,7 @@
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private static IBpfMap<S32, U8> getUidPermissionMap() {
try {
- return new SingleWriterBpfMap<>(
+ return SingleWriterBpfMap.getSingleton(
UID_PERMISSION_MAP_PATH, S32.class, U8.class);
} catch (ErrnoException e) {
throw new IllegalStateException("Cannot open uid permission map", e);
@@ -230,7 +230,7 @@
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private static IBpfMap<S32, U8> getDataSaverEnabledMap() {
try {
- return new SingleWriterBpfMap<>(
+ return SingleWriterBpfMap.getSingleton(
DATA_SAVER_ENABLED_MAP_PATH, S32.class, U8.class);
} catch (ErrnoException e) {
throw new IllegalStateException("Cannot open data saver enabled map", e);
@@ -240,7 +240,7 @@
@RequiresApi(Build.VERSION_CODES.TIRAMISU)
private static IBpfMap<IngressDiscardKey, IngressDiscardValue> getIngressDiscardMap() {
try {
- return new SingleWriterBpfMap<>(INGRESS_DISCARD_MAP_PATH,
+ return SingleWriterBpfMap.getSingleton(INGRESS_DISCARD_MAP_PATH,
IngressDiscardKey.class, IngressDiscardValue.class);
} catch (ErrnoException e) {
throw new IllegalStateException("Cannot open ingress discard map", e);
diff --git a/service/src/com/android/server/ConnectivityService.java b/service/src/com/android/server/ConnectivityService.java
index ca2cb15..be1d3c7 100755
--- a/service/src/com/android/server/ConnectivityService.java
+++ b/service/src/com/android/server/ConnectivityService.java
@@ -109,14 +109,24 @@
import static android.os.Process.INVALID_UID;
import static android.os.Process.VPN_UID;
import static android.system.OsConstants.ETH_P_ALL;
+import static android.system.OsConstants.F_OK;
import static android.system.OsConstants.IPPROTO_TCP;
import static android.system.OsConstants.IPPROTO_UDP;
+import static com.android.net.module.util.BpfUtils.BPF_CGROUP_GETSOCKOPT;
import static com.android.net.module.util.BpfUtils.BPF_CGROUP_INET4_BIND;
+import static com.android.net.module.util.BpfUtils.BPF_CGROUP_INET4_CONNECT;
import static com.android.net.module.util.BpfUtils.BPF_CGROUP_INET6_BIND;
+import static com.android.net.module.util.BpfUtils.BPF_CGROUP_INET6_CONNECT;
import static com.android.net.module.util.BpfUtils.BPF_CGROUP_INET_EGRESS;
import static com.android.net.module.util.BpfUtils.BPF_CGROUP_INET_INGRESS;
import static com.android.net.module.util.BpfUtils.BPF_CGROUP_INET_SOCK_CREATE;
+import static com.android.net.module.util.BpfUtils.BPF_CGROUP_INET_SOCK_RELEASE;
+import static com.android.net.module.util.BpfUtils.BPF_CGROUP_SETSOCKOPT;
+import static com.android.net.module.util.BpfUtils.BPF_CGROUP_UDP4_RECVMSG;
+import static com.android.net.module.util.BpfUtils.BPF_CGROUP_UDP4_SENDMSG;
+import static com.android.net.module.util.BpfUtils.BPF_CGROUP_UDP6_RECVMSG;
+import static com.android.net.module.util.BpfUtils.BPF_CGROUP_UDP6_SENDMSG;
import static com.android.net.module.util.NetworkMonitorUtils.isPrivateDnsValidationRequired;
import static com.android.net.module.util.PermissionUtils.enforceAnyPermissionOf;
import static com.android.net.module.util.PermissionUtils.enforceNetworkStackPermission;
@@ -133,6 +143,7 @@
import android.annotation.CheckResult;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.RequiresApi;
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.ActivityManager;
@@ -268,6 +279,7 @@
import android.stats.connectivity.ValidatedState;
import android.sysprop.NetworkProperties;
import android.system.ErrnoException;
+import android.system.Os;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
@@ -281,8 +293,6 @@
import android.util.SparseIntArray;
import android.util.StatsEvent;
-import androidx.annotation.RequiresApi;
-
import com.android.connectivity.resources.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -383,6 +393,7 @@
import java.util.Map.Entry;
import java.util.NoSuchElementException;
import java.util.Objects;
+import java.util.Random;
import java.util.Set;
import java.util.SortedSet;
import java.util.StringJoiner;
@@ -1834,6 +1845,33 @@
new PermissionMonitor(mContext, mNetd, mBpfNetMaps, mHandlerThread);
mHandlerThread.start();
mHandler = new InternalHandler(mHandlerThread.getLooper());
+ // Temporary hack to report netbpfload result.
+ // TODO: remove in 2024-09 when netbpfload starts loading mainline bpf programs.
+ mHandler.postDelayed(() -> {
+ // Test Pitot pipeline, ignore this Log.wtf if it shows up in the logs.
+ final Random r = new Random();
+ if (Build.TYPE.equals("user") && r.nextInt(1000) == 0) {
+ Log.wtf(TAG, "NOT A FAILURE, PLEASE IGNORE! Test Pitot pipeline works correctly");
+ }
+ // Did netbpfload create the map?
+ try {
+ Os.access("/sys/fs/bpf/net_shared/map_gentle_test", F_OK);
+ } catch (ErrnoException e) {
+ Log.wtf(TAG, "netbpfload did not create map", e);
+ }
+ // Did netbpfload create the program?
+ try {
+ Os.access("/sys/fs/bpf/net_shared/prog_gentle_skfilter_accept", F_OK);
+ } catch (ErrnoException e) {
+ Log.wtf(TAG, "netbpfload did not create program", e);
+ }
+ // Did netbpfload run to completion?
+ try {
+ Os.access("/sys/fs/bpf/netd_shared/mainline_done", F_OK);
+ } catch (ErrnoException e) {
+ Log.wtf(TAG, "netbpfload did not run to completion", e);
+ }
+ }, 30_000 /* delayMillis */);
mTrackerHandler = new NetworkStateTrackerHandler(mHandlerThread.getLooper());
mConnectivityDiagnosticsHandler =
new ConnectivityDiagnosticsHandler(mHandlerThread.getLooper());
@@ -3566,6 +3604,7 @@
pw.decreaseIndent();
}
+ @RequiresApi(Build.VERSION_CODES.TIRAMISU)
private void dumpBpfProgramStatus(IndentingPrintWriter pw) {
pw.println("Bpf Program Status:");
pw.increaseIndent();
@@ -3574,12 +3613,37 @@
pw.println(mDeps.getBpfProgramId(BPF_CGROUP_INET_INGRESS));
pw.print("CGROUP_INET_EGRESS: ");
pw.println(mDeps.getBpfProgramId(BPF_CGROUP_INET_EGRESS));
+
pw.print("CGROUP_INET_SOCK_CREATE: ");
pw.println(mDeps.getBpfProgramId(BPF_CGROUP_INET_SOCK_CREATE));
+
pw.print("CGROUP_INET4_BIND: ");
pw.println(mDeps.getBpfProgramId(BPF_CGROUP_INET4_BIND));
pw.print("CGROUP_INET6_BIND: ");
pw.println(mDeps.getBpfProgramId(BPF_CGROUP_INET6_BIND));
+
+ pw.print("CGROUP_INET4_CONNECT: ");
+ pw.println(mDeps.getBpfProgramId(BPF_CGROUP_INET4_CONNECT));
+ pw.print("CGROUP_INET6_CONNECT: ");
+ pw.println(mDeps.getBpfProgramId(BPF_CGROUP_INET6_CONNECT));
+
+ pw.print("CGROUP_UDP4_SENDMSG: ");
+ pw.println(mDeps.getBpfProgramId(BPF_CGROUP_UDP4_SENDMSG));
+ pw.print("CGROUP_UDP6_SENDMSG: ");
+ pw.println(mDeps.getBpfProgramId(BPF_CGROUP_UDP6_SENDMSG));
+
+ pw.print("CGROUP_UDP4_RECVMSG: ");
+ pw.println(mDeps.getBpfProgramId(BPF_CGROUP_UDP4_RECVMSG));
+ pw.print("CGROUP_UDP6_RECVMSG: ");
+ pw.println(mDeps.getBpfProgramId(BPF_CGROUP_UDP6_RECVMSG));
+
+ pw.print("CGROUP_GETSOCKOPT: ");
+ pw.println(mDeps.getBpfProgramId(BPF_CGROUP_GETSOCKOPT));
+ pw.print("CGROUP_SETSOCKOPT: ");
+ pw.println(mDeps.getBpfProgramId(BPF_CGROUP_SETSOCKOPT));
+
+ pw.print("CGROUP_INET_SOCK_RELEASE: ");
+ pw.println(mDeps.getBpfProgramId(BPF_CGROUP_INET_SOCK_RELEASE));
} catch (IOException e) {
pw.println(" IOException");
}
@@ -4229,8 +4293,19 @@
pw.println();
dumpDestroySockets(pw);
- pw.println();
- dumpBpfProgramStatus(pw);
+ if (mDeps.isAtLeastT()) {
+ // R: https://android.googlesource.com/platform/system/core/+/refs/heads/android11-release/rootdir/init.rc
+ // shows /dev/cg2_bpf
+ // S: https://android.googlesource.com/platform/system/core/+/refs/heads/android12-release/rootdir/init.rc
+ // does not
+ // Thus cgroups are mounted at /dev/cg2_bpf on R and not on /sys/fs/cgroup
+ // so the following won't work (on R) anyway.
+ // The /sys/fs/cgroup path is only actually enforced/required starting with U,
+ // but it is very likely to already be the case (though not guaranteed) on T.
+ // I'm not at all sure about S - let's just skip it to get rid of lint warnings.
+ pw.println();
+ dumpBpfProgramStatus(pw);
+ }
if (null != mCarrierPrivilegeAuthenticator) {
pw.println();
diff --git a/service/src/com/android/server/connectivity/ClatCoordinator.java b/service/src/com/android/server/connectivity/ClatCoordinator.java
index f333dae..b1c770b 100644
--- a/service/src/com/android/server/connectivity/ClatCoordinator.java
+++ b/service/src/com/android/server/connectivity/ClatCoordinator.java
@@ -45,6 +45,7 @@
import com.android.net.module.util.BpfMap;
import com.android.net.module.util.IBpfMap;
import com.android.net.module.util.InterfaceParams;
+import com.android.net.module.util.SingleWriterBpfMap;
import com.android.net.module.util.TcUtils;
import com.android.net.module.util.bpf.ClatEgress4Key;
import com.android.net.module.util.bpf.ClatEgress4Value;
@@ -256,7 +257,7 @@
@Nullable
public IBpfMap<ClatIngress6Key, ClatIngress6Value> getBpfIngress6Map() {
try {
- return new BpfMap<>(CLAT_INGRESS6_MAP_PATH,
+ return SingleWriterBpfMap.getSingleton(CLAT_INGRESS6_MAP_PATH,
ClatIngress6Key.class, ClatIngress6Value.class);
} catch (ErrnoException e) {
Log.e(TAG, "Cannot create ingress6 map: " + e);
@@ -268,7 +269,7 @@
@Nullable
public IBpfMap<ClatEgress4Key, ClatEgress4Value> getBpfEgress4Map() {
try {
- return new BpfMap<>(CLAT_EGRESS4_MAP_PATH,
+ return SingleWriterBpfMap.getSingleton(CLAT_EGRESS4_MAP_PATH,
ClatEgress4Key.class, ClatEgress4Value.class);
} catch (ErrnoException e) {
Log.e(TAG, "Cannot create egress4 map: " + e);
@@ -280,6 +281,7 @@
@Nullable
public IBpfMap<CookieTagMapKey, CookieTagMapValue> getBpfCookieTagMap() {
try {
+ // also read and written from other locations
return new BpfMap<>(COOKIE_TAG_MAP_PATH,
CookieTagMapKey.class, CookieTagMapValue.class);
} catch (ErrnoException e) {
diff --git a/staticlibs/device/com/android/net/module/util/BpfMap.java b/staticlibs/device/com/android/net/module/util/BpfMap.java
index da77ae8..0fbc25d 100644
--- a/staticlibs/device/com/android/net/module/util/BpfMap.java
+++ b/staticlibs/device/com/android/net/module/util/BpfMap.java
@@ -15,6 +15,7 @@
*/
package com.android.net.module.util;
+import static android.system.OsConstants.EBUSY;
import static android.system.OsConstants.EEXIST;
import static android.system.OsConstants.ENOENT;
@@ -52,6 +53,9 @@
public static final int BPF_F_RDONLY = 1 << 3;
public static final int BPF_F_WRONLY = 1 << 4;
+ // magic value for jni consumption, invalid from kernel point of view
+ public static final int BPF_F_RDWR_EXCLUSIVE = BPF_F_RDONLY | BPF_F_WRONLY;
+
public static final int BPF_MAP_TYPE_HASH = 1;
private static final int BPF_F_NO_PREALLOC = 1;
@@ -69,6 +73,12 @@
private static ConcurrentHashMap<Pair<String, Integer>, ParcelFileDescriptor> sFdCache =
new ConcurrentHashMap<>();
+ private static ParcelFileDescriptor checkModeExclusivity(ParcelFileDescriptor fd, int mode)
+ throws ErrnoException {
+ if (mode == BPF_F_RDWR_EXCLUSIVE) throw new ErrnoException("cachedBpfFdGet", EBUSY);
+ return fd;
+ }
+
private static ParcelFileDescriptor cachedBpfFdGet(String path, int mode,
int keySize, int valueSize)
throws ErrnoException, NullPointerException {
@@ -79,12 +89,12 @@
var key = Pair.create(path, (mode << 26) ^ (keySize << 16) ^ valueSize);
// unlocked fetch is safe: map is concurrent read capable, and only inserted into
ParcelFileDescriptor fd = sFdCache.get(key);
- if (fd != null) return fd;
+ if (fd != null) return checkModeExclusivity(fd, mode);
// ok, no cached fd present, need to grab a lock
synchronized (BpfMap.class) {
// need to redo the check
fd = sFdCache.get(key);
- if (fd != null) return fd;
+ if (fd != null) return checkModeExclusivity(fd, mode);
// okay, we really haven't opened this before...
fd = ParcelFileDescriptor.adoptFd(nativeBpfFdGet(path, mode, keySize, valueSize));
sFdCache.put(key, fd);
diff --git a/staticlibs/device/com/android/net/module/util/BpfUtils.java b/staticlibs/device/com/android/net/module/util/BpfUtils.java
index cdd6fd7..a41eeba 100644
--- a/staticlibs/device/com/android/net/module/util/BpfUtils.java
+++ b/staticlibs/device/com/android/net/module/util/BpfUtils.java
@@ -39,6 +39,15 @@
public static final int BPF_CGROUP_INET_SOCK_CREATE = 2;
public static final int BPF_CGROUP_INET4_BIND = 8;
public static final int BPF_CGROUP_INET6_BIND = 9;
+ public static final int BPF_CGROUP_INET4_CONNECT = 10;
+ public static final int BPF_CGROUP_INET6_CONNECT = 11;
+ public static final int BPF_CGROUP_UDP4_SENDMSG = 14;
+ public static final int BPF_CGROUP_UDP6_SENDMSG = 15;
+ public static final int BPF_CGROUP_UDP4_RECVMSG = 19;
+ public static final int BPF_CGROUP_UDP6_RECVMSG = 20;
+ public static final int BPF_CGROUP_GETSOCKOPT = 21;
+ public static final int BPF_CGROUP_SETSOCKOPT = 22;
+ public static final int BPF_CGROUP_INET_SOCK_RELEASE = 34;
// Note: This is only guaranteed to be accurate on U+ devices. It is likely to be accurate
// on T+ devices as well, but this is not guaranteed.
diff --git a/staticlibs/device/com/android/net/module/util/SingleWriterBpfMap.java b/staticlibs/device/com/android/net/module/util/SingleWriterBpfMap.java
index 3eb59d8..cd6bfec 100644
--- a/staticlibs/device/com/android/net/module/util/SingleWriterBpfMap.java
+++ b/staticlibs/device/com/android/net/module/util/SingleWriterBpfMap.java
@@ -17,6 +17,7 @@
import android.os.Build;
import android.system.ErrnoException;
+import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
@@ -61,14 +62,14 @@
// our code can contain hundreds of items.
private final HashMap<K, V> mCache = new HashMap<>();
- protected SingleWriterBpfMap(@NonNull final String path, final int flag, final Class<K> key,
+ // This should only ever be called (hence private) once for a given 'path'.
+ // Java-wise what matters is the entire {path, key, value} triplet,
+ // but of course the kernel exclusive lock is just on the path (fd),
+ // and any BpfMap has (or should have...) well defined key/value types
+ // (or at least their sizes) so in practice it doesn't really matter.
+ private SingleWriterBpfMap(@NonNull final String path, final Class<K> key,
final Class<V> value) throws ErrnoException, NullPointerException {
- super(path, flag, key, value);
-
- if (flag != BPF_F_RDWR) {
- throw new IllegalArgumentException(
- "Using " + getClass().getName() + " for read-only maps does not make sense");
- }
+ super(path, BPF_F_RDWR_EXCLUSIVE, key, value);
// Populate cache with the current map contents.
K currentKey = super.getFirstKey();
@@ -78,9 +79,22 @@
}
}
- public SingleWriterBpfMap(@NonNull final String path, final Class<K> key,
- final Class<V> value) throws ErrnoException, NullPointerException {
- this(path, BPF_F_RDWR, key, value);
+ // This allows reuse of SingleWriterBpfMap objects for the same {path, keyClass, valueClass}.
+ // These are never destroyed, so once created the lock is (effectively) held till process death
+ // (even if fixed, there would still be a write-only fd cache in underlying BpfMap base class).
+ private static final HashMap<Pair<String, Pair<Class, Class>>, SingleWriterBpfMap>
+ singletonCache = new HashMap<>();
+
+ // This is the public 'factory method' that (creates if needed and) returns a singleton instance
+ // for a given map. This holds an exclusive lock and has a permanent write-through cache.
+ // It will not be released until process death (or at least unload of the relevant class loader)
+ public synchronized static <KK extends Struct, VV extends Struct> SingleWriterBpfMap<KK,VV>
+ getSingleton(@NonNull final String path, final Class<KK> key, final Class<VV> value)
+ throws ErrnoException, NullPointerException {
+ var cacheKey = new Pair<>(path, new Pair<Class,Class>(key, value));
+ if (!singletonCache.containsKey(cacheKey))
+ singletonCache.put(cacheKey, new SingleWriterBpfMap(path, key, value));
+ return singletonCache.get(cacheKey);
}
@Override
diff --git a/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h b/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h
index d716358..cd51004 100644
--- a/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h
+++ b/staticlibs/native/bpf_headers/include/bpf/BpfRingbuf.h
@@ -151,7 +151,7 @@
inline base::Result<void> BpfRingbufBase::Init(const char* path) {
- mRingFd.reset(mapRetrieveRW(path));
+ mRingFd.reset(mapRetrieveExclusiveRW(path));
if (!mRingFd.ok()) {
return android::base::ErrnoError()
<< "failed to retrieve ringbuffer at " << path;
diff --git a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h
index 6864bad..e11a9e2 100644
--- a/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h
+++ b/staticlibs/native/bpf_headers/include/bpf/bpf_helpers.h
@@ -117,6 +117,9 @@
unsigned _btf_min_bpfloader_ver SECTION("btf_min_bpfloader_ver") = 39u; \
unsigned _btf_user_min_bpfloader_ver SECTION("btf_user_min_bpfloader_ver") = 0xFFFFFFFFu
+#define DISABLE_ON_MAINLINE_BEFORE_U_QPR3() \
+ unsigned _netbpfload_min_ver SECTION("netbpfload_min_ver") = BPFLOADER_MAINLINE_U_QPR3_VERSION;
+
/* flag the resulting bpf .o file as critical to system functionality,
* loading all kernel version appropriate programs in it must succeed
* for bpfloader success
@@ -137,6 +140,7 @@
#define KVER_5_4 KVER(5, 4, 0)
#define KVER_5_8 KVER(5, 8, 0)
#define KVER_5_9 KVER(5, 9, 0)
+#define KVER_5_10 KVER(5, 10, 0)
#define KVER_5_15 KVER(5, 15, 0)
#define KVER_6_1 KVER(6, 1, 0)
#define KVER_6_6 KVER(6, 6, 0)
diff --git a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h
index 2a0e8e0..73cef89 100644
--- a/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h
+++ b/staticlibs/native/bpf_syscall_wrappers/include/BpfSyscallWrappers.h
@@ -16,8 +16,11 @@
#pragma once
+#include <stdlib.h>
+#include <unistd.h>
#include <linux/bpf.h>
#include <linux/unistd.h>
+#include <sys/file.h>
#ifdef BPF_FD_JUST_USE_INT
#define BPF_FD_TYPE int
@@ -128,16 +131,61 @@
});
}
-inline int mapRetrieveRW(const char* pathname) {
+int bpfGetFdMapId(const BPF_FD_TYPE map_fd);
+
+inline int bpfLock(int fd, short type) {
+ if (fd < 0) return fd; // pass any errors straight through
+#ifdef BPF_MAP_LOCKLESS_FOR_TEST
+ return fd;
+#endif
+#ifdef BPF_FD_JUST_USE_INT
+ int mapId = bpfGetFdMapId(fd);
+ int saved_errno = errno;
+#else
+ base::unique_fd ufd(fd);
+ int mapId = bpfGetFdMapId(ufd);
+ int saved_errno = errno;
+ (void)ufd.release();
+#endif
+ // 4.14+ required to fetch map id, but we don't want to call isAtLeastKernelVersion
+ if (mapId == -1 && saved_errno == EINVAL) return fd;
+ if (mapId <= 0) abort(); // should not be possible
+
+ // on __LP64__ (aka. 64-bit userspace) 'struct flock64' is the same as 'struct flock'
+ struct flock64 fl = {
+ .l_type = type, // short: F_{RD,WR,UN}LCK
+ .l_whence = SEEK_SET, // short: SEEK_{SET,CUR,END}
+ .l_start = mapId, // off_t: start offset
+ .l_len = 1, // off_t: number of bytes
+ };
+
+ // see: bionic/libc/bionic/fcntl.cpp: iff !__LP64__ this uses fcntl64
+ int ret = fcntl(fd, F_OFD_SETLK, &fl);
+ if (!ret) return fd; // success
+ close(fd);
+ return ret; // most likely -1 with errno == EAGAIN, due to already held lock
+}
+
+inline int mapRetrieveLocklessRW(const char* pathname) {
return bpfFdGet(pathname, 0);
}
+inline int mapRetrieveExclusiveRW(const char* pathname) {
+ return bpfLock(mapRetrieveLocklessRW(pathname), F_WRLCK);
+}
+
+inline int mapRetrieveRW(const char* pathname) {
+ return bpfLock(mapRetrieveLocklessRW(pathname), F_RDLCK);
+}
+
inline int mapRetrieveRO(const char* pathname) {
return bpfFdGet(pathname, BPF_F_RDONLY);
}
+// WARNING: it's impossible to grab a shared (ie. read) lock on a write-only fd,
+// so we instead choose to grab an exclusive (ie. write) lock.
inline int mapRetrieveWO(const char* pathname) {
- return bpfFdGet(pathname, BPF_F_WRONLY);
+ return bpfLock(bpfFdGet(pathname, BPF_F_WRONLY), F_WRLCK);
}
inline int retrieveProgram(const char* pathname) {
diff --git a/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp b/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp
index b92f107..1923ceb 100644
--- a/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp
+++ b/staticlibs/native/bpfmapjni/com_android_net_module_util_BpfMap.cpp
@@ -35,7 +35,24 @@
jstring path, jint mode, jint keySize, jint valueSize) {
ScopedUtfChars pathname(env, path);
- jint fd = bpf::bpfFdGet(pathname.c_str(), static_cast<unsigned>(mode));
+ jint fd = -1;
+ switch (mode) {
+ case 0:
+ fd = bpf::mapRetrieveRW(pathname.c_str());
+ break;
+ case BPF_F_RDONLY:
+ fd = bpf::mapRetrieveRO(pathname.c_str());
+ break;
+ case BPF_F_WRONLY:
+ fd = bpf::mapRetrieveWO(pathname.c_str());
+ break;
+ case BPF_F_RDONLY|BPF_F_WRONLY:
+ fd = bpf::mapRetrieveExclusiveRW(pathname.c_str());
+ break;
+ default:
+ errno = EINVAL;
+ break;
+ }
if (fd < 0) {
jniThrowErrnoException(env, "nativeBpfFdGet", errno);
diff --git a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNlAttrTest.java b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNlAttrTest.java
index 4c3fde6..b5e3dff 100644
--- a/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNlAttrTest.java
+++ b/staticlibs/tests/unit/src/com/android/net/module/util/netlink/StructNlAttrTest.java
@@ -69,11 +69,11 @@
}
@Test
- public void testGetValueAsIntger() {
+ public void testGetValueAsInteger() {
final StructNlAttr attr1 = new StructNlAttr(IFA_FLAGS, TEST_ADDR_FLAGS);
final Integer integer1 = attr1.getValueAsInteger();
final int int1 = attr1.getValueAsInt(0x08 /* default value */);
- assertEquals(integer1, new Integer(TEST_ADDR_FLAGS));
+ assertEquals(integer1, Integer.valueOf(TEST_ADDR_FLAGS));
assertEquals(int1, TEST_ADDR_FLAGS);
// Malformed attribute.
diff --git a/tests/mts/bpf_existence_test.cpp b/tests/mts/bpf_existence_test.cpp
index 51a4eca..3f0f3e9 100644
--- a/tests/mts/bpf_existence_test.cpp
+++ b/tests/mts/bpf_existence_test.cpp
@@ -68,6 +68,8 @@
TETHERING "map_offload_tether_upstream6_map",
TETHERING "map_test_bitmap",
TETHERING "map_test_tether_downstream6_map",
+ TETHERING "map_test_tether2_downstream6_map",
+ TETHERING "map_test_tether3_downstream6_map",
TETHERING "prog_offload_schedcls_tether_downstream4_ether",
TETHERING "prog_offload_schedcls_tether_downstream4_rawip",
TETHERING "prog_offload_schedcls_tether_downstream6_ether",
@@ -91,6 +93,8 @@
SHARED "map_dscpPolicy_ipv4_dscp_policies_map",
SHARED "map_dscpPolicy_ipv6_dscp_policies_map",
SHARED "map_dscpPolicy_socket_policy_cache_map",
+ SHARED "map_gentle_test",
+ SHARED "prog_gentle_skfilter_accept",
NETD "map_netd_app_uid_stats_map",
NETD "map_netd_configuration_map",
NETD "map_netd_cookie_tag_map",
@@ -141,6 +145,23 @@
NETD "map_netd_packet_trace_ringbuf",
};
+// Provided by *current* mainline module for V+ devices
+static const set<string> MAINLINE_FOR_V_PLUS = {
+};
+
+// Provided by *current* mainline module for V+ devices with 5.15+ kernels
+static const set<string> MAINLINE_FOR_V_5_15_PLUS = {
+ NETD "prog_netd_connect4_inet4_connect",
+ NETD "prog_netd_connect6_inet6_connect",
+ NETD "prog_netd_recvmsg4_udp4_recvmsg",
+ NETD "prog_netd_recvmsg6_udp6_recvmsg",
+ NETD "prog_netd_sendmsg4_udp4_sendmsg",
+ NETD "prog_netd_sendmsg6_udp6_sendmsg",
+ NETD "prog_netd_getsockopt_prog",
+ NETD "prog_netd_setsockopt_prog",
+ NETD "prog_netd_cgroupsockrelease_inet_release",
+};
+
static void addAll(set<string>& a, const set<string>& b) {
a.insert(b.begin(), b.end());
}
@@ -188,6 +209,8 @@
// V requires Linux Kernel 4.19+, but nothing (as yet) added or removed in V.
if (IsAtLeastV()) ASSERT_TRUE(isAtLeastKernelVersion(4, 19, 0));
+ DO_EXPECT(IsAtLeastV(), MAINLINE_FOR_V_PLUS);
+ DO_EXPECT(IsAtLeastV() && isAtLeastKernelVersion(5, 15, 0), MAINLINE_FOR_V_5_15_PLUS);
for (const auto& file : mustExist) {
EXPECT_EQ(0, access(file.c_str(), R_OK)) << file << " does not exist";
diff --git a/tests/native/utilities/firewall.h b/tests/native/utilities/firewall.h
index b3d69bf..a5cb0b9 100644
--- a/tests/native/utilities/firewall.h
+++ b/tests/native/utilities/firewall.h
@@ -18,6 +18,7 @@
#pragma once
#include <android-base/thread_annotations.h>
+#define BPF_MAP_LOCKLESS_FOR_TEST
#include <bpf/BpfMap.h>
#include "netd.h"