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