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