Merge "[TetheringGoogle] Remove explicit targetSdkVersion"
diff --git a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
index ebc9d26..6a5089d 100644
--- a/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
+++ b/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java
@@ -403,6 +403,18 @@
return null;
}
}
+
+ /** Get error BPF map. */
+ @Nullable public IBpfMap<S32, S32> getBpfErrorMap() {
+ if (!isAtLeastS()) return null;
+ try {
+ return new BpfMap<>(TETHER_ERROR_MAP_PATH,
+ BpfMap.BPF_F_RDONLY, S32.class, S32.class);
+ } catch (ErrnoException e) {
+ Log.e(TAG, "Cannot create error map: " + e);
+ return null;
+ }
+ }
}
@VisibleForTesting
@@ -1287,13 +1299,15 @@
}
private void dumpCounters(@NonNull IndentingPrintWriter pw) {
- if (!mDeps.isAtLeastS()) {
- pw.println("No counter support");
- return;
- }
- try (IBpfMap<S32, S32> map = new BpfMap<>(TETHER_ERROR_MAP_PATH, BpfMap.BPF_F_RDONLY,
- S32.class, S32.class)) {
-
+ try (IBpfMap<S32, S32> map = mDeps.getBpfErrorMap()) {
+ if (map == null) {
+ pw.println("No error counter support");
+ return;
+ }
+ if (map.isEmpty()) {
+ pw.println("<empty>");
+ return;
+ }
map.forEach((k, v) -> {
String counterName;
try {
@@ -1307,7 +1321,7 @@
if (v.val > 0) pw.println(String.format("%s: %d", counterName, v.val));
});
} catch (ErrnoException | IOException e) {
- pw.println("Error dumping counter map: " + e);
+ pw.println("Error dumping error counter map: " + e);
}
}
diff --git a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
index b7eb92c..f0d9057 100644
--- a/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
+++ b/Tethering/tests/unit/src/android/net/ip/IpServerTest.java
@@ -100,6 +100,7 @@
import com.android.net.module.util.InterfaceParams;
import com.android.net.module.util.NetworkStackConstants;
import com.android.net.module.util.SharedLog;
+import com.android.net.module.util.Struct.S32;
import com.android.net.module.util.bpf.Tether4Key;
import com.android.net.module.util.bpf.Tether4Value;
import com.android.net.module.util.bpf.TetherStatsKey;
@@ -199,6 +200,7 @@
@Mock private BpfMap<TetherStatsKey, TetherStatsValue> mBpfStatsMap;
@Mock private BpfMap<TetherLimitKey, TetherLimitValue> mBpfLimitMap;
@Mock private BpfMap<TetherDevKey, TetherDevValue> mBpfDevMap;
+ @Mock private BpfMap<S32, S32> mBpfErrorMap;
@Captor private ArgumentCaptor<DhcpServingParamsParcel> mDhcpParamsCaptor;
@@ -362,6 +364,11 @@
public BpfMap<TetherDevKey, TetherDevValue> getBpfDevMap() {
return mBpfDevMap;
}
+
+ @Nullable
+ public BpfMap<S32, S32> getBpfErrorMap() {
+ return mBpfErrorMap;
+ }
};
mBpfCoordinator = spy(new BpfCoordinator(mBpfDeps));
diff --git a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
index bbca565..0bd6380 100644
--- a/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
+++ b/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java
@@ -94,11 +94,13 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.internal.util.IndentingPrintWriter;
import com.android.net.module.util.CollectionUtils;
import com.android.net.module.util.IBpfMap;
import com.android.net.module.util.InterfaceParams;
import com.android.net.module.util.NetworkStackConstants;
import com.android.net.module.util.SharedLog;
+import com.android.net.module.util.Struct.S32;
import com.android.net.module.util.bpf.Tether4Key;
import com.android.net.module.util.bpf.Tether4Value;
import com.android.net.module.util.bpf.TetherStatsKey;
@@ -128,6 +130,7 @@
import org.mockito.MockitoAnnotations;
import org.mockito.MockitoSession;
+import java.io.StringWriter;
import java.net.Inet4Address;
import java.net.Inet6Address;
import java.net.InetAddress;
@@ -362,9 +365,6 @@
@Mock private IpServer mIpServer2;
@Mock private TetheringConfiguration mTetherConfig;
@Mock private ConntrackMonitor mConntrackMonitor;
- @Mock private IBpfMap<TetherDownstream6Key, Tether6Value> mBpfDownstream6Map;
- @Mock private IBpfMap<TetherUpstream6Key, Tether6Value> mBpfUpstream6Map;
- @Mock private IBpfMap<TetherDevKey, TetherDevValue> mBpfDevMap;
// Late init since methods must be called by the thread that created this object.
private TestableNetworkStatsProviderCbBinder mTetherStatsProviderCb;
@@ -383,10 +383,18 @@
spy(new TestBpfMap<>(Tether4Key.class, Tether4Value.class));
private final IBpfMap<Tether4Key, Tether4Value> mBpfUpstream4Map =
spy(new TestBpfMap<>(Tether4Key.class, Tether4Value.class));
+ private final IBpfMap<TetherDownstream6Key, Tether6Value> mBpfDownstream6Map =
+ spy(new TestBpfMap<>(TetherDownstream6Key.class, Tether6Value.class));
+ private final IBpfMap<TetherUpstream6Key, Tether6Value> mBpfUpstream6Map =
+ spy(new TestBpfMap<>(TetherUpstream6Key.class, Tether6Value.class));
private final IBpfMap<TetherStatsKey, TetherStatsValue> mBpfStatsMap =
spy(new TestBpfMap<>(TetherStatsKey.class, TetherStatsValue.class));
private final IBpfMap<TetherLimitKey, TetherLimitValue> mBpfLimitMap =
spy(new TestBpfMap<>(TetherLimitKey.class, TetherLimitValue.class));
+ private final IBpfMap<TetherDevKey, TetherDevValue> mBpfDevMap =
+ spy(new TestBpfMap<>(TetherDevKey.class, TetherDevValue.class));
+ private final IBpfMap<S32, S32> mBpfErrorMap =
+ spy(new TestBpfMap<>(S32.class, S32.class));
private BpfCoordinator.Dependencies mDeps =
spy(new BpfCoordinator.Dependencies() {
@NonNull
@@ -457,6 +465,11 @@
public IBpfMap<TetherDevKey, TetherDevValue> getBpfDevMap() {
return mBpfDevMap;
}
+
+ @Nullable
+ public IBpfMap<S32, S32> getBpfErrorMap() {
+ return mBpfErrorMap;
+ }
});
@Before public void setUp() {
@@ -2099,4 +2112,88 @@
assertEquals("upstreamIfindex: 1001, downstreamIfindex: 1003, address: 2001:db8::1, "
+ "srcMac: 12:34:56:78:90:ab, dstMac: 00:00:00:00:00:0a", rule.toString());
}
+
+ private void verifyDump(@NonNull final BpfCoordinator coordinator) {
+ final StringWriter stringWriter = new StringWriter();
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(stringWriter, " ");
+ coordinator.dump(ipw);
+ assertFalse(stringWriter.toString().isEmpty());
+ }
+
+ @Test
+ public void testDumpDoesNotCrash() throws Exception {
+ // This dump test only used to for improving mainline module test coverage and doesn't
+ // really do any meaningful tests.
+ // TODO: consider verifying the dump content and separate tests into testDumpXXX().
+ final BpfCoordinator coordinator = makeBpfCoordinator();
+
+ // [1] Dump mostly empty content.
+ verifyDump(coordinator);
+
+ // [2] Dump mostly non-empty content.
+ // Test the following dump function and fill the corresponding content to execute
+ // code as more as possible for test coverage.
+ // - dumpBpfForwardingRulesIpv4
+ // * mBpfDownstream4Map
+ // * mBpfUpstream4Map
+ // - dumpBpfForwardingRulesIpv6
+ // * mBpfDownstream6Map
+ // * mBpfUpstream6Map
+ // - dumpStats
+ // * mBpfStatsMap
+ // - dumpDevmap
+ // * mBpfDevMap
+ // - dumpCounters
+ // * mBpfErrorMap
+ // - dumpIpv6ForwardingRulesByDownstream
+ // * mIpv6ForwardingRules
+
+ // dumpBpfForwardingRulesIpv4
+ mBpfDownstream4Map.insertEntry(
+ new TestDownstream4Key.Builder().build(),
+ new TestDownstream4Value.Builder().build());
+ mBpfUpstream4Map.insertEntry(
+ new TestUpstream4Key.Builder().build(),
+ new TestUpstream4Value.Builder().build());
+
+ // dumpBpfForwardingRulesIpv6
+ final Ipv6ForwardingRule rule = buildTestForwardingRule(UPSTREAM_IFINDEX, NEIGH_A, MAC_A);
+ mBpfDownstream6Map.insertEntry(rule.makeTetherDownstream6Key(), rule.makeTether6Value());
+
+ final TetherUpstream6Key upstream6Key = new TetherUpstream6Key(DOWNSTREAM_IFINDEX,
+ DOWNSTREAM_MAC);
+ final Tether6Value upstream6Value = new Tether6Value(UPSTREAM_IFINDEX,
+ MacAddress.ALL_ZEROS_ADDRESS, MacAddress.ALL_ZEROS_ADDRESS,
+ ETH_P_IPV6, NetworkStackConstants.ETHER_MTU);
+ mBpfUpstream6Map.insertEntry(upstream6Key, upstream6Value);
+
+ // dumpStats
+ mBpfStatsMap.insertEntry(
+ new TetherStatsKey(UPSTREAM_IFINDEX),
+ new TetherStatsValue(
+ 0L /* rxPackets */, 0L /* rxBytes */, 0L /* rxErrors */,
+ 0L /* txPackets */, 0L /* txBytes */, 0L /* txErrors */));
+
+ // dumpDevmap
+ coordinator.addUpstreamNameToLookupTable(UPSTREAM_IFINDEX, UPSTREAM_IFACE);
+ mBpfDevMap.insertEntry(
+ new TetherDevKey(UPSTREAM_IFINDEX),
+ new TetherDevValue(UPSTREAM_IFINDEX));
+
+ // dumpCounters
+ // The error code is defined in packages/modules/Connectivity/bpf_progs/bpf_tethering.h.
+ mBpfErrorMap.insertEntry(
+ new S32(0 /* INVALID_IPV4_VERSION */),
+ new S32(1000 /* count */));
+
+ // dumpIpv6ForwardingRulesByDownstream
+ final HashMap<IpServer, LinkedHashMap<Inet6Address, Ipv6ForwardingRule>>
+ ipv6ForwardingRules = coordinator.getForwardingRulesForTesting();
+ final LinkedHashMap<Inet6Address, Ipv6ForwardingRule> addressRuleMap =
+ new LinkedHashMap<>();
+ addressRuleMap.put(rule.address, rule);
+ ipv6ForwardingRules.put(mIpServer, addressRuleMap);
+
+ verifyDump(coordinator);
+ }
}
diff --git a/bpf_progs/bpf_net_helpers.h b/bpf_progs/bpf_net_helpers.h
index e382713..c39269e 100644
--- a/bpf_progs/bpf_net_helpers.h
+++ b/bpf_progs/bpf_net_helpers.h
@@ -28,9 +28,12 @@
static int (*bpf_skb_pull_data)(struct __sk_buff* skb, __u32 len) = (void*)BPF_FUNC_skb_pull_data;
-static int (*bpf_skb_load_bytes)(struct __sk_buff* skb, int off, void* to,
+static int (*bpf_skb_load_bytes)(const struct __sk_buff* skb, int off, void* to,
int len) = (void*)BPF_FUNC_skb_load_bytes;
+static int (*bpf_skb_load_bytes_relative)(const struct __sk_buff* skb, int off, void* to, int len,
+ int start_hdr) = (void*)BPF_FUNC_skb_load_bytes_relative;
+
static int (*bpf_skb_store_bytes)(struct __sk_buff* skb, __u32 offset, const void* from, __u32 len,
__u64 flags) = (void*)BPF_FUNC_skb_store_bytes;
diff --git a/bpf_progs/netd.c b/bpf_progs/netd.c
index 10559dd..f9484fc 100644
--- a/bpf_progs/netd.c
+++ b/bpf_progs/netd.c
@@ -47,9 +47,16 @@
#define IP_PROTO_OFF offsetof(struct iphdr, protocol)
#define IPV6_PROTO_OFF offsetof(struct ipv6hdr, nexthdr)
+
+// offsetof(struct iphdr, ihl) -- but that's a bitfield
#define IPPROTO_IHL_OFF 0
-#define TCP_FLAG_OFF 13
-#define RST_OFFSET 2
+
+// This is offsetof(struct tcphdr, "32 bit tcp flag field")
+// The tcp flags are after be16 source, dest & be32 seq, ack_seq, hence 12 bytes in.
+//
+// Note that TCP_FLAG_{ACK,PSH,RST,SYN,FIN} are htonl(0x00{10,08,04,02,01}0000)
+// see include/uapi/linux/tcp.h
+#define TCP_FLAG32_OFF 12
// For maps netd does not need to access
#define DEFINE_BPF_MAP_NO_NETD(the_map, TYPE, TypeOfKey, TypeOfValue, num_entries) \
@@ -97,9 +104,15 @@
// programs that need to be usable by netd, but not by netutils_wrappers
// (this is because these are currently attached by the mainline provided libnetd_updatable .so
// which is loaded into netd and thus runs as netd uid/gid/selinux context)
-#define DEFINE_NETD_BPF_PROG(SECTION_NAME, prog_uid, prog_gid, the_prog) \
+#define DEFINE_NETD_BPF_PROG_KVER_RANGE(SECTION_NAME, prog_uid, prog_gid, the_prog, minKV, maxKV) \
DEFINE_BPF_PROG_EXT(SECTION_NAME, prog_uid, prog_gid, the_prog, \
- KVER_NONE, KVER_INF, false, "fs_bpf_netd_readonly", "")
+ minKV, maxKV, false, "fs_bpf_netd_readonly", "")
+
+#define DEFINE_NETD_BPF_PROG_KVER(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv) \
+ DEFINE_NETD_BPF_PROG_KVER_RANGE(SECTION_NAME, prog_uid, prog_gid, the_prog, min_kv, KVER_INF)
+
+#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)
// programs that only need to be usable by the system server
#define DEFINE_SYS_BPF_PROG(SECTION_NAME, prog_uid, prog_gid, the_prog) \
@@ -176,46 +189,49 @@
DEFINE_UPDATE_STATS(stats_map_A, StatsKey)
DEFINE_UPDATE_STATS(stats_map_B, StatsKey)
-static inline bool skip_owner_match(struct __sk_buff* skb) {
- int offset = -1;
- int ret = 0;
+// both of these return 0 on success or -EFAULT on failure (and zero out the buffer)
+static __always_inline inline int bpf_skb_load_bytes_net(const struct __sk_buff* skb, int off,
+ void* to, int len, bool is_4_19) {
+ return is_4_19
+ ? bpf_skb_load_bytes_relative(skb, off, to, len, BPF_HDR_START_NET)
+ : bpf_skb_load_bytes(skb, off, to, len);
+}
+
+static __always_inline inline bool skip_owner_match(struct __sk_buff* skb, bool is_4_19) {
if (skb->protocol == htons(ETH_P_IP)) {
- offset = IP_PROTO_OFF;
- uint8_t proto, ihl;
- uint8_t flag;
- ret = bpf_skb_load_bytes(skb, offset, &proto, 1);
- if (!ret) {
- if (proto == IPPROTO_ESP) {
- return true;
- } else if (proto == IPPROTO_TCP) {
- ret = bpf_skb_load_bytes(skb, IPPROTO_IHL_OFF, &ihl, 1);
- ihl = ihl & 0x0F;
- ret = bpf_skb_load_bytes(skb, ihl * 4 + TCP_FLAG_OFF, &flag, 1);
- if (ret == 0 && (flag >> RST_OFFSET & 1)) {
- return true;
- }
- }
- }
- } else if (skb->protocol == htons(ETH_P_IPV6)) {
- offset = IPV6_PROTO_OFF;
uint8_t proto;
- ret = bpf_skb_load_bytes(skb, offset, &proto, 1);
- if (!ret) {
- if (proto == IPPROTO_ESP) {
- return true;
- } else if (proto == IPPROTO_TCP) {
- uint8_t flag;
- ret = bpf_skb_load_bytes(skb, sizeof(struct ipv6hdr) + TCP_FLAG_OFF, &flag, 1);
- if (ret == 0 && (flag >> RST_OFFSET & 1)) {
- return true;
- }
- }
- }
+ // no need to check for success, proto will be zeroed if bpf_skb_load_bytes_net() fails
+ (void)bpf_skb_load_bytes_net(skb, IP_PROTO_OFF, &proto, sizeof(proto), is_4_19);
+ if (proto == IPPROTO_ESP) return true;
+ if (proto != IPPROTO_TCP) return false; // handles read failure above
+ uint8_t ihl;
+ // we don't check for success, as this cannot fail, as it is earlier in the packet than
+ // proto, the reading of which must have succeeded, additionally the next read
+ // (a little bit deeper in the packet in spite of ihl being zeroed) of the tcp flags
+ // field will also fail, and that failure we already handle correctly
+ // (we also don't check that ihl in [0x45,0x4F] nor that ipv4 header checksum is correct)
+ (void)bpf_skb_load_bytes_net(skb, IPPROTO_IHL_OFF, &ihl, sizeof(ihl), is_4_19);
+ uint32_t flag;
+ // if the read below fails, we'll just assume no TCP flags are set, which is fine.
+ (void)bpf_skb_load_bytes_net(skb, (ihl & 0xF) * 4 + TCP_FLAG32_OFF,
+ &flag, sizeof(flag), is_4_19);
+ return flag & TCP_FLAG_RST; // false on read failure
+ } else if (skb->protocol == htons(ETH_P_IPV6)) {
+ uint8_t proto;
+ // no need to check for success, proto will be zeroed if bpf_skb_load_bytes_net() fails
+ (void)bpf_skb_load_bytes_net(skb, IPV6_PROTO_OFF, &proto, sizeof(proto), is_4_19);
+ if (proto == IPPROTO_ESP) return true;
+ if (proto != IPPROTO_TCP) return false; // handles read failure above
+ uint32_t flag;
+ // if the read below fails, we'll just assume no TCP flags are set, which is fine.
+ (void)bpf_skb_load_bytes_net(skb, sizeof(struct ipv6hdr) + TCP_FLAG32_OFF,
+ &flag, sizeof(flag), is_4_19);
+ return flag & TCP_FLAG_RST; // false on read failure
}
return false;
}
-static __always_inline BpfConfig getConfig(uint32_t configKey) {
+static __always_inline inline BpfConfig getConfig(uint32_t configKey) {
uint32_t mapSettingKey = configKey;
BpfConfig* config = bpf_configuration_map_lookup_elem(&mapSettingKey);
if (!config) {
@@ -230,8 +246,9 @@
// DROP_IF_UNSET is set of rules that should DROP if globally enabled, and per-uid bit is NOT set
#define DROP_IF_UNSET (DOZABLE_MATCH | POWERSAVE_MATCH | RESTRICTED_MATCH | LOW_POWER_STANDBY_MATCH)
-static inline int bpf_owner_match(struct __sk_buff* skb, uint32_t uid, int direction) {
- if (skip_owner_match(skb)) return BPF_PASS;
+static __always_inline inline int bpf_owner_match(struct __sk_buff* skb, uint32_t uid,
+ int direction, bool is_4_19) {
+ if (skip_owner_match(skb, is_4_19)) return BPF_PASS;
if (is_system_uid(uid)) return BPF_PASS;
@@ -273,7 +290,8 @@
}
}
-static __always_inline inline int bpf_traffic_account(struct __sk_buff* skb, int direction) {
+static __always_inline inline int bpf_traffic_account(struct __sk_buff* skb, int direction,
+ bool is_4_19) {
uint32_t sock_uid = bpf_get_socket_uid(skb);
uint64_t cookie = bpf_get_socket_cookie(skb);
UidTagValue* utag = bpf_cookie_tag_map_lookup_elem(&cookie);
@@ -293,7 +311,7 @@
return BPF_PASS;
}
- int match = bpf_owner_match(skb, sock_uid, direction);
+ int match = bpf_owner_match(skb, sock_uid, direction, is_4_19);
if ((direction == BPF_EGRESS) && (match == BPF_DROP)) {
// If an outbound packet is going to be dropped, we do not count that
// traffic.
@@ -338,14 +356,28 @@
return match;
}
-DEFINE_NETD_BPF_PROG("cgroupskb/ingress/stats", AID_ROOT, AID_SYSTEM, bpf_cgroup_ingress)
+DEFINE_NETD_BPF_PROG_KVER_RANGE("cgroupskb/ingress/stats$4_19", AID_ROOT, AID_SYSTEM,
+ bpf_cgroup_ingress_4_19, KVER(4, 19, 0), KVER_INF)
(struct __sk_buff* skb) {
- return bpf_traffic_account(skb, BPF_INGRESS);
+ return bpf_traffic_account(skb, BPF_INGRESS, /* is_4_19 */ true);
}
-DEFINE_NETD_BPF_PROG("cgroupskb/egress/stats", AID_ROOT, AID_SYSTEM, bpf_cgroup_egress)
+DEFINE_NETD_BPF_PROG_KVER_RANGE("cgroupskb/ingress/stats$4_14", AID_ROOT, AID_SYSTEM,
+ bpf_cgroup_ingress_4_14, KVER_NONE, KVER(4, 19, 0))
(struct __sk_buff* skb) {
- return bpf_traffic_account(skb, BPF_EGRESS);
+ return bpf_traffic_account(skb, BPF_INGRESS, /* is_4_19 */ false);
+}
+
+DEFINE_NETD_BPF_PROG_KVER_RANGE("cgroupskb/egress/stats$4_19", AID_ROOT, AID_SYSTEM,
+ bpf_cgroup_egress_4_19, KVER(4, 19, 0), KVER_INF)
+(struct __sk_buff* skb) {
+ return bpf_traffic_account(skb, BPF_EGRESS, /* is_4_19 */ true);
+}
+
+DEFINE_NETD_BPF_PROG_KVER_RANGE("cgroupskb/egress/stats$4_14", AID_ROOT, AID_SYSTEM,
+ bpf_cgroup_egress_4_14, KVER_NONE, KVER(4, 19, 0))
+(struct __sk_buff* skb) {
+ return bpf_traffic_account(skb, BPF_EGRESS, /* is_4_19 */ false);
}
// WARNING: Android T's non-updatable netd depends on the name of this program.
@@ -419,7 +451,8 @@
return BPF_NOMATCH;
}
-DEFINE_NETD_BPF_PROG("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, 0))
(struct bpf_sock* sk) {
uint64_t gid_uid = bpf_get_current_uid_gid();
/*
diff --git a/nearby/halfsheet/Android.bp b/nearby/halfsheet/Android.bp
index 486a3ff..c84caa6 100644
--- a/nearby/halfsheet/Android.bp
+++ b/nearby/halfsheet/Android.bp
@@ -23,7 +23,6 @@
sdk_version: "module_current",
// This is included in tethering apex, which uses min SDK 30
min_sdk_version: "30",
- target_sdk_version: "current",
updatable: true,
certificate: ":com.android.nearby.halfsheetcertificate",
libs: [
diff --git a/netd/BpfHandler.cpp b/netd/BpfHandler.cpp
index 3f7ed2a..7950ff7 100644
--- a/netd/BpfHandler.cpp
+++ b/netd/BpfHandler.cpp
@@ -87,7 +87,16 @@
RETURN_IF_NOT_OK(checkProgramAccessible(XT_BPF_INGRESS_PROG_PATH));
RETURN_IF_NOT_OK(attachProgramToCgroup(BPF_EGRESS_PROG_PATH, cg_fd, BPF_CGROUP_INET_EGRESS));
RETURN_IF_NOT_OK(attachProgramToCgroup(BPF_INGRESS_PROG_PATH, cg_fd, BPF_CGROUP_INET_INGRESS));
- RETURN_IF_NOT_OK(attachProgramToCgroup(CGROUP_SOCKET_PROG_PATH, cg_fd, BPF_CGROUP_INET_SOCK_CREATE));
+
+ // For the devices that support cgroup socket filter, the socket filter
+ // should be loaded successfully by bpfloader. So we attach the filter to
+ // cgroup if the program is pinned properly.
+ // TODO: delete the if statement once all devices should support cgroup
+ // socket filter (ie. the minimum kernel version required is 4.14).
+ if (!access(CGROUP_SOCKET_PROG_PATH, F_OK)) {
+ RETURN_IF_NOT_OK(
+ attachProgramToCgroup(CGROUP_SOCKET_PROG_PATH, cg_fd, BPF_CGROUP_INET_SOCK_CREATE));
+ }
return netdutils::status::ok;
}
diff --git a/tests/mts/bpf_existence_test.cpp b/tests/mts/bpf_existence_test.cpp
index bb07a98..aa5654a 100644
--- a/tests/mts/bpf_existence_test.cpp
+++ b/tests/mts/bpf_existence_test.cpp
@@ -105,7 +105,6 @@
SHARED "prog_clatd_schedcls_ingress6_clat_rawip",
NETD "prog_netd_cgroupskb_egress_stats",
NETD "prog_netd_cgroupskb_ingress_stats",
- NETD "prog_netd_cgroupsock_inet_create",
NETD "prog_netd_schedact_ingress_account",
NETD "prog_netd_skfilter_allowlist_xtbpf",
NETD "prog_netd_skfilter_denylist_xtbpf",
@@ -113,6 +112,11 @@
NETD "prog_netd_skfilter_ingress_xtbpf",
};
+// Provided by *current* mainline module for T+ devices with 4.14+ kernels
+static const set<string> MAINLINE_FOR_T_4_14_PLUS = {
+ NETD "prog_netd_cgroupsock_inet_create",
+};
+
// Provided by *current* mainline module for T+ devices with 5.4+ kernels
static const set<string> MAINLINE_FOR_T_5_4_PLUS = {
SHARED "prog_block_bind4_block_port",
@@ -151,6 +155,7 @@
// Nothing added or removed in SCv2.
DO_EXPECT(IsAtLeastT(), MAINLINE_FOR_T_PLUS);
+ DO_EXPECT(IsAtLeastT() && isAtLeastKernelVersion(4, 14, 0), MAINLINE_FOR_T_4_14_PLUS);
DO_EXPECT(IsAtLeastT() && isAtLeastKernelVersion(5, 4, 0), MAINLINE_FOR_T_5_4_PLUS);
DO_EXPECT(IsAtLeastT() && isAtLeastKernelVersion(5, 15, 0), MAINLINE_FOR_T_5_15_PLUS);
}
diff --git a/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java b/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
index 49e3514..b651c33 100644
--- a/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
+++ b/tests/unit/java/com/android/server/connectivity/ClatCoordinatorTest.java
@@ -222,7 +222,7 @@
public String generateIpv6Address(@NonNull String iface, @NonNull String v4,
@NonNull String prefix64, int mark) throws IOException {
if (BASE_IFACE.equals(iface) && XLAT_LOCAL_IPV4ADDR_STRING.equals(v4)
- && NAT64_PREFIX_STRING.equals(prefix64)) {
+ && NAT64_PREFIX_STRING.equals(prefix64) && MARK == mark) {
return XLAT_LOCAL_IPV6ADDR_STRING;
}
fail("unsupported args: " + iface + ", " + v4 + ", " + prefix64 + ", " + mark);
diff --git a/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketClientTests.java b/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketClientTests.java
index f84ebfb..b4442a5 100644
--- a/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketClientTests.java
+++ b/tests/unit/java/com/android/server/connectivity/mdns/MdnsSocketClientTests.java
@@ -24,6 +24,7 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.argThat;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.never;
@@ -513,11 +514,8 @@
mdnsClient.setCallback(mockCallback);
mdnsClient.startDiscovery();
- ArgumentCaptor<MdnsResponse> mdnsResponseCaptor =
- ArgumentCaptor.forClass(MdnsResponse.class);
- verify(mockCallback, timeout(TIMEOUT).atLeast(1))
- .onResponseReceived(mdnsResponseCaptor.capture());
- assertEquals(21, mdnsResponseCaptor.getValue().getInterfaceIndex());
+ verify(mockCallback, timeout(TIMEOUT).atLeastOnce())
+ .onResponseReceived(argThat(response -> response.getInterfaceIndex() == 21));
}
@Test
diff --git a/tools/gn2bp/gen_android_bp b/tools/gn2bp/gen_android_bp
index 1422b69..ee092db 100755
--- a/tools/gn2bp/gen_android_bp
+++ b/tools/gn2bp/gen_android_bp
@@ -339,7 +339,7 @@
self.local_include_dirs = set()
self.header_libs = set()
self.required = set()
- self.tool_files = []
+ self.tool_files = set()
self.android = Target('android')
self.host = Target('host')
self.stl = None
@@ -467,7 +467,7 @@
def is_supported_source_file(name):
"""Returns True if |name| can appear in a 'srcs' list."""
- return os.path.splitext(name)[1] in ['.c', '.cc', '.proto']
+ return os.path.splitext(name)[1] in ['.c', '.cc', '.java', '.proto']
def create_proto_modules(blueprint, gn, target):
@@ -598,9 +598,7 @@
def create_amalgamated_sql_metrics_module(blueprint, target):
bp_module_name = label_to_module_name(target.name)
module = Module('genrule', bp_module_name, target.name)
- module.tool_files = [
- 'tools/gen_amalgamated_sql_metrics.py',
- ]
+ module.tool_files.add('tools/gen_amalgamated_sql_metrics.py')
module.cmd = ' '.join([
'$(location tools/gen_amalgamated_sql_metrics.py)',
'--cpp_out=$(out)',
@@ -616,9 +614,7 @@
def create_cc_proto_descriptor_module(blueprint, target):
bp_module_name = label_to_module_name(target.name)
module = Module('genrule', bp_module_name, target.name)
- module.tool_files = [
- 'tools/gen_cc_proto_descriptor.py',
- ]
+ module.tool_files.add('tools/gen_cc_proto_descriptor.py')
module.cmd = ' '.join([
'$(location tools/gen_cc_proto_descriptor.py)', '--gen_dir=$(genDir)',
'--cpp_out=$(out)', '$(in)'
@@ -639,7 +635,7 @@
module = Module('genrule', bp_module_name, gn_utils.GEN_VERSION_TARGET)
script_path = gn_utils.label_to_path(target.script)
module.genrule_headers.add(bp_module_name)
- module.tool_files = [script_path]
+ module.tool_files.add(script_path)
module.out.update(target.outputs)
module.srcs.update(gn_utils.label_to_path(src) for src in target.inputs)
module.cmd = ' '.join([
@@ -668,22 +664,39 @@
blueprint.add_module(module)
+
def create_action_module(blueprint, target):
bp_module_name = label_to_module_name(target.name)
module = Module('genrule', bp_module_name, target.name)
script = gn_utils.label_to_path(target.script)
- module.tool_files = [script]
+ module.tool_files.add(script)
+
+ # Handle passing parameters via response file by piping them into the script
+ # and reading them from /dev/stdin.
+ response_file = '{{response_file_name}}'
+ use_response_file = response_file in target.args
+ if use_response_file:
+ # Replace {{response_file_contents}} with /dev/stdin
+ target.args = ['/dev/stdin' if it == response_file else it for it in target.args]
arg_string = ' '.join(target.args)
module.cmd = '$(location %s) %s' % (script, arg_string)
+ if use_response_file:
+ # Pipe response file contents into script
+ module.cmd = 'echo \'%s\' | %s' % (target.response_file_contents, module.cmd)
+
if all(os.path.splitext(it)[1] == '.h' for it in target.outputs):
module.genrule_headers.add(bp_module_name)
- # For gn actions, sources and inputs are treated equally.
- # TODO: there should be a label_to_path function that takes a set / list.
- module.srcs.update(gn_utils.label_to_path(it) for it in target.inputs)
- module.srcs.update(gn_utils.label_to_path(it) for it in target.sources)
+ # gn treats inputs and sources for actions equally.
+ # soong only supports source files inside srcs, non-source files are added as
+ # tool_files dependency.
+ for it in target.sources or target.inputs:
+ if is_supported_source_file(it):
+ module.srcs.add(gn_utils.label_to_path(it))
+ else:
+ module.tool_files.add(gn_utils.label_to_path(it))
# Actions using template "action_with_pydeps" also put script inside inputs.
# TODO: it might make sense to filter inputs inside GnParser.
@@ -826,11 +839,6 @@
if not module_is_compiled:
continue
-
- # Don't recurse in any other //gn dep if not handled by builtin_deps.
- if dep_name.startswith('//gn:'):
- continue
-
if dep_module is None:
continue
if dep_module.type == 'cc_library_shared':
diff --git a/tools/gn2bp/gn_utils.py b/tools/gn2bp/gn_utils.py
index 6cf5b7d..ef3bf55 100644
--- a/tools/gn2bp/gn_utils.py
+++ b/tools/gn2bp/gn_utils.py
@@ -120,6 +120,7 @@
self.outputs = set()
self.script = None
self.args = []
+ self.response_file_contents = None
# These variables are propagated up when encountering a dependency
# on a source_set target.
@@ -169,6 +170,13 @@
self.actions = {}
self.proto_libs = {}
+ def _get_response_file_contents(self, action_desc):
+ contents = ' '.join(action_desc.get('response_file_contents', []))
+ # escape both single and double quotes.
+ contents.replace('"', '\"')
+ contents.replace("'", '\'')
+ return contents
+
def get_target(self, gn_target_name):
"""Returns a Target object from the fully qualified GN target name.
@@ -225,6 +233,7 @@
# Args are typically relative to the root build dir (../../xxx)
# because root build dir is typically out/xxx/).
target.args = [re.sub('^../../', '//', x) for x in desc['args']]
+ target.response_file_contents = self._get_response_file_contents(desc)
elif target.type == 'copy':
# TODO: copy rules are not currently implemented.
self.actions[gn_target_name] = target