blob: d2ff4a7578d01194f8c0dd2a4fa0fc77b2cfdf1a [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;
Hungming Chen41b0ed92020-06-02 00:13:20 +000046using TetherOffloadStats = android::net::TetherController::TetherOffloadStats;
47using TetherOffloadStatsList = android::net::TetherController::TetherOffloadStatsList;
Lorenzo Colittia93126d2017-08-24 13:28:19 +090048
49namespace android {
50namespace net {
51
Automerger Merge Worker40265052020-03-06 01:42:40 +000052constexpr int TEST_MAP_SIZE = 10;
53
Hungming Chen41b0ed92020-06-02 00:13:20 +000054// Comparison for TetherOffloadStats. Need to override operator== because class TetherOffloadStats
55// doesn't have one.
56// TODO: once C++20 is used, use default operator== in TetherOffloadStats and remove the overriding
57// here.
58bool operator==(const TetherOffloadStats& lhs, const TetherOffloadStats& rhs) {
59 return lhs.ifIndex == rhs.ifIndex && lhs.rxBytes == rhs.rxBytes && lhs.txBytes == rhs.txBytes &&
Automerger Merge Worker40265052020-03-06 01:42:40 +000060 lhs.rxPackets == rhs.rxPackets && lhs.txPackets == rhs.txPackets;
61}
62
Lorenzo Colittia93126d2017-08-24 13:28:19 +090063class TetherControllerTest : public IptablesBaseTest {
64public:
65 TetherControllerTest() {
66 TetherController::iptablesRestoreFunction = fakeExecIptablesRestoreWithOutput;
67 }
68
69protected:
70 TetherController mTetherCtrl;
Automerger Merge Worker40265052020-03-06 01:42:40 +000071 BpfMap<uint32_t, TetherStatsValue> mFakeTetherStatsMap{BPF_MAP_TYPE_HASH, TEST_MAP_SIZE};
Maciej Żenczykowskid25a7342020-05-04 18:18:38 -070072 BpfMap<uint32_t, uint64_t> mFakeTetherLimitMap{BPF_MAP_TYPE_HASH, TEST_MAP_SIZE};
Automerger Merge Worker40265052020-03-06 01:42:40 +000073
74 void SetUp() {
75 SKIP_IF_BPF_NOT_SUPPORTED;
76
Automerger Merge Worker40265052020-03-06 01:42:40 +000077 ASSERT_TRUE(mFakeTetherStatsMap.isValid());
Maciej Żenczykowskid25a7342020-05-04 18:18:38 -070078 ASSERT_TRUE(mFakeTetherLimitMap.isValid());
Automerger Merge Worker40265052020-03-06 01:42:40 +000079
Automerger Merge Worker40265052020-03-06 01:42:40 +000080 mTetherCtrl.mBpfStatsMap = mFakeTetherStatsMap;
81 ASSERT_TRUE(mTetherCtrl.mBpfStatsMap.isValid());
Maciej Żenczykowskid25a7342020-05-04 18:18:38 -070082 mTetherCtrl.mBpfLimitMap = mFakeTetherLimitMap;
83 ASSERT_TRUE(mTetherCtrl.mBpfLimitMap.isValid());
Automerger Merge Worker40265052020-03-06 01:42:40 +000084 }
85
Hungming Chen41b0ed92020-06-02 00:13:20 +000086 std::string toString(const TetherOffloadStatsList& statsList) {
Automerger Merge Worker40265052020-03-06 01:42:40 +000087 std::string result;
88 for (const auto& stats : statsList) {
Hungming Chen41b0ed92020-06-02 00:13:20 +000089 result += StringPrintf("%d, %" PRId64 ", %" PRId64 ", %" PRId64 ", %" PRId64 "\n",
90 stats.ifIndex, stats.rxBytes, stats.rxPackets, stats.txBytes,
91 stats.txPackets);
Automerger Merge Worker40265052020-03-06 01:42:40 +000092 }
93 return result;
94 }
95
Hungming Chen41b0ed92020-06-02 00:13:20 +000096 void updateMaps(uint32_t ifaceIndex, uint64_t rxBytes, uint64_t rxPackets, uint64_t txBytes,
97 uint64_t txPackets) {
Automerger Merge Worker40265052020-03-06 01:42:40 +000098 // {rx, tx}Errors in |tetherStats| are set zero because getTetherStats doesn't use them.
99 const TetherStatsValue tetherStats = {rxPackets, rxBytes, 0 /*unused*/,
100 txPackets, txBytes, 0 /*unused*/};
101 ASSERT_RESULT_OK(mFakeTetherStatsMap.writeValue(ifaceIndex, tetherStats, BPF_ANY));
102 };
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900103
104 int setDefaults() {
105 return mTetherCtrl.setDefaults();
106 }
107
108 const ExpectedIptablesCommands FLUSH_COMMANDS = {
Luke Huangae038f82018-11-05 11:17:31 +0900109 {V4,
110 "*filter\n"
111 ":tetherctrl_FORWARD -\n"
112 "-A tetherctrl_FORWARD -j DROP\n"
113 "COMMIT\n"
114 "*nat\n"
115 ":tetherctrl_nat_POSTROUTING -\n"
116 "COMMIT\n"},
117 {V6,
118 "*filter\n"
119 ":tetherctrl_FORWARD -\n"
120 "COMMIT\n"
121 "*raw\n"
122 ":tetherctrl_raw_PREROUTING -\n"
123 "COMMIT\n"},
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900124 };
125
126 const ExpectedIptablesCommands SETUP_COMMANDS = {
Luke Huangae038f82018-11-05 11:17:31 +0900127 {V4,
128 "*filter\n"
129 ":tetherctrl_FORWARD -\n"
130 "-A tetherctrl_FORWARD -j DROP\n"
131 "COMMIT\n"
132 "*nat\n"
133 ":tetherctrl_nat_POSTROUTING -\n"
134 "COMMIT\n"},
135 {V6,
136 "*filter\n"
137 ":tetherctrl_FORWARD -\n"
138 "COMMIT\n"
139 "*raw\n"
140 ":tetherctrl_raw_PREROUTING -\n"
141 "COMMIT\n"},
142 {V4,
143 "*mangle\n"
144 "-A tetherctrl_mangle_FORWARD -p tcp --tcp-flags SYN SYN "
145 "-j TCPMSS --clamp-mss-to-pmtu\n"
146 "COMMIT\n"},
147 {V4V6,
148 "*filter\n"
149 ":tetherctrl_counters -\n"
150 "COMMIT\n"},
151 };
152
153 const ExpectedIptablesCommands ALERT_ADD_COMMAND = {
154 {V4V6,
155 "*filter\n"
156 "-I tetherctrl_FORWARD -j bw_global_alert\n"
157 "COMMIT\n"},
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900158 };
159
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900160 ExpectedIptablesCommands firstIPv4UpstreamCommands(const char *extIf) {
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900161 std::string v4Cmd = StringPrintf(
162 "*nat\n"
Lorenzo Colitti4604b4a2017-08-24 19:21:50 +0900163 "-A tetherctrl_nat_POSTROUTING -o %s -j MASQUERADE\n"
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900164 "COMMIT\n", extIf);
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900165 return {
166 { V4, v4Cmd },
167 };
168 }
169
170 ExpectedIptablesCommands firstIPv6UpstreamCommands() {
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900171 std::string v6Cmd =
Luke Huangae038f82018-11-05 11:17:31 +0900172 "*filter\n"
173 "-A tetherctrl_FORWARD -g tetherctrl_counters\n"
174 "COMMIT\n";
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900175 return {
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900176 { V6, v6Cmd },
177 };
178 }
179
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900180 template<typename T>
181 void appendAll(std::vector<T>& cmds, const std::vector<T>& appendCmds) {
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900182 cmds.insert(cmds.end(), appendCmds.begin(), appendCmds.end());
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900183 }
184
185 ExpectedIptablesCommands startNatCommands(const char *intIf, const char *extIf,
186 bool withCounterChainRules) {
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900187 std::string rpfilterCmd = StringPrintf(
188 "*raw\n"
Lorenzo Colitti4604b4a2017-08-24 19:21:50 +0900189 "-A tetherctrl_raw_PREROUTING -i %s -m rpfilter --invert ! -s fe80::/64 -j DROP\n"
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900190 "COMMIT\n", intIf);
191
192 std::vector<std::string> v4Cmds = {
hiroaki.yokoyama04f2cb52018-06-13 18:47:30 +0900193 "*raw",
194 StringPrintf(
195 "-A tetherctrl_raw_PREROUTING -p tcp --dport 21 -i %s -j CT --helper ftp",
196 intIf),
197 StringPrintf("-A tetherctrl_raw_PREROUTING -p tcp --dport 1723 -i %s -j CT "
198 "--helper pptp",
199 intIf),
200 "COMMIT",
201 "*filter",
202 StringPrintf("-A tetherctrl_FORWARD -i %s -o %s -m state --state"
203 " ESTABLISHED,RELATED -g tetherctrl_counters",
204 extIf, intIf),
205 StringPrintf("-A tetherctrl_FORWARD -i %s -o %s -m state --state INVALID -j DROP",
206 intIf, extIf),
207 StringPrintf("-A tetherctrl_FORWARD -i %s -o %s -g tetherctrl_counters", intIf,
208 extIf),
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900209 };
210
211 std::vector<std::string> v6Cmds = {
212 "*filter",
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900213 };
214
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900215 if (withCounterChainRules) {
216 const std::vector<std::string> counterRules = {
217 StringPrintf("-A tetherctrl_counters -i %s -o %s -j RETURN", intIf, extIf),
218 StringPrintf("-A tetherctrl_counters -i %s -o %s -j RETURN", extIf, intIf),
219 };
220
221 appendAll(v4Cmds, counterRules);
222 appendAll(v6Cmds, counterRules);
223 }
224
225 appendAll(v4Cmds, {
226 "-D tetherctrl_FORWARD -j DROP",
227 "-A tetherctrl_FORWARD -j DROP",
228 "COMMIT\n",
229 });
230
231 v6Cmds.push_back("COMMIT\n");
232
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900233 return {
234 { V6, rpfilterCmd },
235 { V4, Join(v4Cmds, '\n') },
236 { V6, Join(v6Cmds, '\n') },
237 };
238 }
239
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900240 constexpr static const bool WITH_COUNTERS = true;
241 constexpr static const bool NO_COUNTERS = false;
242 constexpr static const bool WITH_IPV6 = true;
243 constexpr static const bool NO_IPV6 = false;
Luke Huangae038f82018-11-05 11:17:31 +0900244 ExpectedIptablesCommands allNewNatCommands(const char* intIf, const char* extIf,
245 bool withCounterChainRules, bool withIPv6Upstream,
246 bool firstEnableNat) {
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900247 ExpectedIptablesCommands commands;
248 ExpectedIptablesCommands setupFirstIPv4Commands = firstIPv4UpstreamCommands(extIf);
249 ExpectedIptablesCommands startFirstNatCommands = startNatCommands(intIf, extIf,
250 withCounterChainRules);
251
252 appendAll(commands, setupFirstIPv4Commands);
253 if (withIPv6Upstream) {
254 ExpectedIptablesCommands setupFirstIPv6Commands = firstIPv6UpstreamCommands();
255 appendAll(commands, setupFirstIPv6Commands);
256 }
Luke Huangae038f82018-11-05 11:17:31 +0900257 if (firstEnableNat) {
258 appendAll(commands, ALERT_ADD_COMMAND);
259 }
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900260 appendAll(commands, startFirstNatCommands);
261
262 return commands;
263 }
264
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900265 ExpectedIptablesCommands stopNatCommands(const char *intIf, const char *extIf) {
266 std::string rpfilterCmd = StringPrintf(
267 "*raw\n"
Lorenzo Colitti4604b4a2017-08-24 19:21:50 +0900268 "-D tetherctrl_raw_PREROUTING -i %s -m rpfilter --invert ! -s fe80::/64 -j DROP\n"
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900269 "COMMIT\n", intIf);
270
271 std::vector<std::string> v4Cmds = {
hiroaki.yokoyama04f2cb52018-06-13 18:47:30 +0900272 "*raw",
273 StringPrintf(
274 "-D tetherctrl_raw_PREROUTING -p tcp --dport 21 -i %s -j CT --helper ftp",
275 intIf),
276 StringPrintf("-D tetherctrl_raw_PREROUTING -p tcp --dport 1723 -i %s -j CT "
277 "--helper pptp",
278 intIf),
279 "COMMIT",
280 "*filter",
281 StringPrintf("-D tetherctrl_FORWARD -i %s -o %s -m state --state"
282 " ESTABLISHED,RELATED -g tetherctrl_counters",
283 extIf, intIf),
284 StringPrintf("-D tetherctrl_FORWARD -i %s -o %s -m state --state INVALID -j DROP",
285 intIf, extIf),
286 StringPrintf("-D tetherctrl_FORWARD -i %s -o %s -g tetherctrl_counters", intIf,
287 extIf),
288 "COMMIT\n",
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900289 };
290
291 return {
292 { V6, rpfilterCmd },
293 { V4, Join(v4Cmds, '\n') },
294 };
295
296 }
297};
298
299TEST_F(TetherControllerTest, TestSetupIptablesHooks) {
300 mTetherCtrl.setupIptablesHooks();
301 expectIptablesRestoreCommands(SETUP_COMMANDS);
302}
303
304TEST_F(TetherControllerTest, TestSetDefaults) {
305 setDefaults();
306 expectIptablesRestoreCommands(FLUSH_COMMANDS);
307}
308
309TEST_F(TetherControllerTest, TestAddAndRemoveNat) {
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900310 // Start first NAT on first upstream interface. Expect the upstream and NAT rules to be created.
Luke Huangae038f82018-11-05 11:17:31 +0900311 ExpectedIptablesCommands firstNat =
312 allNewNatCommands("wlan0", "rmnet0", WITH_COUNTERS, WITH_IPV6, true);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900313 mTetherCtrl.enableNat("wlan0", "rmnet0");
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900314 expectIptablesRestoreCommands(firstNat);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900315
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900316 // Start second NAT on same upstream. Expect only the counter rules to be created.
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900317 ExpectedIptablesCommands startOtherNatOnSameUpstream = startNatCommands(
318 "usb0", "rmnet0", WITH_COUNTERS);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900319 mTetherCtrl.enableNat("usb0", "rmnet0");
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900320 expectIptablesRestoreCommands(startOtherNatOnSameUpstream);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900321
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900322 // Remove the first NAT.
323 ExpectedIptablesCommands stopFirstNat = stopNatCommands("wlan0", "rmnet0");
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900324 mTetherCtrl.disableNat("wlan0", "rmnet0");
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900325 expectIptablesRestoreCommands(stopFirstNat);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900326
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900327 // Remove the last NAT. Expect rules to be cleared.
328 ExpectedIptablesCommands stopLastNat = stopNatCommands("usb0", "rmnet0");
329
330 appendAll(stopLastNat, FLUSH_COMMANDS);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900331 mTetherCtrl.disableNat("usb0", "rmnet0");
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900332 expectIptablesRestoreCommands(stopLastNat);
333
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900334 // Re-add a NAT removed previously: tetherctrl_counters chain rules are not re-added
Luke Huangae038f82018-11-05 11:17:31 +0900335 firstNat = allNewNatCommands("wlan0", "rmnet0", NO_COUNTERS, WITH_IPV6, true);
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900336 mTetherCtrl.enableNat("wlan0", "rmnet0");
337 expectIptablesRestoreCommands(firstNat);
338
339 // Remove it again. Expect rules to be cleared.
340 stopLastNat = stopNatCommands("wlan0", "rmnet0");
341 appendAll(stopLastNat, FLUSH_COMMANDS);
342 mTetherCtrl.disableNat("wlan0", "rmnet0");
343 expectIptablesRestoreCommands(stopLastNat);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900344}
345
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900346TEST_F(TetherControllerTest, TestMultipleUpstreams) {
347 // Start first NAT on first upstream interface. Expect the upstream and NAT rules to be created.
Luke Huangae038f82018-11-05 11:17:31 +0900348 ExpectedIptablesCommands firstNat =
349 allNewNatCommands("wlan0", "rmnet0", WITH_COUNTERS, WITH_IPV6, true);
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900350 mTetherCtrl.enableNat("wlan0", "rmnet0");
351 expectIptablesRestoreCommands(firstNat);
352
353 // Start second NAT, on new upstream. Expect the upstream and NAT rules to be created for IPv4,
354 // but no counter rules for IPv6.
Luke Huangae038f82018-11-05 11:17:31 +0900355 ExpectedIptablesCommands secondNat =
356 allNewNatCommands("wlan0", "v4-rmnet0", WITH_COUNTERS, NO_IPV6, false);
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900357 mTetherCtrl.enableNat("wlan0", "v4-rmnet0");
358 expectIptablesRestoreCommands(secondNat);
359
360 // Pretend that the caller has forgotten that it set up the second NAT, and asks us to do so
361 // again. Expect that we take no action.
362 const ExpectedIptablesCommands NONE = {};
363 mTetherCtrl.enableNat("wlan0", "v4-rmnet0");
364 expectIptablesRestoreCommands(NONE);
365
366 // Remove the second NAT.
367 ExpectedIptablesCommands stopSecondNat = stopNatCommands("wlan0", "v4-rmnet0");
368 mTetherCtrl.disableNat("wlan0", "v4-rmnet0");
369 expectIptablesRestoreCommands(stopSecondNat);
370
371 // Remove the first NAT. Expect rules to be cleared.
372 ExpectedIptablesCommands stopFirstNat = stopNatCommands("wlan0", "rmnet0");
373 appendAll(stopFirstNat, FLUSH_COMMANDS);
374 mTetherCtrl.disableNat("wlan0", "rmnet0");
375 expectIptablesRestoreCommands(stopFirstNat);
376}
377
Lorenzo Colitti09353392017-08-24 14:20:32 +0900378std::string kTetherCounterHeaders = Join(std::vector<std::string> {
Lorenzo Colitti4604b4a2017-08-24 19:21:50 +0900379 "Chain tetherctrl_counters (4 references)",
Lorenzo Colitti09353392017-08-24 14:20:32 +0900380 " pkts bytes target prot opt in out source destination",
381}, '\n');
382
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900383std::string kIPv4TetherCounters = Join(std::vector<std::string> {
Lorenzo Colitti4604b4a2017-08-24 19:21:50 +0900384 "Chain tetherctrl_counters (4 references)",
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900385 " pkts bytes target prot opt in out source destination",
386 " 26 2373 RETURN all -- wlan0 rmnet0 0.0.0.0/0 0.0.0.0/0",
387 " 27 2002 RETURN all -- rmnet0 wlan0 0.0.0.0/0 0.0.0.0/0",
388 " 1040 107471 RETURN all -- bt-pan rmnet0 0.0.0.0/0 0.0.0.0/0",
389 " 1450 1708806 RETURN all -- rmnet0 bt-pan 0.0.0.0/0 0.0.0.0/0",
390}, '\n');
391
392std::string kIPv6TetherCounters = Join(std::vector<std::string> {
Lorenzo Colitti4604b4a2017-08-24 19:21:50 +0900393 "Chain tetherctrl_counters (2 references)",
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900394 " pkts bytes target prot opt in out source destination",
395 " 10000 10000000 RETURN all wlan0 rmnet0 ::/0 ::/0",
396 " 20000 20000000 RETURN all rmnet0 wlan0 ::/0 ::/0",
397}, '\n');
398
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900399void expectTetherStatsEqual(const TetherController::TetherStats& expected,
400 const TetherController::TetherStats& actual) {
401 EXPECT_EQ(expected.intIface, actual.intIface);
402 EXPECT_EQ(expected.extIface, actual.extIface);
403 EXPECT_EQ(expected.rxBytes, actual.rxBytes);
404 EXPECT_EQ(expected.txBytes, actual.txBytes);
405 EXPECT_EQ(expected.rxPackets, actual.rxPackets);
406 EXPECT_EQ(expected.txPackets, actual.txPackets);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900407}
408
409TEST_F(TetherControllerTest, TestGetTetherStats) {
Lorenzo Colitti38fd1362017-09-15 11:40:01 +0900410 // Finding no headers is an error.
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900411 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900412 clearIptablesRestoreOutput();
413
Lorenzo Colitti38fd1362017-09-15 11:40:01 +0900414 // Finding only v4 or only v6 headers is an error.
415 addIptablesRestoreOutput(kTetherCounterHeaders, "");
416 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
417 clearIptablesRestoreOutput();
418
419 addIptablesRestoreOutput("", kTetherCounterHeaders);
420 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
421 clearIptablesRestoreOutput();
422
423 // Finding headers but no stats is not an error.
424 addIptablesRestoreOutput(kTetherCounterHeaders, kTetherCounterHeaders);
425 StatusOr<TetherStatsList> result = mTetherCtrl.getTetherStats();
426 ASSERT_TRUE(isOk(result));
427 TetherStatsList actual = result.value();
428 ASSERT_EQ(0U, actual.size());
429 clearIptablesRestoreOutput();
430
431
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900432 addIptablesRestoreOutput(kIPv6TetherCounters);
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900433 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900434 clearIptablesRestoreOutput();
435
436 // IPv4 and IPv6 counters are properly added together.
437 addIptablesRestoreOutput(kIPv4TetherCounters, kIPv6TetherCounters);
Lorenzo Colitti9a65ac62017-09-04 18:07:56 +0900438 TetherStats expected0("wlan0", "rmnet0", 20002002, 20027, 10002373, 10026);
439 TetherStats expected1("bt-pan", "rmnet0", 1708806, 1450, 107471, 1040);
Lorenzo Colitti38fd1362017-09-15 11:40:01 +0900440 result = mTetherCtrl.getTetherStats();
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900441 ASSERT_TRUE(isOk(result));
Lorenzo Colitti38fd1362017-09-15 11:40:01 +0900442 actual = result.value();
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900443 ASSERT_EQ(2U, actual.size());
444 expectTetherStatsEqual(expected0, result.value()[0]);
445 expectTetherStatsEqual(expected1, result.value()[1]);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900446 clearIptablesRestoreOutput();
447
Lorenzo Colitti09353392017-08-24 14:20:32 +0900448 // No stats: error.
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900449 addIptablesRestoreOutput("", kIPv6TetherCounters);
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900450 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900451 clearIptablesRestoreOutput();
452
453 addIptablesRestoreOutput(kIPv4TetherCounters, "");
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900454 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900455 clearIptablesRestoreOutput();
456
457 // Include only one pair of interfaces and things are fine.
458 std::vector<std::string> counterLines = android::base::Split(kIPv4TetherCounters, "\n");
459 std::vector<std::string> brokenCounterLines = counterLines;
460 counterLines.resize(4);
461 std::string counters = Join(counterLines, "\n") + "\n";
462 addIptablesRestoreOutput(counters, counters);
Lorenzo Colitti9a65ac62017-09-04 18:07:56 +0900463 TetherStats expected1_0("wlan0", "rmnet0", 4004, 54, 4746, 52);
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900464 result = mTetherCtrl.getTetherStats();
465 ASSERT_TRUE(isOk(result));
466 actual = result.value();
467 ASSERT_EQ(1U, actual.size());
468 expectTetherStatsEqual(expected1_0, actual[0]);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900469 clearIptablesRestoreOutput();
470
471 // But if interfaces aren't paired, it's always an error.
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900472 counterLines.resize(3);
473 counters = Join(counterLines, "\n") + "\n";
474 addIptablesRestoreOutput(counters, counters);
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900475 result = mTetherCtrl.getTetherStats();
476 ASSERT_FALSE(isOk(result));
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900477 clearIptablesRestoreOutput();
478
479 // Token unit test of the fact that we return the stats in the error message which the caller
480 // ignores.
waynema71a0b592018-11-21 13:31:34 +0800481 // Skip header since we only saved the last line we parsed.
482 std::string expectedError = counterLines[2];
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900483 std::string err = result.status().msg();
Lorenzo Colitti9a8a9ff2017-01-31 19:06:59 +0900484 ASSERT_LE(expectedError.size(), err.size());
485 EXPECT_TRUE(std::equal(expectedError.rbegin(), expectedError.rend(), err.rbegin()));
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900486}
487
Hungming Chen41b0ed92020-06-02 00:13:20 +0000488TEST_F(TetherControllerTest, TestTetherOffloadGetStats) {
Automerger Merge Worker40265052020-03-06 01:42:40 +0000489 SKIP_IF_BPF_NOT_SUPPORTED;
490
Hungming Chen41b0ed92020-06-02 00:13:20 +0000491 updateMaps(101, 100, 10, 200, 20);
492 updateMaps(102, 300, 30, 400, 40);
493 const TetherOffloadStats expected0{101, 100, 10, 200, 20};
494 const TetherOffloadStats expected1{102, 300, 30, 400, 40};
Automerger Merge Worker40265052020-03-06 01:42:40 +0000495
Hungming Chen41b0ed92020-06-02 00:13:20 +0000496 const StatusOr<TetherOffloadStatsList> result = mTetherCtrl.getTetherOffloadStats();
Automerger Merge Worker40265052020-03-06 01:42:40 +0000497 ASSERT_OK(result);
Hungming Chen41b0ed92020-06-02 00:13:20 +0000498 const TetherOffloadStatsList& actual = result.value();
499 ASSERT_EQ(2U, actual.size());
Automerger Merge Worker40265052020-03-06 01:42:40 +0000500 EXPECT_THAT(actual, Contains(expected0)) << toString(actual);
501 EXPECT_THAT(actual, Contains(expected1)) << toString(actual);
Automerger Merge Worker40265052020-03-06 01:42:40 +0000502 clearIptablesRestoreOutput();
503}
504
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900505} // namespace net
506} // namespace android