1 /*
2 * Copyright (C) 2018 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 <fstream>
18 #include <iostream>
19 #include <string>
20 #include <vector>
21
22 #include <fcntl.h>
23 #include <inttypes.h>
24 #include <linux/inet_diag.h>
25 #include <linux/sock_diag.h>
26 #include <net/if.h>
27 #include <sys/socket.h>
28 #include <sys/types.h>
29 #include <unistd.h>
30
31 #include <gtest/gtest.h>
32
33 #include <android-base/stringprintf.h>
34 #include <android-base/strings.h>
35
36 #include <netdutils/MockSyscalls.h>
37 #include "bpf/BpfMap.h"
38 #include "bpf/BpfUtils.h"
39 #include "netdbpf/BpfNetworkStats.h"
40
41 using ::testing::Test;
42
43 namespace android {
44 namespace bpf {
45
46 using base::Result;
47 using base::unique_fd;
48
49 constexpr int TEST_MAP_SIZE = 10;
50 constexpr uid_t TEST_UID1 = 10086;
51 constexpr uid_t TEST_UID2 = 12345;
52 constexpr uint32_t TEST_TAG = 42;
53 constexpr int TEST_COUNTERSET0 = 0;
54 constexpr int TEST_COUNTERSET1 = 1;
55 constexpr uint64_t TEST_BYTES0 = 1000;
56 constexpr uint64_t TEST_BYTES1 = 2000;
57 constexpr uint64_t TEST_PACKET0 = 100;
58 constexpr uint64_t TEST_PACKET1 = 200;
59 constexpr const char IFACE_NAME1[] = "lo";
60 constexpr const char IFACE_NAME2[] = "wlan0";
61 constexpr const char IFACE_NAME3[] = "rmnet_data0";
62 // A iface name that the size is bigger then IFNAMSIZ
63 constexpr const char LONG_IFACE_NAME[] = "wlanWithALongName";
64 constexpr const char TRUNCATED_IFACE_NAME[] = "wlanWithALongNa";
65 constexpr uint32_t IFACE_INDEX1 = 1;
66 constexpr uint32_t IFACE_INDEX2 = 2;
67 constexpr uint32_t IFACE_INDEX3 = 3;
68 constexpr uint32_t IFACE_INDEX4 = 4;
69 constexpr uint32_t UNKNOWN_IFACE = 0;
70
71 class BpfNetworkStatsHelperTest : public testing::Test {
72 protected:
BpfNetworkStatsHelperTest()73 BpfNetworkStatsHelperTest() {}
74 BpfMap<uint64_t, UidTagValue> mFakeCookieTagMap;
75 BpfMap<uint32_t, StatsValue> mFakeAppUidStatsMap;
76 BpfMap<StatsKey, StatsValue> mFakeStatsMap;
77 BpfMap<uint32_t, IfaceValue> mFakeIfaceIndexNameMap;
78 BpfMap<uint32_t, StatsValue> mFakeIfaceStatsMap;
79
SetUp()80 void SetUp() {
81 SKIP_IF_BPF_NOT_SUPPORTED;
82 ASSERT_EQ(0, setrlimitForTest());
83
84 mFakeCookieTagMap = BpfMap<uint64_t, UidTagValue>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, 0);
85 ASSERT_LE(0, mFakeCookieTagMap.getMap());
86
87 mFakeAppUidStatsMap = BpfMap<uint32_t, StatsValue>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, 0);
88 ASSERT_LE(0, mFakeAppUidStatsMap.getMap());
89
90 mFakeStatsMap = BpfMap<StatsKey, StatsValue>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, 0);
91 ASSERT_LE(0, mFakeStatsMap.getMap());
92
93 mFakeIfaceIndexNameMap = BpfMap<uint32_t, IfaceValue>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, 0);
94 ASSERT_LE(0, mFakeIfaceIndexNameMap.getMap());
95
96 mFakeIfaceStatsMap = BpfMap<uint32_t, StatsValue>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, 0);
97 ASSERT_LE(0, mFakeIfaceStatsMap.getMap());
98 }
99
expectUidTag(uint64_t cookie,uid_t uid,uint32_t tag)100 void expectUidTag(uint64_t cookie, uid_t uid, uint32_t tag) {
101 auto tagResult = mFakeCookieTagMap.readValue(cookie);
102 EXPECT_RESULT_OK(tagResult);
103 EXPECT_EQ(uid, tagResult.value().uid);
104 EXPECT_EQ(tag, tagResult.value().tag);
105 }
106
populateFakeStats(uid_t uid,uint32_t tag,uint32_t ifaceIndex,uint32_t counterSet,StatsValue value,BpfMap<StatsKey,StatsValue> & map)107 void populateFakeStats(uid_t uid, uint32_t tag, uint32_t ifaceIndex, uint32_t counterSet,
108 StatsValue value, BpfMap<StatsKey, StatsValue>& map) {
109 StatsKey key = {
110 .uid = (uint32_t)uid, .tag = tag, .counterSet = counterSet, .ifaceIndex = ifaceIndex};
111 EXPECT_RESULT_OK(map.writeValue(key, value, BPF_ANY));
112 }
113
updateIfaceMap(const char * ifaceName,uint32_t ifaceIndex)114 void updateIfaceMap(const char* ifaceName, uint32_t ifaceIndex) {
115 IfaceValue iface;
116 strlcpy(iface.name, ifaceName, IFNAMSIZ);
117 EXPECT_RESULT_OK(mFakeIfaceIndexNameMap.writeValue(ifaceIndex, iface, BPF_ANY));
118 }
119
expectStatsEqual(const StatsValue & target,const Stats & result)120 void expectStatsEqual(const StatsValue& target, const Stats& result) {
121 EXPECT_EQ(target.rxPackets, result.rxPackets);
122 EXPECT_EQ(target.rxBytes, result.rxBytes);
123 EXPECT_EQ(target.txPackets, result.txPackets);
124 EXPECT_EQ(target.txBytes, result.txBytes);
125 }
126
expectStatsLineEqual(const StatsValue target,const char * iface,uint32_t uid,int counterSet,uint32_t tag,const stats_line & result)127 void expectStatsLineEqual(const StatsValue target, const char* iface, uint32_t uid,
128 int counterSet, uint32_t tag, const stats_line& result) {
129 EXPECT_EQ(0, strcmp(iface, result.iface));
130 EXPECT_EQ(uid, (uint32_t)result.uid);
131 EXPECT_EQ((uint32_t) counterSet, result.set);
132 EXPECT_EQ(tag, (uint32_t)result.tag);
133 EXPECT_EQ(target.rxPackets, (uint64_t)result.rxPackets);
134 EXPECT_EQ(target.rxBytes, (uint64_t)result.rxBytes);
135 EXPECT_EQ(target.txPackets, (uint64_t)result.txPackets);
136 EXPECT_EQ(target.txBytes, (uint64_t)result.txBytes);
137 }
138 };
139
140 // TEST to verify the behavior of bpf map when cocurrent deletion happens when
141 // iterating the same map.
TEST_F(BpfNetworkStatsHelperTest,TestIterateMapWithDeletion)142 TEST_F(BpfNetworkStatsHelperTest, TestIterateMapWithDeletion) {
143 SKIP_IF_BPF_NOT_SUPPORTED;
144
145 for (int i = 0; i < 5; i++) {
146 uint64_t cookie = i + 1;
147 UidTagValue tag = {.uid = TEST_UID1, .tag = TEST_TAG};
148 EXPECT_RESULT_OK(mFakeCookieTagMap.writeValue(cookie, tag, BPF_ANY));
149 }
150 uint64_t curCookie = 0;
151 auto nextCookie = mFakeCookieTagMap.getNextKey(curCookie);
152 EXPECT_RESULT_OK(nextCookie);
153 uint64_t headOfMap = nextCookie.value();
154 curCookie = nextCookie.value();
155 // Find the second entry in the map, then immediately delete it.
156 nextCookie = mFakeCookieTagMap.getNextKey(curCookie);
157 EXPECT_RESULT_OK(nextCookie);
158 EXPECT_RESULT_OK(mFakeCookieTagMap.deleteValue((nextCookie.value())));
159 // Find the entry that is now immediately after headOfMap, then delete that.
160 nextCookie = mFakeCookieTagMap.getNextKey(curCookie);
161 EXPECT_RESULT_OK(nextCookie);
162 EXPECT_RESULT_OK(mFakeCookieTagMap.deleteValue((nextCookie.value())));
163 // Attempting to read an entry that has been deleted fails with ENOENT.
164 curCookie = nextCookie.value();
165 auto tagResult = mFakeCookieTagMap.readValue(curCookie);
166 EXPECT_EQ(ENOENT, tagResult.error().code());
167 // Finding the entry after our deleted entry restarts iteration from the beginning of the map.
168 nextCookie = mFakeCookieTagMap.getNextKey(curCookie);
169 EXPECT_RESULT_OK(nextCookie);
170 EXPECT_EQ(headOfMap, nextCookie.value());
171 }
172
TEST_F(BpfNetworkStatsHelperTest,TestBpfIterateMap)173 TEST_F(BpfNetworkStatsHelperTest, TestBpfIterateMap) {
174 SKIP_IF_BPF_NOT_SUPPORTED;
175
176 for (int i = 0; i < 5; i++) {
177 uint64_t cookie = i + 1;
178 UidTagValue tag = {.uid = TEST_UID1, .tag = TEST_TAG};
179 EXPECT_RESULT_OK(mFakeCookieTagMap.writeValue(cookie, tag, BPF_ANY));
180 }
181 int totalCount = 0;
182 int totalSum = 0;
183 const auto iterateWithoutDeletion =
184 [&totalCount, &totalSum](const uint64_t& key, const BpfMap<uint64_t, UidTagValue>&) {
185 EXPECT_GE((uint64_t)5, key);
186 totalCount++;
187 totalSum += key;
188 return Result<void>();
189 };
190 EXPECT_RESULT_OK(mFakeCookieTagMap.iterate(iterateWithoutDeletion));
191 EXPECT_EQ(5, totalCount);
192 EXPECT_EQ(1 + 2 + 3 + 4 + 5, totalSum);
193 }
194
TEST_F(BpfNetworkStatsHelperTest,TestUidStatsNoTraffic)195 TEST_F(BpfNetworkStatsHelperTest, TestUidStatsNoTraffic) {
196 SKIP_IF_BPF_NOT_SUPPORTED;
197
198 StatsValue value1 = {
199 .rxPackets = 0,
200 .rxBytes = 0,
201 .txPackets = 0,
202 .txBytes = 0,
203 };
204 Stats result1 = {};
205 ASSERT_EQ(0, bpfGetUidStatsInternal(TEST_UID1, &result1, mFakeAppUidStatsMap));
206 expectStatsEqual(value1, result1);
207 }
208
TEST_F(BpfNetworkStatsHelperTest,TestGetUidStatsTotal)209 TEST_F(BpfNetworkStatsHelperTest, TestGetUidStatsTotal) {
210 SKIP_IF_BPF_NOT_SUPPORTED;
211
212 updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
213 updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
214 updateIfaceMap(IFACE_NAME3, IFACE_INDEX3);
215 StatsValue value1 = {
216 .rxPackets = TEST_PACKET0,
217 .rxBytes = TEST_BYTES0,
218 .txPackets = TEST_PACKET1,
219 .txBytes = TEST_BYTES1,
220 };
221 StatsValue value2 = {
222 .rxPackets = TEST_PACKET0 * 2,
223 .rxBytes = TEST_BYTES0 * 2,
224 .txPackets = TEST_PACKET1 * 2,
225 .txBytes = TEST_BYTES1 * 2,
226 };
227 ASSERT_RESULT_OK(mFakeAppUidStatsMap.writeValue(TEST_UID1, value1, BPF_ANY));
228 ASSERT_RESULT_OK(mFakeAppUidStatsMap.writeValue(TEST_UID2, value2, BPF_ANY));
229 Stats result1 = {};
230 ASSERT_EQ(0, bpfGetUidStatsInternal(TEST_UID1, &result1, mFakeAppUidStatsMap));
231 expectStatsEqual(value1, result1);
232
233 Stats result2 = {};
234 ASSERT_EQ(0, bpfGetUidStatsInternal(TEST_UID2, &result2, mFakeAppUidStatsMap));
235 expectStatsEqual(value2, result2);
236 std::vector<stats_line> lines;
237 std::vector<std::string> ifaces;
238 populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
239 populateFakeStats(TEST_UID1, 0, IFACE_INDEX2, TEST_COUNTERSET1, value1, mFakeStatsMap);
240 populateFakeStats(TEST_UID2, 0, IFACE_INDEX3, TEST_COUNTERSET1, value1, mFakeStatsMap);
241 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID1,
242 mFakeStatsMap, mFakeIfaceIndexNameMap));
243 ASSERT_EQ((unsigned long)2, lines.size());
244 lines.clear();
245 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID2,
246 mFakeStatsMap, mFakeIfaceIndexNameMap));
247 ASSERT_EQ((unsigned long)1, lines.size());
248 expectStatsLineEqual(value1, IFACE_NAME3, TEST_UID2, TEST_COUNTERSET1, 0, lines.front());
249 }
250
TEST_F(BpfNetworkStatsHelperTest,TestGetIfaceStatsInternal)251 TEST_F(BpfNetworkStatsHelperTest, TestGetIfaceStatsInternal) {
252 SKIP_IF_BPF_NOT_SUPPORTED;
253
254 updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
255 updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
256 updateIfaceMap(IFACE_NAME3, IFACE_INDEX3);
257 StatsValue value1 = {
258 .rxPackets = TEST_PACKET0,
259 .rxBytes = TEST_BYTES0,
260 .txPackets = TEST_PACKET1,
261 .txBytes = TEST_BYTES1,
262 };
263 StatsValue value2 = {
264 .rxPackets = TEST_PACKET1,
265 .rxBytes = TEST_BYTES1,
266 .txPackets = TEST_PACKET0,
267 .txBytes = TEST_BYTES0,
268 };
269 uint32_t ifaceStatsKey = IFACE_INDEX1;
270 EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value1, BPF_ANY));
271 ifaceStatsKey = IFACE_INDEX2;
272 EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value2, BPF_ANY));
273 ifaceStatsKey = IFACE_INDEX3;
274 EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value1, BPF_ANY));
275
276 Stats result1 = {};
277 ASSERT_EQ(0, bpfGetIfaceStatsInternal(IFACE_NAME1, &result1, mFakeIfaceStatsMap,
278 mFakeIfaceIndexNameMap));
279 expectStatsEqual(value1, result1);
280 Stats result2 = {};
281 ASSERT_EQ(0, bpfGetIfaceStatsInternal(IFACE_NAME2, &result2, mFakeIfaceStatsMap,
282 mFakeIfaceIndexNameMap));
283 expectStatsEqual(value2, result2);
284 Stats totalResult = {};
285 ASSERT_EQ(0, bpfGetIfaceStatsInternal(NULL, &totalResult, mFakeIfaceStatsMap,
286 mFakeIfaceIndexNameMap));
287 StatsValue totalValue = {
288 .rxPackets = TEST_PACKET0 * 2 + TEST_PACKET1,
289 .rxBytes = TEST_BYTES0 * 2 + TEST_BYTES1,
290 .txPackets = TEST_PACKET1 * 2 + TEST_PACKET0,
291 .txBytes = TEST_BYTES1 * 2 + TEST_BYTES0,
292 };
293 expectStatsEqual(totalValue, totalResult);
294 }
295
TEST_F(BpfNetworkStatsHelperTest,TestGetStatsDetail)296 TEST_F(BpfNetworkStatsHelperTest, TestGetStatsDetail) {
297 SKIP_IF_BPF_NOT_SUPPORTED;
298
299 updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
300 updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
301 StatsValue value1 = {
302 .rxPackets = TEST_PACKET0,
303 .rxBytes = TEST_BYTES0,
304 .txPackets = TEST_PACKET1,
305 .txBytes = TEST_BYTES1,
306 };
307 populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
308 populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX2, TEST_COUNTERSET0, value1, mFakeStatsMap);
309 populateFakeStats(TEST_UID1, TEST_TAG + 1, IFACE_INDEX1, TEST_COUNTERSET0, value1,
310 mFakeStatsMap);
311 populateFakeStats(TEST_UID2, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
312 std::vector<stats_line> lines;
313 std::vector<std::string> ifaces;
314 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
315 mFakeIfaceIndexNameMap));
316 ASSERT_EQ((unsigned long)4, lines.size());
317 lines.clear();
318 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID1,
319 mFakeStatsMap, mFakeIfaceIndexNameMap));
320 ASSERT_EQ((unsigned long)3, lines.size());
321 lines.clear();
322 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TEST_TAG, TEST_UID1,
323 mFakeStatsMap, mFakeIfaceIndexNameMap));
324 ASSERT_EQ((unsigned long)2, lines.size());
325 lines.clear();
326 ifaces.push_back(std::string(IFACE_NAME1));
327 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TEST_TAG, TEST_UID1,
328 mFakeStatsMap, mFakeIfaceIndexNameMap));
329 ASSERT_EQ((unsigned long)1, lines.size());
330 expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines.front());
331 }
332
TEST_F(BpfNetworkStatsHelperTest,TestGetStatsWithSkippedIface)333 TEST_F(BpfNetworkStatsHelperTest, TestGetStatsWithSkippedIface) {
334 SKIP_IF_BPF_NOT_SUPPORTED;
335
336 updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
337 updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
338 StatsValue value1 = {
339 .rxPackets = TEST_PACKET0,
340 .rxBytes = TEST_BYTES0,
341 .txPackets = TEST_PACKET1,
342 .txBytes = TEST_BYTES1,
343 };
344 populateFakeStats(0, 0, 0, OVERFLOW_COUNTERSET, value1, mFakeStatsMap);
345 populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
346 populateFakeStats(TEST_UID1, 0, IFACE_INDEX2, TEST_COUNTERSET0, value1, mFakeStatsMap);
347 populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET1, value1, mFakeStatsMap);
348 populateFakeStats(TEST_UID2, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
349 std::vector<stats_line> lines;
350 std::vector<std::string> ifaces;
351 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
352 mFakeIfaceIndexNameMap));
353 ASSERT_EQ((unsigned long)4, lines.size());
354 lines.clear();
355 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID1,
356 mFakeStatsMap, mFakeIfaceIndexNameMap));
357 ASSERT_EQ((unsigned long)3, lines.size());
358 lines.clear();
359 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID2,
360 mFakeStatsMap, mFakeIfaceIndexNameMap));
361 ASSERT_EQ((unsigned long)1, lines.size());
362 expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID2, TEST_COUNTERSET0, 0, lines.front());
363 lines.clear();
364 ifaces.push_back(std::string(IFACE_NAME1));
365 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID1,
366 mFakeStatsMap, mFakeIfaceIndexNameMap));
367 ASSERT_EQ((unsigned long)2, lines.size());
368 }
369
TEST_F(BpfNetworkStatsHelperTest,TestUnkownIfaceError)370 TEST_F(BpfNetworkStatsHelperTest, TestUnkownIfaceError) {
371 SKIP_IF_BPF_NOT_SUPPORTED;
372
373 updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
374 StatsValue value1 = {
375 .rxPackets = TEST_PACKET0,
376 .rxBytes = TEST_BYTES0 * 20,
377 .txPackets = TEST_PACKET1,
378 .txBytes = TEST_BYTES1 * 20,
379 };
380 uint32_t ifaceIndex = UNKNOWN_IFACE;
381 populateFakeStats(TEST_UID1, 0, ifaceIndex, TEST_COUNTERSET0, value1, mFakeStatsMap);
382 populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
383 StatsValue value2 = {
384 .rxPackets = TEST_PACKET0,
385 .rxBytes = TEST_BYTES0 * 40,
386 .txPackets = TEST_PACKET1,
387 .txBytes = TEST_BYTES1 * 40,
388 };
389 populateFakeStats(TEST_UID1, 0, IFACE_INDEX2, TEST_COUNTERSET0, value2, mFakeStatsMap);
390 StatsKey curKey = {
391 .uid = TEST_UID1,
392 .tag = 0,
393 .counterSet = TEST_COUNTERSET0,
394 .ifaceIndex = ifaceIndex,
395 };
396 char ifname[IFNAMSIZ];
397 int64_t unknownIfaceBytesTotal = 0;
398 ASSERT_EQ(-ENODEV, getIfaceNameFromMap(mFakeIfaceIndexNameMap, mFakeStatsMap, ifaceIndex,
399 ifname, curKey, &unknownIfaceBytesTotal));
400 ASSERT_EQ(((int64_t)(TEST_BYTES0 * 20 + TEST_BYTES1 * 20)), unknownIfaceBytesTotal);
401 curKey.ifaceIndex = IFACE_INDEX2;
402 ASSERT_EQ(-ENODEV, getIfaceNameFromMap(mFakeIfaceIndexNameMap, mFakeStatsMap, ifaceIndex,
403 ifname, curKey, &unknownIfaceBytesTotal));
404 ASSERT_EQ(-1, unknownIfaceBytesTotal);
405 std::vector<stats_line> lines;
406 std::vector<std::string> ifaces;
407 // TODO: find a way to test the total of unknown Iface Bytes go above limit.
408 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
409 mFakeIfaceIndexNameMap));
410 ASSERT_EQ((unsigned long)1, lines.size());
411 expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, 0, lines.front());
412 }
413
TEST_F(BpfNetworkStatsHelperTest,TestGetIfaceStatsDetail)414 TEST_F(BpfNetworkStatsHelperTest, TestGetIfaceStatsDetail) {
415 SKIP_IF_BPF_NOT_SUPPORTED;
416
417 updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
418 updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
419 updateIfaceMap(IFACE_NAME3, IFACE_INDEX3);
420 updateIfaceMap(LONG_IFACE_NAME, IFACE_INDEX4);
421 StatsValue value1 = {
422 .rxPackets = TEST_PACKET0,
423 .rxBytes = TEST_BYTES0,
424 .txPackets = TEST_PACKET1,
425 .txBytes = TEST_BYTES1,
426 };
427 StatsValue value2 = {
428 .rxPackets = TEST_PACKET1,
429 .rxBytes = TEST_BYTES1,
430 .txPackets = TEST_PACKET0,
431 .txBytes = TEST_BYTES0,
432 };
433 uint32_t ifaceStatsKey = IFACE_INDEX1;
434 EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value1, BPF_ANY));
435 ifaceStatsKey = IFACE_INDEX2;
436 EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value2, BPF_ANY));
437 ifaceStatsKey = IFACE_INDEX3;
438 EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value1, BPF_ANY));
439 ifaceStatsKey = IFACE_INDEX4;
440 EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value2, BPF_ANY));
441 std::vector<stats_line> lines;
442 ASSERT_EQ(0,
443 parseBpfNetworkStatsDevInternal(&lines, mFakeIfaceStatsMap, mFakeIfaceIndexNameMap));
444 ASSERT_EQ((unsigned long)4, lines.size());
445
446 expectStatsLineEqual(value1, IFACE_NAME1, UID_ALL, SET_ALL, TAG_NONE, lines[0]);
447 expectStatsLineEqual(value1, IFACE_NAME3, UID_ALL, SET_ALL, TAG_NONE, lines[1]);
448 expectStatsLineEqual(value2, IFACE_NAME2, UID_ALL, SET_ALL, TAG_NONE, lines[2]);
449 ASSERT_EQ(0, strcmp(TRUNCATED_IFACE_NAME, lines[3].iface));
450 expectStatsLineEqual(value2, TRUNCATED_IFACE_NAME, UID_ALL, SET_ALL, TAG_NONE, lines[3]);
451 }
452
TEST_F(BpfNetworkStatsHelperTest,TestGetStatsSortedAndGrouped)453 TEST_F(BpfNetworkStatsHelperTest, TestGetStatsSortedAndGrouped) {
454 SKIP_IF_BPF_NOT_SUPPORTED;
455
456 // Create iface indexes with duplicate iface name.
457 updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
458 updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
459 updateIfaceMap(IFACE_NAME1, IFACE_INDEX3); // Duplicate!
460
461 StatsValue value1 = {
462 .rxPackets = TEST_PACKET0,
463 .rxBytes = TEST_BYTES0,
464 .txPackets = TEST_PACKET1,
465 .txBytes = TEST_BYTES1,
466 };
467 StatsValue value2 = {
468 .rxPackets = TEST_PACKET1,
469 .rxBytes = TEST_BYTES1,
470 .txPackets = TEST_PACKET0,
471 .txBytes = TEST_BYTES0,
472 };
473 StatsValue value3 = {
474 .rxPackets = TEST_PACKET0 * 2,
475 .rxBytes = TEST_BYTES0 * 2,
476 .txPackets = TEST_PACKET1 * 2,
477 .txBytes = TEST_BYTES1 * 2,
478 };
479
480 std::vector<stats_line> lines;
481 std::vector<std::string> ifaces;
482
483 // Test empty stats.
484 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
485 mFakeIfaceIndexNameMap));
486 ASSERT_EQ((size_t) 0, lines.size());
487 lines.clear();
488
489 // Test 1 line stats.
490 populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
491 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
492 mFakeIfaceIndexNameMap));
493 ASSERT_EQ((size_t) 1, lines.size());
494 expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines[0]);
495 lines.clear();
496
497 // These items should not be grouped.
498 populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX2, TEST_COUNTERSET0, value2, mFakeStatsMap);
499 populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX3, TEST_COUNTERSET1, value2, mFakeStatsMap);
500 populateFakeStats(TEST_UID1, TEST_TAG + 1, IFACE_INDEX1, TEST_COUNTERSET0, value2,
501 mFakeStatsMap);
502 populateFakeStats(TEST_UID2, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
503 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
504 mFakeIfaceIndexNameMap));
505 ASSERT_EQ((size_t) 5, lines.size());
506 lines.clear();
507
508 // These items should be grouped.
509 populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX3, TEST_COUNTERSET0, value1, mFakeStatsMap);
510 populateFakeStats(TEST_UID2, TEST_TAG, IFACE_INDEX3, TEST_COUNTERSET0, value1, mFakeStatsMap);
511
512 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
513 mFakeIfaceIndexNameMap));
514 ASSERT_EQ((size_t) 5, lines.size());
515
516 // Verify Sorted & Grouped.
517 expectStatsLineEqual(value3, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines[0]);
518 expectStatsLineEqual(value2, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET1, TEST_TAG, lines[1]);
519 expectStatsLineEqual(value2, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG + 1, lines[2]);
520 expectStatsLineEqual(value3, IFACE_NAME1, TEST_UID2, TEST_COUNTERSET0, TEST_TAG, lines[3]);
521 expectStatsLineEqual(value2, IFACE_NAME2, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines[4]);
522 lines.clear();
523
524 // Perform test on IfaceStats.
525 uint32_t ifaceStatsKey = IFACE_INDEX2;
526 EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value2, BPF_ANY));
527 ifaceStatsKey = IFACE_INDEX1;
528 EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value1, BPF_ANY));
529
530 // This should be grouped.
531 ifaceStatsKey = IFACE_INDEX3;
532 EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value1, BPF_ANY));
533
534 ASSERT_EQ(0,
535 parseBpfNetworkStatsDevInternal(&lines, mFakeIfaceStatsMap, mFakeIfaceIndexNameMap));
536 ASSERT_EQ((size_t) 2, lines.size());
537
538 expectStatsLineEqual(value3, IFACE_NAME1, UID_ALL, SET_ALL, TAG_NONE, lines[0]);
539 expectStatsLineEqual(value2, IFACE_NAME2, UID_ALL, SET_ALL, TAG_NONE, lines[1]);
540 lines.clear();
541 }
542
543 // Test to verify that subtract overflow will not be triggered by the compare function invoked from
544 // sorting. See http:/b/119193941.
TEST_F(BpfNetworkStatsHelperTest,TestGetStatsSortAndOverflow)545 TEST_F(BpfNetworkStatsHelperTest, TestGetStatsSortAndOverflow) {
546 SKIP_IF_BPF_NOT_SUPPORTED;
547
548 updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
549
550 StatsValue value1 = {
551 .rxPackets = TEST_PACKET0,
552 .rxBytes = TEST_BYTES0,
553 .txPackets = TEST_PACKET1,
554 .txBytes = TEST_BYTES1,
555 };
556
557 // Mutate uid, 0 < TEST_UID1 < INT_MAX < INT_MIN < UINT_MAX.
558 populateFakeStats(0, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
559 populateFakeStats(UINT_MAX, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
560 populateFakeStats(INT_MIN, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
561 populateFakeStats(INT_MAX, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
562
563 // Mutate tag, 0 < TEST_TAG < INT_MAX < INT_MIN < UINT_MAX.
564 populateFakeStats(TEST_UID1, INT_MAX, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
565 populateFakeStats(TEST_UID1, INT_MIN, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
566 populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
567 populateFakeStats(TEST_UID1, UINT_MAX, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
568
569 // TODO: Mutate counterSet and enlarge TEST_MAP_SIZE if overflow on counterSet is possible.
570
571 std::vector<stats_line> lines;
572 std::vector<std::string> ifaces;
573 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
574 mFakeIfaceIndexNameMap));
575 ASSERT_EQ((size_t) 8, lines.size());
576
577 // Uid 0 first
578 expectStatsLineEqual(value1, IFACE_NAME1, 0, TEST_COUNTERSET0, TEST_TAG, lines[0]);
579
580 // Test uid, mutate tag.
581 expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, 0, lines[1]);
582 expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, INT_MAX, lines[2]);
583 expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, INT_MIN, lines[3]);
584 expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, UINT_MAX, lines[4]);
585
586 // Mutate uid.
587 expectStatsLineEqual(value1, IFACE_NAME1, INT_MAX, TEST_COUNTERSET0, TEST_TAG, lines[5]);
588 expectStatsLineEqual(value1, IFACE_NAME1, INT_MIN, TEST_COUNTERSET0, TEST_TAG, lines[6]);
589 expectStatsLineEqual(value1, IFACE_NAME1, UINT_MAX, TEST_COUNTERSET0, TEST_TAG, lines[7]);
590 lines.clear();
591 }
592 } // namespace bpf
593 } // namespace android
594