blob: 7199a3d6754240602e143a9d56442522a1ccbc66 [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};
70
71 void SetUp() {
72 SKIP_IF_BPF_NOT_SUPPORTED;
73
74 ASSERT_TRUE(mFakeIfaceIndexNameMap.isValid());
75 ASSERT_TRUE(mFakeTetherStatsMap.isValid());
76
77 mTetherCtrl.mIfaceIndexNameMap = mFakeIfaceIndexNameMap;
78 ASSERT_TRUE(mTetherCtrl.mIfaceIndexNameMap.isValid());
79 mTetherCtrl.mBpfStatsMap = mFakeTetherStatsMap;
80 ASSERT_TRUE(mTetherCtrl.mBpfStatsMap.isValid());
81 }
82
83 std::string toString(const TetherStatsList& statsList) {
84 std::string result;
85 for (const auto& stats : statsList) {
86 result += StringPrintf("%s, %s, %" PRId64 ", %" PRId64 ", %" PRId64 ", %" PRId64 "\n",
87 stats.intIface.c_str(), stats.extIface.c_str(), stats.rxBytes,
88 stats.rxPackets, stats.txBytes, stats.txPackets);
89 }
90 return result;
91 }
92
93 void updateMaps(uint32_t ifaceIndex, const char* ifaceName, uint64_t rxBytes,
94 uint64_t rxPackets, uint64_t txBytes, uint64_t txPackets) {
95 IfaceValue iface{};
96 strlcpy(iface.name, ifaceName, sizeof(iface.name));
97 ASSERT_RESULT_OK(mFakeIfaceIndexNameMap.writeValue(ifaceIndex, iface, BPF_ANY));
98
99 // {rx, tx}Errors in |tetherStats| are set zero because getTetherStats doesn't use them.
100 const TetherStatsValue tetherStats = {rxPackets, rxBytes, 0 /*unused*/,
101 txPackets, txBytes, 0 /*unused*/};
102 ASSERT_RESULT_OK(mFakeTetherStatsMap.writeValue(ifaceIndex, tetherStats, BPF_ANY));
103 };
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900104
105 int setDefaults() {
106 return mTetherCtrl.setDefaults();
107 }
108
109 const ExpectedIptablesCommands FLUSH_COMMANDS = {
Luke Huangae038f82018-11-05 11:17:31 +0900110 {V4,
111 "*filter\n"
112 ":tetherctrl_FORWARD -\n"
113 "-A tetherctrl_FORWARD -j DROP\n"
114 "COMMIT\n"
115 "*nat\n"
116 ":tetherctrl_nat_POSTROUTING -\n"
117 "COMMIT\n"},
118 {V6,
119 "*filter\n"
120 ":tetherctrl_FORWARD -\n"
121 "COMMIT\n"
122 "*raw\n"
123 ":tetherctrl_raw_PREROUTING -\n"
124 "COMMIT\n"},
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900125 };
126
127 const ExpectedIptablesCommands SETUP_COMMANDS = {
Luke Huangae038f82018-11-05 11:17:31 +0900128 {V4,
129 "*filter\n"
130 ":tetherctrl_FORWARD -\n"
131 "-A tetherctrl_FORWARD -j DROP\n"
132 "COMMIT\n"
133 "*nat\n"
134 ":tetherctrl_nat_POSTROUTING -\n"
135 "COMMIT\n"},
136 {V6,
137 "*filter\n"
138 ":tetherctrl_FORWARD -\n"
139 "COMMIT\n"
140 "*raw\n"
141 ":tetherctrl_raw_PREROUTING -\n"
142 "COMMIT\n"},
143 {V4,
144 "*mangle\n"
145 "-A tetherctrl_mangle_FORWARD -p tcp --tcp-flags SYN SYN "
146 "-j TCPMSS --clamp-mss-to-pmtu\n"
147 "COMMIT\n"},
148 {V4V6,
149 "*filter\n"
150 ":tetherctrl_counters -\n"
151 "COMMIT\n"},
152 };
153
154 const ExpectedIptablesCommands ALERT_ADD_COMMAND = {
155 {V4V6,
156 "*filter\n"
157 "-I tetherctrl_FORWARD -j bw_global_alert\n"
158 "COMMIT\n"},
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900159 };
160
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900161 ExpectedIptablesCommands firstIPv4UpstreamCommands(const char *extIf) {
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900162 std::string v4Cmd = StringPrintf(
163 "*nat\n"
Lorenzo Colitti4604b4a2017-08-24 19:21:50 +0900164 "-A tetherctrl_nat_POSTROUTING -o %s -j MASQUERADE\n"
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900165 "COMMIT\n", extIf);
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900166 return {
167 { V4, v4Cmd },
168 };
169 }
170
171 ExpectedIptablesCommands firstIPv6UpstreamCommands() {
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900172 std::string v6Cmd =
Luke Huangae038f82018-11-05 11:17:31 +0900173 "*filter\n"
174 "-A tetherctrl_FORWARD -g tetherctrl_counters\n"
175 "COMMIT\n";
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900176 return {
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900177 { V6, v6Cmd },
178 };
179 }
180
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900181 template<typename T>
182 void appendAll(std::vector<T>& cmds, const std::vector<T>& appendCmds) {
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900183 cmds.insert(cmds.end(), appendCmds.begin(), appendCmds.end());
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900184 }
185
186 ExpectedIptablesCommands startNatCommands(const char *intIf, const char *extIf,
187 bool withCounterChainRules) {
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900188 std::string rpfilterCmd = StringPrintf(
189 "*raw\n"
Lorenzo Colitti4604b4a2017-08-24 19:21:50 +0900190 "-A tetherctrl_raw_PREROUTING -i %s -m rpfilter --invert ! -s fe80::/64 -j DROP\n"
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900191 "COMMIT\n", intIf);
192
193 std::vector<std::string> v4Cmds = {
hiroaki.yokoyama04f2cb52018-06-13 18:47:30 +0900194 "*raw",
195 StringPrintf(
196 "-A tetherctrl_raw_PREROUTING -p tcp --dport 21 -i %s -j CT --helper ftp",
197 intIf),
198 StringPrintf("-A tetherctrl_raw_PREROUTING -p tcp --dport 1723 -i %s -j CT "
199 "--helper pptp",
200 intIf),
201 "COMMIT",
202 "*filter",
203 StringPrintf("-A tetherctrl_FORWARD -i %s -o %s -m state --state"
204 " ESTABLISHED,RELATED -g tetherctrl_counters",
205 extIf, intIf),
206 StringPrintf("-A tetherctrl_FORWARD -i %s -o %s -m state --state INVALID -j DROP",
207 intIf, extIf),
208 StringPrintf("-A tetherctrl_FORWARD -i %s -o %s -g tetherctrl_counters", intIf,
209 extIf),
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900210 };
211
212 std::vector<std::string> v6Cmds = {
213 "*filter",
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900214 };
215
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900216 if (withCounterChainRules) {
217 const std::vector<std::string> counterRules = {
218 StringPrintf("-A tetherctrl_counters -i %s -o %s -j RETURN", intIf, extIf),
219 StringPrintf("-A tetherctrl_counters -i %s -o %s -j RETURN", extIf, intIf),
220 };
221
222 appendAll(v4Cmds, counterRules);
223 appendAll(v6Cmds, counterRules);
224 }
225
226 appendAll(v4Cmds, {
227 "-D tetherctrl_FORWARD -j DROP",
228 "-A tetherctrl_FORWARD -j DROP",
229 "COMMIT\n",
230 });
231
232 v6Cmds.push_back("COMMIT\n");
233
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900234 return {
235 { V6, rpfilterCmd },
236 { V4, Join(v4Cmds, '\n') },
237 { V6, Join(v6Cmds, '\n') },
238 };
239 }
240
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900241 constexpr static const bool WITH_COUNTERS = true;
242 constexpr static const bool NO_COUNTERS = false;
243 constexpr static const bool WITH_IPV6 = true;
244 constexpr static const bool NO_IPV6 = false;
Luke Huangae038f82018-11-05 11:17:31 +0900245 ExpectedIptablesCommands allNewNatCommands(const char* intIf, const char* extIf,
246 bool withCounterChainRules, bool withIPv6Upstream,
247 bool firstEnableNat) {
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900248 ExpectedIptablesCommands commands;
249 ExpectedIptablesCommands setupFirstIPv4Commands = firstIPv4UpstreamCommands(extIf);
250 ExpectedIptablesCommands startFirstNatCommands = startNatCommands(intIf, extIf,
251 withCounterChainRules);
252
253 appendAll(commands, setupFirstIPv4Commands);
254 if (withIPv6Upstream) {
255 ExpectedIptablesCommands setupFirstIPv6Commands = firstIPv6UpstreamCommands();
256 appendAll(commands, setupFirstIPv6Commands);
257 }
Luke Huangae038f82018-11-05 11:17:31 +0900258 if (firstEnableNat) {
259 appendAll(commands, ALERT_ADD_COMMAND);
260 }
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900261 appendAll(commands, startFirstNatCommands);
262
263 return commands;
264 }
265
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900266 ExpectedIptablesCommands stopNatCommands(const char *intIf, const char *extIf) {
267 std::string rpfilterCmd = StringPrintf(
268 "*raw\n"
Lorenzo Colitti4604b4a2017-08-24 19:21:50 +0900269 "-D tetherctrl_raw_PREROUTING -i %s -m rpfilter --invert ! -s fe80::/64 -j DROP\n"
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900270 "COMMIT\n", intIf);
271
272 std::vector<std::string> v4Cmds = {
hiroaki.yokoyama04f2cb52018-06-13 18:47:30 +0900273 "*raw",
274 StringPrintf(
275 "-D tetherctrl_raw_PREROUTING -p tcp --dport 21 -i %s -j CT --helper ftp",
276 intIf),
277 StringPrintf("-D tetherctrl_raw_PREROUTING -p tcp --dport 1723 -i %s -j CT "
278 "--helper pptp",
279 intIf),
280 "COMMIT",
281 "*filter",
282 StringPrintf("-D tetherctrl_FORWARD -i %s -o %s -m state --state"
283 " ESTABLISHED,RELATED -g tetherctrl_counters",
284 extIf, intIf),
285 StringPrintf("-D tetherctrl_FORWARD -i %s -o %s -m state --state INVALID -j DROP",
286 intIf, extIf),
287 StringPrintf("-D tetherctrl_FORWARD -i %s -o %s -g tetherctrl_counters", intIf,
288 extIf),
289 "COMMIT\n",
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900290 };
291
292 return {
293 { V6, rpfilterCmd },
294 { V4, Join(v4Cmds, '\n') },
295 };
296
297 }
298};
299
300TEST_F(TetherControllerTest, TestSetupIptablesHooks) {
301 mTetherCtrl.setupIptablesHooks();
302 expectIptablesRestoreCommands(SETUP_COMMANDS);
303}
304
305TEST_F(TetherControllerTest, TestSetDefaults) {
306 setDefaults();
307 expectIptablesRestoreCommands(FLUSH_COMMANDS);
308}
309
310TEST_F(TetherControllerTest, TestAddAndRemoveNat) {
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900311 // Start first NAT on first upstream interface. Expect the upstream and NAT rules to be created.
Luke Huangae038f82018-11-05 11:17:31 +0900312 ExpectedIptablesCommands firstNat =
313 allNewNatCommands("wlan0", "rmnet0", WITH_COUNTERS, WITH_IPV6, true);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900314 mTetherCtrl.enableNat("wlan0", "rmnet0");
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900315 expectIptablesRestoreCommands(firstNat);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900316
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900317 // Start second NAT on same upstream. Expect only the counter rules to be created.
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900318 ExpectedIptablesCommands startOtherNatOnSameUpstream = startNatCommands(
319 "usb0", "rmnet0", WITH_COUNTERS);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900320 mTetherCtrl.enableNat("usb0", "rmnet0");
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900321 expectIptablesRestoreCommands(startOtherNatOnSameUpstream);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900322
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900323 // Remove the first NAT.
324 ExpectedIptablesCommands stopFirstNat = stopNatCommands("wlan0", "rmnet0");
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900325 mTetherCtrl.disableNat("wlan0", "rmnet0");
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900326 expectIptablesRestoreCommands(stopFirstNat);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900327
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900328 // Remove the last NAT. Expect rules to be cleared.
329 ExpectedIptablesCommands stopLastNat = stopNatCommands("usb0", "rmnet0");
330
331 appendAll(stopLastNat, FLUSH_COMMANDS);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900332 mTetherCtrl.disableNat("usb0", "rmnet0");
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900333 expectIptablesRestoreCommands(stopLastNat);
334
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900335 // Re-add a NAT removed previously: tetherctrl_counters chain rules are not re-added
Luke Huangae038f82018-11-05 11:17:31 +0900336 firstNat = allNewNatCommands("wlan0", "rmnet0", NO_COUNTERS, WITH_IPV6, true);
Remi NGUYEN VAN70a269a2018-03-19 11:24:10 +0900337 mTetherCtrl.enableNat("wlan0", "rmnet0");
338 expectIptablesRestoreCommands(firstNat);
339
340 // Remove it again. Expect rules to be cleared.
341 stopLastNat = stopNatCommands("wlan0", "rmnet0");
342 appendAll(stopLastNat, FLUSH_COMMANDS);
343 mTetherCtrl.disableNat("wlan0", "rmnet0");
344 expectIptablesRestoreCommands(stopLastNat);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900345}
346
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900347TEST_F(TetherControllerTest, TestMultipleUpstreams) {
348 // Start first NAT on first upstream interface. Expect the upstream and NAT rules to be created.
Luke Huangae038f82018-11-05 11:17:31 +0900349 ExpectedIptablesCommands firstNat =
350 allNewNatCommands("wlan0", "rmnet0", WITH_COUNTERS, WITH_IPV6, true);
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900351 mTetherCtrl.enableNat("wlan0", "rmnet0");
352 expectIptablesRestoreCommands(firstNat);
353
354 // Start second NAT, on new upstream. Expect the upstream and NAT rules to be created for IPv4,
355 // but no counter rules for IPv6.
Luke Huangae038f82018-11-05 11:17:31 +0900356 ExpectedIptablesCommands secondNat =
357 allNewNatCommands("wlan0", "v4-rmnet0", WITH_COUNTERS, NO_IPV6, false);
Remi NGUYEN VAN3b47c792018-03-20 14:44:12 +0900358 mTetherCtrl.enableNat("wlan0", "v4-rmnet0");
359 expectIptablesRestoreCommands(secondNat);
360
361 // Pretend that the caller has forgotten that it set up the second NAT, and asks us to do so
362 // again. Expect that we take no action.
363 const ExpectedIptablesCommands NONE = {};
364 mTetherCtrl.enableNat("wlan0", "v4-rmnet0");
365 expectIptablesRestoreCommands(NONE);
366
367 // Remove the second NAT.
368 ExpectedIptablesCommands stopSecondNat = stopNatCommands("wlan0", "v4-rmnet0");
369 mTetherCtrl.disableNat("wlan0", "v4-rmnet0");
370 expectIptablesRestoreCommands(stopSecondNat);
371
372 // Remove the first NAT. Expect rules to be cleared.
373 ExpectedIptablesCommands stopFirstNat = stopNatCommands("wlan0", "rmnet0");
374 appendAll(stopFirstNat, FLUSH_COMMANDS);
375 mTetherCtrl.disableNat("wlan0", "rmnet0");
376 expectIptablesRestoreCommands(stopFirstNat);
377}
378
Lorenzo Colitti09353392017-08-24 14:20:32 +0900379std::string kTetherCounterHeaders = Join(std::vector<std::string> {
Lorenzo Colitti4604b4a2017-08-24 19:21:50 +0900380 "Chain tetherctrl_counters (4 references)",
Lorenzo Colitti09353392017-08-24 14:20:32 +0900381 " pkts bytes target prot opt in out source destination",
382}, '\n');
383
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900384std::string kIPv4TetherCounters = Join(std::vector<std::string> {
Lorenzo Colitti4604b4a2017-08-24 19:21:50 +0900385 "Chain tetherctrl_counters (4 references)",
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900386 " pkts bytes target prot opt in out source destination",
387 " 26 2373 RETURN all -- wlan0 rmnet0 0.0.0.0/0 0.0.0.0/0",
388 " 27 2002 RETURN all -- rmnet0 wlan0 0.0.0.0/0 0.0.0.0/0",
389 " 1040 107471 RETURN all -- bt-pan rmnet0 0.0.0.0/0 0.0.0.0/0",
390 " 1450 1708806 RETURN all -- rmnet0 bt-pan 0.0.0.0/0 0.0.0.0/0",
391}, '\n');
392
393std::string kIPv6TetherCounters = Join(std::vector<std::string> {
Lorenzo Colitti4604b4a2017-08-24 19:21:50 +0900394 "Chain tetherctrl_counters (2 references)",
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900395 " pkts bytes target prot opt in out source destination",
396 " 10000 10000000 RETURN all wlan0 rmnet0 ::/0 ::/0",
397 " 20000 20000000 RETURN all rmnet0 wlan0 ::/0 ::/0",
398}, '\n');
399
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900400void expectTetherStatsEqual(const TetherController::TetherStats& expected,
401 const TetherController::TetherStats& actual) {
402 EXPECT_EQ(expected.intIface, actual.intIface);
403 EXPECT_EQ(expected.extIface, actual.extIface);
404 EXPECT_EQ(expected.rxBytes, actual.rxBytes);
405 EXPECT_EQ(expected.txBytes, actual.txBytes);
406 EXPECT_EQ(expected.rxPackets, actual.rxPackets);
407 EXPECT_EQ(expected.txPackets, actual.txPackets);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900408}
409
410TEST_F(TetherControllerTest, TestGetTetherStats) {
Lorenzo Colitti38fd1362017-09-15 11:40:01 +0900411 // Finding no headers is an error.
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900412 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900413 clearIptablesRestoreOutput();
414
Lorenzo Colitti38fd1362017-09-15 11:40:01 +0900415 // Finding only v4 or only v6 headers is an error.
416 addIptablesRestoreOutput(kTetherCounterHeaders, "");
417 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
418 clearIptablesRestoreOutput();
419
420 addIptablesRestoreOutput("", kTetherCounterHeaders);
421 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
422 clearIptablesRestoreOutput();
423
424 // Finding headers but no stats is not an error.
425 addIptablesRestoreOutput(kTetherCounterHeaders, kTetherCounterHeaders);
426 StatusOr<TetherStatsList> result = mTetherCtrl.getTetherStats();
427 ASSERT_TRUE(isOk(result));
428 TetherStatsList actual = result.value();
429 ASSERT_EQ(0U, actual.size());
430 clearIptablesRestoreOutput();
431
432
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900433 addIptablesRestoreOutput(kIPv6TetherCounters);
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900434 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900435 clearIptablesRestoreOutput();
436
437 // IPv4 and IPv6 counters are properly added together.
438 addIptablesRestoreOutput(kIPv4TetherCounters, kIPv6TetherCounters);
Lorenzo Colitti9a65ac62017-09-04 18:07:56 +0900439 TetherStats expected0("wlan0", "rmnet0", 20002002, 20027, 10002373, 10026);
440 TetherStats expected1("bt-pan", "rmnet0", 1708806, 1450, 107471, 1040);
Lorenzo Colitti38fd1362017-09-15 11:40:01 +0900441 result = mTetherCtrl.getTetherStats();
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900442 ASSERT_TRUE(isOk(result));
Lorenzo Colitti38fd1362017-09-15 11:40:01 +0900443 actual = result.value();
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900444 ASSERT_EQ(2U, actual.size());
445 expectTetherStatsEqual(expected0, result.value()[0]);
446 expectTetherStatsEqual(expected1, result.value()[1]);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900447 clearIptablesRestoreOutput();
448
Lorenzo Colitti09353392017-08-24 14:20:32 +0900449 // No stats: error.
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900450 addIptablesRestoreOutput("", kIPv6TetherCounters);
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900451 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900452 clearIptablesRestoreOutput();
453
454 addIptablesRestoreOutput(kIPv4TetherCounters, "");
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900455 ASSERT_FALSE(isOk(mTetherCtrl.getTetherStats()));
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900456 clearIptablesRestoreOutput();
457
458 // Include only one pair of interfaces and things are fine.
459 std::vector<std::string> counterLines = android::base::Split(kIPv4TetherCounters, "\n");
460 std::vector<std::string> brokenCounterLines = counterLines;
461 counterLines.resize(4);
462 std::string counters = Join(counterLines, "\n") + "\n";
463 addIptablesRestoreOutput(counters, counters);
Lorenzo Colitti9a65ac62017-09-04 18:07:56 +0900464 TetherStats expected1_0("wlan0", "rmnet0", 4004, 54, 4746, 52);
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900465 result = mTetherCtrl.getTetherStats();
466 ASSERT_TRUE(isOk(result));
467 actual = result.value();
468 ASSERT_EQ(1U, actual.size());
469 expectTetherStatsEqual(expected1_0, actual[0]);
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900470 clearIptablesRestoreOutput();
471
472 // But if interfaces aren't paired, it's always an error.
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900473 counterLines.resize(3);
474 counters = Join(counterLines, "\n") + "\n";
475 addIptablesRestoreOutput(counters, counters);
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900476 result = mTetherCtrl.getTetherStats();
477 ASSERT_FALSE(isOk(result));
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900478 clearIptablesRestoreOutput();
479
480 // Token unit test of the fact that we return the stats in the error message which the caller
481 // ignores.
waynema71a0b592018-11-21 13:31:34 +0800482 // Skip header since we only saved the last line we parsed.
483 std::string expectedError = counterLines[2];
Lorenzo Colitti5192bf72017-09-04 13:30:59 +0900484 std::string err = result.status().msg();
Lorenzo Colitti9a8a9ff2017-01-31 19:06:59 +0900485 ASSERT_LE(expectedError.size(), err.size());
486 EXPECT_TRUE(std::equal(expectedError.rbegin(), expectedError.rend(), err.rbegin()));
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900487}
488
Automerger Merge Worker40265052020-03-06 01:42:40 +0000489TEST_F(TetherControllerTest, TestGetTetherStatsWithBpfTetherStatsMap) {
490 SKIP_IF_BPF_NOT_SUPPORTED;
491
492 // Setup BPF tether stats maps. The tether stats of interface rmnet0 comes from two tether
493 // stats map items with different interface index. Therefore, need to sum up both of them
494 // for the tether stats of interface rmnet0.
495 updateMaps(101, "wlan0", 100, 10, 200, 20);
496 updateMaps(102, "rmnet0", 300, 30, 400, 40);
497 updateMaps(103, "rmnet0", 500, 50, 600, 60);
498 const TetherStats expected0("BPFOffloadInterface", "wlan0", 100, 10, 200, 20);
499 const TetherStats expected1("BPFOffloadInterface", "rmnet0", 800, 80, 1000, 100);
500
501 // Setup iptables tether counters. IPv4 and IPv6 counters are added together.
502 addIptablesRestoreOutput(kIPv4TetherCounters, kIPv6TetherCounters);
503 const TetherStats expected2("wlan0", "rmnet0", 20002002, 20027, 10002373, 10026);
504 const TetherStats expected3("bt-pan", "rmnet0", 1708806, 1450, 107471, 1040);
505
506 const StatusOr<TetherStatsList> result = mTetherCtrl.getTetherStats();
507 ASSERT_OK(result);
508 const TetherStatsList& actual = result.value();
509 ASSERT_EQ(4U, actual.size());
510 EXPECT_THAT(actual, Contains(expected0)) << toString(actual);
511 EXPECT_THAT(actual, Contains(expected1)) << toString(actual);
512 EXPECT_THAT(actual, Contains(expected2)) << toString(actual);
513 EXPECT_THAT(actual, Contains(expected3)) << toString(actual);
514 clearIptablesRestoreOutput();
515}
516
Lorenzo Colittia93126d2017-08-24 13:28:19 +0900517} // namespace net
518} // namespace android