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