summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHungming Chen <nuccachen@google.com>2020-03-12 16:21:03 +0800
committerHungming Chen <nuccachen@google.com>2020-05-29 22:50:24 +0800
commitf40dc09cc7008ded099bd9d8a61df3ee92a23685 (patch)
tree74b793e6945f13cb42b15a211e3856ea3f464f54
parentf14b23d56eba8ed2d5c4be2a753a8444916c2069 (diff)
downloadplatform_system_netd-f40dc09cc7008ded099bd9d8a61df3ee92a23685.tar.gz
platform_system_netd-f40dc09cc7008ded099bd9d8a61df3ee92a23685.tar.bz2
platform_system_netd-f40dc09cc7008ded099bd9d8a61df3ee92a23685.zip
Add binder call tetherOffloadGetStats
This binder call is separated from the existing call tetherGetStats and used for for BPF tether stats. Note that the default value of ifIndex of TetherStatsParcel.aidl is applied for backward compatibility because it is added from this commit. Make netd modules to use netd_aidl_interface-unstable-cpp. Both netd and libnetd_server use unstable aidl for new api tetherOffload* and modified parcel TetherStatsParcel. Generated with: m netd_aidl_interface-update-api Bug: 150736748 Test: atest Change-Id: Ie03834bc40992a4abdc8ef70150569982092b386
-rw-r--r--server/Android.bp4
-rw-r--r--server/NetdNativeService.cpp35
-rw-r--r--server/NetdNativeService.h2
-rw-r--r--server/TetherController.cpp42
-rw-r--r--server/TetherController.h11
-rw-r--r--server/TetherControllerTest.cpp60
-rw-r--r--server/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl1
-rw-r--r--server/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl1
-rw-r--r--server/binder/android/net/INetd.aidl13
-rw-r--r--server/binder/android/net/TetherStatsParcel.aidl25
10 files changed, 123 insertions, 71 deletions
diff --git a/server/Android.bp b/server/Android.bp
index 3ac162e78..bc48c4163 100644
--- a/server/Android.bp
+++ b/server/Android.bp
@@ -143,7 +143,7 @@ cc_library_static {
"libpcap",
"libqtaguid",
"libssl",
- "netd_aidl_interface-cpp",
+ "netd_aidl_interface-unstable-cpp",
"netd_event_listener_interface-cpp",
],
aidl: {
@@ -188,7 +188,7 @@ cc_binary {
"libselinux",
"libsysutils",
"libutils",
- "netd_aidl_interface-cpp",
+ "netd_aidl_interface-unstable-cpp",
"netd_event_listener_interface-cpp",
"oemnetd_aidl_interface-cpp",
],
diff --git a/server/NetdNativeService.cpp b/server/NetdNativeService.cpp
index b6c0d4e87..ecb9da818 100644
--- a/server/NetdNativeService.cpp
+++ b/server/NetdNativeService.cpp
@@ -436,6 +436,8 @@ binder::Status NetdNativeService::tetherApplyDnsInterfaces(bool *ret) {
namespace {
+constexpr const int UNUSED_IFINDEX = 0;
+
void tetherAddStatsByInterface(TetherController::TetherStats* tetherStatsParcel,
const TetherController::TetherStats& tetherStats) {
if (tetherStatsParcel->extIface == tetherStats.extIface) {
@@ -453,6 +455,7 @@ TetherStatsParcel toTetherStatsParcel(const TetherController::TetherStats& stats
result.rxPackets = stats.rxPackets;
result.txBytes = stats.txBytes;
result.txPackets = stats.txPackets;
+ result.ifIndex = UNUSED_IFINDEX;
return result;
}
@@ -1260,5 +1263,37 @@ binder::Status NetdNativeService::tetherOffloadRuleRemove(const TetherOffloadRul
return asBinderStatus(gCtls->tetherCtrl.removeOffloadRule(rule));
}
+namespace {
+
+constexpr const char UNUSED_IFNAME[] = "";
+
+TetherStatsParcel toTetherStatsParcel(const TetherController::TetherOffloadStats& stats) {
+ TetherStatsParcel result;
+ result.iface = UNUSED_IFNAME;
+ result.rxBytes = stats.rxBytes;
+ result.rxPackets = stats.rxPackets;
+ result.txBytes = stats.txBytes;
+ result.txPackets = stats.txPackets;
+ result.ifIndex = stats.ifIndex;
+ return result;
+}
+
+} // namespace
+
+binder::Status NetdNativeService::tetherOffloadGetStats(
+ std::vector<TetherStatsParcel>* tetherStatsParcelVec) {
+ NETD_LOCKING_RPC(gCtls->tetherCtrl.lock, PERM_NETWORK_STACK, PERM_MAINLINE_NETWORK_STACK);
+
+ tetherStatsParcelVec->clear();
+ const auto& statsList = gCtls->tetherCtrl.getTetherOffloadStats();
+ if (!isOk(statsList)) {
+ return asBinderStatus(statsList);
+ }
+ for (const auto& stats : statsList.value()) {
+ tetherStatsParcelVec->push_back(toTetherStatsParcel(stats));
+ }
+ return binder::Status::ok();
+}
+
} // namespace net
} // namespace android
diff --git a/server/NetdNativeService.h b/server/NetdNativeService.h
index 0d95c8ea4..f9979d316 100644
--- a/server/NetdNativeService.h
+++ b/server/NetdNativeService.h
@@ -123,6 +123,8 @@ class NetdNativeService : public BinderService<NetdNativeService>, public BnNetd
binder::Status tetherApplyDnsInterfaces(bool *ret) override;
binder::Status tetherGetStats(
std::vector<android::net::TetherStatsParcel>* tetherStatsVec) override;
+ binder::Status tetherOffloadGetStats(
+ std::vector<android::net::TetherStatsParcel>* tetherStatsVec) override;
binder::Status tetherStart(const std::vector<std::string>& dhcpRanges) override;
binder::Status tetherStartWithConfiguration(const TetherConfigParcel& config) override;
binder::Status tetherStop() override;
diff --git a/server/TetherController.cpp b/server/TetherController.cpp
index 50ae9661d..04af0aee2 100644
--- a/server/TetherController.cpp
+++ b/server/TetherController.cpp
@@ -81,10 +81,6 @@ const char IPV6_FORWARDING_PROC_FILE[] = "/proc/sys/net/ipv6/conf/all/forwarding
const char SEPARATOR[] = "|";
constexpr const char kTcpBeLiberal[] = "/proc/sys/net/netfilter/nf_conntrack_tcp_be_liberal";
-// Dummy interface name, the name needs to be longer than 16 characters so it can never conflict
-// with a real interface name. See also IFNAMSIZ.
-constexpr const char kBpfOffloadInterface[] = "BPFOffloadInterface";
-
// Chosen to match AID_DNS_TETHER, as made "friendly" by fs_config_generator.py.
constexpr const char kDnsmasqUsername[] = "dns_tether";
@@ -205,11 +201,6 @@ bool TetherController::disableForwarding(const char* requester) {
void TetherController::maybeInitMaps() {
if (!bpf::isBpfSupported()) return;
- // Used for parsing tether stats from BPF maps. If open the map failed, skip to open
- // tether BPF offload maps.
- mIfaceIndexNameMap.init(IFACE_INDEX_NAME_MAP_PATH);
- if (!mIfaceIndexNameMap.isValid()) return;
-
// Open BPF maps, ignoring errors because the device might not support BPF offload.
int fd = getTetherIngressMapFd();
if (fd >= 0) {
@@ -1027,32 +1018,25 @@ StatusOr<TetherController::TetherStatsList> TetherController::getTetherStats() {
}
}
- if (!mBpfStatsMap.isValid()) {
- return statsList;
- }
+ return statsList;
+}
- const auto processTetherStats = [this, &statsList](const uint32_t& key,
- const TetherStatsValue& value,
- const BpfMap<uint32_t, TetherStatsValue>&) {
- auto ifname = mIfaceIndexNameMap.readValue(key);
- if (!ifname.ok()) {
- // Keep on going regardless to parse as much as possible.
- return Result<void>();
- }
- // Because the same interface name can have different interface IDs over time, there might
- // already be a TetherStats in the list with this interface name. This is fine because
- // addStats will increment an existing TetherStats if there is one in the list already,
- // and add a new TetherStats to the list if there isn't.
- addStats(statsList,
- {kBpfOffloadInterface, ifname.value().name, static_cast<int64_t>(value.rxBytes),
- static_cast<int64_t>(value.rxPackets), static_cast<int64_t>(value.txBytes),
- static_cast<int64_t>(value.txPackets)});
+StatusOr<TetherController::TetherOffloadStatsList> TetherController::getTetherOffloadStats() {
+ TetherOffloadStatsList statsList;
+
+ const auto processTetherStats = [&statsList](const uint32_t& key, const TetherStatsValue& value,
+ const BpfMap<uint32_t, TetherStatsValue>&) {
+ statsList.push_back({.ifIndex = static_cast<int>(key),
+ .rxBytes = static_cast<int64_t>(value.rxBytes),
+ .rxPackets = static_cast<int64_t>(value.rxPackets),
+ .txBytes = static_cast<int64_t>(value.txBytes),
+ .txPackets = static_cast<int64_t>(value.txPackets)});
return Result<void>();
};
auto ret = mBpfStatsMap.iterateWithValue(processTetherStats);
if (!ret.ok()) {
- // Ignore error to return the non-BPF tether stats result.
+ // Ignore error to return the remaining tether stats result.
ALOGE("Error processing tether stats from BPF maps: %s", ret.error().message().c_str());
}
diff --git a/server/TetherController.h b/server/TetherController.h
index 3b266e7f4..513a6596f 100644
--- a/server/TetherController.h
+++ b/server/TetherController.h
@@ -76,7 +76,6 @@ class TetherController {
bpf::BpfMap<TetherIngressKey, TetherIngressValue> mBpfIngressMap;
bpf::BpfMap<uint32_t, TetherStatsValue> mBpfStatsMap;
bpf::BpfMap<uint32_t, uint64_t> mBpfLimitMap;
- bpf::BpfMap<uint32_t, IfaceValue> mIfaceIndexNameMap;
public:
TetherController();
@@ -137,9 +136,19 @@ class TetherController {
}
};
+ struct TetherOffloadStats {
+ int ifIndex;
+ int64_t rxBytes;
+ int64_t rxPackets;
+ int64_t txBytes;
+ int64_t txPackets;
+ };
+
typedef std::vector<TetherStats> TetherStatsList;
+ typedef std::vector<TetherOffloadStats> TetherOffloadStatsList;
netdutils::StatusOr<TetherStatsList> getTetherStats();
+ netdutils::StatusOr<TetherOffloadStatsList> getTetherOffloadStats();
/*
* extraProcessingInfo: contains raw parsed data, and error info.
diff --git a/server/TetherControllerTest.cpp b/server/TetherControllerTest.cpp
index fd6e43a82..d2ff4a757 100644
--- a/server/TetherControllerTest.cpp
+++ b/server/TetherControllerTest.cpp
@@ -43,17 +43,20 @@ using android::netdutils::StatusOr;
using ::testing::Contains;
using TetherStats = android::net::TetherController::TetherStats;
using TetherStatsList = android::net::TetherController::TetherStatsList;
+using TetherOffloadStats = android::net::TetherController::TetherOffloadStats;
+using TetherOffloadStatsList = android::net::TetherController::TetherOffloadStatsList;
namespace android {
namespace net {
constexpr int TEST_MAP_SIZE = 10;
-// Comparison for TetherStats. Need to override operator== because class TetherStats doesn't have.
-// TODO: once C++20 is used, use default operator== in TetherStats and remove the overriding here.
-bool operator==(const TetherStats& lhs, const TetherStats& rhs) {
- return lhs.intIface == rhs.intIface && lhs.extIface == rhs.extIface &&
- lhs.rxBytes == rhs.rxBytes && lhs.txBytes == rhs.txBytes &&
+// Comparison for TetherOffloadStats. Need to override operator== because class TetherOffloadStats
+// doesn't have one.
+// TODO: once C++20 is used, use default operator== in TetherOffloadStats and remove the overriding
+// here.
+bool operator==(const TetherOffloadStats& lhs, const TetherOffloadStats& rhs) {
+ return lhs.ifIndex == rhs.ifIndex && lhs.rxBytes == rhs.rxBytes && lhs.txBytes == rhs.txBytes &&
lhs.rxPackets == rhs.rxPackets && lhs.txPackets == rhs.txPackets;
}
@@ -65,41 +68,33 @@ public:
protected:
TetherController mTetherCtrl;
- BpfMap<uint32_t, IfaceValue> mFakeIfaceIndexNameMap{BPF_MAP_TYPE_HASH, TEST_MAP_SIZE};
BpfMap<uint32_t, TetherStatsValue> mFakeTetherStatsMap{BPF_MAP_TYPE_HASH, TEST_MAP_SIZE};
BpfMap<uint32_t, uint64_t> mFakeTetherLimitMap{BPF_MAP_TYPE_HASH, TEST_MAP_SIZE};
void SetUp() {
SKIP_IF_BPF_NOT_SUPPORTED;
- ASSERT_TRUE(mFakeIfaceIndexNameMap.isValid());
ASSERT_TRUE(mFakeTetherStatsMap.isValid());
ASSERT_TRUE(mFakeTetherLimitMap.isValid());
- mTetherCtrl.mIfaceIndexNameMap = mFakeIfaceIndexNameMap;
- ASSERT_TRUE(mTetherCtrl.mIfaceIndexNameMap.isValid());
mTetherCtrl.mBpfStatsMap = mFakeTetherStatsMap;
ASSERT_TRUE(mTetherCtrl.mBpfStatsMap.isValid());
mTetherCtrl.mBpfLimitMap = mFakeTetherLimitMap;
ASSERT_TRUE(mTetherCtrl.mBpfLimitMap.isValid());
}
- std::string toString(const TetherStatsList& statsList) {
+ std::string toString(const TetherOffloadStatsList& statsList) {
std::string result;
for (const auto& stats : statsList) {
- result += StringPrintf("%s, %s, %" PRId64 ", %" PRId64 ", %" PRId64 ", %" PRId64 "\n",
- stats.intIface.c_str(), stats.extIface.c_str(), stats.rxBytes,
- stats.rxPackets, stats.txBytes, stats.txPackets);
+ result += StringPrintf("%d, %" PRId64 ", %" PRId64 ", %" PRId64 ", %" PRId64 "\n",
+ stats.ifIndex, stats.rxBytes, stats.rxPackets, stats.txBytes,
+ stats.txPackets);
}
return result;
}
- void updateMaps(uint32_t ifaceIndex, const char* ifaceName, uint64_t rxBytes,
- uint64_t rxPackets, uint64_t txBytes, uint64_t txPackets) {
- IfaceValue iface{};
- strlcpy(iface.name, ifaceName, sizeof(iface.name));
- ASSERT_RESULT_OK(mFakeIfaceIndexNameMap.writeValue(ifaceIndex, iface, BPF_ANY));
-
+ void updateMaps(uint32_t ifaceIndex, uint64_t rxBytes, uint64_t rxPackets, uint64_t txBytes,
+ uint64_t txPackets) {
// {rx, tx}Errors in |tetherStats| are set zero because getTetherStats doesn't use them.
const TetherStatsValue tetherStats = {rxPackets, rxBytes, 0 /*unused*/,
txPackets, txBytes, 0 /*unused*/};
@@ -490,31 +485,20 @@ TEST_F(TetherControllerTest, TestGetTetherStats) {
EXPECT_TRUE(std::equal(expectedError.rbegin(), expectedError.rend(), err.rbegin()));
}
-TEST_F(TetherControllerTest, TestGetTetherStatsWithBpfTetherStatsMap) {
+TEST_F(TetherControllerTest, TestTetherOffloadGetStats) {
SKIP_IF_BPF_NOT_SUPPORTED;
- // Setup BPF tether stats maps. The tether stats of interface rmnet0 comes from two tether
- // stats map items with different interface index. Therefore, need to sum up both of them
- // for the tether stats of interface rmnet0.
- updateMaps(101, "wlan0", 100, 10, 200, 20);
- updateMaps(102, "rmnet0", 300, 30, 400, 40);
- updateMaps(103, "rmnet0", 500, 50, 600, 60);
- const TetherStats expected0("BPFOffloadInterface", "wlan0", 100, 10, 200, 20);
- const TetherStats expected1("BPFOffloadInterface", "rmnet0", 800, 80, 1000, 100);
-
- // Setup iptables tether counters. IPv4 and IPv6 counters are added together.
- addIptablesRestoreOutput(kIPv4TetherCounters, kIPv6TetherCounters);
- const TetherStats expected2("wlan0", "rmnet0", 20002002, 20027, 10002373, 10026);
- const TetherStats expected3("bt-pan", "rmnet0", 1708806, 1450, 107471, 1040);
+ updateMaps(101, 100, 10, 200, 20);
+ updateMaps(102, 300, 30, 400, 40);
+ const TetherOffloadStats expected0{101, 100, 10, 200, 20};
+ const TetherOffloadStats expected1{102, 300, 30, 400, 40};
- const StatusOr<TetherStatsList> result = mTetherCtrl.getTetherStats();
+ const StatusOr<TetherOffloadStatsList> result = mTetherCtrl.getTetherOffloadStats();
ASSERT_OK(result);
- const TetherStatsList& actual = result.value();
- ASSERT_EQ(4U, actual.size());
+ const TetherOffloadStatsList& actual = result.value();
+ ASSERT_EQ(2U, actual.size());
EXPECT_THAT(actual, Contains(expected0)) << toString(actual);
EXPECT_THAT(actual, Contains(expected1)) << toString(actual);
- EXPECT_THAT(actual, Contains(expected2)) << toString(actual);
- EXPECT_THAT(actual, Contains(expected3)) << toString(actual);
clearIptablesRestoreOutput();
}
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl
index 135b73850..5bb3bcf59 100644
--- a/server/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/INetd.aidl
@@ -119,6 +119,7 @@ interface INetd {
void networkRemoveRouteParcel(int netId, in android.net.RouteInfoParcel routeInfo);
void tetherOffloadRuleAdd(in android.net.TetherOffloadRuleParcel rule);
void tetherOffloadRuleRemove(in android.net.TetherOffloadRuleParcel rule);
+ android.net.TetherStatsParcel[] tetherOffloadGetStats();
const int IPV4 = 4;
const int IPV6 = 6;
const int CONF = 1;
diff --git a/server/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl b/server/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl
index 71ffb9b96..0b0960efc 100644
--- a/server/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl
+++ b/server/aidl_api/netd_aidl_interface/current/android/net/TetherStatsParcel.aidl
@@ -23,4 +23,5 @@ parcelable TetherStatsParcel {
long rxPackets;
long txBytes;
long txPackets;
+ int ifIndex = 0;
}
diff --git a/server/binder/android/net/INetd.aidl b/server/binder/android/net/INetd.aidl
index dff021c5c..2377a284c 100644
--- a/server/binder/android/net/INetd.aidl
+++ b/server/binder/android/net/INetd.aidl
@@ -192,7 +192,7 @@ interface INetd {
* Return tethering statistics.
*
* @return an array of TetherStatsParcel, where each entry contains the upstream interface
- * name and its tethering statistics.
+ * name and its tethering statistics since netd startup.
* There will only ever be one entry for a given interface.
* @throws ServiceSpecificException in case of failure, with an error code indicating the
* cause of the failure.
@@ -1269,4 +1269,15 @@ interface INetd {
* cause of the failure.
*/
void tetherOffloadRuleRemove(in TetherOffloadRuleParcel rule);
+
+ /**
+ * Return BPF tethering offload statistics.
+ *
+ * @return an array of TetherStatsParcel's, where each entry contains the upstream interface
+ * index and its tethering statistics since tethering was first started.
+ * There will only ever be one entry for a given interface index.
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the failure.
+ */
+ TetherStatsParcel[] tetherOffloadGetStats();
}
diff --git a/server/binder/android/net/TetherStatsParcel.aidl b/server/binder/android/net/TetherStatsParcel.aidl
index 25e200c20..6bf60a86e 100644
--- a/server/binder/android/net/TetherStatsParcel.aidl
+++ b/server/binder/android/net/TetherStatsParcel.aidl
@@ -22,9 +22,34 @@ package android.net;
* {@hide}
*/
parcelable TetherStatsParcel {
+ /**
+ * Parcel representing tethering interface statistics.
+ *
+ * This parcel is used by tetherGetStats, tetherOffloadGetStats and
+ * tetherOffloadGetAndClearStats in INetd.aidl. tetherGetStats uses this parcel to return the
+ * tethering statistics since netd startup and presents the interface via its interface name.
+ * Both tetherOffloadGetStats and tetherOffloadGetAndClearStats use this parcel to return
+ * the tethering statistics since tethering was first started. They present the interface via
+ * its interface index. Note that the interface must be presented by either interface name
+ * |iface| or interface index |ifIndex| in this parcel. The unused interface name is set to
+ * an empty string "" by default and the unused interface index is set to 0 by default.
+ */
+
+ /** The interface name. */
@utf8InCpp String iface;
+
+ /** Total number of received bytes. */
long rxBytes;
+
+ /** Total number of received packets. */
long rxPackets;
+
+ /** Total number of transmitted bytes. */
long txBytes;
+
+ /** Total number of transmitted packets. */
long txPackets;
+
+ /** The interface index. */
+ int ifIndex = 0;
}