blob: 42273324acc3f8c81c93863cdcb53f55786588bd [file] [log] [blame]
Chenbo Fengdc4e3252017-12-22 11:00:52 -08001/*
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/BpfNetworkStats.h"
38#include "bpf/BpfUtils.h"
39
40using namespace android::bpf;
41
42using ::testing::_;
43using ::testing::ByMove;
44using ::testing::Invoke;
45using ::testing::Return;
46using ::testing::StrictMock;
47using ::testing::Test;
48
49namespace android {
50namespace bpf {
51
52using base::unique_fd;
53using netdutils::status::ok;
54
55constexpr int TEST_MAP_SIZE = 10;
56constexpr uid_t TEST_UID1 = 10086;
57constexpr uid_t TEST_UID2 = 12345;
58constexpr uint32_t TEST_TAG = 42;
59constexpr int TEST_COUNTERSET0 = 0;
60constexpr int TEST_COUNTERSET1 = 1;
Chenbo Fengdc4e3252017-12-22 11:00:52 -080061constexpr const int COUNTERSETS_LIMIT = 2;
62constexpr uint64_t TEST_BYTES0 = 1000;
63constexpr uint64_t TEST_BYTES1 = 2000;
Chenbo Fengdc4e3252017-12-22 11:00:52 -080064constexpr uint64_t TEST_PACKET0 = 100;
65constexpr uint64_t TEST_PACKET1 = 200;
Chenbo Fengdc4e3252017-12-22 11:00:52 -080066constexpr uint32_t IFACE0 = 1;
Chenbo Fengdc4e3252017-12-22 11:00:52 -080067
68class BpfNetworkStatsHelperTest : public testing::Test {
69 protected:
70 BpfNetworkStatsHelperTest() {}
71 unique_fd mFakeCookieTagMap;
72 unique_fd mFakeUidStatsMap;
73 unique_fd mFakeTagStatsMap;
74
75 void SetUp() {
76 mFakeCookieTagMap = unique_fd(createMap(BPF_MAP_TYPE_HASH, sizeof(uint64_t),
77 sizeof(struct UidTag), TEST_MAP_SIZE, 0));
78 ASSERT_LE(0, mFakeCookieTagMap);
79
80 mFakeUidStatsMap = unique_fd(createMap(BPF_MAP_TYPE_HASH, sizeof(struct StatsKey),
81 sizeof(struct StatsValue), TEST_MAP_SIZE, 0));
82 ASSERT_LE(0, mFakeUidStatsMap);
83
84 mFakeTagStatsMap = unique_fd(createMap(BPF_MAP_TYPE_HASH, sizeof(struct StatsKey),
85 sizeof(struct StatsValue), TEST_MAP_SIZE, 0));
86 ASSERT_LE(0, mFakeTagStatsMap);
87 }
88
89 void TearDown() {
90 mFakeCookieTagMap.reset();
91 mFakeUidStatsMap.reset();
92 mFakeTagStatsMap.reset();
93 }
94
95 void expectUidTag(uint64_t cookie, uid_t uid, uint32_t tag) {
96 struct UidTag tagResult;
97 EXPECT_EQ(0, findMapEntry(mFakeCookieTagMap, &cookie, &tagResult));
98 EXPECT_EQ(uid, tagResult.uid);
99 EXPECT_EQ(tag, tagResult.tag);
100 }
101
102 void populateFakeStats(uid_t uid, uint32_t tag, uint32_t ifaceIndex, uint32_t counterSet,
103 StatsValue* value, const base::unique_fd& map_fd) {
104 StatsKey key = {
105 .uid = (uint32_t)uid, .tag = tag, .counterSet = counterSet, .ifaceIndex = ifaceIndex};
106 EXPECT_EQ(0, writeToMapEntry(map_fd, &key, value, BPF_ANY));
107 }
108};
109
110// TEST to verify the behavior of bpf map when cocurrent deletion happens when
111// iterating the same map.
112TEST_F(BpfNetworkStatsHelperTest, TestIterateMapWithDeletion) {
113 for (int i = 0; i < 5; i++) {
114 uint64_t cookie = i + 1;
115 struct UidTag tag = {.uid = TEST_UID1, .tag = TEST_TAG};
116 EXPECT_EQ(0, writeToMapEntry(mFakeCookieTagMap, &cookie, &tag, BPF_ANY));
117 }
118 uint64_t curCookie = 0;
119 uint64_t nextCookie = 0;
120 struct UidTag tagResult;
121 EXPECT_EQ(0, getNextMapKey(mFakeCookieTagMap, &curCookie, &nextCookie));
122 uint64_t headOfMap = nextCookie;
123 curCookie = nextCookie;
124 // Find the second entry in the map, then immediately delete it.
125 EXPECT_EQ(0, getNextMapKey(mFakeCookieTagMap, &curCookie, &nextCookie));
126 EXPECT_EQ(0, deleteMapEntry(mFakeCookieTagMap, &nextCookie));
127 // Find the entry that is now immediately after headOfMap, then delete that.
128 EXPECT_EQ(0, getNextMapKey(mFakeCookieTagMap, &curCookie, &nextCookie));
129 EXPECT_EQ(0, deleteMapEntry(mFakeCookieTagMap, &nextCookie));
130 // Attempting to read an entry that has been deleted fails with ENOENT.
131 curCookie = nextCookie;
132 EXPECT_EQ(-1, findMapEntry(mFakeCookieTagMap, &curCookie, &tagResult));
133 EXPECT_EQ(ENOENT, errno);
134 // Finding the entry after our deleted entry restarts iteration from the beginning of the map.
135 EXPECT_EQ(0, getNextMapKey(mFakeCookieTagMap, &curCookie, &nextCookie));
136 EXPECT_EQ(headOfMap, nextCookie);
137}
138
139TEST_F(BpfNetworkStatsHelperTest, TestGetUidStatsTotal) {
Chenbo Fengeac6c472018-02-05 15:06:23 -0800140 StatsValue value1 = {.rxBytes = TEST_BYTES0,
141 .rxPackets = TEST_PACKET0,
142 .txBytes = TEST_BYTES1,
143 .txPackets = TEST_PACKET1,};
Chenbo Fengdc4e3252017-12-22 11:00:52 -0800144 populateFakeStats(TEST_UID1, 0, IFACE0, TEST_COUNTERSET0, &value1, mFakeUidStatsMap);
145 populateFakeStats(TEST_UID1, 0, IFACE0, TEST_COUNTERSET1, &value1, mFakeUidStatsMap);
146 populateFakeStats(TEST_UID2, 0, IFACE0, TEST_COUNTERSET1, &value1, mFakeUidStatsMap);
147 Stats result1 = {};
148 ASSERT_EQ(0, bpfGetUidStatsInternal(TEST_UID1, &result1, mFakeUidStatsMap));
Chenbo Feng0bdcf252018-03-04 23:38:12 -0800149 ASSERT_EQ(TEST_PACKET0 * 2, result1.rxPackets);
150 ASSERT_EQ(TEST_BYTES0 * 2, result1.rxBytes);
151 ASSERT_EQ(TEST_PACKET1 * 2, result1.txPackets);
152 ASSERT_EQ(TEST_BYTES1 * 2, result1.txBytes);
Chenbo Fengdc4e3252017-12-22 11:00:52 -0800153 Stats result2 = {};
154 ASSERT_EQ(0, bpfGetUidStatsInternal(TEST_UID2, &result2, mFakeUidStatsMap));
Chenbo Feng0bdcf252018-03-04 23:38:12 -0800155 ASSERT_EQ(TEST_PACKET0, result2.rxPackets);
156 ASSERT_EQ(TEST_BYTES0, result2.rxBytes);
157 ASSERT_EQ(TEST_PACKET1, result2.txPackets);
158 ASSERT_EQ(TEST_BYTES1, result2.txBytes);
Chenbo Fengdc4e3252017-12-22 11:00:52 -0800159 std::vector<stats_line> lines;
160 std::vector<std::string> ifaces;
161 ASSERT_EQ(0, parseBpfUidStatsDetail(&lines, ifaces, TEST_UID1, mFakeUidStatsMap));
162 ASSERT_EQ((unsigned long)2, lines.size());
163 lines.clear();
164 ASSERT_EQ(0, parseBpfUidStatsDetail(&lines, ifaces, TEST_UID2, mFakeUidStatsMap));
165 ASSERT_EQ((unsigned long)1, lines.size());
166}
167
168TEST_F(BpfNetworkStatsHelperTest, TestGetIfaceStatsInternal) {
169 const char* fakeFilePath = "/data/local/tmp/testIface.txt";
170 std::ofstream fakeProcFile(fakeFilePath);
171 ASSERT_TRUE(fakeProcFile.is_open());
172 fakeProcFile << "Inter-| Receive | Transmit "
173 " \n";
174 fakeProcFile << " face |bytes packets errs drop fifo frame compressed multicast|bytes "
175 "packets errs drop fifo colls carrier compressed\n";
176 fakeProcFile << " lo: 8308 116 0 0 0 0 0 0 8308 "
177 " 116 0 0 0 0 0 0\n";
178 fakeProcFile << "rmnet0: 1507570 2205 0 0 0 0 0 0 489339 "
179 "2237 0 0 0 0 0 0\n";
180 fakeProcFile << " ifb0: 52454 151 0 151 0 0 0 0 0 "
181 " 0 0 0 0 0 0 0\n";
182 fakeProcFile << " ifb1: 52454 151 0 151 0 0 0 0 0 "
183 " 0 0 0 0 0 0 0\n";
184 fakeProcFile << " sit0: 0 0 0 0 0 0 0 0 0 "
185 " 0 148 0 0 0 0 0\n";
186 fakeProcFile << "ip6tnl0: 0 0 0 0 0 0 0 0 0 "
187 " 0 151 151 0 0 0 0\n";
188 fakeProcFile.close();
189 const char* iface = "lo";
190 Stats result1 = {};
191 ASSERT_EQ(0, bpfGetIfaceStatsInternal(iface, &result1, fakeFilePath));
192 EXPECT_EQ(116UL, result1.rxPackets);
193 EXPECT_EQ(8308UL, result1.rxBytes);
194 EXPECT_EQ(116UL, result1.txPackets);
195 EXPECT_EQ(8308UL, result1.txBytes);
196 Stats result2 = {};
197 const char* iface2 = "rmnet0";
198 EXPECT_EQ(0, bpfGetIfaceStatsInternal(iface2, &result2, fakeFilePath));
199 EXPECT_EQ(2205UL, result2.rxPackets);
200 EXPECT_EQ(1507570UL, result2.rxBytes);
201 EXPECT_EQ(2237UL, result2.txPackets);
202 EXPECT_EQ(489339UL, result2.txBytes);
203}
204
205TEST_F(BpfNetworkStatsHelperTest, TestGetStatsDetail) {
206 const char* iface = "lo";
207 int ifaceIndex = if_nametoindex(iface);
208 ASSERT_LT(0, ifaceIndex);
Chenbo Fengeac6c472018-02-05 15:06:23 -0800209 StatsValue value1 = {.rxBytes = TEST_BYTES0,
210 .rxPackets = TEST_PACKET0,
211 .txBytes = TEST_BYTES1,
212 .txPackets = TEST_PACKET1,};
Chenbo Fengdc4e3252017-12-22 11:00:52 -0800213 populateFakeStats(0, 0, 0, COUNTERSETS_LIMIT, &value1, mFakeTagStatsMap);
214 populateFakeStats(TEST_UID1, TEST_TAG, ifaceIndex, TEST_COUNTERSET0, &value1, mFakeTagStatsMap);
215 populateFakeStats(TEST_UID1, TEST_TAG, ifaceIndex + 1, TEST_COUNTERSET0, &value1,
216 mFakeTagStatsMap);
217 populateFakeStats(TEST_UID1, TEST_TAG + 1, ifaceIndex, TEST_COUNTERSET0, &value1,
218 mFakeTagStatsMap);
219 populateFakeStats(TEST_UID2, TEST_TAG, ifaceIndex, TEST_COUNTERSET0, &value1, mFakeTagStatsMap);
220 std::vector<stats_line> lines;
221 std::vector<std::string> ifaces;
222 ASSERT_EQ(0, parseBpfTagStatsDetail(&lines, ifaces, TAG_ALL, UID_ALL, mFakeTagStatsMap));
223 ASSERT_EQ((unsigned long)4, lines.size());
224 lines.clear();
225 ASSERT_EQ(0, parseBpfTagStatsDetail(&lines, ifaces, TAG_ALL, TEST_UID1, mFakeTagStatsMap));
226 ASSERT_EQ((unsigned long)3, lines.size());
227 lines.clear();
228 ASSERT_EQ(0, parseBpfTagStatsDetail(&lines, ifaces, TEST_TAG, TEST_UID1, mFakeTagStatsMap));
229 ASSERT_EQ((unsigned long)2, lines.size());
230 lines.clear();
231 ifaces.push_back(std::string(iface));
232 ASSERT_EQ(0, parseBpfTagStatsDetail(&lines, ifaces, TEST_TAG, TEST_UID1, mFakeTagStatsMap));
233 ASSERT_EQ((unsigned long)1, lines.size());
234}
235
236TEST_F(BpfNetworkStatsHelperTest, TestGetStatsWithSkippedIface) {
237 const char* iface = "lo";
238 int ifaceIndex = if_nametoindex(iface);
239 ASSERT_LT(0, ifaceIndex);
Chenbo Fengeac6c472018-02-05 15:06:23 -0800240 StatsValue value1 = {.rxBytes = TEST_BYTES0,
241 .rxPackets = TEST_PACKET0,
242 .txBytes = TEST_BYTES1,
243 .txPackets = TEST_PACKET1,};
Chenbo Fengdc4e3252017-12-22 11:00:52 -0800244 populateFakeStats(0, 0, 0, COUNTERSETS_LIMIT, &value1, mFakeUidStatsMap);
245 populateFakeStats(TEST_UID1, 0, ifaceIndex, TEST_COUNTERSET0, &value1, mFakeUidStatsMap);
246 populateFakeStats(TEST_UID1, 0, ifaceIndex + 1, TEST_COUNTERSET0, &value1, mFakeUidStatsMap);
247 populateFakeStats(TEST_UID1, 0, ifaceIndex, TEST_COUNTERSET1, &value1, mFakeUidStatsMap);
248 populateFakeStats(TEST_UID2, 0, ifaceIndex, TEST_COUNTERSET0, &value1, mFakeUidStatsMap);
249 std::vector<stats_line> lines;
250 std::vector<std::string> ifaces;
251 ASSERT_EQ(0, parseBpfUidStatsDetail(&lines, ifaces, -1, mFakeUidStatsMap));
252 ASSERT_EQ((unsigned long)4, lines.size());
253 lines.clear();
254 ASSERT_EQ(0, parseBpfUidStatsDetail(&lines, ifaces, TEST_UID1, mFakeUidStatsMap));
255 ASSERT_EQ((unsigned long)3, lines.size());
256 lines.clear();
257 ASSERT_EQ(0, parseBpfUidStatsDetail(&lines, ifaces, TEST_UID2, mFakeUidStatsMap));
258 ASSERT_EQ((unsigned long)1, lines.size());
259 lines.clear();
260 ifaces.push_back(std::string(iface));
261 ASSERT_EQ(0, parseBpfUidStatsDetail(&lines, ifaces, TEST_UID1, mFakeUidStatsMap));
262 ASSERT_EQ((unsigned long)2, lines.size());
263}
264
265} // namespace bpf
266} // namespace android