blob: 446fa2bc7ea17c494d9907bd4463c5265504135d [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"
28#include "bpf/BpfNetworkStats.h"
29#include "bpf/BpfUtils.h"
30
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 Fengf43bf812017-12-15 18:27:22 -080040
Chenbo Feng7e974052018-02-28 22:57:21 -080041// The limit for stats received by a unknown interface;
Chenbo Feng33a4de12018-03-16 18:10:07 -070042static const int64_t MAX_UNKNOWN_IFACE_BYTES = 100*1000;
Chenbo Feng7e974052018-02-28 22:57:21 -080043
Chenbo Feng06c73642018-03-05 04:10:38 -080044static constexpr uint32_t BPF_OPEN_FLAGS = BPF_F_RDONLY;
Lorenzo Colittif9c654c2018-03-01 18:02:15 +090045
Chenbo Fengf43bf812017-12-15 18:27:22 -080046int bpfGetUidStatsInternal(uid_t uid, Stats* stats, const base::unique_fd& map_fd) {
Chenbo Feng16513482018-03-15 17:59:58 -070047 struct StatsValue dummyValue;
48 auto processUidStats = [uid, stats](void *key, const base::unique_fd& map_fd) {
49 if (((StatsKey *) key)->uid != uid) {
Chenbo Fengef1cab32018-04-13 19:50:49 -070050 return BPF_CONTINUE;
Chenbo Fengf43bf812017-12-15 18:27:22 -080051 }
Chenbo Feng16513482018-03-15 17:59:58 -070052 StatsValue statsEntry;
53 int ret = bpf::findMapEntry(map_fd, key, &statsEntry);
54 if (ret) return -errno;
55 stats->rxPackets += statsEntry.rxPackets;
56 stats->txPackets += statsEntry.txPackets;
57 stats->rxBytes += statsEntry.rxBytes;
58 stats->txBytes += statsEntry.txBytes;
Chenbo Fengef1cab32018-04-13 19:50:49 -070059 return BPF_CONTINUE;
Chenbo Feng16513482018-03-15 17:59:58 -070060 };
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -070061 return bpfIterateMap(dummyValue, map_fd, processUidStats);
Chenbo Fengf43bf812017-12-15 18:27:22 -080062}
63
64int bpfGetUidStats(uid_t uid, Stats* stats) {
Lorenzo Colittif9c654c2018-03-01 18:02:15 +090065 base::unique_fd uidStatsMap(bpf::mapRetrieve(UID_STATS_MAP_PATH, BPF_OPEN_FLAGS));
Chenbo Fengf43bf812017-12-15 18:27:22 -080066 if (uidStatsMap < 0) {
67 int ret = -errno;
Lorenzo Colittif9c654c2018-03-01 18:02:15 +090068 ALOGE("Opening map fd from %s failed: %s", UID_STATS_MAP_PATH, strerror(errno));
Chenbo Fengf43bf812017-12-15 18:27:22 -080069 return ret;
70 }
71 return bpfGetUidStatsInternal(uid, stats, uidStatsMap);
72}
73
Chenbo Feng33a4de12018-03-16 18:10:07 -070074int bpfGetIfaceStatsInternal(const char* iface, Stats* stats,
75 const base::unique_fd& ifaceStatsMapFd,
76 const base::unique_fd& ifaceNameMapFd) {
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -070077 uint32_t dummyKey;
Chenbo Feng33a4de12018-03-16 18:10:07 -070078 int64_t unknownIfaceBytesTotal = 0;
Chenbo Fengf43bf812017-12-15 18:27:22 -080079 stats->tcpRxPackets = -1;
80 stats->tcpTxPackets = -1;
Chenbo Feng33a4de12018-03-16 18:10:07 -070081 auto processIfaceStats = [iface, stats, &ifaceNameMapFd, &unknownIfaceBytesTotal](
82 void* key, const base::unique_fd& ifaceStatsMapFd) {
83 char ifname[IFNAMSIZ];
84 int ifIndex = *(int *)key;
85 if (getIfaceNameFromMap(ifaceNameMapFd, ifaceStatsMapFd, ifIndex, ifname, &ifIndex,
86 &unknownIfaceBytesTotal)) {
Chenbo Fengef1cab32018-04-13 19:50:49 -070087 return BPF_CONTINUE;
Chenbo Feng33a4de12018-03-16 18:10:07 -070088 }
89 if (!iface || !strcmp(iface, ifname)) {
90 StatsValue statsEntry;
91 int ret = bpf::findMapEntry(ifaceStatsMapFd, &ifIndex, &statsEntry);
92 if (ret) return -errno;
93 stats->rxPackets += statsEntry.rxPackets;
94 stats->txPackets += statsEntry.txPackets;
95 stats->rxBytes += statsEntry.rxBytes;
96 stats->txBytes += statsEntry.txBytes;
97 }
Chenbo Fengef1cab32018-04-13 19:50:49 -070098 return BPF_CONTINUE;
Chenbo Feng33a4de12018-03-16 18:10:07 -070099 };
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -0700100 return bpfIterateMap(dummyKey, ifaceStatsMapFd, processIfaceStats);
Chenbo Fengf43bf812017-12-15 18:27:22 -0800101}
102
103int bpfGetIfaceStats(const char* iface, Stats* stats) {
Chenbo Feng33a4de12018-03-16 18:10:07 -0700104 base::unique_fd ifaceStatsMap(bpf::mapRetrieve(IFACE_STATS_MAP_PATH, BPF_OPEN_FLAGS));
105 int ret;
106 if (ifaceStatsMap < 0) {
107 ret = -errno;
108 ALOGE("get ifaceStats map fd failed: %s", strerror(errno));
109 return ret;
110 }
111 base::unique_fd ifaceIndexNameMap(bpf::mapRetrieve(IFACE_INDEX_NAME_MAP_PATH, BPF_OPEN_FLAGS));
112 if (ifaceIndexNameMap < 0) {
113 ret = -errno;
114 ALOGE("get ifaceIndexName map fd failed: %s", strerror(errno));
115 return ret;
116 }
117 return bpfGetIfaceStatsInternal(iface, stats, ifaceStatsMap, ifaceIndexNameMap);
Chenbo Fengf43bf812017-12-15 18:27:22 -0800118}
119
120stats_line populateStatsEntry(const StatsKey& statsKey, const StatsValue& statsEntry,
121 const char* ifname) {
122 stats_line newLine;
123 strlcpy(newLine.iface, ifname, sizeof(newLine.iface));
Chenbo Fengf4b812d2018-04-18 15:27:19 -0700124 newLine.uid = (int32_t)statsKey.uid;
125 newLine.set = (int32_t)statsKey.counterSet;
126 newLine.tag = (int32_t)statsKey.tag;
Chenbo Fengeac6c472018-02-05 15:06:23 -0800127 newLine.rxPackets = statsEntry.rxPackets;
128 newLine.txPackets = statsEntry.txPackets;
129 newLine.rxBytes = statsEntry.rxBytes;
130 newLine.txBytes = statsEntry.txBytes;
Chenbo Fengf43bf812017-12-15 18:27:22 -0800131 return newLine;
132}
133
Chenbo Feng33a4de12018-03-16 18:10:07 -0700134void maybeLogUnknownIface(int ifaceIndex, const base::unique_fd& statsMapFd, void* curKey,
135 int64_t* unknownIfaceBytesTotal) {
136 // Have we already logged an error?
137 if (*unknownIfaceBytesTotal == -1) {
138 return;
139 }
140
141 // Are we undercounting enough data to be worth logging?
142 StatsValue statsEntry;
143 if (bpf::findMapEntry(statsMapFd, curKey, &statsEntry) < 0) {
144 // No data is being undercounted.
145 return;
146 }
147
148 *unknownIfaceBytesTotal += (statsEntry.rxBytes + statsEntry.txBytes);
149 if (*unknownIfaceBytesTotal >= MAX_UNKNOWN_IFACE_BYTES) {
150 ALOGE("Unknown name for ifindex %d with more than %" PRId64 " bytes of traffic",
151 ifaceIndex, *unknownIfaceBytesTotal);
152 *unknownIfaceBytesTotal = -1;
153 }
154}
155
Chenbo Feng7e974052018-02-28 22:57:21 -0800156int getIfaceNameFromMap(const base::unique_fd& ifaceMapFd, const base::unique_fd& statsMapFd,
Chenbo Feng33a4de12018-03-16 18:10:07 -0700157 uint32_t ifaceIndex, char* ifname, void* curKey,
158 int64_t* unknownIfaceBytesTotal) {
159 if (bpf::findMapEntry(ifaceMapFd, &ifaceIndex, ifname) < 0) {
160 maybeLogUnknownIface(ifaceIndex, statsMapFd, curKey, unknownIfaceBytesTotal);
Chenbo Feng7e974052018-02-28 22:57:21 -0800161 return -ENODEV;
162 }
163 return 0;
164}
165
Chenbo Feng16513482018-03-15 17:59:58 -0700166int parseBpfNetworkStatsDetailInternal(std::vector<stats_line>* lines,
167 const std::vector<std::string>& limitIfaces, int limitTag,
168 int limitUid, const base::unique_fd& statsMapFd,
169 const base::unique_fd& ifaceMapFd) {
Chenbo Feng33a4de12018-03-16 18:10:07 -0700170 int64_t unknownIfaceBytesTotal = 0;
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -0700171 struct StatsKey dummyKey;
Chenbo Feng16513482018-03-15 17:59:58 -0700172 auto processDetailUidStats = [lines, &limitIfaces, limitTag, limitUid,
173 &unknownIfaceBytesTotal, &ifaceMapFd]
174 (void* key, const base::unique_fd& statsMapFd) {
175 struct StatsKey curKey = * (struct StatsKey*)key;
Chenbo Feng7e974052018-02-28 22:57:21 -0800176 char ifname[IFNAMSIZ];
Chenbo Feng33a4de12018-03-16 18:10:07 -0700177 if (getIfaceNameFromMap(ifaceMapFd, statsMapFd, curKey.ifaceIndex, ifname, &curKey,
178 &unknownIfaceBytesTotal)) {
Chenbo Fengef1cab32018-04-13 19:50:49 -0700179 return BPF_CONTINUE;
Chenbo Feng7e974052018-02-28 22:57:21 -0800180 }
Chenbo Fengf43bf812017-12-15 18:27:22 -0800181 std::string ifnameStr(ifname);
182 if (limitIfaces.size() > 0 &&
183 std::find(limitIfaces.begin(), limitIfaces.end(), ifnameStr) == limitIfaces.end()) {
184 // Nothing matched; skip this line.
Chenbo Fengef1cab32018-04-13 19:50:49 -0700185 return BPF_CONTINUE;
Chenbo Fengf43bf812017-12-15 18:27:22 -0800186 }
Chenbo Feng16513482018-03-15 17:59:58 -0700187 if (limitTag != TAG_ALL && uint32_t(limitTag) != curKey.tag) {
Chenbo Fengef1cab32018-04-13 19:50:49 -0700188 return BPF_CONTINUE;
Chenbo Feng16513482018-03-15 17:59:58 -0700189 }
190 if (limitUid != UID_ALL && uint32_t(limitUid) != curKey.uid) {
Chenbo Fengef1cab32018-04-13 19:50:49 -0700191 return BPF_CONTINUE;
Chenbo Feng16513482018-03-15 17:59:58 -0700192 }
Chenbo Fengf43bf812017-12-15 18:27:22 -0800193 StatsValue statsEntry;
Chenbo Feng7e974052018-02-28 22:57:21 -0800194 if (bpf::findMapEntry(statsMapFd, &curKey, &statsEntry) < 0) return -errno;
Chenbo Fengf43bf812017-12-15 18:27:22 -0800195 lines->push_back(populateStatsEntry(curKey, statsEntry, ifname));
Chenbo Fengef1cab32018-04-13 19:50:49 -0700196 return BPF_CONTINUE;
Chenbo Feng16513482018-03-15 17:59:58 -0700197 };
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -0700198 return bpfIterateMap(dummyKey, statsMapFd, processDetailUidStats);
Chenbo Fengf43bf812017-12-15 18:27:22 -0800199}
200
201int parseBpfNetworkStatsDetail(std::vector<stats_line>* lines,
202 const std::vector<std::string>& limitIfaces, int limitTag,
203 int limitUid) {
Chenbo Fengf43bf812017-12-15 18:27:22 -0800204 int ret = 0;
Chenbo Feng7e974052018-02-28 22:57:21 -0800205 base::unique_fd ifaceIndexNameMap(bpf::mapRetrieve(IFACE_INDEX_NAME_MAP_PATH, BPF_OPEN_FLAGS));
206 if (ifaceIndexNameMap < 0) {
207 ret = -errno;
208 ALOGE("get ifaceIndexName map fd failed: %s", strerror(errno));
209 return ret;
210 }
Chenbo Fengf43bf812017-12-15 18:27:22 -0800211
Chenbo Feng16513482018-03-15 17:59:58 -0700212 // If the caller did not pass in TAG_NONE, read tag data.
213 if (limitTag != TAG_NONE) {
214 base::unique_fd tagStatsMap(bpf::mapRetrieve(TAG_STATS_MAP_PATH, BPF_OPEN_FLAGS));
215 if (tagStatsMap < 0) {
216 ret = -errno;
217 ALOGE("get tagStats map fd failed: %s", strerror(errno));
218 return ret;
219 }
220 ret = parseBpfNetworkStatsDetailInternal(lines, limitIfaces, limitTag, limitUid,
221 tagStatsMap, ifaceIndexNameMap);
222 if (ret) return ret;
223 }
224
225 // If the caller did not pass in a specific tag (i.e., if limitTag is TAG_NONE(0) or
226 // TAG_ALL(-1)) read UID data.
227 if (limitTag == TAG_NONE || limitTag == TAG_ALL) {
Lorenzo Colittif9c654c2018-03-01 18:02:15 +0900228 base::unique_fd uidStatsMap(bpf::mapRetrieve(UID_STATS_MAP_PATH, BPF_OPEN_FLAGS));
Chenbo Fengf43bf812017-12-15 18:27:22 -0800229 if (uidStatsMap < 0) {
230 ret = -errno;
Lorenzo Colittif9c654c2018-03-01 18:02:15 +0900231 ALOGE("Opening map fd from %s failed: %s", UID_STATS_MAP_PATH, strerror(errno));
Chenbo Fengf43bf812017-12-15 18:27:22 -0800232 return ret;
233 }
Chenbo Feng16513482018-03-15 17:59:58 -0700234 ret = parseBpfNetworkStatsDetailInternal(lines, limitIfaces, limitTag, limitUid,
235 uidStatsMap, ifaceIndexNameMap);
Chenbo Fengf43bf812017-12-15 18:27:22 -0800236 }
237 return ret;
238}
239
Chenbo Fengf4b812d2018-04-18 15:27:19 -0700240int parseBpfNetworkStatsDevInternal(std::vector<stats_line>* lines,
241 const base::unique_fd& statsMapFd,
242 const base::unique_fd& ifaceMapFd) {
243 int64_t unknownIfaceBytesTotal = 0;
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -0700244 uint32_t dummyKey;
Chenbo Fengf4b812d2018-04-18 15:27:19 -0700245 struct StatsValue dummyValue;
246 auto processDetailIfaceStats = [lines, &unknownIfaceBytesTotal, &ifaceMapFd](
247 void* key, void* value, const base::unique_fd& statsMapFd) {
248 uint32_t ifIndex = *(uint32_t*)key;
249 char ifname[IFNAMSIZ];
250 if (getIfaceNameFromMap(ifaceMapFd, statsMapFd, ifIndex, ifname, &ifIndex,
251 &unknownIfaceBytesTotal)) {
252 return BPF_CONTINUE;
253 }
254 StatsValue* statsEntry = (StatsValue*)value;
255 StatsKey fakeKey = {
256 .uid = (uint32_t)UID_ALL, .counterSet = (uint32_t)SET_ALL, .tag = (uint32_t)TAG_NONE};
257 lines->push_back(populateStatsEntry(fakeKey, *statsEntry, ifname));
258 return BPF_CONTINUE;
259 };
Chenbo Fengc3bfd3e2018-04-24 11:50:02 -0700260 return bpfIterateMapWithValue(dummyKey, dummyValue, statsMapFd, processDetailIfaceStats);
Chenbo Fengf4b812d2018-04-18 15:27:19 -0700261}
262
263int parseBpfNetworkStatsDev(std::vector<stats_line>* lines) {
264 int ret = 0;
265 base::unique_fd ifaceIndexNameMap(bpf::mapRetrieve(IFACE_INDEX_NAME_MAP_PATH, BPF_OPEN_FLAGS));
266 if (ifaceIndexNameMap < 0) {
267 ret = -errno;
268 ALOGE("get ifaceIndexName map fd failed: %s", strerror(errno));
269 return ret;
270 }
271
272 base::unique_fd ifaceStatsMap(bpf::mapRetrieve(IFACE_STATS_MAP_PATH, BPF_OPEN_FLAGS));
273 if (ifaceStatsMap < 0) {
274 ret = -errno;
275 ALOGE("get ifaceStats map fd failed: %s", strerror(errno));
276 return ret;
277 }
278 return parseBpfNetworkStatsDevInternal(lines, ifaceStatsMap, ifaceIndexNameMap);
279}
280
Chenbo Fengf43bf812017-12-15 18:27:22 -0800281uint64_t combineUidTag(const uid_t uid, const uint32_t tag) {
282 return (uint64_t)uid << 32 | tag;
283}
284
Chenbo Fengf43bf812017-12-15 18:27:22 -0800285} // namespace bpf
286} // namespace android