blob: aa604ce9019f150d1399c78169bac0e368e3213d [file] [log] [blame]
Chenbo Fengf43bf812017-12-15 18:27:22 -08001/*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <inttypes.h>
18#include <net/if.h>
19#include <string.h>
20#include <unordered_set>
21
22#include <utils/Log.h>
23#include <utils/misc.h>
24
25#include "android-base/file.h"
26#include "android-base/strings.h"
27#include "android-base/unique_fd.h"
Chenbo Feng4f6c2372018-04-26 10:37:55 -070028#include "bpf/BpfMap.h"
Chenbo Fengf43bf812017-12-15 18:27:22 -080029#include "bpf/BpfNetworkStats.h"
Chenbo Fengf43bf812017-12-15 18:27:22 -080030
Lorenzo Colittif9c654c2018-03-01 18:02:15 +090031#ifdef LOG_TAG
32#undef LOG_TAG
33#endif
34
35#define LOG_TAG "BpfNetworkStats"
36
Chenbo Fengf43bf812017-12-15 18:27:22 -080037namespace android {
38namespace bpf {
39
Chenbo Feng4f6c2372018-04-26 10:37:55 -070040using netdutils::Status;
Chenbo Feng7e974052018-02-28 22:57:21 -080041
Chenbo Feng06c73642018-03-05 04:10:38 -080042static constexpr uint32_t BPF_OPEN_FLAGS = BPF_F_RDONLY;
Lorenzo Colittif9c654c2018-03-01 18:02:15 +090043
Chenbo Feng4f6c2372018-04-26 10:37:55 -070044int bpfGetUidStatsInternal(uid_t uid, Stats* stats,
45 const BpfMap<StatsKey, StatsValue>& uidStatsMap) {
46 const auto processUidStats = [stats, uid](const StatsKey& key,
47 const BpfMap<StatsKey, StatsValue>& uidStatsMap) {
48 if (key.uid == uid) {
49 StatsValue statsEntry;
50 ASSIGN_OR_RETURN(statsEntry, uidStatsMap.readValue(key));
51 stats->rxPackets += statsEntry.rxPackets;
52 stats->txPackets += statsEntry.txPackets;
53 stats->rxBytes += statsEntry.rxBytes;
54 stats->txBytes += statsEntry.txBytes;
Chenbo Fengf43bf812017-12-15 18:27:22 -080055 }
Chenbo Feng4f6c2372018-04-26 10:37:55 -070056 return netdutils::status::ok;
Chenbo Feng16513482018-03-15 17:59:58 -070057 };
Chenbo Feng4f6c2372018-04-26 10:37:55 -070058 return -uidStatsMap.iterate(processUidStats).code();
Chenbo Fengf43bf812017-12-15 18:27:22 -080059}
60
61int bpfGetUidStats(uid_t uid, Stats* stats) {
Chenbo Feng4f6c2372018-04-26 10:37:55 -070062 BpfMap<StatsKey, StatsValue> uidStatsMap(mapRetrieve(UID_STATS_MAP_PATH, BPF_OPEN_FLAGS));
63
64 if (!uidStatsMap.isValid()) {
Chenbo Fengf43bf812017-12-15 18:27:22 -080065 int ret = -errno;
Lorenzo Colittif9c654c2018-03-01 18:02:15 +090066 ALOGE("Opening map fd from %s failed: %s", UID_STATS_MAP_PATH, strerror(errno));
Chenbo Fengf43bf812017-12-15 18:27:22 -080067 return ret;
68 }
69 return bpfGetUidStatsInternal(uid, stats, uidStatsMap);
70}
71
Chenbo Feng33a4de12018-03-16 18:10:07 -070072int bpfGetIfaceStatsInternal(const char* iface, Stats* stats,
Chenbo Feng4f6c2372018-04-26 10:37:55 -070073 const BpfMap<uint32_t, StatsValue>& ifaceStatsMap,
74 const BpfMap<uint32_t, IfaceValue>& ifaceNameMap) {
Chenbo Feng33a4de12018-03-16 18:10:07 -070075 int64_t unknownIfaceBytesTotal = 0;
Chenbo Fengf43bf812017-12-15 18:27:22 -080076 stats->tcpRxPackets = -1;
77 stats->tcpTxPackets = -1;
Chenbo Feng4f6c2372018-04-26 10:37:55 -070078 const auto processIfaceStats = [iface, stats, &ifaceNameMap, &unknownIfaceBytesTotal]
79 (const uint32_t& key,
80 const BpfMap<uint32_t, StatsValue>& ifaceStatsMap) {
Chenbo Feng33a4de12018-03-16 18:10:07 -070081 char ifname[IFNAMSIZ];
Chenbo Feng4f6c2372018-04-26 10:37:55 -070082 if (getIfaceNameFromMap(ifaceNameMap, ifaceStatsMap, key, ifname, key,
Chenbo Feng33a4de12018-03-16 18:10:07 -070083 &unknownIfaceBytesTotal)) {
Chenbo Feng4f6c2372018-04-26 10:37:55 -070084 return netdutils::status::ok;
Chenbo Feng33a4de12018-03-16 18:10:07 -070085 }
86 if (!iface || !strcmp(iface, ifname)) {
87 StatsValue statsEntry;
Chenbo Feng4f6c2372018-04-26 10:37:55 -070088 ASSIGN_OR_RETURN(statsEntry, ifaceStatsMap.readValue(key));
Chenbo Feng33a4de12018-03-16 18:10:07 -070089 stats->rxPackets += statsEntry.rxPackets;
90 stats->txPackets += statsEntry.txPackets;
91 stats->rxBytes += statsEntry.rxBytes;
92 stats->txBytes += statsEntry.txBytes;
93 }
Chenbo Feng4f6c2372018-04-26 10:37:55 -070094 return netdutils::status::ok;
Chenbo Feng33a4de12018-03-16 18:10:07 -070095 };
Chenbo Feng4f6c2372018-04-26 10:37:55 -070096 return -ifaceStatsMap.iterate(processIfaceStats).code();
Chenbo Fengf43bf812017-12-15 18:27:22 -080097}
98
99int bpfGetIfaceStats(const char* iface, Stats* stats) {
Chenbo Feng4f6c2372018-04-26 10:37:55 -0700100 BpfMap<uint32_t, StatsValue> ifaceStatsMap(mapRetrieve(IFACE_STATS_MAP_PATH, BPF_OPEN_FLAGS));
Chenbo Feng33a4de12018-03-16 18:10:07 -0700101 int ret;
Chenbo Feng4f6c2372018-04-26 10:37:55 -0700102 if (!ifaceStatsMap.isValid()) {
Chenbo Feng33a4de12018-03-16 18:10:07 -0700103 ret = -errno;
104 ALOGE("get ifaceStats map fd failed: %s", strerror(errno));
105 return ret;
106 }
Chenbo Feng4f6c2372018-04-26 10:37:55 -0700107 BpfMap<uint32_t, IfaceValue> ifaceIndexNameMap(
108 mapRetrieve(IFACE_INDEX_NAME_MAP_PATH, BPF_OPEN_FLAGS));
109 if (!ifaceIndexNameMap.isValid()) {
Chenbo Feng33a4de12018-03-16 18:10:07 -0700110 ret = -errno;
111 ALOGE("get ifaceIndexName map fd failed: %s", strerror(errno));
112 return ret;
113 }
114 return bpfGetIfaceStatsInternal(iface, stats, ifaceStatsMap, ifaceIndexNameMap);
Chenbo Fengf43bf812017-12-15 18:27:22 -0800115}
116
117stats_line populateStatsEntry(const StatsKey& statsKey, const StatsValue& statsEntry,
118 const char* ifname) {
119 stats_line newLine;
120 strlcpy(newLine.iface, ifname, sizeof(newLine.iface));
Chenbo Fengf4b812d2018-04-18 15:27:19 -0700121 newLine.uid = (int32_t)statsKey.uid;
122 newLine.set = (int32_t)statsKey.counterSet;
123 newLine.tag = (int32_t)statsKey.tag;
Chenbo Fengeac6c472018-02-05 15:06:23 -0800124 newLine.rxPackets = statsEntry.rxPackets;
125 newLine.txPackets = statsEntry.txPackets;
126 newLine.rxBytes = statsEntry.rxBytes;
127 newLine.txBytes = statsEntry.txBytes;
Chenbo Fengf43bf812017-12-15 18:27:22 -0800128 return newLine;
129}
130
Chenbo Feng16513482018-03-15 17:59:58 -0700131int parseBpfNetworkStatsDetailInternal(std::vector<stats_line>* lines,
132 const std::vector<std::string>& limitIfaces, int limitTag,
Chenbo Feng4f6c2372018-04-26 10:37:55 -0700133 int limitUid, const BpfMap<StatsKey, StatsValue>& statsMap,
134 const BpfMap<uint32_t, IfaceValue>& ifaceMap) {
Chenbo Feng33a4de12018-03-16 18:10:07 -0700135 int64_t unknownIfaceBytesTotal = 0;
Chenbo Feng4f6c2372018-04-26 10:37:55 -0700136 const auto processDetailUidStats = [lines, &limitIfaces, &limitTag, &limitUid,
137 &unknownIfaceBytesTotal,
138 &ifaceMap](const StatsKey& key,
139 const BpfMap<StatsKey, StatsValue>& statsMap) {
Chenbo Feng7e974052018-02-28 22:57:21 -0800140 char ifname[IFNAMSIZ];
Chenbo Feng4f6c2372018-04-26 10:37:55 -0700141 if (getIfaceNameFromMap(ifaceMap, statsMap, key.ifaceIndex, ifname, key,
Chenbo Feng33a4de12018-03-16 18:10:07 -0700142 &unknownIfaceBytesTotal)) {
Chenbo Feng4f6c2372018-04-26 10:37:55 -0700143 return netdutils::status::ok;
Chenbo Feng7e974052018-02-28 22:57:21 -0800144 }
Chenbo Fengf43bf812017-12-15 18:27:22 -0800145 std::string ifnameStr(ifname);
146 if (limitIfaces.size() > 0 &&
147 std::find(limitIfaces.begin(), limitIfaces.end(), ifnameStr) == limitIfaces.end()) {
148 // Nothing matched; skip this line.
Chenbo Feng4f6c2372018-04-26 10:37:55 -0700149 return netdutils::status::ok;
Chenbo Fengf43bf812017-12-15 18:27:22 -0800150 }
Chenbo Feng4f6c2372018-04-26 10:37:55 -0700151 if (limitTag != TAG_ALL && uint32_t(limitTag) != key.tag) {
152 return netdutils::status::ok;
Chenbo Feng16513482018-03-15 17:59:58 -0700153 }
Chenbo Feng4f6c2372018-04-26 10:37:55 -0700154 if (limitUid != UID_ALL && uint32_t(limitUid) != key.uid) {
155 return netdutils::status::ok;
Chenbo Feng16513482018-03-15 17:59:58 -0700156 }
Chenbo Fengf43bf812017-12-15 18:27:22 -0800157 StatsValue statsEntry;
Chenbo Feng4f6c2372018-04-26 10:37:55 -0700158 ASSIGN_OR_RETURN(statsEntry, statsMap.readValue(key));
159 lines->push_back(populateStatsEntry(key, statsEntry, ifname));
160 return netdutils::status::ok;
Chenbo Feng16513482018-03-15 17:59:58 -0700161 };
Chenbo Feng4f6c2372018-04-26 10:37:55 -0700162 Status res = statsMap.iterate(processDetailUidStats);
163 if (!isOk(res)) {
164 ALOGE("failed to iterate per uid Stats map for detail traffic stats: %s",
165 strerror(res.code()));
166 return -res.code();
167 }
168 return 0;
Chenbo Fengf43bf812017-12-15 18:27:22 -0800169}
170
171int parseBpfNetworkStatsDetail(std::vector<stats_line>* lines,
172 const std::vector<std::string>& limitIfaces, int limitTag,
173 int limitUid) {
Chenbo Fengf43bf812017-12-15 18:27:22 -0800174 int ret = 0;
Chenbo Feng4f6c2372018-04-26 10:37:55 -0700175 BpfMap<uint32_t, IfaceValue> ifaceIndexNameMap(
176 mapRetrieve(IFACE_INDEX_NAME_MAP_PATH, BPF_OPEN_FLAGS));
177 if (!ifaceIndexNameMap.isValid()) {
Chenbo Feng7e974052018-02-28 22:57:21 -0800178 ret = -errno;
179 ALOGE("get ifaceIndexName map fd failed: %s", strerror(errno));
180 return ret;
181 }
Chenbo Fengf43bf812017-12-15 18:27:22 -0800182
Chenbo Feng16513482018-03-15 17:59:58 -0700183 // If the caller did not pass in TAG_NONE, read tag data.
184 if (limitTag != TAG_NONE) {
Chenbo Feng4f6c2372018-04-26 10:37:55 -0700185 BpfMap<StatsKey, StatsValue> tagStatsMap(mapRetrieve(TAG_STATS_MAP_PATH, BPF_OPEN_FLAGS));
186 if (!tagStatsMap.isValid()) {
Chenbo Feng16513482018-03-15 17:59:58 -0700187 ret = -errno;
188 ALOGE("get tagStats map fd failed: %s", strerror(errno));
189 return ret;
190 }
191 ret = parseBpfNetworkStatsDetailInternal(lines, limitIfaces, limitTag, limitUid,
192 tagStatsMap, ifaceIndexNameMap);
193 if (ret) return ret;
194 }
195
196 // If the caller did not pass in a specific tag (i.e., if limitTag is TAG_NONE(0) or
197 // TAG_ALL(-1)) read UID data.
198 if (limitTag == TAG_NONE || limitTag == TAG_ALL) {
Chenbo Feng4f6c2372018-04-26 10:37:55 -0700199 BpfMap<StatsKey, StatsValue> uidStatsMap(mapRetrieve(UID_STATS_MAP_PATH, BPF_OPEN_FLAGS));
200 if (!uidStatsMap.isValid()) {
Chenbo Fengf43bf812017-12-15 18:27:22 -0800201 ret = -errno;
Lorenzo Colittif9c654c2018-03-01 18:02:15 +0900202 ALOGE("Opening map fd from %s failed: %s", UID_STATS_MAP_PATH, strerror(errno));
Chenbo Fengf43bf812017-12-15 18:27:22 -0800203 return ret;
204 }
Chenbo Feng16513482018-03-15 17:59:58 -0700205 ret = parseBpfNetworkStatsDetailInternal(lines, limitIfaces, limitTag, limitUid,
206 uidStatsMap, ifaceIndexNameMap);
Chenbo Fengf43bf812017-12-15 18:27:22 -0800207 }
208 return ret;
209}
210
Chenbo Fengf4b812d2018-04-18 15:27:19 -0700211int parseBpfNetworkStatsDevInternal(std::vector<stats_line>* lines,
Chenbo Feng4f6c2372018-04-26 10:37:55 -0700212 const BpfMap<uint32_t, StatsValue>& statsMap,
213 const BpfMap<uint32_t, IfaceValue>& ifaceMap) {
Chenbo Fengf4b812d2018-04-18 15:27:19 -0700214 int64_t unknownIfaceBytesTotal = 0;
Chenbo Feng4f6c2372018-04-26 10:37:55 -0700215 const auto processDetailIfaceStats = [lines, &unknownIfaceBytesTotal, &ifaceMap, &statsMap](
216 const uint32_t& key, const StatsValue& value,
217 const BpfMap<uint32_t, StatsValue>&) {
Chenbo Fengf4b812d2018-04-18 15:27:19 -0700218 char ifname[IFNAMSIZ];
Chenbo Feng4f6c2372018-04-26 10:37:55 -0700219 if (getIfaceNameFromMap(ifaceMap, statsMap, key, ifname, key, &unknownIfaceBytesTotal)) {
220 return netdutils::status::ok;
Chenbo Fengf4b812d2018-04-18 15:27:19 -0700221 }
Chenbo Fengf4b812d2018-04-18 15:27:19 -0700222 StatsKey fakeKey = {
223 .uid = (uint32_t)UID_ALL, .counterSet = (uint32_t)SET_ALL, .tag = (uint32_t)TAG_NONE};
Chenbo Feng4f6c2372018-04-26 10:37:55 -0700224 lines->push_back(populateStatsEntry(fakeKey, value, ifname));
225 return netdutils::status::ok;
Chenbo Fengf4b812d2018-04-18 15:27:19 -0700226 };
Chenbo Feng4f6c2372018-04-26 10:37:55 -0700227 Status res = statsMap.iterateWithValue(processDetailIfaceStats);
228 if (!isOk(res)) {
229 ALOGE("failed to iterate per uid Stats map for detail traffic stats: %s",
230 strerror(res.code()));
231 return -res.code();
232 }
233 return 0;
Chenbo Fengf4b812d2018-04-18 15:27:19 -0700234}
235
236int parseBpfNetworkStatsDev(std::vector<stats_line>* lines) {
237 int ret = 0;
Chenbo Feng4f6c2372018-04-26 10:37:55 -0700238 BpfMap<uint32_t, IfaceValue> ifaceIndexNameMap(
239 mapRetrieve(IFACE_INDEX_NAME_MAP_PATH, BPF_OPEN_FLAGS));
240 if (!ifaceIndexNameMap.isValid()) {
Chenbo Fengf4b812d2018-04-18 15:27:19 -0700241 ret = -errno;
242 ALOGE("get ifaceIndexName map fd failed: %s", strerror(errno));
243 return ret;
244 }
245
Chenbo Feng4f6c2372018-04-26 10:37:55 -0700246 BpfMap<uint32_t, StatsValue> ifaceStatsMap(mapRetrieve(IFACE_STATS_MAP_PATH, BPF_OPEN_FLAGS));
247 if (!ifaceStatsMap.isValid()) {
Chenbo Fengf4b812d2018-04-18 15:27:19 -0700248 ret = -errno;
249 ALOGE("get ifaceStats map fd failed: %s", strerror(errno));
250 return ret;
251 }
252 return parseBpfNetworkStatsDevInternal(lines, ifaceStatsMap, ifaceIndexNameMap);
253}
254
Chenbo Fengf43bf812017-12-15 18:27:22 -0800255uint64_t combineUidTag(const uid_t uid, const uint32_t tag) {
256 return (uint64_t)uid << 32 | tag;
257}
258
Chenbo Fengf43bf812017-12-15 18:27:22 -0800259} // namespace bpf
260} // namespace android