blob: 7c41fa9556e4ac63e91d9858dd2f070cfe9c2508 [file] [log] [blame]
Chenbo Fenged37fea2017-12-13 19:35:01 -08001/*
2 * Copyright 2017 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 * TrafficControllerTest.cpp - unit tests for TrafficController.cpp
17 */
18
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 <sys/socket.h>
27#include <sys/types.h>
28#include <unistd.h>
29
30#include <gtest/gtest.h>
31
32#include <android-base/stringprintf.h>
33#include <android-base/strings.h>
34
35#include <netdutils/MockSyscalls.h>
36#include "TrafficController.h"
37#include "bpf/BpfUtils.h"
38
39using namespace android::bpf;
40
41using ::testing::_;
42using ::testing::ByMove;
43using ::testing::Invoke;
44using ::testing::Return;
45using ::testing::StrictMock;
46using ::testing::Test;
47
48namespace android {
49namespace net {
50
51using base::unique_fd;
52using netdutils::status::ok;
53
54constexpr int TEST_MAP_SIZE = 10;
55constexpr uid_t TEST_UID = 10086;
56constexpr uint32_t TEST_TAG = 42;
57constexpr int TEST_COUNTERSET = 1;
58constexpr int DEFAULT_COUNTERSET = 0;
59
Lorenzo Colitti23e5c7f2018-01-12 17:55:59 +090060#define SKIP_IF_BPF_NOT_SUPPORTED do { if (!bpfSupported()) return; } while(0);
61
Chenbo Fenged37fea2017-12-13 19:35:01 -080062class TrafficControllerTest : public ::testing::Test {
63 protected:
64 TrafficControllerTest() {}
65 TrafficController mTc;
66 unique_fd mFakeCookieTagMap;
67 unique_fd mFakeUidCounterSetMap;
68 unique_fd mFakeUidStatsMap;
69 unique_fd mFakeTagStatsMap;
70
71 void SetUp() {
Lorenzo Colitti23e5c7f2018-01-12 17:55:59 +090072 SKIP_IF_BPF_NOT_SUPPORTED;
73
Chenbo Fenged37fea2017-12-13 19:35:01 -080074 mFakeCookieTagMap = unique_fd(createMap(BPF_MAP_TYPE_HASH, sizeof(uint64_t),
75 sizeof(struct UidTag), TEST_MAP_SIZE, 0));
76 ASSERT_LE(0, mFakeCookieTagMap);
77
78 mFakeUidCounterSetMap = unique_fd(
79 createMap(BPF_MAP_TYPE_HASH, sizeof(uint32_t), sizeof(uint32_t), TEST_MAP_SIZE, 0));
80 ASSERT_LE(0, mFakeUidCounterSetMap);
81
82 mFakeUidStatsMap = unique_fd(createMap(BPF_MAP_TYPE_HASH, sizeof(struct StatsKey),
83 sizeof(struct Stats), TEST_MAP_SIZE, 0));
84 ASSERT_LE(0, mFakeUidStatsMap);
85
86 mFakeTagStatsMap = unique_fd(createMap(BPF_MAP_TYPE_HASH, sizeof(struct StatsKey),
87 sizeof(struct Stats), TEST_MAP_SIZE, 0));
88 ASSERT_LE(0, mFakeTagStatsMap);
89
90 // Make sure trafficController use the eBPF code path.
91 mTc.ebpfSupported = true;
92
93 mTc.mCookieTagMap.reset(mFakeCookieTagMap);
94 mTc.mUidCounterSetMap.reset(mFakeUidCounterSetMap);
95 mTc.mUidStatsMap.reset(mFakeUidStatsMap);
96 mTc.mTagStatsMap.reset(mFakeTagStatsMap);
97 }
98
99 int setUpSocketAndTag(int protocol, uint64_t* cookie, uint32_t tag, uid_t uid) {
100 int sock = socket(protocol, SOCK_STREAM, 0);
101 EXPECT_LE(0, sock);
102 *cookie = getSocketCookie(sock);
103 EXPECT_NE(INET_DIAG_NOCOOKIE, *cookie);
104 EXPECT_EQ(0, mTc.tagSocket(sock, tag, uid));
105 return sock;
106 }
107
108 void expectUidTag(uint64_t cookie, uid_t uid, uint32_t tag) {
109 struct UidTag tagResult;
110 EXPECT_EQ(0, findMapEntry(mFakeCookieTagMap, &cookie, &tagResult));
111 EXPECT_EQ(uid, tagResult.uid);
112 EXPECT_EQ(tag, tagResult.tag);
113 }
114
115 void expectNoTag(uint64_t cookie) {
116 struct UidTag tagResult;
117 EXPECT_EQ(-1, findMapEntry(mFakeCookieTagMap, &cookie, &tagResult));
118 }
119
120 void expectTagMapEmpty() {
121 uint64_t invalidCookie = INET_DIAG_NOCOOKIE;
122 uint64_t cookie;
123 EXPECT_EQ(-1, getNextMapKey(mFakeCookieTagMap, &invalidCookie, &cookie));
124 }
125
126 void populateFakeStats(uint64_t cookie, uid_t uid, uint32_t tag, StatsKey* key) {
127 UidTag cookieMapkey = {.uid = (uint32_t)uid, .tag = tag};
128 EXPECT_EQ(0, writeToMapEntry(mFakeCookieTagMap, &cookie, &cookieMapkey, BPF_ANY));
129 *key = {.uid = uid, .tag = tag, .counterSet = TEST_COUNTERSET, .ifaceIndex = 1};
130 Stats statsMapValue = {.rxTcpPackets = 1, .rxTcpBytes = 100};
131 int counterSet = TEST_COUNTERSET;
132 EXPECT_EQ(0, writeToMapEntry(mFakeUidCounterSetMap, &uid, &counterSet, BPF_ANY));
133 EXPECT_EQ(0, writeToMapEntry(mFakeTagStatsMap, key, &statsMapValue, BPF_ANY));
134 key->tag = 0;
135 EXPECT_EQ(0, writeToMapEntry(mFakeUidStatsMap, key, &statsMapValue, BPF_ANY));
136 }
137
138 void TearDown() {
139 mFakeCookieTagMap.reset();
140 mFakeUidCounterSetMap.reset();
141 mFakeUidStatsMap.reset();
142 mFakeTagStatsMap.reset();
143 }
144};
145
146TEST_F(TrafficControllerTest, TestTagSocketV4) {
Lorenzo Colitti23e5c7f2018-01-12 17:55:59 +0900147 SKIP_IF_BPF_NOT_SUPPORTED;
148
Chenbo Fenged37fea2017-12-13 19:35:01 -0800149 uint64_t sockCookie;
150 int v4socket = setUpSocketAndTag(AF_INET, &sockCookie, TEST_TAG, TEST_UID);
151 expectUidTag(sockCookie, TEST_UID, TEST_TAG);
152 ASSERT_EQ(0, mTc.untagSocket(v4socket));
153 expectNoTag(sockCookie);
154 expectTagMapEmpty();
155}
156
157TEST_F(TrafficControllerTest, TestReTagSocket) {
Lorenzo Colitti23e5c7f2018-01-12 17:55:59 +0900158 SKIP_IF_BPF_NOT_SUPPORTED;
159
Chenbo Fenged37fea2017-12-13 19:35:01 -0800160 uint64_t sockCookie;
161 int v4socket = setUpSocketAndTag(AF_INET, &sockCookie, TEST_TAG, TEST_UID);
162 expectUidTag(sockCookie, TEST_UID, TEST_TAG);
163 ASSERT_EQ(0, mTc.tagSocket(v4socket, TEST_TAG + 1, TEST_UID + 1));
164 expectUidTag(sockCookie, TEST_UID + 1, TEST_TAG + 1);
165}
166
167TEST_F(TrafficControllerTest, TestTagTwoSockets) {
Lorenzo Colitti23e5c7f2018-01-12 17:55:59 +0900168 SKIP_IF_BPF_NOT_SUPPORTED;
169
Chenbo Fenged37fea2017-12-13 19:35:01 -0800170 uint64_t sockCookie1;
171 uint64_t sockCookie2;
172 int v4socket1 = setUpSocketAndTag(AF_INET, &sockCookie1, TEST_TAG, TEST_UID);
173 setUpSocketAndTag(AF_INET, &sockCookie2, TEST_TAG, TEST_UID);
174 expectUidTag(sockCookie1, TEST_UID, TEST_TAG);
175 expectUidTag(sockCookie2, TEST_UID, TEST_TAG);
176 ASSERT_EQ(0, mTc.untagSocket(v4socket1));
177 expectNoTag(sockCookie1);
178 expectUidTag(sockCookie2, TEST_UID, TEST_TAG);
179 uint64_t cookieResult;
180 ASSERT_EQ(-1, getNextMapKey(mFakeCookieTagMap, &sockCookie2, &cookieResult));
181}
182
183TEST_F(TrafficControllerTest, TestTagSocketV6) {
Lorenzo Colitti23e5c7f2018-01-12 17:55:59 +0900184 SKIP_IF_BPF_NOT_SUPPORTED;
185
Chenbo Fenged37fea2017-12-13 19:35:01 -0800186 uint64_t sockCookie;
187 int v6socket = setUpSocketAndTag(AF_INET6, &sockCookie, TEST_TAG, TEST_UID);
188 expectUidTag(sockCookie, TEST_UID, TEST_TAG);
189 ASSERT_EQ(0, mTc.untagSocket(v6socket));
190 expectNoTag(sockCookie);
191 expectTagMapEmpty();
192}
193
194TEST_F(TrafficControllerTest, TestTagInvalidSocket) {
Lorenzo Colitti23e5c7f2018-01-12 17:55:59 +0900195 SKIP_IF_BPF_NOT_SUPPORTED;
196
Chenbo Fenged37fea2017-12-13 19:35:01 -0800197 int invalidSocket = -1;
198 ASSERT_GT(0, mTc.tagSocket(invalidSocket, TEST_TAG, TEST_UID));
199 expectTagMapEmpty();
200}
201
202TEST_F(TrafficControllerTest, TestUntagInvalidSocket) {
Lorenzo Colitti23e5c7f2018-01-12 17:55:59 +0900203 SKIP_IF_BPF_NOT_SUPPORTED;
204
Chenbo Fenged37fea2017-12-13 19:35:01 -0800205 int invalidSocket = -1;
206 ASSERT_GT(0, mTc.untagSocket(invalidSocket));
207 int v4socket = socket(AF_INET, SOCK_STREAM, 0);
208 ASSERT_GT(0, mTc.untagSocket(v4socket));
209 expectTagMapEmpty();
210}
211
212TEST_F(TrafficControllerTest, TestSetCounterSet) {
Lorenzo Colitti23e5c7f2018-01-12 17:55:59 +0900213 SKIP_IF_BPF_NOT_SUPPORTED;
214
Chenbo Fenged37fea2017-12-13 19:35:01 -0800215 ASSERT_EQ(0, mTc.setCounterSet(TEST_COUNTERSET, TEST_UID));
216 uid_t uid = TEST_UID;
217 int counterSetResult;
218 ASSERT_EQ(0, findMapEntry(mFakeUidCounterSetMap, &uid, &counterSetResult));
219 ASSERT_EQ(TEST_COUNTERSET, counterSetResult);
220 ASSERT_EQ(0, mTc.setCounterSet(DEFAULT_COUNTERSET, TEST_UID));
221 ASSERT_EQ(-1, findMapEntry(mFakeUidCounterSetMap, &uid, &counterSetResult));
222 uid = TEST_UID;
223 ASSERT_EQ(-1, getNextMapKey(mFakeUidCounterSetMap, &uid, &counterSetResult));
224}
225
226TEST_F(TrafficControllerTest, TestSetInvalidCounterSet) {
Lorenzo Colitti23e5c7f2018-01-12 17:55:59 +0900227 SKIP_IF_BPF_NOT_SUPPORTED;
228
Chenbo Fenged37fea2017-12-13 19:35:01 -0800229 ASSERT_GT(0, mTc.setCounterSet(COUNTERSETS_LIMIT, TEST_UID));
230 uid_t uid = TEST_UID;
231 int counterSetResult;
232 ASSERT_EQ(-1, findMapEntry(mFakeUidCounterSetMap, &uid, &counterSetResult));
233 uid = TEST_UID;
234 ASSERT_EQ(-1, getNextMapKey(mFakeUidCounterSetMap, &uid, &counterSetResult));
235}
236
237TEST_F(TrafficControllerTest, TestDeleteTagData) {
Lorenzo Colitti23e5c7f2018-01-12 17:55:59 +0900238 SKIP_IF_BPF_NOT_SUPPORTED;
239
Chenbo Fenged37fea2017-12-13 19:35:01 -0800240 uint64_t cookie = 1;
241 uid_t uid = TEST_UID;
242 uint32_t tag = TEST_TAG;
243 StatsKey tagStatsMapKey;
244 populateFakeStats(cookie, uid, tag, &tagStatsMapKey);
245 ASSERT_EQ(0, mTc.deleteTagData(TEST_TAG, TEST_UID));
246 UidTag cookieMapkey;
247 ASSERT_EQ(-1, findMapEntry(mFakeCookieTagMap, &cookie, &cookieMapkey));
248 int counterSetResult;
249 ASSERT_EQ(0, findMapEntry(mFakeUidCounterSetMap, &uid, &counterSetResult));
250 ASSERT_EQ(TEST_COUNTERSET, counterSetResult);
251 Stats statsMapResult;
252 ASSERT_EQ(-1, findMapEntry(mFakeTagStatsMap, &tagStatsMapKey, &statsMapResult));
253 ASSERT_EQ(0, findMapEntry(mFakeUidStatsMap, &tagStatsMapKey, &statsMapResult));
254 ASSERT_EQ((uint64_t)1, statsMapResult.rxTcpPackets);
255 ASSERT_EQ((uint64_t)100, statsMapResult.rxTcpBytes);
256}
257
258TEST_F(TrafficControllerTest, TestDeleteAllUidData) {
Lorenzo Colitti23e5c7f2018-01-12 17:55:59 +0900259 SKIP_IF_BPF_NOT_SUPPORTED;
260
Chenbo Fenged37fea2017-12-13 19:35:01 -0800261 uint64_t cookie = 1;
262 uid_t uid = TEST_UID;
263 uint32_t tag = TEST_TAG;
264 StatsKey tagStatsMapKey;
265 populateFakeStats(cookie, uid, tag, &tagStatsMapKey);
266 ASSERT_EQ(0, mTc.deleteTagData(0, TEST_UID));
267 UidTag cookieMapkey;
268 ASSERT_EQ(-1, findMapEntry(mFakeCookieTagMap, &cookie, &cookieMapkey));
269 int counterSetResult;
270 ASSERT_EQ(-1, findMapEntry(mFakeUidCounterSetMap, &uid, &counterSetResult));
271 Stats statsMapResult;
272 ASSERT_EQ(-1, findMapEntry(mFakeTagStatsMap, &tagStatsMapKey, &statsMapResult));
273 ASSERT_EQ(-1, findMapEntry(mFakeUidStatsMap, &tagStatsMapKey, &statsMapResult));
274 StatsKey removedStatsKey= {.uid = 0, .tag = 0, .counterSet = COUNTERSETS_LIMIT,
275 .ifaceIndex = 0};
276 ASSERT_EQ(0, findMapEntry(mFakeUidStatsMap, &removedStatsKey, &statsMapResult));
277 ASSERT_EQ((uint64_t)1, statsMapResult.rxTcpPackets);
278 ASSERT_EQ((uint64_t)100, statsMapResult.rxTcpBytes);
279}
280
281TEST_F(TrafficControllerTest, TestDeleteDataWithTwoTags) {
Lorenzo Colitti23e5c7f2018-01-12 17:55:59 +0900282 SKIP_IF_BPF_NOT_SUPPORTED;
283
Chenbo Fenged37fea2017-12-13 19:35:01 -0800284 uint64_t cookie1 = 1;
285 uint64_t cookie2 = 2;
286 uid_t uid = TEST_UID;
287 uint32_t tag1 = TEST_TAG;
288 uint32_t tag2 = TEST_TAG + 1;
289 StatsKey tagStatsMapKey1;
290 StatsKey tagStatsMapKey2;
291 populateFakeStats(cookie1, uid, tag1, &tagStatsMapKey1);
292 populateFakeStats(cookie2, uid, tag2, &tagStatsMapKey2);
293 ASSERT_EQ(0, mTc.deleteTagData(TEST_TAG, TEST_UID));
294 UidTag cookieMapResult;
295 ASSERT_EQ(-1, findMapEntry(mFakeCookieTagMap, &cookie1, &cookieMapResult));
296 ASSERT_EQ(0, findMapEntry(mFakeCookieTagMap, &cookie2, &cookieMapResult));
297 ASSERT_EQ(TEST_UID, cookieMapResult.uid);
298 ASSERT_EQ(TEST_TAG + 1, cookieMapResult.tag);
299 int counterSetResult;
300 ASSERT_EQ(0, findMapEntry(mFakeUidCounterSetMap, &uid, &counterSetResult));
301 ASSERT_EQ(TEST_COUNTERSET, counterSetResult);
302 Stats statsMapResult;
303 ASSERT_EQ(-1, findMapEntry(mFakeTagStatsMap, &tagStatsMapKey1, &statsMapResult));
304 ASSERT_EQ(0, findMapEntry(mFakeTagStatsMap, &tagStatsMapKey2, &statsMapResult));
305 ASSERT_EQ((uint64_t)1, statsMapResult.rxTcpPackets);
306 ASSERT_EQ((uint64_t)100, statsMapResult.rxTcpBytes);
307}
308
309TEST_F(TrafficControllerTest, TestDeleteDataWithTwoUids) {
Lorenzo Colitti23e5c7f2018-01-12 17:55:59 +0900310 SKIP_IF_BPF_NOT_SUPPORTED;
311
Chenbo Fenged37fea2017-12-13 19:35:01 -0800312 uint64_t cookie1 = 1;
313 uint64_t cookie2 = 2;
314 uid_t uid1 = TEST_UID;
315 uid_t uid2 = TEST_UID + 1;
316 uint32_t tag = TEST_TAG;
317 StatsKey tagStatsMapKey1;
318 StatsKey tagStatsMapKey2;
319 populateFakeStats(cookie1, uid1, tag, &tagStatsMapKey1);
320 populateFakeStats(cookie2, uid2, tag, &tagStatsMapKey2);
321
322 // Delete the stats of one of the uid. Check if it is properly collected by
323 // removedStats.
324 ASSERT_EQ(0, mTc.deleteTagData(0, uid2));
325 UidTag cookieMapResult;
326 ASSERT_EQ(-1, findMapEntry(mFakeCookieTagMap, &cookie2, &cookieMapResult));
327 int counterSetResult;
328 ASSERT_EQ(0, findMapEntry(mFakeUidCounterSetMap, &uid1, &counterSetResult));
329 ASSERT_EQ(TEST_COUNTERSET, counterSetResult);
330 ASSERT_EQ(-1, findMapEntry(mFakeUidCounterSetMap, &uid2, &counterSetResult));
331 Stats statsMapResult;
332 ASSERT_EQ(-1, findMapEntry(mFakeTagStatsMap, &tagStatsMapKey2, &statsMapResult));
333 ASSERT_EQ(-1, findMapEntry(mFakeUidStatsMap, &tagStatsMapKey2, &statsMapResult));
334 ASSERT_EQ(0, findMapEntry(mFakeUidStatsMap, &tagStatsMapKey1, &statsMapResult));
335 ASSERT_EQ((uint64_t)1, statsMapResult.rxTcpPackets);
336 ASSERT_EQ((uint64_t)100, statsMapResult.rxTcpBytes);
337 StatsKey removedStatsKey= {.uid = 0, .tag = 0, .counterSet = COUNTERSETS_LIMIT,
338 .ifaceIndex = 0};
339 ASSERT_EQ(0, findMapEntry(mFakeUidStatsMap, &removedStatsKey, &statsMapResult));
340 ASSERT_EQ((uint64_t)1, statsMapResult.rxTcpPackets);
341 ASSERT_EQ((uint64_t)100, statsMapResult.rxTcpBytes);
342
343 // Delete the stats of the other uid. Check if it is properly added on the
344 // previous removedStats data.
345 ASSERT_EQ(0, mTc.deleteTagData(0, uid1));
346 ASSERT_EQ(-1, findMapEntry(mFakeUidStatsMap, &tagStatsMapKey1, &statsMapResult));
347 ASSERT_EQ(0, findMapEntry(mFakeUidStatsMap, &removedStatsKey, &statsMapResult));
348 ASSERT_EQ((uint64_t)2, statsMapResult.rxTcpPackets);
349 ASSERT_EQ((uint64_t)200, statsMapResult.rxTcpBytes);
350}
351
352} // namespace net
353} // namespace android