TetherController: Process tether stats from bpf maps
Test: Manual test
1. Add two interface tether stats manually
2. Call getTetherStats() and check the content
Change-Id: I5bf7e57e67cf61829ef71fd7caccdb60d4c35213
diff --git a/server/TetherController.cpp b/server/TetherController.cpp
index a1e2ea4..16f272c 100644
--- a/server/TetherController.cpp
+++ b/server/TetherController.cpp
@@ -77,6 +77,7 @@
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";
+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";
@@ -162,16 +163,7 @@
} else {
setIpFwdEnabled();
}
-
- // Open BPF maps, ignoring errors because the device might not support BPF offload.
- int fd = getTetherIngressMapFd();
- if (fd != -1) {
- mBpfIngressMap.reset(fd);
- }
- fd = getTetherStatsMapFd();
- if (fd != -1) {
- mBpfStatsMap.reset(fd);
- }
+ maybeInitMaps();
}
bool TetherController::setIpFwdEnabled() {
@@ -204,6 +196,25 @@
return setIpFwdEnabled();
}
+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 != -1) {
+ mBpfIngressMap.reset(fd);
+ }
+ fd = getTetherStatsMapFd();
+ if (fd != -1) {
+ mBpfStatsMap.reset(fd);
+ }
+}
+
const std::set<std::string>& TetherController::getIpfwdRequesterList() const {
return mForwardingRequests;
}
@@ -988,6 +999,29 @@
}
}
+ if (mBpfStatsMap.isValid()) {
+ 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>();
+ }
+ 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)});
+ return Result<void>();
+ };
+
+ auto ret = mBpfStatsMap.iterateWithValue(processTetherStats);
+ if (!ret.ok()) {
+ // Ignore error to return the non-BPF tether stats result.
+ ALOGE("Error processing tether stats from BPF maps: %s", ret.error().message().c_str());
+ }
+ }
+
return statsList;
}
diff --git a/server/TetherController.h b/server/TetherController.h
index 7bf8d32..7835cf6 100644
--- a/server/TetherController.h
+++ b/server/TetherController.h
@@ -70,8 +70,10 @@
int sendAllState(int daemonFd) const;
} mDnsmasqState{};
+ // BPF maps, initialized by maybeInitMaps.
bpf::BpfMap<TetherIngressKey, TetherIngressValue> mBpfIngressMap;
bpf::BpfMap<uint32_t, TetherStatsValue> mBpfStatsMap;
+ bpf::BpfMap<uint32_t, IfaceValue> mIfaceIndexNameMap;
public:
TetherController();
@@ -183,6 +185,7 @@
int setForwardRules(bool set, const char *intIface, const char *extIface);
int setTetherCountingRules(bool add, const char *intIface, const char *extIface);
+ void maybeInitMaps();
void maybeStartBpf(const char* extIface);
void maybeStopBpf(const char* extIface);