blob: fd6e43a82a63331e56a58e79670e3693b89bb8a6 [file] [log] [blame]
Lorenzo Colittia93126d2017-08-24 13:28:19 +09001/*
2 * Copyright 2016 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 * TetherControllerTest.cpp - unit tests for TetherController.cpp
17 */
18
19#include <string>
20#include <vector>
21
22#include <fcntl.h>
Automerger Merge Worker40265052020-03-06 01:42:40 +000023#include <inttypes.h>
Lorenzo Colittia93126d2017-08-24 13:28:19 +090024#include <sys/socket.h>
Automerger Merge Worker40265052020-03-06 01:42:40 +000025#include <sys/types.h>
26#include <unistd.h>
Lorenzo Colittia93126d2017-08-24 13:28:19 +090027
28#include <gtest/gtest.h>
29
30#include <android-base/stringprintf.h>
31#include <android-base/strings.h>
Automerger Merge Worker40265052020-03-06 01:42:40 +000032#include <gmock/gmock.h>
Lorenzo Colitti5192bf72017-09-04 13:30:59 +090033#include <netdutils/StatusOr.h>
Lorenzo Colittia93126d2017-08-24 13:28:19 +090034
Lorenzo Colittia93126d2017-08-24 13:28:19 +090035#include "IptablesBaseTest.h"
Automerger Merge Worker40265052020-03-06 01:42:40 +000036#include "OffloadUtils.h"
37#include "TetherController.h"
Lorenzo Colittia93126d2017-08-24 13:28:19 +090038
39using android::base::Join;
40using android::base::StringPrintf;
Automerger Merge Worker40265052020-03-06 01:42:40 +000041using android::bpf::BpfMap;
Lorenzo Colitti5192bf72017-09-04 13:30:59 +090042using android::netdutils::StatusOr;
Automerger Merge Worker40265052020-03-06 01:42:40 +000043using ::testing::Contains;
Lorenzo Colitti5192bf72017-09-04 13:30:59 +090044using TetherStats = android::net::TetherController::TetherStats;
45using TetherStatsList = android::net::TetherController::TetherStatsList;
Lorenzo Colittia93126d2017-08-24 13:28:19 +090046
47namespace android {
48namespace net {
49
Automerger Merge Worker40265052020-03-06 01:42:40 +000050constexpr int TEST_MAP_SIZE = 10;
51
52// Comparison for TetherStats. Need to override operator== because class TetherStats doesn't have.
53// TODO: once C++20 is used, use default operator== in TetherStats and remove the overriding here.
54bool operator==(const TetherStats& lhs, const TetherStats& rhs) {
55 return lhs.intIface == rhs.intIface && lhs.extIface == rhs.extIface &&
56 lhs.rxBytes == rhs.rxBytes && lhs.txBytes == rhs.txBytes &&
57 lhs.rxPackets == rhs.rxPackets && lhs.txPackets == rhs.txPackets;
58}
59
Lorenzo Colittia93126d2017-08-24 13:28:19 +090060class TetherControllerTest : public IptablesBaseTest {
61public:
62 TetherControllerTest() {
63 TetherController::iptablesRestoreFunction = fakeExecIptablesRestoreWithOutput;
64 }
65
66protected:
67 TetherController mTetherCtrl;
Automerger Merge Worker40265052020-03-06 01:42:40 +000068 BpfMap<uint32_t, IfaceValue> mFakeIfaceIndexNameMap{BPF_MAP_TYPE_HASH, TEST_MAP_SIZE};
69 BpfMap<uint32_t, TetherStatsValue> mFakeTetherStatsMap{BPF_MAP_TYPE_HASH, TEST_MAP_SIZE};
Maciej Żenczykowskid25a7342020-05-04 18:18:38 -070070 BpfMap<uint32_t, uint64_t> mFakeTetherLimitMap{BPF_MAP_TYPE_HASH, TEST_MAP_SIZE};
Automerger Merge Worker40265052020-03-06 01:42:40 +000071
72 void SetUp() {
73 SKIP_IF_BPF_NOT_SUPPORTED;
74
75 ASSERT_TRUE(mFakeIfaceIndexNameMap.isValid());
76 ASSERT_TRUE(mFakeTetherStatsMap.isValid());
Maciej Żenczykowskid25a7342020-05-04 18:18:38 -070077 ASSERT_TRUE(mFakeTetherLimitMap.isValid());
Automerger Merge Worker40265052020-03-06 01:42:40 +000078
79 mTetherCtrl.mIfaceIndexNameMap = mFakeIfaceIndexNameMap;
80 ASSERT_TRUE(mTetherCtrl.mIfaceIndexNameMap.isValid());
81 mTetherCtrl.mBpfStatsMap = mFakeTetherStatsMap;
82 ASSERT_TRUE(mTetherCtrl.mBpfStatsMap.isValid());
Maciej Żenczykowskid25a7342020-05-04 18:18:38 -070083 mTetherCtrl.mBpfLimitMap = mFakeTetherLimitMap;
84 ASSERT_TRUE(mTetherCtrl.mBpfLimitMap.isValid());
Automerger Merge Worker40265052020-03-06 01:42:40 +000085 }
86
87 std::string toString(const TetherStatsList& statsList) {
88 std::string result;
89 for (const auto& stats : statsList) {
90 result += StringPrintf("%s, %s, %" PRId64 ", %" PRId64 ", %" PRId64 ", %" PRId64 "\n",
91 stats.intIface.c_str(), stats.extIface.c_str(), stats.rxBytes,
92 stats.rxPackets, stats.txBytes, stats.txPackets);
93 }
94 return result;
95 }
96
97 void updateMaps(uint32_t ifaceIndex, const char* ifaceName, uint64_t rxBytes,
98 uint64_t rxPackets, uint64_t txBytes, uint64_t txPackets) {
99 IfaceValue iface{};
100 strlcpy(iface.name, ifaceName, sizeof(iface.name));
101 ASSERT_RESULT_OK(mFakeIfaceIndexNameMap.writeValue(ifaceIndex, iface, BPF_ANY));
102
103 // {rx, tx}Errors in |tetherStats| are set zero because getTetherStats doesn't use them.
104 const TetherStatsValue tetherStats = {rxPackets, rxBytes, 0 /*unused*/,
105 txPackets, txBytes, 0 /*unused*/};
106 ASSERT_RESULT_OK(mFakeTetherStatsMap.writeValue(ifaceIndex, tetherStats, BPF_ANY));
107 };
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900108
109 int setDefaults() {
110 return mTetherCtrl.setDefaults();
111 }
112
113 const ExpectedIptablesCommands FLUSH_COMMANDS = {
Luke Huangae038f82018-11-05 11:17:31 +0900114 {V4,
115 "*filter\n"
116 ":tetherctrl_FORWARD -\n"
117 "-A tetherctrl_FORWARD -j DROP\n"
118 "COMMIT\n"
119 "*nat\n"
120 ":tetherctrl_nat_POSTROUTING -\n"
121 "COMMIT\n"},
122 {V6,
123 "*filter\n"
124 ":tetherctrl_FORWARD -\n"
125 "COMMIT\n"
126 "*raw\n"
127 ":tetherctrl_raw_PREROUTING -\n"
128 "COMMIT\n"},
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900129 };
130
131 const ExpectedIptablesCommands SETUP_COMMANDS = {
Luke Huangae038f82018-11-05 11:17:31 +0900132 {V4,
133 "*filter\n"
134 ":tetherctrl_FORWARD -\n"
135 "-A tetherctrl_FORWARD -j DROP\n"
136 "COMMIT\n"
137 "*nat\n"
138 ":tetherctrl_nat_POSTROUTING -\n"
139 "COMMIT\n"},
140 {V6,
141 "*filter\n"
142 ":tetherctrl_FORWARD -\n"
143 "COMMIT\n"
144 "*raw\n"
145 ":tetherctrl_raw_PREROUTING -\n"
146 "COMMIT\n"},
147 {V4,
148 "*mangle\n"
149 "-A tetherctrl_mangle_FORWARD -p tcp --tcp-flags SYN SYN "
150 "-j TCPMSS --clamp-mss-to-pmtu\n"
151 "COMMIT\n"},
152 {V4V6,
153 "*filter\n"
154 ":tetherctrl_counters -\n"
155 "COMMIT\n"},
156 };
157
158 const ExpectedIptablesCommands ALERT_ADD_COMMAND = {
159 {V4V6,
160 "*filter\n"
161 "-I tetherctrl_FORWARD -j bw_global_alert\n"
162 "COMMIT\n"},
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900163 };
164
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900165 ExpectedIptablesCommands firstIPv4UpstreamCommands(const char *extIf) {
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900166 std::string v4Cmd = StringPrintf(
167 "*nat\n"
Lorenzo Colitti4604b4a2017-08-24 19:21:50 +0900168 "-A tetherctrl_nat_POSTROUTING -o %s -j MASQUERADE\n"
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900169 "COMMIT\n", extIf);
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900170 return {
171 { V4, v4Cmd },
172 };
173 }
174
175 ExpectedIptablesCommands firstIPv6UpstreamCommands() {
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900176 std::string v6Cmd =
Luke Huangae038f82018-11-05 11:17:31 +0900177 "*filter\n"
178 "-A tetherctrl_FORWARD -g tetherctrl_counters\n"
179 "COMMIT\n";
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900180 return {
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900181 { V6, v6Cmd },
182 };
183 }
184
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900185 template<typename T>
186 void appendAll(std::vector<T>& cmds, const std::vector<T>& appendCmds) {
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900187 cmds.insert(cmds.end(), appendCmds.begin(), appendCmds.end());
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900188 }
189
190 ExpectedIptablesCommands startNatCommands(const char *intIf, const char *extIf,
191 bool withCounterChainRules) {
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900192 std::string rpfilterCmd = StringPrintf(
193 "*raw\n"
Lorenzo Colitti4604b4a2017-08-24 19:21:50 +0900194 "-A tetherctrl_raw_PREROUTING -i %s -m rpfilter --invert ! -s fe80::/64 -j DROP\n"
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900195 "COMMIT\n", intIf);
196
197 std::vector<std::string> v4Cmds = {
hiroaki.yokoyama04f2cb52018-06-13 18:47:30 +0900198 "*raw",
199 StringPrintf(
200 "-A tetherctrl_raw_PREROUTING -p tcp --dport 21 -i %s -j CT --helper ftp",
201 intIf),
202 StringPrintf("-A tetherctrl_raw_PREROUTING -p tcp --dport 1723 -i %s -j CT "
203 "--helper pptp",
204 intIf),
205 "COMMIT",
206 "*filter",
207 StringPrintf("-A tetherctrl_FORWARD -i %s -o %s -m state --state"
208 " ESTABLISHED,RELATED -g tetherctrl_counters",
209 extIf, intIf),
210 StringPrintf("-A tetherctrl_FORWARD -i %s -o %s -m state --state INVALID -j DROP",
211 intIf, extIf),
212 StringPrintf("-A tetherctrl_FORWARD -i %s -o %s -g tetherctrl_counters", intIf,
213 extIf),
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900214 };
215
216 std::vector<std::string> v6Cmds = {
217 "*filter",
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900218 };
219
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900220 if (withCounterChainRules) {
221 const std::vector<std::string> counterRules = {
222 StringPrintf("-A tetherctrl_counters -i %s -o %s -j RETURN", intIf, extIf),
223 StringPrintf("-A tetherctrl_counters -i %s -o %s -j RETURN", extIf, intIf),
224 };
225
226 appendAll(v4Cmds, counterRules);
227 appendAll(v6Cmds, counterRules);
228 }
229
230 appendAll(v4Cmds, {
231 "-D tetherctrl_FORWARD -j DROP",
232 "-A tetherctrl_FORWARD -j DROP",
233 "COMMIT\n",
234 });
235
236 v6Cmds.push_back("COMMIT\n");
237
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900238 return {
239 { V6, rpfilterCmd },
240 { V4, Join(v4Cmds, '\n') },
241 { V6, Join(v6Cmds, '\n') },
242 };
243 }
244
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900245 constexpr static const bool WITH_COUNTERS = true;
246 constexpr static const bool NO_COUNTERS = false;
247 constexpr static const bool WITH_IPV6 = true;
248 constexpr static const bool NO_IPV6 = false;
Luke Huangae038f82018-11-05 11:17:31 +0900249 ExpectedIptablesCommands allNewNatCommands(const char* intIf, const char* extIf,
250 bool withCounterChainRules, bool withIPv6Upstream,
251 bool firstEnableNat) {
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900252 ExpectedIptablesCommands commands;
253 ExpectedIptablesCommands setupFirstIPv4Commands = firstIPv4UpstreamCommands(extIf);
254 ExpectedIptablesCommands startFirstNatCommands = startNatCommands(intIf, extIf,
255 withCounterChainRules);
256
257 appendAll(commands, setupFirstIPv4Commands);
258 if (withIPv6Upstream) {
259 ExpectedIptablesCommands setupFirstIPv6Commands = firstIPv6UpstreamCommands();
260 appendAll(commands, setupFirstIPv6Commands);
261 }
Luke Huangae038f82018-11-05 11:17:31 +0900262 if (firstEnableNat) {
263 appendAll(commands, ALERT_ADD_COMMAND);
264 }
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900265 appendAll(commands, startFirstNatCommands);
266
267 return commands;
268 }
269
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900270 ExpectedIptablesCommands stopNatCommands(const char *intIf, const char *extIf) {
271 std::string rpfilterCmd = StringPrintf(
272 "*raw\n"
Lorenzo Colitti4604b4a2017-08-24 19:21:50 +0900273 "-D tetherctrl_raw_PREROUTING -i %s -m rpfilter --invert ! -s fe80::/64 -j DROP\n"
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900274 "COMMIT\n", intIf);
275
276 std::vector<std::string> v4Cmds = {
hiroaki.yokoyama04f2cb52018-06-13 18:47:30 +0900277 "*raw",
278 StringPrintf(
279 "-D tetherctrl_raw_PREROUTING -p tcp --dport 21 -i %s -j CT --helper ftp",
280 intIf),
281 StringPrintf("-D tetherctrl_raw_PREROUTING -p tcp --dport 1723 -i %s -j CT "
282 "--helper pptp",
283 intIf),
284 "COMMIT",
285 "*filter",
286 StringPrintf("-D tetherctrl_FORWARD -i %s -o %s -m state --state"
287 " ESTABLISHED,RELATED -g tetherctrl_counters",
288 extIf, intIf),
289 StringPrintf("-D tetherctrl_FORWARD -i %s -o %s -m state --state INVALID -j DROP",
290 intIf, extIf),
291 StringPrintf("-D tetherctrl_FORWARD -i %s -o %s -g tetherctrl_counters", intIf,
292 extIf),
293 "COMMIT\n",
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900294 };
295
296 return {
297 { V6, rpfilterCmd },
298 { V4, Join(v4Cmds, '\n') },
299 };
300
301 }
302};
303
304TEST_F(TetherControllerTest, TestSetupIptablesHooks) {
305 mTetherCtrl.setupIptablesHooks();
306 expectIptablesRestoreCommands(SETUP_COMMANDS);
307}
308
309TEST_F(TetherControllerTest, TestSetDefaults) {
310 setDefaults();
311 expectIptablesRestoreCommands(FLUSH_COMMANDS);
312}
313
314TEST_F(TetherControllerTest, TestAddAndRemoveNat) {
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900315 // Start first NAT on first upstream interface. Expect the upstream and NAT rules to be created.
Luke Huangae038f82018-11-05 11:17:31 +0900316 ExpectedIptablesCommands firstNat =
317 allNewNatCommands("wlan0", "rmnet0", WITH_COUNTERS, WITH_IPV6, true);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900318 mTetherCtrl.enableNat("wlan0", "rmnet0");
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900319 expectIptablesRestoreCommands(firstNat);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900320
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900321 // Start second NAT on same upstream. Expect only the counter rules to be created.
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900322 ExpectedIptablesCommands startOtherNatOnSameUpstream = startNatCommands(
323 "usb0", "rmnet0", WITH_COUNTERS);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900324 mTetherCtrl.enableNat("usb0", "rmnet0");
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900325 expectIptablesRestoreCommands(startOtherNatOnSameUpstream);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900326
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900327 // Remove the first NAT.
328 ExpectedIptablesCommands stopFirstNat = stopNatCommands("wlan0", "rmnet0");
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900329 mTetherCtrl.disableNat("wlan0", "rmnet0");
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900330 expectIptablesRestoreCommands(stopFirstNat);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900331
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900332 // Remove the last NAT. Expect rules to be cleared.
333 ExpectedIptablesCommands stopLastNat = stopNatCommands("usb0", "rmnet0");
334
335 appendAll(stopLastNat, FLUSH_COMMANDS);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900336 mTetherCtrl.disableNat("usb0", "rmnet0");
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900337 expectIptablesRestoreCommands(stopLastNat);
338
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900339 // Re-add a NAT removed previously: tetherctrl_counters chain rules are not re-added
Luke Huangae038f82018-11-05 11:17:31 +0900340 firstNat = allNewNatCommands("wlan0", "rmnet0", NO_COUNTERS, WITH_IPV6, true);
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900341 mTetherCtrl.enableNat("wlan0", "rmnet0");
342 expectIptablesRestoreCommands(firstNat);
343
344 // Remove it again. Expect rules to be cleared.
345 stopLastNat = stopNatCommands("wlan0", "rmnet0");
346 appendAll(stopLastNat, FLUSH_COMMANDS);
347 mTetherCtrl.disableNat("wlan0", "rmnet0");
348 expectIptablesRestoreCommands(stopLastNat);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900349}
350
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900351TEST_F(TetherControllerTest, TestMultipleUpstreams) {
352 // Start first NAT on first upstream interface. Expect the upstream and NAT rules to be created.
Luke Huangae038f82018-11-05 11:17:31 +0900353 ExpectedIptablesCommands firstNat =
354 allNewNatCommands("wlan0", "rmnet0", WITH_COUNTERS, WITH_IPV6, true);
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900355 mTetherCtrl.enableNat("wlan0", "rmnet0");
356 expectIptablesRestoreCommands(firstNat);
357
358 // Start second NAT, on new upstream. Expect the upstream and NAT rules to be created for IPv4,
359 // but no counter rules for IPv6.
Luke Huangae038f82018-11-05 11:17:31 +0900360 ExpectedIptablesCommands secondNat =
361 allNewNatCommands("wlan0", "v4-rmnet0", WITH_COUNTERS, NO_IPV6, false);
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900362 mTetherCtrl.enableNat("wlan0", "v4-rmnet0");
363 expectIptablesRestoreCommands(secondNat);
364
365 // Pretend that the caller has forgotten that it set up the second NAT, and asks us to do so
366 // again. Expect that we take no action.
367 const ExpectedIptablesCommands NONE = {};
368 mTetherCtrl.enableNat("wlan0", "v4-rmnet0");
369 expectIptablesRestoreCommands(NONE);
370
371 // Remove the second NAT.
372 ExpectedIptablesCommands stopSecondNat = stopNatCommands("wlan0", "v4-rmnet0");
373 mTetherCtrl.disableNat("wlan0", "v4-rmnet0");
374 expectIptablesRestoreCommands(stopSecondNat);
375
376 // Remove the first NAT. Expect rules to be cleared.
377 ExpectedIptablesCommands stopFirstNat = stopNatCommands("wlan0", "rmnet0");
378 appendAll(stopFirstNat, FLUSH_COMMANDS);
379 mTetherCtrl.disableNat("wlan0", "rmnet0");
380 expectIptablesRestoreCommands(stopFirstNat);
381}
382
Lorenzo Colitti09353392017-08-24 14:20:32 +0900383std::string kTetherCounterHeaders = Join(std::vector<std::string> {
Lorenzo Colitti4604b4a2017-08-24 19:21:50 +0900384 "Chain tetherctrl_counters (4 references)",
Lorenzo Colitti09353392017-08-24 14:20:32 +0900385 " pkts bytes target prot opt in out source destination",
386}, '\n');
387
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900388std::string kIPv4TetherCounters = Join(std::vector<std::string> {
Lorenzo Colitti4604b4a2017-08-24 19:21:50 +0900389 "Chain tetherctrl_counters (4 references)",
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900390 " pkts bytes target prot opt in out source destination",
391 " 26 2373 RETURN all -- wlan0 rmnet0 0.0.0.0/0 0.0.0.0/0",
392 " 27 2002 RETURN all -- rmnet0 wlan0 0.0.0.0/0 0.0.0.0/0",
393 " 1040 107471 RETURN all -- bt-pan rmnet0 0.0.0.0/0 0.0.0.0/0",
394 " 1450 1708806 RETURN all -- rmnet0 bt-pan 0.0.0.0/0 0.0.0.0/0",
395}, '\n');
396
397std::string kIPv6TetherCounters = Join(std::vector<std::string> {
Lorenzo Colitti4604b4a2017-08-24 19:21:50 +0900398 "Chain tetherctrl_counters (2 references)",
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900399 " pkts bytes target prot opt in out source destination",
400 " 10000 10000000 RETURN all wlan0 rmnet0 ::/0 ::/0",
401 " 20000 20000000 RETURN all rmnet0 wlan0 ::/0 ::/0",
402}, '\n');
403
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900404void expectTetherStatsEqual(const TetherController::TetherStats& expected,
405 const TetherController::TetherStats& actual) {
406 EXPECT_EQ(expected.intIface, actual.intIface);
407 EXPECT_EQ(expected.extIface, actual.extIface);
408 EXPECT_EQ(expected.rxBytes, actual.rxBytes);
409 EXPECT_EQ(expected.txBytes, actual.txBytes);
410 EXPECT_EQ(expected.rxPackets, actual.rxPackets);
411 EXPECT_EQ(expected.txPackets, actual.txPackets);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900412}
413
414TEST_F(TetherControllerTest, TestGetTetherStats) {
Lorenzo Colitti38fd1362017-09-15 11:40:01 +0900415 // Finding no headers is an error.
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900416 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900417 clearIptablesRestoreOutput();
418
Lorenzo Colitti38fd1362017-09-15 11:40:01 +0900419 // Finding only v4 or only v6 headers is an error.
420 addIptablesRestoreOutput(kTetherCounterHeaders, "");
421 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
422 clearIptablesRestoreOutput();
423
424 addIptablesRestoreOutput("", kTetherCounterHeaders);
425 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
426 clearIptablesRestoreOutput();
427
428 // Finding headers but no stats is not an error.
429 addIptablesRestoreOutput(kTetherCounterHeaders, kTetherCounterHeaders);
430 StatusOr<TetherStatsList> result = mTetherCtrl.getTetherStats();
431 ASSERT_TRUE(isOk(result));
432 TetherStatsList actual = result.value();
433 ASSERT_EQ(0U, actual.size());
434 clearIptablesRestoreOutput();
435
436
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900437 addIptablesRestoreOutput(kIPv6TetherCounters);
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900438 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900439 clearIptablesRestoreOutput();
440
441 // IPv4 and IPv6 counters are properly added together.
442 addIptablesRestoreOutput(kIPv4TetherCounters, kIPv6TetherCounters);
Lorenzo Colitti9a65ac62017-09-04 18:07:56 +0900443 TetherStats expected0("wlan0", "rmnet0", 20002002, 20027, 10002373, 10026);
444 TetherStats expected1("bt-pan", "rmnet0", 1708806, 1450, 107471, 1040);
Lorenzo Colitti38fd1362017-09-15 11:40:01 +0900445 result = mTetherCtrl.getTetherStats();
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900446 ASSERT_TRUE(isOk(result));
Lorenzo Colitti38fd1362017-09-15 11:40:01 +0900447 actual = result.value();
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900448 ASSERT_EQ(2U, actual.size());
449 expectTetherStatsEqual(expected0, result.value()[0]);
450 expectTetherStatsEqual(expected1, result.value()[1]);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900451 clearIptablesRestoreOutput();
452
Lorenzo Colitti09353392017-08-24 14:20:32 +0900453 // No stats: error.
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900454 addIptablesRestoreOutput("", kIPv6TetherCounters);
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900455 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900456 clearIptablesRestoreOutput();
457
458 addIptablesRestoreOutput(kIPv4TetherCounters, "");
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900459 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900460 clearIptablesRestoreOutput();
461
462 // Include only one pair of interfaces and things are fine.
463 std::vector<std::string> counterLines = android::base::Split(kIPv4TetherCounters, "\n");
464 std::vector<std::string> brokenCounterLines = counterLines;
465 counterLines.resize(4);
466 std::string counters = Join(counterLines, "\n") + "\n";
467 addIptablesRestoreOutput(counters, counters);
Lorenzo Colitti9a65ac62017-09-04 18:07:56 +0900468 TetherStats expected1_0("wlan0", "rmnet0", 4004, 54, 4746, 52);
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900469 result = mTetherCtrl.getTetherStats();
470 ASSERT_TRUE(isOk(result));
471 actual = result.value();
472 ASSERT_EQ(1U, actual.size());
473 expectTetherStatsEqual(expected1_0, actual[0]);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900474 clearIptablesRestoreOutput();
475
476 // But if interfaces aren't paired, it's always an error.
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900477 counterLines.resize(3);
478 counters = Join(counterLines, "\n") + "\n";
479 addIptablesRestoreOutput(counters, counters);
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900480 result = mTetherCtrl.getTetherStats();
481 ASSERT_FALSE(isOk(result));
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900482 clearIptablesRestoreOutput();
483
484 // Token unit test of the fact that we return the stats in the error message which the caller
485 // ignores.
waynema71a0b592018-11-21 13:31:34 +0800486 // Skip header since we only saved the last line we parsed.
487 std::string expectedError = counterLines[2];
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900488 std::string err = result.status().msg();
Lorenzo Colitti9a8a9ff2017-01-31 19:06:59 +0900489 ASSERT_LE(expectedError.size(), err.size());
490 EXPECT_TRUE(std::equal(expectedError.rbegin(), expectedError.rend(), err.rbegin()));
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900491}
492
Automerger Merge Worker40265052020-03-06 01:42:40 +0000493TEST_F(TetherControllerTest, TestGetTetherStatsWithBpfTetherStatsMap) {
494 SKIP_IF_BPF_NOT_SUPPORTED;
495
496 // Setup BPF tether stats maps. The tether stats of interface rmnet0 comes from two tether
497 // stats map items with different interface index. Therefore, need to sum up both of them
498 // for the tether stats of interface rmnet0.
499 updateMaps(101, "wlan0", 100, 10, 200, 20);
500 updateMaps(102, "rmnet0", 300, 30, 400, 40);
501 updateMaps(103, "rmnet0", 500, 50, 600, 60);
502 const TetherStats expected0("BPFOffloadInterface", "wlan0", 100, 10, 200, 20);
503 const TetherStats expected1("BPFOffloadInterface", "rmnet0", 800, 80, 1000, 100);
504
505 // Setup iptables tether counters. IPv4 and IPv6 counters are added together.
506 addIptablesRestoreOutput(kIPv4TetherCounters, kIPv6TetherCounters);
507 const TetherStats expected2("wlan0", "rmnet0", 20002002, 20027, 10002373, 10026);
508 const TetherStats expected3("bt-pan", "rmnet0", 1708806, 1450, 107471, 1040);
509
510 const StatusOr<TetherStatsList> result = mTetherCtrl.getTetherStats();
511 ASSERT_OK(result);
512 const TetherStatsList& actual = result.value();
513 ASSERT_EQ(4U, actual.size());
514 EXPECT_THAT(actual, Contains(expected0)) << toString(actual);
515 EXPECT_THAT(actual, Contains(expected1)) << toString(actual);
516 EXPECT_THAT(actual, Contains(expected2)) << toString(actual);
517 EXPECT_THAT(actual, Contains(expected3)) << toString(actual);
518 clearIptablesRestoreOutput();
519}
520
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900521} // namespace net
522} // namespace android