• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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