diff options
author | Lorenzo Colitti <lorenzo@google.com> | 2018-02-08 19:58:31 +0900 |
---|---|---|
committer | Steven Moreland <smoreland@google.com> | 2018-03-30 16:02:20 +0000 |
commit | f95d0c28b6c63df181c4796f736c7894aaafa09f (patch) | |
tree | a7ad4b9631349c667c2fb8be7ea6f2d02320f46c | |
parent | 65ae996fcaa61c9d1daabc2a9ee322a931cd709c (diff) | |
download | interfaces-f95d0c28b6c63df181c4796f736c7894aaafa09f.tar.gz |
Add tests for INetd 1.1.
Bug: 73032258
Test: VtsHalNetNetdV1_0TargetTest and VtsHalNetNetdV1_1TargetTest passes on marlin
Change-Id: Id4d49f08563982353a9a7db79b569e933ea03c46
Merged-In: Id4d49f08563982353a9a7db79b569e933ea03c46
(cherry picked from commit 94832f94dc902b130bf3b2814e9addc2f27a2840)
-rw-r--r-- | net/netd/1.0/vts/functional/Android.bp | 10 | ||||
-rw-r--r-- | net/netd/1.1/vts/functional/Android.bp | 30 | ||||
-rw-r--r-- | net/netd/1.1/vts/functional/VtsHalNetNetdV1_1TargetTest.cpp | 345 | ||||
-rw-r--r-- | net/netd/testutils/Android.bp | 23 | ||||
-rw-r--r-- | net/netd/testutils/VtsHalNetNetdTestUtils.cpp | 30 | ||||
-rw-r--r-- | net/netd/testutils/VtsHalNetNetdTestUtils.h | 15 |
6 files changed, 440 insertions, 13 deletions
diff --git a/net/netd/1.0/vts/functional/Android.bp b/net/netd/1.0/vts/functional/Android.bp index 80e157a..9887638 100644 --- a/net/netd/1.0/vts/functional/Android.bp +++ b/net/netd/1.0/vts/functional/Android.bp @@ -18,6 +18,7 @@ cc_test { srcs: [ "VtsHalNetNetdV1_0TargetTest.cpp", ], + defaults: ["VtsHalNetNetdTestDefaults"], shared_libs: [ "android.system.net.netd@1.0", "libandroid_net", @@ -26,13 +27,4 @@ cc_test { "liblog", "libutils", ], - static_libs: [ - "VtsHalHidlTargetTestBase", - "VtsHalNetNetdTestUtils", - ], - cflags: [ - "-Og", - "-Wall", - "-Werror", - ], } diff --git a/net/netd/1.1/vts/functional/Android.bp b/net/netd/1.1/vts/functional/Android.bp new file mode 100644 index 0000000..4b411ff --- /dev/null +++ b/net/netd/1.1/vts/functional/Android.bp @@ -0,0 +1,30 @@ +// +// 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. + +cc_test { + name: "VtsHalNetNetdV1_1TargetTest", + srcs: [ + "VtsHalNetNetdV1_1TargetTest.cpp", + ], + defaults: ["VtsHalNetNetdTestDefaults"], + static_libs: [ + "android.system.net.netd@1.0", + "android.system.net.netd@1.1", + "libnetd_test_tun_interface", + ], + shared_libs: [ + "libnetutils", + ], +} diff --git a/net/netd/1.1/vts/functional/VtsHalNetNetdV1_1TargetTest.cpp b/net/netd/1.1/vts/functional/VtsHalNetNetdV1_1TargetTest.cpp new file mode 100644 index 0000000..73cd3f4 --- /dev/null +++ b/net/netd/1.1/vts/functional/VtsHalNetNetdV1_1TargetTest.cpp @@ -0,0 +1,345 @@ +/* + * Copyright 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. + */ + +#define LOG_TAG "netd_hidl_test" + +#include <linux/if.h> + +#include <VtsHalHidlTargetTestBase.h> +#include <android-base/stringprintf.h> +#include <android/system/net/netd/1.1/INetd.h> +#include <log/log.h> +#include <netutils/ifc.h> + +#include "VtsHalNetNetdTestUtils.h" +#include "tun_interface.h" + +using android::sp; +using android::base::StringPrintf; +using android::hardware::Return; +using android::net::TunInterface; +using android::system::net::netd::V1_1::INetd; + +namespace { +const net_handle_t INVALID_NET_HANDLE = 0x6600FACADE; + +constexpr const char* IPV4_ROUTER = "192.0.2.1"; +constexpr const char* IPV4_CONNECTED = "192.0.2.0/25"; +constexpr const char* IPV4_SUBNET_1 = "192.0.2.192/28"; +constexpr const char* IPV4_HOST_1 = "192.0.2.195"; +constexpr const char* IPV4_SUBNET_2 = "192.0.2.240/28"; +constexpr const char* IPV4_HOST_2 = "192.0.2.245"; +constexpr const char* IPV4_UNREACHABLE = "192.0.2.239"; + +constexpr const char* IPV6_ROUTER = "2001:db8::cafe"; +constexpr const char* IPV6_CONNECTED = "2001:db8::/64"; +constexpr const char* IPV6_SUBNET_1 = "2001:db8:babe::/48"; +constexpr const char* IPV6_HOST_1 = "2001:db8:babe::1"; +constexpr const char* IPV6_SUBNET_2 = "2001:db8:d00d::/48"; +constexpr const char* IPV6_HOST_2 = "2001:db8:d00d::1"; +constexpr const char* IPV6_UNREACHABLE = "2001:db8:d0a::"; + +std::vector<const char*> REACHABLE = { + IPV4_ROUTER, IPV4_HOST_1, IPV4_HOST_2, IPV6_ROUTER, IPV6_HOST_1, IPV6_HOST_2, +}; + +void checkAllReachable(net_handle_t handle) { + int ret; + for (const auto& dst : REACHABLE) { + ret = checkReachability(handle, dst); + EXPECT_EQ(0, ret) << "Expected reachability to " << dst << " but got %s" << strerror(-ret); + } + for (const auto& dst : {IPV4_UNREACHABLE, IPV6_UNREACHABLE}) { + EXPECT_EQ(-ENETUNREACH, checkReachability(handle, dst)) + << "Expected " << dst << " to be unreachable, but was reachable"; + } +} + +void checkAllUnreachable(net_handle_t handle) { + for (const auto& dst : REACHABLE) { + EXPECT_EQ(-ENETUNREACH, checkReachability(handle, dst)); + } + for (const auto& dst : {IPV4_UNREACHABLE, IPV6_UNREACHABLE}) { + EXPECT_EQ(-ENETUNREACH, checkReachability(handle, dst)); + } +} +} // namespace + +// Test environment for Netd HIDL HAL. +class NetdHidlEnvironment : public ::testing::VtsHalHidlTargetTestEnvBase { + public: + // get the test environment singleton + static NetdHidlEnvironment* Instance() { + static NetdHidlEnvironment* instance = new NetdHidlEnvironment; + return instance; + } + + virtual void registerTestServices() override { registerTestService<INetd>(); } + + private: + NetdHidlEnvironment() {} +}; + +class NetdHidlTest : public ::testing::VtsHalHidlTargetTestBase { + public: + // Netd HAL instance. + sp<INetd> netd; + + // The nethandle of our test network, and its packet mark. + net_handle_t mNetHandle; + uint32_t mPacketMark; + + // Two interfaces that we can add and remove from our test network. + static TunInterface sTun1; + static TunInterface sTun2; + + // The interface name of sTun1, for convenience. + static const char* sIfaceName; + + static void SetUpTestCase() { + ASSERT_EQ(0, sTun1.init()); + ASSERT_EQ(0, sTun2.init()); + ASSERT_LE(sTun1.name().size(), static_cast<size_t>(IFNAMSIZ)); + ASSERT_LE(sTun2.name().size(), static_cast<size_t>(IFNAMSIZ)); + ifc_init(); + ASSERT_EQ(0, ifc_up(sTun1.name().c_str())); + ASSERT_EQ(0, ifc_up(sTun2.name().c_str())); + sIfaceName = sTun1.name().c_str(); + } + + static void TearDownTestCase() { + sTun1.destroy(); + sTun2.destroy(); + ifc_close(); + } + + virtual void SetUp() override { + netd = ::testing::VtsHalHidlTargetTestBase::getService<INetd>( + NetdHidlEnvironment::Instance()->getServiceName<INetd>()); + + ASSERT_NE(netd, nullptr) << "Could not get HIDL instance"; + + // Set up an OEM network. + INetd::StatusCode status; + Return<void> ret = + netd->createOemNetwork([&](net_handle_t n, uint32_t p, INetd::StatusCode s) { + status = s; + mNetHandle = n; + mPacketMark = p; + }); + ASSERT_TRUE(ret.isOk()); + ASSERT_EQ(INetd::StatusCode::OK, status); + ASSERT_NE(NETWORK_UNSPECIFIED, mNetHandle); + ASSERT_NE((uint32_t)0, mPacketMark); + } + + virtual void TearDown() override { netd->destroyOemNetwork(mNetHandle); } + + void expectAddRoute(INetd::StatusCode expectedStatus, net_handle_t handle, const char* iface, + const char* destination, const char* nexthop) { + Return<INetd::StatusCode> retStatus = + netd->addRouteToOemNetwork(handle, iface, destination, nexthop); + EXPECT_STATUS(expectedStatus, retStatus); + } + + void expectAddRouteSuccess(net_handle_t h, const char* i, const char* d, const char* n) { + expectAddRoute(INetd::StatusCode::OK, h, i, d, n); + } + + void expectRemoveRoute(INetd::StatusCode expectedStatus, net_handle_t handle, const char* iface, + const char* destination, const char* nexthop) { + Return<INetd::StatusCode> retStatus = + netd->removeRouteFromOemNetwork(handle, iface, destination, nexthop); + EXPECT_STATUS(expectedStatus, retStatus); + } + + void expectRemoveRouteSuccess(net_handle_t h, const char* i, const char* d, const char* n) { + expectRemoveRoute(INetd::StatusCode::OK, h, i, d, n); + } +}; + +TunInterface NetdHidlTest::sTun1; +TunInterface NetdHidlTest::sTun2; +const char* NetdHidlTest::sIfaceName; + +// Tests adding and removing interfaces from the OEM network. +TEST_F(NetdHidlTest, TestAddRemoveInterfaces) { + // HACK: mark out permissions bits. + uint32_t packetMark = mPacketMark & 0xffff; + + EXPECT_EQ(0, checkNetworkExists(mNetHandle)); + EXPECT_EQ(0, countRulesForFwmark(packetMark)); + + // Adding an interface creates the routing rules. + Return<INetd::StatusCode> retStatus = netd->addInterfaceToOemNetwork(mNetHandle, sIfaceName); + EXPECT_TRUE(retStatus.isOk()); + EXPECT_EQ(0, checkNetworkExists(mNetHandle)); + EXPECT_EQ(2, countRulesForFwmark(packetMark)); + + // Adding an interface again silently succeeds. + retStatus = netd->addInterfaceToOemNetwork(mNetHandle, sIfaceName); + EXPECT_TRUE(retStatus.isOk()); + EXPECT_EQ(0, checkNetworkExists(mNetHandle)); + EXPECT_EQ(2, countRulesForFwmark(packetMark)); + + // More than one network can be created. + net_handle_t netHandle2; + uint32_t packetMark2; + + Return<void> ret = netd->createOemNetwork([&](net_handle_t n, uint32_t p, INetd::StatusCode) { + netHandle2 = n; + packetMark2 = p & 0xffff; + }); + EXPECT_TRUE(ret.isOk()); + EXPECT_NE(mNetHandle, netHandle2); + EXPECT_NE(packetMark, packetMark2); + EXPECT_EQ(0, checkNetworkExists(netHandle2)); + EXPECT_EQ(0, countRulesForFwmark(packetMark2)); + + // An interface can only be in one network. + retStatus = netd->addInterfaceToOemNetwork(netHandle2, sIfaceName); + EXPECT_STATUS(INetd::StatusCode::UNKNOWN_ERROR, retStatus); + + // Removing the interface removes the rules. + retStatus = netd->removeInterfaceFromOemNetwork(mNetHandle, sIfaceName); + EXPECT_STATUS(INetd::StatusCode::OK, retStatus); + EXPECT_EQ(0, countRulesForFwmark(packetMark)); + + retStatus = netd->addInterfaceToOemNetwork(netHandle2, sIfaceName); + EXPECT_STATUS(INetd::StatusCode::OK, retStatus); + EXPECT_EQ(2, countRulesForFwmark(packetMark2)); + + // When a network is removed the interfaces are deleted. + retStatus = netd->destroyOemNetwork(netHandle2); + EXPECT_STATUS(INetd::StatusCode::OK, retStatus); + EXPECT_EQ(-ENONET, checkNetworkExists(netHandle2)); + EXPECT_EQ(0, countRulesForFwmark(packetMark2)); + + // Adding an interface to a non-existent network fails. + retStatus = netd->addInterfaceToOemNetwork(INVALID_NET_HANDLE, sIfaceName); + EXPECT_STATUS(INetd::StatusCode::INVALID_ARGUMENTS, retStatus); + retStatus = netd->removeInterfaceFromOemNetwork(INVALID_NET_HANDLE, sIfaceName); + EXPECT_STATUS(INetd::StatusCode::INVALID_ARGUMENTS, retStatus); +} + +// Tests adding and removing routes from the OEM network. +TEST_F(NetdHidlTest, TestAddRemoveRoutes) { + Return<INetd::StatusCode> retStatus = netd->addInterfaceToOemNetwork(mNetHandle, sIfaceName); + ASSERT_TRUE(retStatus.isOk()); + + // Network exists, but has no routes and no connectivity. + EXPECT_EQ(0, checkNetworkExists(mNetHandle)); + checkAllUnreachable(mNetHandle); + + // Add a directly-connected route and two gatewayed routes through it. + expectAddRouteSuccess(mNetHandle, sIfaceName, IPV4_CONNECTED, ""); + expectAddRouteSuccess(mNetHandle, sIfaceName, IPV4_SUBNET_1, IPV4_ROUTER); + expectAddRouteSuccess(mNetHandle, sIfaceName, IPV4_SUBNET_2, IPV4_ROUTER); + expectAddRouteSuccess(mNetHandle, sIfaceName, IPV6_CONNECTED, ""); + expectAddRouteSuccess(mNetHandle, sIfaceName, IPV6_SUBNET_1, IPV6_ROUTER); + expectAddRouteSuccess(mNetHandle, sIfaceName, IPV6_SUBNET_2, IPV6_ROUTER); + + // Test some destinations. + checkAllReachable(mNetHandle); + + // Remove the directly-connected routes and everything is unreachable again. + expectRemoveRouteSuccess(mNetHandle, sIfaceName, IPV4_CONNECTED, ""); + expectRemoveRouteSuccess(mNetHandle, sIfaceName, IPV6_CONNECTED, ""); + expectRemoveRouteSuccess(mNetHandle, sIfaceName, IPV4_SUBNET_1, IPV4_ROUTER); + expectRemoveRouteSuccess(mNetHandle, sIfaceName, IPV4_SUBNET_2, IPV4_ROUTER); + expectRemoveRouteSuccess(mNetHandle, sIfaceName, IPV6_SUBNET_1, IPV6_ROUTER); + expectRemoveRouteSuccess(mNetHandle, sIfaceName, IPV6_SUBNET_2, IPV6_ROUTER); + + checkAllUnreachable(mNetHandle); + + // Invalid: route doesn't exist so can't be deleted. + expectRemoveRoute(INetd::StatusCode::UNKNOWN_ERROR, mNetHandle, sIfaceName, IPV4_CONNECTED, ""); + + // Invalid: IP address instead of prefix. + expectAddRoute(INetd::StatusCode::INVALID_ARGUMENTS, mNetHandle, sIfaceName, IPV4_HOST_1, ""); + expectAddRoute(INetd::StatusCode::INVALID_ARGUMENTS, mNetHandle, sIfaceName, IPV6_HOST_1, ""); + + // Invalid: both nexthop and interface are empty. + expectAddRoute(INetd::StatusCode::UNKNOWN_ERROR, mNetHandle, "", IPV4_SUBNET_1, ""); + expectAddRoute(INetd::StatusCode::UNKNOWN_ERROR, mNetHandle, "", IPV6_SUBNET_1, ""); + + // The kernel deletes the routes when the interfaces go away. +} + +// Tests enabling and disabling forwarding between interfaces. +TEST_F(NetdHidlTest, TestForwarding) { + Return<INetd::StatusCode> retStatus = + netd->addInterfaceToOemNetwork(mNetHandle, sTun1.name().c_str()); + EXPECT_STATUS(INetd::StatusCode::OK, retStatus); + retStatus = netd->addInterfaceToOemNetwork(mNetHandle, sTun2.name().c_str()); + EXPECT_STATUS(INetd::StatusCode::OK, retStatus); + + // TODO: move this test to netd and use ROUTE_TABLE_OFFSET_FROM_INDEX directly. + uint32_t table1 = 1000 + sTun1.ifindex(); + uint32_t table2 = 1000 + sTun1.ifindex(); + const char* regexTemplate = "from all iif %s .*lookup (%s|%d)"; + std::string regex1 = + StringPrintf(regexTemplate, sTun1.name().c_str(), sTun2.name().c_str(), table2); + std::string regex2 = + StringPrintf(regexTemplate, sTun2.name().c_str(), sTun1.name().c_str(), table1); + + EXPECT_EQ(0, countMatchingIpRules(regex1)); + EXPECT_EQ(0, countMatchingIpRules(regex2)); + + retStatus = netd->setForwardingBetweenInterfaces(sTun1.name(), sTun2.name(), true); + EXPECT_STATUS(INetd::StatusCode::OK, retStatus); + EXPECT_EQ(2, countMatchingIpRules(regex1)); + EXPECT_EQ(0, countMatchingIpRules(regex2)); + + // No attempt at deduplicating rules is made. + retStatus = netd->setForwardingBetweenInterfaces(sTun1.name(), sTun2.name(), true); + EXPECT_STATUS(INetd::StatusCode::OK, retStatus); + EXPECT_EQ(4, countMatchingIpRules(regex1)); + + retStatus = netd->setForwardingBetweenInterfaces(sTun1.name(), sTun2.name(), false); + EXPECT_STATUS(INetd::StatusCode::OK, retStatus); + EXPECT_EQ(2, countMatchingIpRules(regex1)); + + retStatus = netd->setForwardingBetweenInterfaces(sTun2.name(), sTun1.name(), true); + EXPECT_STATUS(INetd::StatusCode::OK, retStatus); + EXPECT_EQ(2, countMatchingIpRules(regex1)); + EXPECT_EQ(2, countMatchingIpRules(regex2)); + + retStatus = netd->setForwardingBetweenInterfaces(sTun1.name(), sTun2.name(), false); + EXPECT_STATUS(INetd::StatusCode::OK, retStatus); + EXPECT_EQ(0, countMatchingIpRules(regex1)); + EXPECT_EQ(2, countMatchingIpRules(regex2)); + + retStatus = netd->setForwardingBetweenInterfaces(sTun2.name(), sTun1.name(), false); + EXPECT_STATUS(INetd::StatusCode::OK, retStatus); + EXPECT_EQ(0, countMatchingIpRules(regex1)); + EXPECT_EQ(0, countMatchingIpRules(regex2)); + + // Deleting rules that don't exist fails. + retStatus = netd->setForwardingBetweenInterfaces(sTun1.name(), sTun2.name(), false); + EXPECT_STATUS(INetd::StatusCode::UNKNOWN_ERROR, retStatus); + EXPECT_EQ(0, countMatchingIpRules(regex1)); + EXPECT_EQ(0, countMatchingIpRules(regex2)); +} + +int main(int argc, char** argv) { + ::testing::AddGlobalTestEnvironment(NetdHidlEnvironment::Instance()); + ::testing::InitGoogleTest(&argc, argv); + NetdHidlEnvironment::Instance()->init(&argc, argv); + int status = RUN_ALL_TESTS(); + ALOGE("Test result with status=%d", status); + return status; +} diff --git a/net/netd/testutils/Android.bp b/net/netd/testutils/Android.bp index a7c33a5..991c272 100644 --- a/net/netd/testutils/Android.bp +++ b/net/netd/testutils/Android.bp @@ -13,6 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. +// Utility code common for all HAL versions. cc_library { name: "VtsHalNetNetdTestUtils", srcs: [ @@ -20,12 +21,34 @@ cc_library { ], export_include_dirs: ["."], shared_libs: [ + "libandroid_net", "libbase", + ], + cflags: [ + "-Og", + "-Wall", + "-Werror", + ], +} + +// Common build settings for all HAL versions. +cc_defaults { + name: "VtsHalNetNetdTestDefaults", + shared_libs: [ "libandroid_net", + "libbase", + "libhidlbase", + "liblog", + "libutils", + ], + static_libs: [ + "VtsHalHidlTargetTestBase", + "VtsHalNetNetdTestUtils", ], cflags: [ "-Og", "-Wall", "-Werror", ], + defaults: ["VtsHalTargetTestDefaults"], } diff --git a/net/netd/testutils/VtsHalNetNetdTestUtils.cpp b/net/netd/testutils/VtsHalNetNetdTestUtils.cpp index 1f7db2b..da377c4 100644 --- a/net/netd/testutils/VtsHalNetNetdTestUtils.cpp +++ b/net/netd/testutils/VtsHalNetNetdTestUtils.cpp @@ -43,7 +43,7 @@ int checkNetworkExists(net_handle_t netHandle) { return ret; } -// TODO: deduplicate this with system/netd/server/binder_test.cpp. +// TODO: deduplicate this with system/netd/tests/binder_test.cpp. static std::vector<std::string> runCommand(const std::string& command) { std::vector<std::string> lines; FILE* f; @@ -70,7 +70,7 @@ static std::vector<std::string> listIpRules(const char* ipVersion) { return runCommand(command); } -static int countMatchingIpRules(const std::string& regexString) { +int countMatchingIpRules(const std::string& regexString) { const std::regex regex(regexString, std::regex_constants::extended); int matches = 0; @@ -87,6 +87,30 @@ static int countMatchingIpRules(const std::string& regexString) { } int countRulesForFwmark(const uint32_t fwmark) { - std::string regex = StringPrintf("from all fwmark 0x%x/.* lookup ", fwmark); + // Skip top nibble, which differs between rules. + std::string regex = StringPrintf("from all fwmark 0x[0-9a-f]+%x/.* lookup ", fwmark); return countMatchingIpRules(regex); } + +int checkReachability(net_handle_t netHandle, const char* addrStr) { + addrinfo *ai, hints = {.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV}; + int ret = getaddrinfo(addrStr, "53", &hints, &ai); + if (ret) { + return -EINVAL; + } + + int sock = socket(ai->ai_family, SOCK_DGRAM, 0); + if (sock == -1 || android_setsocknetwork(netHandle, sock) == -1) { + ret = -errno; + freeaddrinfo(ai); + return ret; + } + + ret = connect(sock, ai->ai_addr, ai->ai_addrlen); + close(sock); + if (ret == -1) { + ret = -errno; + } + freeaddrinfo(ai); + return ret; +} diff --git a/net/netd/testutils/VtsHalNetNetdTestUtils.h b/net/netd/testutils/VtsHalNetNetdTestUtils.h index 71d9174..ef0c7ed 100644 --- a/net/netd/testutils/VtsHalNetNetdTestUtils.h +++ b/net/netd/testutils/VtsHalNetNetdTestUtils.h @@ -19,12 +19,25 @@ #include <android/multinetwork.h> -#define IP_PATH "/system/bin/ip" +#define EXPECT_STATUS(expectedStatus, ret) \ + do { \ + EXPECT_TRUE((ret).isOk()); \ + EXPECT_EQ((expectedStatus), (ret)); \ + } while (0) + +constexpr const char* IP_PATH = "/system/bin/ip"; // Checks that the given network exists. // Returns 0 if it exists or -errno if it does not. int checkNetworkExists(net_handle_t netHandle); +// Checks that the given network provides reachability to the given address. +// Returns 0 if it so or -errno if not. +int checkReachability(net_handle_t netHandle, const char* addrStr); + +// Counts the number of IPv4 and IPv6 routing rules that match the given regexp string. +int countMatchingIpRules(const std::string& regexString); + // Counts the number of IPv4 and IPv6 routing rules that select the specified fwmark. int countRulesForFwmark(const uint32_t fwmark); |