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 ASSERT_EQ(0, setrlimitForTest());
82
83 mFakeCookieTagMap = BpfMap<uint64_t, UidTagValue>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, 0);
84 ASSERT_LE(0, mFakeCookieTagMap.getMap());
85
86 mFakeAppUidStatsMap = BpfMap<uint32_t, StatsValue>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, 0);
87 ASSERT_LE(0, mFakeAppUidStatsMap.getMap());
88
89 mFakeStatsMap = BpfMap<StatsKey, StatsValue>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, 0);
90 ASSERT_LE(0, mFakeStatsMap.getMap());
91
92 mFakeIfaceIndexNameMap = BpfMap<uint32_t, IfaceValue>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, 0);
93 ASSERT_LE(0, mFakeIfaceIndexNameMap.getMap());
94
95 mFakeIfaceStatsMap = BpfMap<uint32_t, StatsValue>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE, 0);
96 ASSERT_LE(0, mFakeIfaceStatsMap.getMap());
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 std::vector<std::string> ifaces;
229 populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
230 populateFakeStats(TEST_UID1, 0, IFACE_INDEX2, TEST_COUNTERSET1, value1, mFakeStatsMap);
231 populateFakeStats(TEST_UID2, 0, IFACE_INDEX3, TEST_COUNTERSET1, value1, mFakeStatsMap);
232 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID1,
233 mFakeStatsMap, mFakeIfaceIndexNameMap));
234 ASSERT_EQ((unsigned long)2, lines.size());
235 lines.clear();
236 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID2,
237 mFakeStatsMap, mFakeIfaceIndexNameMap));
238 ASSERT_EQ((unsigned long)1, lines.size());
239 expectStatsLineEqual(value1, IFACE_NAME3, TEST_UID2, TEST_COUNTERSET1, 0, lines.front());
240 }
241
TEST_F(BpfNetworkStatsHelperTest,TestGetIfaceStatsInternal)242 TEST_F(BpfNetworkStatsHelperTest, TestGetIfaceStatsInternal) {
243 updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
244 updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
245 updateIfaceMap(IFACE_NAME3, IFACE_INDEX3);
246 StatsValue value1 = {
247 .rxPackets = TEST_PACKET0,
248 .rxBytes = TEST_BYTES0,
249 .txPackets = TEST_PACKET1,
250 .txBytes = TEST_BYTES1,
251 };
252 StatsValue value2 = {
253 .rxPackets = TEST_PACKET1,
254 .rxBytes = TEST_BYTES1,
255 .txPackets = TEST_PACKET0,
256 .txBytes = TEST_BYTES0,
257 };
258 uint32_t ifaceStatsKey = IFACE_INDEX1;
259 EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value1, BPF_ANY));
260 ifaceStatsKey = IFACE_INDEX2;
261 EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value2, BPF_ANY));
262 ifaceStatsKey = IFACE_INDEX3;
263 EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value1, BPF_ANY));
264
265 Stats result1 = {};
266 ASSERT_EQ(0, bpfGetIfaceStatsInternal(IFACE_NAME1, &result1, mFakeIfaceStatsMap,
267 mFakeIfaceIndexNameMap));
268 expectStatsEqual(value1, result1);
269 Stats result2 = {};
270 ASSERT_EQ(0, bpfGetIfaceStatsInternal(IFACE_NAME2, &result2, mFakeIfaceStatsMap,
271 mFakeIfaceIndexNameMap));
272 expectStatsEqual(value2, result2);
273 Stats totalResult = {};
274 ASSERT_EQ(0, bpfGetIfaceStatsInternal(NULL, &totalResult, mFakeIfaceStatsMap,
275 mFakeIfaceIndexNameMap));
276 StatsValue totalValue = {
277 .rxPackets = TEST_PACKET0 * 2 + TEST_PACKET1,
278 .rxBytes = TEST_BYTES0 * 2 + TEST_BYTES1,
279 .txPackets = TEST_PACKET1 * 2 + TEST_PACKET0,
280 .txBytes = TEST_BYTES1 * 2 + TEST_BYTES0,
281 };
282 expectStatsEqual(totalValue, totalResult);
283 }
284
TEST_F(BpfNetworkStatsHelperTest,TestGetStatsDetail)285 TEST_F(BpfNetworkStatsHelperTest, TestGetStatsDetail) {
286 updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
287 updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
288 StatsValue value1 = {
289 .rxPackets = TEST_PACKET0,
290 .rxBytes = TEST_BYTES0,
291 .txPackets = TEST_PACKET1,
292 .txBytes = TEST_BYTES1,
293 };
294 populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
295 populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX2, TEST_COUNTERSET0, value1, mFakeStatsMap);
296 populateFakeStats(TEST_UID1, TEST_TAG + 1, IFACE_INDEX1, TEST_COUNTERSET0, value1,
297 mFakeStatsMap);
298 populateFakeStats(TEST_UID2, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
299 std::vector<stats_line> lines;
300 std::vector<std::string> ifaces;
301 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
302 mFakeIfaceIndexNameMap));
303 ASSERT_EQ((unsigned long)4, lines.size());
304 lines.clear();
305 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID1,
306 mFakeStatsMap, mFakeIfaceIndexNameMap));
307 ASSERT_EQ((unsigned long)3, lines.size());
308 lines.clear();
309 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TEST_TAG, TEST_UID1,
310 mFakeStatsMap, mFakeIfaceIndexNameMap));
311 ASSERT_EQ((unsigned long)2, lines.size());
312 lines.clear();
313 ifaces.push_back(std::string(IFACE_NAME1));
314 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TEST_TAG, TEST_UID1,
315 mFakeStatsMap, mFakeIfaceIndexNameMap));
316 ASSERT_EQ((unsigned long)1, lines.size());
317 expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines.front());
318 }
319
TEST_F(BpfNetworkStatsHelperTest,TestGetStatsWithSkippedIface)320 TEST_F(BpfNetworkStatsHelperTest, TestGetStatsWithSkippedIface) {
321 updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
322 updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
323 StatsValue value1 = {
324 .rxPackets = TEST_PACKET0,
325 .rxBytes = TEST_BYTES0,
326 .txPackets = TEST_PACKET1,
327 .txBytes = TEST_BYTES1,
328 };
329 populateFakeStats(0, 0, 0, OVERFLOW_COUNTERSET, value1, mFakeStatsMap);
330 populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
331 populateFakeStats(TEST_UID1, 0, IFACE_INDEX2, TEST_COUNTERSET0, value1, mFakeStatsMap);
332 populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET1, value1, mFakeStatsMap);
333 populateFakeStats(TEST_UID2, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
334 std::vector<stats_line> lines;
335 std::vector<std::string> ifaces;
336 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
337 mFakeIfaceIndexNameMap));
338 ASSERT_EQ((unsigned long)4, lines.size());
339 lines.clear();
340 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID1,
341 mFakeStatsMap, mFakeIfaceIndexNameMap));
342 ASSERT_EQ((unsigned long)3, lines.size());
343 lines.clear();
344 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID2,
345 mFakeStatsMap, mFakeIfaceIndexNameMap));
346 ASSERT_EQ((unsigned long)1, lines.size());
347 expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID2, TEST_COUNTERSET0, 0, lines.front());
348 lines.clear();
349 ifaces.push_back(std::string(IFACE_NAME1));
350 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID1,
351 mFakeStatsMap, mFakeIfaceIndexNameMap));
352 ASSERT_EQ((unsigned long)2, lines.size());
353 }
354
TEST_F(BpfNetworkStatsHelperTest,TestUnkownIfaceError)355 TEST_F(BpfNetworkStatsHelperTest, TestUnkownIfaceError) {
356 updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
357 StatsValue value1 = {
358 .rxPackets = TEST_PACKET0,
359 .rxBytes = TEST_BYTES0 * 20,
360 .txPackets = TEST_PACKET1,
361 .txBytes = TEST_BYTES1 * 20,
362 };
363 uint32_t ifaceIndex = UNKNOWN_IFACE;
364 populateFakeStats(TEST_UID1, 0, ifaceIndex, TEST_COUNTERSET0, value1, mFakeStatsMap);
365 populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
366 StatsValue value2 = {
367 .rxPackets = TEST_PACKET0,
368 .rxBytes = TEST_BYTES0 * 40,
369 .txPackets = TEST_PACKET1,
370 .txBytes = TEST_BYTES1 * 40,
371 };
372 populateFakeStats(TEST_UID1, 0, IFACE_INDEX2, TEST_COUNTERSET0, value2, mFakeStatsMap);
373 StatsKey curKey = {
374 .uid = TEST_UID1,
375 .tag = 0,
376 .counterSet = TEST_COUNTERSET0,
377 .ifaceIndex = ifaceIndex,
378 };
379 char ifname[IFNAMSIZ];
380 int64_t unknownIfaceBytesTotal = 0;
381 ASSERT_EQ(-ENODEV, getIfaceNameFromMap(mFakeIfaceIndexNameMap, mFakeStatsMap, ifaceIndex,
382 ifname, curKey, &unknownIfaceBytesTotal));
383 ASSERT_EQ(((int64_t)(TEST_BYTES0 * 20 + TEST_BYTES1 * 20)), unknownIfaceBytesTotal);
384 curKey.ifaceIndex = IFACE_INDEX2;
385 ASSERT_EQ(-ENODEV, getIfaceNameFromMap(mFakeIfaceIndexNameMap, mFakeStatsMap, ifaceIndex,
386 ifname, curKey, &unknownIfaceBytesTotal));
387 ASSERT_EQ(-1, unknownIfaceBytesTotal);
388 std::vector<stats_line> lines;
389 std::vector<std::string> ifaces;
390 // TODO: find a way to test the total of unknown Iface Bytes go above limit.
391 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
392 mFakeIfaceIndexNameMap));
393 ASSERT_EQ((unsigned long)1, lines.size());
394 expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, 0, lines.front());
395 }
396
TEST_F(BpfNetworkStatsHelperTest,TestGetIfaceStatsDetail)397 TEST_F(BpfNetworkStatsHelperTest, TestGetIfaceStatsDetail) {
398 updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
399 updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
400 updateIfaceMap(IFACE_NAME3, IFACE_INDEX3);
401 updateIfaceMap(LONG_IFACE_NAME, IFACE_INDEX4);
402 StatsValue value1 = {
403 .rxPackets = TEST_PACKET0,
404 .rxBytes = TEST_BYTES0,
405 .txPackets = TEST_PACKET1,
406 .txBytes = TEST_BYTES1,
407 };
408 StatsValue value2 = {
409 .rxPackets = TEST_PACKET1,
410 .rxBytes = TEST_BYTES1,
411 .txPackets = TEST_PACKET0,
412 .txBytes = TEST_BYTES0,
413 };
414 uint32_t ifaceStatsKey = IFACE_INDEX1;
415 EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value1, BPF_ANY));
416 ifaceStatsKey = IFACE_INDEX2;
417 EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value2, BPF_ANY));
418 ifaceStatsKey = IFACE_INDEX3;
419 EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value1, BPF_ANY));
420 ifaceStatsKey = IFACE_INDEX4;
421 EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value2, BPF_ANY));
422 std::vector<stats_line> lines;
423 ASSERT_EQ(0,
424 parseBpfNetworkStatsDevInternal(&lines, mFakeIfaceStatsMap, mFakeIfaceIndexNameMap));
425 ASSERT_EQ((unsigned long)4, lines.size());
426
427 expectStatsLineEqual(value1, IFACE_NAME1, UID_ALL, SET_ALL, TAG_NONE, lines[0]);
428 expectStatsLineEqual(value1, IFACE_NAME3, UID_ALL, SET_ALL, TAG_NONE, lines[1]);
429 expectStatsLineEqual(value2, IFACE_NAME2, UID_ALL, SET_ALL, TAG_NONE, lines[2]);
430 ASSERT_EQ(0, strcmp(TRUNCATED_IFACE_NAME, lines[3].iface));
431 expectStatsLineEqual(value2, TRUNCATED_IFACE_NAME, UID_ALL, SET_ALL, TAG_NONE, lines[3]);
432 }
433
TEST_F(BpfNetworkStatsHelperTest,TestGetStatsSortedAndGrouped)434 TEST_F(BpfNetworkStatsHelperTest, TestGetStatsSortedAndGrouped) {
435 // Create iface indexes with duplicate iface name.
436 updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
437 updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
438 updateIfaceMap(IFACE_NAME1, IFACE_INDEX3); // Duplicate!
439
440 StatsValue value1 = {
441 .rxPackets = TEST_PACKET0,
442 .rxBytes = TEST_BYTES0,
443 .txPackets = TEST_PACKET1,
444 .txBytes = TEST_BYTES1,
445 };
446 StatsValue value2 = {
447 .rxPackets = TEST_PACKET1,
448 .rxBytes = TEST_BYTES1,
449 .txPackets = TEST_PACKET0,
450 .txBytes = TEST_BYTES0,
451 };
452 StatsValue value3 = {
453 .rxPackets = TEST_PACKET0 * 2,
454 .rxBytes = TEST_BYTES0 * 2,
455 .txPackets = TEST_PACKET1 * 2,
456 .txBytes = TEST_BYTES1 * 2,
457 };
458
459 std::vector<stats_line> lines;
460 std::vector<std::string> ifaces;
461
462 // Test empty stats.
463 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
464 mFakeIfaceIndexNameMap));
465 ASSERT_EQ((size_t) 0, lines.size());
466 lines.clear();
467
468 // Test 1 line stats.
469 populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
470 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
471 mFakeIfaceIndexNameMap));
472 ASSERT_EQ((size_t) 1, lines.size());
473 expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines[0]);
474 lines.clear();
475
476 // These items should not be grouped.
477 populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX2, TEST_COUNTERSET0, value2, mFakeStatsMap);
478 populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX3, TEST_COUNTERSET1, value2, mFakeStatsMap);
479 populateFakeStats(TEST_UID1, TEST_TAG + 1, IFACE_INDEX1, TEST_COUNTERSET0, value2,
480 mFakeStatsMap);
481 populateFakeStats(TEST_UID2, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
482 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
483 mFakeIfaceIndexNameMap));
484 ASSERT_EQ((size_t) 5, lines.size());
485 lines.clear();
486
487 // These items should be grouped.
488 populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX3, TEST_COUNTERSET0, value1, mFakeStatsMap);
489 populateFakeStats(TEST_UID2, TEST_TAG, IFACE_INDEX3, TEST_COUNTERSET0, value1, mFakeStatsMap);
490
491 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
492 mFakeIfaceIndexNameMap));
493 ASSERT_EQ((size_t) 5, lines.size());
494
495 // Verify Sorted & Grouped.
496 expectStatsLineEqual(value3, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines[0]);
497 expectStatsLineEqual(value2, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET1, TEST_TAG, lines[1]);
498 expectStatsLineEqual(value2, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, TEST_TAG + 1, lines[2]);
499 expectStatsLineEqual(value3, IFACE_NAME1, TEST_UID2, TEST_COUNTERSET0, TEST_TAG, lines[3]);
500 expectStatsLineEqual(value2, IFACE_NAME2, TEST_UID1, TEST_COUNTERSET0, TEST_TAG, lines[4]);
501 lines.clear();
502
503 // Perform test on IfaceStats.
504 uint32_t ifaceStatsKey = IFACE_INDEX2;
505 EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value2, BPF_ANY));
506 ifaceStatsKey = IFACE_INDEX1;
507 EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value1, BPF_ANY));
508
509 // This should be grouped.
510 ifaceStatsKey = IFACE_INDEX3;
511 EXPECT_RESULT_OK(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value1, BPF_ANY));
512
513 ASSERT_EQ(0,
514 parseBpfNetworkStatsDevInternal(&lines, mFakeIfaceStatsMap, mFakeIfaceIndexNameMap));
515 ASSERT_EQ((size_t) 2, lines.size());
516
517 expectStatsLineEqual(value3, IFACE_NAME1, UID_ALL, SET_ALL, TAG_NONE, lines[0]);
518 expectStatsLineEqual(value2, IFACE_NAME2, UID_ALL, SET_ALL, TAG_NONE, lines[1]);
519 lines.clear();
520 }
521
522 // Test to verify that subtract overflow will not be triggered by the compare function invoked from
523 // sorting. See http:/b/119193941.
TEST_F(BpfNetworkStatsHelperTest,TestGetStatsSortAndOverflow)524 TEST_F(BpfNetworkStatsHelperTest, TestGetStatsSortAndOverflow) {
525 updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
526
527 StatsValue value1 = {
528 .rxPackets = TEST_PACKET0,
529 .rxBytes = TEST_BYTES0,
530 .txPackets = TEST_PACKET1,
531 .txBytes = TEST_BYTES1,
532 };
533
534 // Mutate uid, 0 < TEST_UID1 < INT_MAX < INT_MIN < UINT_MAX.
535 populateFakeStats(0, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
536 populateFakeStats(UINT_MAX, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
537 populateFakeStats(INT_MIN, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
538 populateFakeStats(INT_MAX, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
539
540 // Mutate tag, 0 < TEST_TAG < INT_MAX < INT_MIN < UINT_MAX.
541 populateFakeStats(TEST_UID1, INT_MAX, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
542 populateFakeStats(TEST_UID1, INT_MIN, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
543 populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
544 populateFakeStats(TEST_UID1, UINT_MAX, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeStatsMap);
545
546 // TODO: Mutate counterSet and enlarge TEST_MAP_SIZE if overflow on counterSet is possible.
547
548 std::vector<stats_line> lines;
549 std::vector<std::string> ifaces;
550 ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL, mFakeStatsMap,
551 mFakeIfaceIndexNameMap));
552 ASSERT_EQ((size_t) 8, lines.size());
553
554 // Uid 0 first
555 expectStatsLineEqual(value1, IFACE_NAME1, 0, TEST_COUNTERSET0, TEST_TAG, lines[0]);
556
557 // Test uid, mutate tag.
558 expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, 0, lines[1]);
559 expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, INT_MAX, lines[2]);
560 expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, INT_MIN, lines[3]);
561 expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID1, TEST_COUNTERSET0, UINT_MAX, lines[4]);
562
563 // Mutate uid.
564 expectStatsLineEqual(value1, IFACE_NAME1, INT_MAX, TEST_COUNTERSET0, TEST_TAG, lines[5]);
565 expectStatsLineEqual(value1, IFACE_NAME1, INT_MIN, TEST_COUNTERSET0, TEST_TAG, lines[6]);
566 expectStatsLineEqual(value1, IFACE_NAME1, UINT_MAX, TEST_COUNTERSET0, TEST_TAG, lines[7]);
567 lines.clear();
568 }
569 } // namespace bpf
570 } // namespace android
571