diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2018-05-13 07:24:36 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2018-05-13 07:24:36 +0000 |
commit | 26246ba974b4857a08102173e0beb0060296ae67 (patch) | |
tree | 51e319fbef4b05d051c2ac1c01d4c6b89f0dadc5 | |
parent | d2b518adc8e7c9c401ee63a78ce6e992994522f6 (diff) | |
parent | f8f683fea2855ffb2d13ea93cfad1dada399c072 (diff) | |
download | netd-26246ba974b4857a08102173e0beb0060296ae67.tar.gz |
Snap for 4778776 from f8f683fea2855ffb2d13ea93cfad1dada399c072 to pi-release
Change-Id: I058fb1ec40d45dc08265809af6def76401b77fa9
-rw-r--r-- | libbpf/BpfNetworkStatsTest.cpp | 16 | ||||
-rw-r--r-- | libbpf/BpfUtils.cpp | 17 | ||||
-rw-r--r-- | libbpf/include/bpf/BpfUtils.h | 7 | ||||
-rw-r--r-- | server/TrafficControllerTest.cpp | 5 | ||||
-rw-r--r-- | server/XfrmController.cpp | 6 | ||||
-rw-r--r-- | tests/Android.mk | 3 | ||||
-rw-r--r-- | tests/binder_test.cpp | 19 | ||||
-rw-r--r-- | tests/bpf_base_test.cpp | 140 |
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); +} + +} +} |