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