summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2018-05-13 07:24:36 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2018-05-13 07:24:36 +0000
commit26246ba974b4857a08102173e0beb0060296ae67 (patch)
tree51e319fbef4b05d051c2ac1c01d4c6b89f0dadc5
parentd2b518adc8e7c9c401ee63a78ce6e992994522f6 (diff)
parentf8f683fea2855ffb2d13ea93cfad1dada399c072 (diff)
downloadnetd-26246ba974b4857a08102173e0beb0060296ae67.tar.gz
Snap for 4778776 from f8f683fea2855ffb2d13ea93cfad1dada399c072 to pi-release
Change-Id: I058fb1ec40d45dc08265809af6def76401b77fa9
-rw-r--r--libbpf/BpfNetworkStatsTest.cpp16
-rw-r--r--libbpf/BpfUtils.cpp17
-rw-r--r--libbpf/include/bpf/BpfUtils.h7
-rw-r--r--server/TrafficControllerTest.cpp5
-rw-r--r--server/XfrmController.cpp6
-rw-r--r--tests/Android.mk3
-rw-r--r--tests/binder_test.cpp19
-rw-r--r--tests/bpf_base_test.cpp140
8 files changed, 202 insertions, 11 deletions
diff --git a/libbpf/BpfNetworkStatsTest.cpp b/libbpf/BpfNetworkStatsTest.cpp
index 33df0f20..d1f81576 100644
--- a/libbpf/BpfNetworkStatsTest.cpp
+++ b/libbpf/BpfNetworkStatsTest.cpp
@@ -153,6 +153,8 @@ class BpfNetworkStatsHelperTest : public testing::Test {
// TEST to verify the behavior of bpf map when cocurrent deletion happens when
// iterating the same map.
TEST_F(BpfNetworkStatsHelperTest, TestIterateMapWithDeletion) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
for (int i = 0; i < 5; i++) {
uint64_t cookie = i + 1;
struct UidTag tag = {.uid = TEST_UID1, .tag = TEST_TAG};
@@ -180,6 +182,8 @@ TEST_F(BpfNetworkStatsHelperTest, TestIterateMapWithDeletion) {
}
TEST_F(BpfNetworkStatsHelperTest, TestGetUidStatsTotal) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
StatsValue value1 = {.rxBytes = TEST_BYTES0,
.rxPackets = TEST_PACKET0,
@@ -214,6 +218,8 @@ TEST_F(BpfNetworkStatsHelperTest, TestGetUidStatsTotal) {
}
TEST_F(BpfNetworkStatsHelperTest, TestGetIfaceStatsInternal) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
updateIfaceMap(IFACE_NAME3, IFACE_INDEX3);
@@ -257,6 +263,8 @@ TEST_F(BpfNetworkStatsHelperTest, TestGetIfaceStatsInternal) {
}
TEST_F(BpfNetworkStatsHelperTest, TestGetStatsDetail) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
StatsValue value1 = {.rxBytes = TEST_BYTES0,
@@ -293,6 +301,8 @@ TEST_F(BpfNetworkStatsHelperTest, TestGetStatsDetail) {
}
TEST_F(BpfNetworkStatsHelperTest, TestGetStatsWithSkippedIface) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
StatsValue value1 = {.rxBytes = TEST_BYTES0,
@@ -326,6 +336,8 @@ TEST_F(BpfNetworkStatsHelperTest, TestGetStatsWithSkippedIface) {
}
TEST_F(BpfNetworkStatsHelperTest, TestGetStatsWithNoExistKey) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
StatsValue value1 = {
.rxBytes = TEST_BYTES0,
@@ -343,6 +355,8 @@ TEST_F(BpfNetworkStatsHelperTest, TestGetStatsWithNoExistKey) {
}
TEST_F(BpfNetworkStatsHelperTest, TestUnkownIfaceError) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
StatsValue value1 = {.rxBytes = TEST_BYTES0 * 20,
.rxPackets = TEST_PACKET0,
@@ -379,6 +393,8 @@ TEST_F(BpfNetworkStatsHelperTest, TestUnkownIfaceError) {
}
TEST_F(BpfNetworkStatsHelperTest, TestGetIfaceStatsDetail) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
updateIfaceMap(IFACE_NAME3, IFACE_INDEX3);
diff --git a/libbpf/BpfUtils.cpp b/libbpf/BpfUtils.cpp
index 41ba24ca..d6ea6d70 100644
--- a/libbpf/BpfUtils.cpp
+++ b/libbpf/BpfUtils.cpp
@@ -19,12 +19,14 @@
#include <linux/in.h>
#include <stdlib.h>
#include <string.h>
+#include <inttypes.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <sstream>
#include <string>
+#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <android-base/unique_fd.h>
#include <netdutils/Slice.h>
@@ -33,6 +35,7 @@
using android::base::StringPrintf;
using android::base::unique_fd;
+using android::base::GetUintProperty;
using android::netdutils::Slice;
using android::netdutils::statusFromErrno;
using android::netdutils::StatusOr;
@@ -206,14 +209,24 @@ bool hasBpfSupport() {
int kernel_version_major;
int kernel_version_minor;
+ uint64_t api_level = GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
+ if (api_level == 0) {
+ ALOGE("Cannot determine initial API level of the device");
+ api_level = GetUintProperty<uint64_t>("ro.build.version.sdk", 0);
+ }
+
int ret = uname(&buf);
if (ret) {
return false;
}
char dummy;
ret = sscanf(buf.release, "%d.%d%c", &kernel_version_major, &kernel_version_minor, &dummy);
- return (ret >= 2 && ((kernel_version_major > 4) ||
- (kernel_version_major == 4 && kernel_version_minor >= 9)));
+ if (ret >= 2 && ((kernel_version_major > 4) ||
+ (kernel_version_major == 4 && kernel_version_minor >= 9))) {
+ // Check if the device is shipped originally with android P.
+ return api_level >= MINIMUM_API_REQUIRED;
+ }
+ return false;
}
} // namespace bpf
diff --git a/libbpf/include/bpf/BpfUtils.h b/libbpf/include/bpf/BpfUtils.h
index 1ad62f41..550c9cae 100644
--- a/libbpf/include/bpf/BpfUtils.h
+++ b/libbpf/include/bpf/BpfUtils.h
@@ -94,6 +94,8 @@ constexpr const uint64_t NONEXISTENT_COOKIE = 0;
constexpr const uint32_t NONEXISTENT_UID = DEFAULT_OVERFLOWUID;
constexpr const uint32_t NONEXISTENT_IFACE_STATS_KEY = 0;
+constexpr const int MINIMUM_API_REQUIRED = 28;
+
int createMap(bpf_map_type map_type, uint32_t key_size, uint32_t value_size,
uint32_t max_entries, uint32_t map_flags);
int writeToMapEntry(const base::unique_fd& map_fd, void* key, void* value, uint64_t flags);
@@ -112,6 +114,11 @@ netdutils::StatusOr<base::unique_fd> setUpBPFMap(uint32_t key_size, uint32_t val
bpf_map_type map_type);
bool hasBpfSupport();
+#define SKIP_IF_BPF_NOT_SUPPORTED \
+ do { \
+ if (!hasBpfSupport()) return; \
+ } while (0);
+
constexpr int BPF_CONTINUE = 0;
constexpr int BPF_DELETED = 1;
diff --git a/server/TrafficControllerTest.cpp b/server/TrafficControllerTest.cpp
index afe5cd6b..187014f4 100644
--- a/server/TrafficControllerTest.cpp
+++ b/server/TrafficControllerTest.cpp
@@ -60,11 +60,6 @@ constexpr uint32_t TEST_TAG = 42;
constexpr int TEST_COUNTERSET = 1;
constexpr int DEFAULT_COUNTERSET = 0;
-#define SKIP_IF_BPF_NOT_SUPPORTED \
- do { \
- if (!hasBpfSupport()) return; \
- } while (0);
-
class TrafficControllerTest : public ::testing::Test {
protected:
TrafficControllerTest() {}
diff --git a/server/XfrmController.cpp b/server/XfrmController.cpp
index d762878e..8a891eb7 100644
--- a/server/XfrmController.cpp
+++ b/server/XfrmController.cpp
@@ -1346,7 +1346,8 @@ int XfrmController::addVirtualTunnelInterface(const std::string& deviceName,
flags |= NLM_F_EXCL | NLM_F_CREATE;
}
- int ret = sendNetlinkRequest(action, flags, iov, ARRAY_SIZE(iov), nullptr);
+ // sendNetlinkRequest returns -errno
+ int ret = -1 * sendNetlinkRequest(action, flags, iov, ARRAY_SIZE(iov), nullptr);
if (ret) {
ALOGE("Error in %s virtual tunnel interface. Error Code: %d",
isUpdate ? "updating" : "adding", ret);
@@ -1383,7 +1384,8 @@ int XfrmController::removeVirtualTunnelInterface(const std::string& deviceName)
uint16_t action = RTM_DELLINK;
uint16_t flags = NLM_F_REQUEST | NLM_F_ACK;
- int ret = sendNetlinkRequest(action, flags, iov, ARRAY_SIZE(iov), nullptr);
+ // sendNetlinkRequest returns -errno
+ int ret = -1 * sendNetlinkRequest(action, flags, iov, ARRAY_SIZE(iov), nullptr);
if (ret) {
ALOGE("Error in removing virtual tunnel interface %s. Error Code: %d", iflaIfNameStrValue,
ret);
diff --git a/tests/Android.mk b/tests/Android.mk
index a2440ea3..29f414a3 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -27,7 +27,7 @@ EXTRA_LDLIBS := -lpthread
LOCAL_SHARED_LIBRARIES += libbase libbinder libcrypto libcutils liblog \
libnetd_client libnetutils libssl libutils
LOCAL_STATIC_LIBRARIES += libnetd_test_dnsresponder liblogwrap libnetdaidl_static \
- libnetdutils libnetd_test_tun_interface
+ libnetdutils libnetd_test_tun_interface libbpf
LOCAL_AIDL_INCLUDES := system/netd/server/binder
LOCAL_C_INCLUDES += system/netd/include system/netd/binder/include \
system/netd/server system/core/logwrapper/include \
@@ -37,6 +37,7 @@ LOCAL_C_INCLUDES += system/netd/include system/netd/binder/include \
# netd_integration_test.cpp is currently empty and exists only so that we can do:
# runtest -x system/netd/tests/netd_integration_test.cpp
LOCAL_SRC_FILES := binder_test.cpp \
+ bpf_base_test.cpp \
dns_responder/dns_responder.cpp \
dns_tls_test.cpp \
netd_integration_test.cpp \
diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp
index 4cbfdf24..257a076d 100644
--- a/tests/binder_test.cpp
+++ b/tests/binder_test.cpp
@@ -37,6 +37,7 @@
#include <android-base/macros.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
+#include <bpf/BpfUtils.h>
#include <cutils/multiuser.h>
#include <gtest/gtest.h>
#include <logwrap/logwrap.h>
@@ -61,6 +62,7 @@ using namespace android;
using namespace android::base;
using namespace android::binder;
using android::base::StartsWith;
+using android::bpf::hasBpfSupport;
using android::net::INetd;
using android::net::TunInterface;
using android::net::UidRange;
@@ -68,6 +70,11 @@ using android::net::XfrmController;
using android::netdutils::sSyscalls;
using android::os::PersistableBundle;
+#define SKIP_IF_BPF_SUPPORTED \
+ do { \
+ if (hasBpfSupport()) return; \
+ } while (0);
+
static const char* IP_RULE_V4 = "-4";
static const char* IP_RULE_V6 = "-6";
static const int TEST_NETID1 = 65501;
@@ -200,6 +207,8 @@ static bool iptablesEspAllowRuleExists(const char *chainName){
}
TEST_F(BinderTest, TestFirewallReplaceUidChain) {
+ SKIP_IF_BPF_SUPPORTED;
+
std::string chainName = StringPrintf("netd_binder_test_%u", arc4random_uniform(10000));
const int kNumUids = 500;
std::vector<int32_t> noUids(0);
@@ -284,6 +293,9 @@ TEST_F(BinderTest, TestVirtualTunnelInterface) {
}
}
+// IPsec tests are not run in 32 bit mode; both 32-bit kernels and
+// mismatched ABIs (64-bit kernel with 32-bit userspace) are unsupported.
+#if INTPTR_MAX != INT32_MAX
#define RETURN_FALSE_IF_NEQ(_expect_, _ret_) \
do { if ((_expect_) != (_ret_)) return false; } while(false)
bool BinderTest::allocateIpSecResources(bool expectOk, int32_t *spi) {
@@ -304,11 +316,15 @@ bool BinderTest::allocateIpSecResources(bool expectOk, int32_t *spi) {
return (status.ok() == expectOk);
}
-
TEST_F(BinderTest, TestXfrmControllerInit) {
netdutils::Status status;
status = XfrmController::Init();
SCOPED_TRACE(status);
+
+ // Older devices or devices with mismatched Kernel/User ABI cannot support the IPsec
+ // feature.
+ if (status.code() == EOPNOTSUPP) return;
+
ASSERT_TRUE(status.ok());
int32_t spi = 0;
@@ -336,6 +352,7 @@ TEST_F(BinderTest, TestXfrmControllerInit) {
ASSERT_TRUE(status.ok());
}
+#endif
static int bandwidthDataSaverEnabled(const char *binary) {
std::vector<std::string> lines = listIptablesRule(binary, "bw_data_saver");
diff --git a/tests/bpf_base_test.cpp b/tests/bpf_base_test.cpp
new file mode 100644
index 00000000..41945e2a
--- /dev/null
+++ b/tests/bpf_base_test.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <string>
+
+#include <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
+#include <linux/inet_diag.h>
+#include <linux/sock_diag.h>
+#include <net/if.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <gtest/gtest.h>
+
+#include <cutils/qtaguid.h>
+
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+
+#include "bpf/BpfUtils.h"
+
+using namespace android::bpf;
+
+using android::base::unique_fd;
+using android::netdutils::status::ok;
+
+namespace android {
+namespace bpf {
+
+// Use the upper limit of uid to avoid conflict with real app uids. We can't use UID_MAX because
+// it's -1, which is INVALID_UID.
+constexpr uid_t TEST_UID = UID_MAX - 1;
+constexpr uint32_t TEST_TAG = 42;
+constexpr int TEST_COUNTERSET = 1;
+constexpr int DEFAULT_COUNTERSET = 0;
+
+class BpfBasicTest : public testing::Test {
+ protected:
+ BpfBasicTest() {}
+};
+
+TEST_F(BpfBasicTest, TestCgroupMounted) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
+ ASSERT_EQ(0, access(CGROUP_ROOT_PATH, R_OK));
+ ASSERT_EQ(0, access("/dev/cg2_bpf/cgroup.controllers", R_OK));
+}
+
+TEST_F(BpfBasicTest, TestTrafficControllerSetUp) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
+ ASSERT_EQ(0, access(BPF_EGRESS_PROG_PATH, R_OK));
+ ASSERT_EQ(0, access(BPF_INGRESS_PROG_PATH, R_OK));
+ ASSERT_EQ(0, access(XT_BPF_INGRESS_PROG_PATH, R_OK));
+ ASSERT_EQ(0, access(XT_BPF_EGRESS_PROG_PATH, R_OK));
+ ASSERT_EQ(0, access(COOKIE_TAG_MAP_PATH, R_OK));
+ ASSERT_EQ(0, access(UID_COUNTERSET_MAP_PATH, R_OK));
+ ASSERT_EQ(0, access(UID_STATS_MAP_PATH, R_OK));
+ ASSERT_EQ(0, access(TAG_STATS_MAP_PATH, R_OK));
+ ASSERT_EQ(0, access(IFACE_INDEX_NAME_MAP_PATH, R_OK));
+ ASSERT_EQ(0, access(IFACE_STATS_MAP_PATH, R_OK));
+ ASSERT_EQ(0, access(DOZABLE_UID_MAP_PATH, R_OK));
+ ASSERT_EQ(0, access(STANDBY_UID_MAP_PATH, R_OK));
+ ASSERT_EQ(0, access(POWERSAVE_UID_MAP_PATH, R_OK));
+}
+
+TEST_F(BpfBasicTest, TestTagSocket) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
+ unique_fd cookieTagMap = unique_fd(mapRetrieve(COOKIE_TAG_MAP_PATH, 0));
+ ASSERT_LE(0, cookieTagMap);
+ int sock = socket(AF_INET6, SOCK_STREAM, 0);
+ ASSERT_LE(0, sock);
+ uint64_t cookie = getSocketCookie(sock);
+ ASSERT_NE(NONEXISTENT_COOKIE, cookie);
+ ASSERT_EQ(0, qtaguid_tagSocket(sock, TEST_TAG, TEST_UID));
+ struct UidTag tagResult;
+ ASSERT_EQ(0, findMapEntry(cookieTagMap, &cookie, &tagResult));
+ ASSERT_EQ(TEST_UID, tagResult.uid);
+ ASSERT_EQ(TEST_TAG, tagResult.tag);
+ ASSERT_EQ(0, qtaguid_untagSocket(sock));
+ ASSERT_EQ(-1, findMapEntry(cookieTagMap, &cookie, &tagResult));
+ ASSERT_EQ(ENOENT, errno);
+}
+
+TEST_F(BpfBasicTest, TestChangeCounterSet) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
+ unique_fd uidCounterSetMap = unique_fd(mapRetrieve(UID_COUNTERSET_MAP_PATH, 0));
+ ASSERT_LE(0, uidCounterSetMap);
+ ASSERT_EQ(0, qtaguid_setCounterSet(TEST_COUNTERSET, TEST_UID));
+ uid_t uid = TEST_UID;
+ int counterSetResult;
+ ASSERT_EQ(0, findMapEntry(uidCounterSetMap, &uid, &counterSetResult));
+ ASSERT_EQ(TEST_COUNTERSET, counterSetResult);
+ ASSERT_EQ(0, qtaguid_setCounterSet(DEFAULT_COUNTERSET, TEST_UID));
+ ASSERT_EQ(-1, findMapEntry(uidCounterSetMap, &uid, &counterSetResult));
+ ASSERT_EQ(ENOENT, errno);
+}
+
+TEST_F(BpfBasicTest, TestDeleteTagData) {
+ SKIP_IF_BPF_NOT_SUPPORTED;
+
+ unique_fd uidStatsMap = unique_fd(mapRetrieve(UID_STATS_MAP_PATH, 0));
+ ASSERT_LE(0, uidStatsMap);
+ unique_fd tagStatsMap = unique_fd(mapRetrieve(TAG_STATS_MAP_PATH, 0));
+ ASSERT_LE(0, tagStatsMap);
+
+ StatsKey key = {.uid = TEST_UID, .tag = TEST_TAG, .counterSet = TEST_COUNTERSET,
+ .ifaceIndex = 1};
+ StatsValue statsMapValue = {.rxPackets = 1, .rxBytes = 100};
+ EXPECT_EQ(0, writeToMapEntry(tagStatsMap, &key, &statsMapValue, BPF_ANY));
+ key.tag = 0;
+ EXPECT_EQ(0, writeToMapEntry(uidStatsMap, &key, &statsMapValue, BPF_ANY));
+ ASSERT_EQ(0, qtaguid_deleteTagData(0, TEST_UID));
+ ASSERT_EQ(-1, findMapEntry(uidStatsMap, &key, &statsMapValue));
+ ASSERT_EQ(ENOENT, errno);
+ key.tag = TEST_TAG;
+ ASSERT_EQ(-1, findMapEntry(tagStatsMap, &key, &statsMapValue));
+ ASSERT_EQ(ENOENT, errno);
+}
+
+}
+}