• 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 #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