1 /*
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 * BandwidthControllerTest.cpp - unit tests for BandwidthController.cpp
17 */
18
19 #include <string>
20 #include <vector>
21
22 #include <inttypes.h>
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27
28 #include <gtest/gtest.h>
29
30 #include <android-base/strings.h>
31 #include <android-base/stringprintf.h>
32
33 #include <netdutils/MockSyscalls.h>
34 #include "BandwidthController.h"
35 #include "Fwmark.h"
36 #include "IptablesBaseTest.h"
37 #include "bpf/BpfUtils.h"
38 #include "netdbpf/bpf_shared.h"
39 #include "tun_interface.h"
40
41 using ::testing::_;
42 using ::testing::ByMove;
43 using ::testing::Invoke;
44 using ::testing::Return;
45 using ::testing::StrictMock;
46
47 using android::base::Join;
48 using android::base::StringPrintf;
49 using android::net::TunInterface;
50 using android::netdutils::UniqueFile;
51 using android::netdutils::status::ok;
52
53 const std::string ACCOUNT_RULES_WITHOUT_BPF =
54 "*filter\n"
55 "-A bw_INPUT -j bw_global_alert\n"
56 "-A bw_INPUT -p esp -j RETURN\n"
57 "-A bw_INPUT -m mark --mark 0x100000/0x100000 -j RETURN\n"
58 "-A bw_INPUT -m owner --socket-exists\n"
59 "-A bw_INPUT -j MARK --or-mark 0x100000\n"
60 "-A bw_OUTPUT -j bw_global_alert\n"
61 "-A bw_OUTPUT -o ipsec+ -j RETURN\n"
62 "-A bw_OUTPUT -m policy --pol ipsec --dir out -j RETURN\n"
63 "-A bw_OUTPUT -m owner --socket-exists\n"
64 "-A bw_costly_shared --jump bw_penalty_box\n"
65 "\n"
66 "-A bw_penalty_box --jump bw_happy_box\n"
67 "-A bw_happy_box --jump bw_data_saver\n"
68 "-A bw_data_saver -j RETURN\n"
69 "-I bw_happy_box -m owner --uid-owner 0-9999 --jump RETURN\n"
70 "COMMIT\n"
71 "*raw\n"
72 "-A bw_raw_PREROUTING -i ipsec+ -j RETURN\n"
73 "-A bw_raw_PREROUTING -m policy --pol ipsec --dir in -j RETURN\n"
74 "-A bw_raw_PREROUTING -m owner --socket-exists\n"
75 "COMMIT\n"
76 "*mangle\n"
77 "-A bw_mangle_POSTROUTING -o ipsec+ -j RETURN\n"
78 "-A bw_mangle_POSTROUTING -m policy --pol ipsec --dir out -j RETURN\n"
79 "-A bw_mangle_POSTROUTING -m owner --socket-exists\n"
80 "-A bw_mangle_POSTROUTING -j MARK --set-mark 0x0/0x100000\n"
81 "\n"
82 "COMMIT\n";
83
84 const std::string ACCOUNT_RULES_WITH_BPF =
85 "*filter\n"
86 "-A bw_INPUT -j bw_global_alert\n"
87 "-A bw_INPUT -p esp -j RETURN\n"
88 "-A bw_INPUT -m mark --mark 0x100000/0x100000 -j RETURN\n"
89 "\n"
90 "-A bw_INPUT -j MARK --or-mark 0x100000\n"
91 "-A bw_OUTPUT -j bw_global_alert\n"
92 "-A bw_OUTPUT -o ipsec+ -j RETURN\n"
93 "-A bw_OUTPUT -m policy --pol ipsec --dir out -j RETURN\n"
94 "\n"
95 "-A bw_costly_shared --jump bw_penalty_box\n" +
96 StringPrintf("-I bw_penalty_box -m bpf --object-pinned %s -j REJECT\n",
97 XT_BPF_BLACKLIST_PROG_PATH) +
98 "-A bw_penalty_box --jump bw_happy_box\n"
99 "-A bw_happy_box --jump bw_data_saver\n"
100 "-A bw_data_saver -j RETURN\n" +
101 StringPrintf("-I bw_happy_box -m bpf --object-pinned %s -j RETURN\n",
102 XT_BPF_WHITELIST_PROG_PATH) +
103 "COMMIT\n"
104 "*raw\n"
105 "-A bw_raw_PREROUTING -i ipsec+ -j RETURN\n"
106 "-A bw_raw_PREROUTING -m policy --pol ipsec --dir in -j RETURN\n" +
107 StringPrintf("-A bw_raw_PREROUTING -m bpf --object-pinned %s\n", XT_BPF_INGRESS_PROG_PATH) +
108 "COMMIT\n"
109 "*mangle\n"
110 "-A bw_mangle_POSTROUTING -o ipsec+ -j RETURN\n"
111 "-A bw_mangle_POSTROUTING -m policy --pol ipsec --dir out -j RETURN\n"
112 "\n"
113 "-A bw_mangle_POSTROUTING -j MARK --set-mark 0x0/0x100000\n" +
114 StringPrintf("-A bw_mangle_POSTROUTING -m bpf --object-pinned %s\n",
115 XT_BPF_EGRESS_PROG_PATH) +
116 "COMMIT\n";
117
118 class BandwidthControllerTest : public IptablesBaseTest {
119 protected:
BandwidthControllerTest()120 BandwidthControllerTest() {
121 BandwidthController::iptablesRestoreFunction = fakeExecIptablesRestoreWithOutput;
122 }
123 BandwidthController mBw;
124 TunInterface mTun;
125
SetUp()126 void SetUp() {
127 ASSERT_EQ(0, mTun.init());
128 }
129
TearDown()130 void TearDown() {
131 mTun.destroy();
132 }
133
expectSetupCommands(const std::string & expectedClean,const std::string & expectedAccounting)134 void expectSetupCommands(const std::string& expectedClean,
135 const std::string& expectedAccounting) {
136 std::string expectedList =
137 "*filter\n"
138 "-S\n"
139 "COMMIT\n";
140
141 std::string expectedFlush =
142 "*filter\n"
143 ":bw_INPUT -\n"
144 ":bw_OUTPUT -\n"
145 ":bw_FORWARD -\n"
146 ":bw_happy_box -\n"
147 ":bw_penalty_box -\n"
148 ":bw_data_saver -\n"
149 ":bw_costly_shared -\n"
150 ":bw_global_alert -\n"
151 "COMMIT\n"
152 "*raw\n"
153 ":bw_raw_PREROUTING -\n"
154 "COMMIT\n"
155 "*mangle\n"
156 ":bw_mangle_POSTROUTING -\n"
157 "COMMIT\n";
158
159 ExpectedIptablesCommands expected = {{ V4, expectedList }};
160 if (expectedClean.size()) {
161 expected.push_back({ V4V6, expectedClean });
162 }
163 expected.push_back({ V4V6, expectedFlush });
164 if (expectedAccounting.size()) {
165 expected.push_back({ V4V6, expectedAccounting });
166 }
167
168 expectIptablesRestoreCommands(expected);
169 }
170
171 using IptOp = BandwidthController::IptOp;
172
runIptablesAlertCmd(IptOp a,const char * b,int64_t c)173 int runIptablesAlertCmd(IptOp a, const char* b, int64_t c) {
174 return mBw.runIptablesAlertCmd(a, b, c);
175 }
176
setCostlyAlert(const std::string & a,int64_t b,int64_t * c)177 int setCostlyAlert(const std::string& a, int64_t b, int64_t* c) {
178 return mBw.setCostlyAlert(a, b, c);
179 }
180
removeCostlyAlert(const std::string & a,int64_t * b)181 int removeCostlyAlert(const std::string& a, int64_t* b) { return mBw.removeCostlyAlert(a, b); }
182
expectUpdateQuota(uint64_t quota)183 void expectUpdateQuota(uint64_t quota) {
184 uintptr_t dummy;
185 FILE* dummyFile = reinterpret_cast<FILE*>(&dummy);
186
187 EXPECT_CALL(mSyscalls, fopen(_, _)).WillOnce(Return(ByMove(UniqueFile(dummyFile))));
188 EXPECT_CALL(mSyscalls, vfprintf(dummyFile, _, _))
189 .WillOnce(Invoke([quota](FILE*, const std::string&, va_list ap) {
190 EXPECT_EQ(quota, va_arg(ap, uint64_t));
191 return 0;
192 }));
193 EXPECT_CALL(mSyscalls, fclose(dummyFile)).WillOnce(Return(ok));
194 }
195
checkBandwithControl(bool useBpf)196 void checkBandwithControl(bool useBpf) {
197 // Pretend no bw_costly_shared_<iface> rules already exist...
198 addIptablesRestoreOutput(
199 "-P OUTPUT ACCEPT\n"
200 "-N bw_costly_shared\n"
201 "-N unrelated\n");
202
203 // ... so none are flushed or deleted.
204 std::string expectedClean = "";
205
206 std::string expectedAccounting =
207 useBpf ? ACCOUNT_RULES_WITH_BPF : ACCOUNT_RULES_WITHOUT_BPF;
208 mBw.setBpfEnabled(useBpf);
209 mBw.enableBandwidthControl();
210 expectSetupCommands(expectedClean, expectedAccounting);
211 }
212
213 StrictMock<android::netdutils::ScopedMockSyscalls> mSyscalls;
214 };
215
TEST_F(BandwidthControllerTest,TestSetupIptablesHooks)216 TEST_F(BandwidthControllerTest, TestSetupIptablesHooks) {
217 // Pretend some bw_costly_shared_<iface> rules already exist...
218 addIptablesRestoreOutput(
219 "-P OUTPUT ACCEPT\n"
220 "-N bw_costly_rmnet_data0\n"
221 "-N bw_costly_shared\n"
222 "-N unrelated\n"
223 "-N bw_costly_rmnet_data7\n");
224
225 // ... and expect that they be flushed and deleted.
226 std::string expectedCleanCmds =
227 "*filter\n"
228 ":bw_costly_rmnet_data0 -\n"
229 "-X bw_costly_rmnet_data0\n"
230 ":bw_costly_rmnet_data7 -\n"
231 "-X bw_costly_rmnet_data7\n"
232 "COMMIT\n";
233
234 mBw.setupIptablesHooks();
235 expectSetupCommands(expectedCleanCmds, "");
236 }
237
TEST_F(BandwidthControllerTest,TestCheckUidBillingMask)238 TEST_F(BandwidthControllerTest, TestCheckUidBillingMask) {
239 uint32_t uidBillingMask = Fwmark::getUidBillingMask();
240
241 // If mask is non-zero, and mask & mask-1 is equal to 0, then the mask is a power of two.
242 bool isPowerOfTwo = uidBillingMask && (uidBillingMask & (uidBillingMask - 1)) == 0;
243
244 // Must be exactly a power of two
245 EXPECT_TRUE(isPowerOfTwo);
246 }
247
TEST_F(BandwidthControllerTest,TestEnableBandwidthControlWithBpf)248 TEST_F(BandwidthControllerTest, TestEnableBandwidthControlWithBpf) {
249 checkBandwithControl(true);
250 }
251
TEST_F(BandwidthControllerTest,TestEnableBandwidthControlWithoutBpf)252 TEST_F(BandwidthControllerTest, TestEnableBandwidthControlWithoutBpf) {
253 checkBandwithControl(false);
254 }
255
TEST_F(BandwidthControllerTest,TestDisableBandwidthControl)256 TEST_F(BandwidthControllerTest, TestDisableBandwidthControl) {
257 // Pretend some bw_costly_shared_<iface> rules already exist...
258 addIptablesRestoreOutput(
259 "-P OUTPUT ACCEPT\n"
260 "-N bw_costly_rmnet_data0\n"
261 "-N bw_costly_shared\n"
262 "-N unrelated\n"
263 "-N bw_costly_rmnet_data7\n");
264
265 // ... and expect that they be flushed.
266 std::string expectedCleanCmds =
267 "*filter\n"
268 ":bw_costly_rmnet_data0 -\n"
269 ":bw_costly_rmnet_data7 -\n"
270 "COMMIT\n";
271
272 mBw.disableBandwidthControl();
273 expectSetupCommands(expectedCleanCmds, "");
274 }
275
TEST_F(BandwidthControllerTest,TestEnableDataSaver)276 TEST_F(BandwidthControllerTest, TestEnableDataSaver) {
277 mBw.enableDataSaver(true);
278 std::string expected4 =
279 "*filter\n"
280 ":bw_data_saver -\n"
281 "-A bw_data_saver --jump REJECT\n"
282 "COMMIT\n";
283 std::string expected6 =
284 "*filter\n"
285 ":bw_data_saver -\n"
286 "-A bw_data_saver -p icmpv6 --icmpv6-type packet-too-big -j RETURN\n"
287 "-A bw_data_saver -p icmpv6 --icmpv6-type router-solicitation -j RETURN\n"
288 "-A bw_data_saver -p icmpv6 --icmpv6-type router-advertisement -j RETURN\n"
289 "-A bw_data_saver -p icmpv6 --icmpv6-type neighbour-solicitation -j RETURN\n"
290 "-A bw_data_saver -p icmpv6 --icmpv6-type neighbour-advertisement -j RETURN\n"
291 "-A bw_data_saver -p icmpv6 --icmpv6-type redirect -j RETURN\n"
292 "-A bw_data_saver --jump REJECT\n"
293 "COMMIT\n";
294 expectIptablesRestoreCommands({
295 {V4, expected4},
296 {V6, expected6},
297 });
298
299 mBw.enableDataSaver(false);
300 std::string expected = {
301 "*filter\n"
302 ":bw_data_saver -\n"
303 "-A bw_data_saver --jump RETURN\n"
304 "COMMIT\n"
305 };
306 expectIptablesRestoreCommands({
307 {V4, expected},
308 {V6, expected},
309 });
310 }
311
makeInterfaceQuotaCommands(const std::string & iface,int ruleIndex,int64_t quota)312 const std::vector<std::string> makeInterfaceQuotaCommands(const std::string& iface, int ruleIndex,
313 int64_t quota) {
314 const std::string chain = "bw_costly_" + iface;
315 const char* c_chain = chain.c_str();
316 const char* c_iface = iface.c_str();
317 std::vector<std::string> cmds = {
318 "*filter",
319 StringPrintf(":%s -", c_chain),
320 StringPrintf("-A %s -j bw_penalty_box", c_chain),
321 StringPrintf("-I bw_INPUT %d -i %s --jump %s", ruleIndex, c_iface, c_chain),
322 StringPrintf("-I bw_OUTPUT %d -o %s --jump %s", ruleIndex, c_iface, c_chain),
323 StringPrintf("-A bw_FORWARD -i %s --jump %s", c_iface, c_chain),
324 StringPrintf("-A bw_FORWARD -o %s --jump %s", c_iface, c_chain),
325 StringPrintf("-A %s -m quota2 ! --quota %" PRIu64 " --name %s --jump REJECT", c_chain,
326 quota, c_iface),
327 "COMMIT\n",
328 };
329 return {Join(cmds, "\n")};
330 }
331
removeInterfaceQuotaCommands(const std::string & iface)332 const std::vector<std::string> removeInterfaceQuotaCommands(const std::string& iface) {
333 const std::string chain = "bw_costly_" + iface;
334 const char* c_chain = chain.c_str();
335 const char* c_iface = iface.c_str();
336 std::vector<std::string> cmds = {
337 "*filter",
338 StringPrintf("-D bw_INPUT -i %s --jump %s", c_iface, c_chain),
339 StringPrintf("-D bw_OUTPUT -o %s --jump %s", c_iface, c_chain),
340 StringPrintf("-D bw_FORWARD -i %s --jump %s", c_iface, c_chain),
341 StringPrintf("-D bw_FORWARD -o %s --jump %s", c_iface, c_chain),
342 StringPrintf("-F %s", c_chain),
343 StringPrintf("-X %s", c_chain),
344 "COMMIT\n",
345 };
346 return {Join(cmds, "\n")};
347 }
348
TEST_F(BandwidthControllerTest,TestSetInterfaceQuota)349 TEST_F(BandwidthControllerTest, TestSetInterfaceQuota) {
350 constexpr uint64_t kOldQuota = 123456;
351 const std::string iface = mTun.name();
352 std::vector<std::string> expected = makeInterfaceQuotaCommands(iface, 1, kOldQuota);
353
354 EXPECT_EQ(0, mBw.setInterfaceQuota(iface, kOldQuota));
355 expectIptablesRestoreCommands(expected);
356
357 constexpr uint64_t kNewQuota = kOldQuota + 1;
358 expected = {};
359 expectUpdateQuota(kNewQuota);
360 EXPECT_EQ(0, mBw.setInterfaceQuota(iface, kNewQuota));
361 expectIptablesRestoreCommands(expected);
362
363 expected = removeInterfaceQuotaCommands(iface);
364 EXPECT_EQ(0, mBw.removeInterfaceQuota(iface));
365 expectIptablesRestoreCommands(expected);
366 }
367
makeInterfaceSharedQuotaCommands(const std::string & iface,int ruleIndex,int64_t quota,bool insertQuota)368 const std::vector<std::string> makeInterfaceSharedQuotaCommands(const std::string& iface,
369 int ruleIndex, int64_t quota,
370 bool insertQuota) {
371 const std::string chain = "bw_costly_shared";
372 const char* c_chain = chain.c_str();
373 const char* c_iface = iface.c_str();
374 std::vector<std::string> cmds = {
375 "*filter",
376 StringPrintf("-I bw_INPUT %d -i %s --jump %s", ruleIndex, c_iface, c_chain),
377 StringPrintf("-I bw_OUTPUT %d -o %s --jump %s", ruleIndex, c_iface, c_chain),
378 StringPrintf("-A bw_FORWARD -i %s --jump %s", c_iface, c_chain),
379 StringPrintf("-A bw_FORWARD -o %s --jump %s", c_iface, c_chain),
380 };
381 if (insertQuota) {
382 cmds.push_back(StringPrintf(
383 "-I %s -m quota2 ! --quota %" PRIu64 " --name shared --jump REJECT", c_chain, quota));
384 }
385 cmds.push_back("COMMIT\n");
386 return {Join(cmds, "\n")};
387 }
388
removeInterfaceSharedQuotaCommands(const std::string & iface,int64_t quota,bool deleteQuota)389 const std::vector<std::string> removeInterfaceSharedQuotaCommands(const std::string& iface,
390 int64_t quota, bool deleteQuota) {
391 const std::string chain = "bw_costly_shared";
392 const char* c_chain = chain.c_str();
393 const char* c_iface = iface.c_str();
394 std::vector<std::string> cmds = {
395 "*filter",
396 StringPrintf("-D bw_INPUT -i %s --jump %s", c_iface, c_chain),
397 StringPrintf("-D bw_OUTPUT -o %s --jump %s", c_iface, c_chain),
398 StringPrintf("-D bw_FORWARD -i %s --jump %s", c_iface, c_chain),
399 StringPrintf("-D bw_FORWARD -o %s --jump %s", c_iface, c_chain),
400 };
401 if (deleteQuota) {
402 cmds.push_back(StringPrintf(
403 "-D %s -m quota2 ! --quota %" PRIu64 " --name shared --jump REJECT", c_chain, quota));
404 }
405 cmds.push_back("COMMIT\n");
406 return {Join(cmds, "\n")};
407 }
408
TEST_F(BandwidthControllerTest,TestSetInterfaceSharedQuotaDuplicate)409 TEST_F(BandwidthControllerTest, TestSetInterfaceSharedQuotaDuplicate) {
410 constexpr uint64_t kQuota = 123456;
411 const std::string iface = mTun.name();
412 std::vector<std::string> expected = makeInterfaceSharedQuotaCommands(iface, 1, 123456, true);
413 EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kQuota));
414 expectIptablesRestoreCommands(expected);
415
416 expected = {};
417 EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kQuota));
418 expectIptablesRestoreCommands(expected);
419
420 expected = removeInterfaceSharedQuotaCommands(iface, kQuota, true);
421 EXPECT_EQ(0, mBw.removeInterfaceSharedQuota(iface));
422 expectIptablesRestoreCommands(expected);
423 }
424
TEST_F(BandwidthControllerTest,TestSetInterfaceSharedQuotaUpdate)425 TEST_F(BandwidthControllerTest, TestSetInterfaceSharedQuotaUpdate) {
426 constexpr uint64_t kOldQuota = 123456;
427 const std::string iface = mTun.name();
428 std::vector<std::string> expected = makeInterfaceSharedQuotaCommands(iface, 1, kOldQuota, true);
429 EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kOldQuota));
430 expectIptablesRestoreCommands(expected);
431
432 constexpr uint64_t kNewQuota = kOldQuota + 1;
433 expected = {};
434 expectUpdateQuota(kNewQuota);
435 EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kNewQuota));
436 expectIptablesRestoreCommands(expected);
437
438 expected = removeInterfaceSharedQuotaCommands(iface, kNewQuota, true);
439 EXPECT_EQ(0, mBw.removeInterfaceSharedQuota(iface));
440 expectIptablesRestoreCommands(expected);
441 }
442
TEST_F(BandwidthControllerTest,TestSetInterfaceSharedQuotaTwoInterfaces)443 TEST_F(BandwidthControllerTest, TestSetInterfaceSharedQuotaTwoInterfaces) {
444 constexpr uint64_t kQuota = 123456;
445 const std::vector<std::string> ifaces{
446 {"a" + mTun.name()},
447 {"b" + mTun.name()},
448 };
449
450 for (const auto& iface : ifaces) {
451 // Quota rule is only added when the total number of
452 // interfaces transitions from 0 -> 1.
453 bool first = (iface == ifaces[0]);
454 auto expected = makeInterfaceSharedQuotaCommands(iface, 1, kQuota, first);
455 EXPECT_EQ(0, mBw.setInterfaceSharedQuota(iface, kQuota));
456 expectIptablesRestoreCommands(expected);
457 }
458
459 for (const auto& iface : ifaces) {
460 // Quota rule is only removed when the total number of
461 // interfaces transitions from 1 -> 0.
462 bool last = (iface == ifaces[1]);
463 auto expected = removeInterfaceSharedQuotaCommands(iface, kQuota, last);
464 EXPECT_EQ(0, mBw.removeInterfaceSharedQuota(iface));
465 expectIptablesRestoreCommands(expected);
466 }
467 }
468
TEST_F(BandwidthControllerTest,IptablesAlertCmd)469 TEST_F(BandwidthControllerTest, IptablesAlertCmd) {
470 std::vector<std::string> expected = {
471 "*filter\n"
472 "-I bw_global_alert -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
473 "COMMIT\n"};
474 EXPECT_EQ(0, runIptablesAlertCmd(IptOp::IptOpInsert, "MyWonderfulAlert", 123456));
475 expectIptablesRestoreCommands(expected);
476
477 expected = {
478 "*filter\n"
479 "-D bw_global_alert -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
480 "COMMIT\n"};
481 EXPECT_EQ(0, runIptablesAlertCmd(IptOp::IptOpDelete, "MyWonderfulAlert", 123456));
482 expectIptablesRestoreCommands(expected);
483 }
484
TEST_F(BandwidthControllerTest,CostlyAlert)485 TEST_F(BandwidthControllerTest, CostlyAlert) {
486 const int64_t kQuota = 123456;
487 int64_t alertBytes = 0;
488
489 std::vector<std::string> expected = {
490 "*filter\n"
491 "-A bw_costly_shared -m quota2 ! --quota 123456 --name sharedAlert\n"
492 "COMMIT\n"
493 };
494 EXPECT_EQ(0, setCostlyAlert("shared", kQuota, &alertBytes));
495 EXPECT_EQ(kQuota, alertBytes);
496 expectIptablesRestoreCommands(expected);
497
498 expected = {};
499 expectUpdateQuota(kQuota);
500 EXPECT_EQ(0, setCostlyAlert("shared", kQuota + 1, &alertBytes));
501 EXPECT_EQ(kQuota + 1, alertBytes);
502 expectIptablesRestoreCommands(expected);
503
504 expected = {
505 "*filter\n"
506 "-D bw_costly_shared -m quota2 ! --quota 123457 --name sharedAlert\n"
507 "COMMIT\n"
508 };
509 EXPECT_EQ(0, removeCostlyAlert("shared", &alertBytes));
510 EXPECT_EQ(0, alertBytes);
511 expectIptablesRestoreCommands(expected);
512 }
513
TEST_F(BandwidthControllerTest,ManipulateSpecialApps)514 TEST_F(BandwidthControllerTest, ManipulateSpecialApps) {
515 std::vector<const char *> appUids = { "1000", "1001", "10012" };
516
517 std::vector<std::string> expected = {
518 "*filter\n"
519 "-I bw_happy_box -m owner --uid-owner 1000 --jump RETURN\n"
520 "-I bw_happy_box -m owner --uid-owner 1001 --jump RETURN\n"
521 "-I bw_happy_box -m owner --uid-owner 10012 --jump RETURN\n"
522 "COMMIT\n"
523 };
524 EXPECT_EQ(0, mBw.addNiceApps(appUids.size(), const_cast<char**>(&appUids[0])));
525 expectIptablesRestoreCommands(expected);
526
527 expected = {
528 "*filter\n"
529 "-D bw_penalty_box -m owner --uid-owner 1000 --jump REJECT\n"
530 "-D bw_penalty_box -m owner --uid-owner 1001 --jump REJECT\n"
531 "-D bw_penalty_box -m owner --uid-owner 10012 --jump REJECT\n"
532 "COMMIT\n"
533 };
534 EXPECT_EQ(0, mBw.removeNaughtyApps(appUids.size(), const_cast<char**>(&appUids[0])));
535 expectIptablesRestoreCommands(expected);
536 }
537