Idletimer-related commands porting
Test: built, flashed, booted
system/netd/tests/runtests.sh passes
Change-Id: I10eec44acca8e4d5a7c8de64b89590e3cccda597
diff --git a/server/CommandListener.cpp b/server/CommandListener.cpp
index 27b117e..3730bce 100644
--- a/server/CommandListener.cpp
+++ b/server/CommandListener.cpp
@@ -114,7 +114,7 @@
registerLockingCmd(new ListTtysCmd());
registerLockingCmd(new PppdCmd());
registerLockingCmd(new BandwidthControlCmd(), gCtls->bandwidthCtrl.lock);
- registerLockingCmd(new IdletimerControlCmd());
+ registerLockingCmd(new IdletimerControlCmd(), gCtls->idletimerCtrl.lock);
registerLockingCmd(new ResolverCmd());
registerLockingCmd(new FirewallCmd(), gCtls->firewallCtrl.lock);
registerLockingCmd(new ClatdCmd());
@@ -972,23 +972,6 @@
ALOGV("idletimerctrlcmd: argc=%d %s %s ...", argc, argv[0], argv[1]);
- if (!strcmp(argv[1], "enable")) {
- if (0 != gCtls->idletimerCtrl.enableIdletimerControl()) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
- } else {
- cli->sendMsg(ResponseCode::CommandOkay, "Enable success", false);
- }
- return 0;
-
- }
- if (!strcmp(argv[1], "disable")) {
- if (0 != gCtls->idletimerCtrl.disableIdletimerControl()) {
- cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
- } else {
- cli->sendMsg(ResponseCode::CommandOkay, "Disable success", false);
- }
- return 0;
- }
if (!strcmp(argv[1], "add")) {
if (argc != 5) {
cli->sendMsg(ResponseCode::CommandSyntaxError, "Missing argument", false);
diff --git a/server/IdletimerController.cpp b/server/IdletimerController.cpp
index 5c0cc86..acb8c6a 100644
--- a/server/IdletimerController.cpp
+++ b/server/IdletimerController.cpp
@@ -138,29 +138,6 @@
return true;
}
-int IdletimerController::setDefaults() {
- std::vector<std::string> cmds = {
- "*raw",
- StringPrintf(":%s -", LOCAL_RAW_PREROUTING),
- "COMMIT",
- "*mangle",
- StringPrintf(":%s -", LOCAL_MANGLE_POSTROUTING),
- "COMMIT\n",
- };
-
- return execIptablesRestore(V4V6, Join(cmds, '\n'));
-}
-
-int IdletimerController::enableIdletimerControl() {
- int res = setDefaults();
- return res;
-}
-
-int IdletimerController::disableIdletimerControl() {
- int res = setDefaults();
- return res;
-}
-
int IdletimerController::modifyInterfaceIdletimer(IptOp op, const char *iface,
uint32_t timeout,
const char *classLabel) {
@@ -181,7 +158,7 @@
"COMMIT\n",
};
- return execIptablesRestore(V4V6, Join(cmds, '\n'));
+ return (execIptablesRestore(V4V6, Join(cmds, '\n')) == 0) ? 0 : -EREMOTEIO;
}
int IdletimerController::addInterfaceIdletimer(const char *iface,
diff --git a/server/IdletimerController.h b/server/IdletimerController.h
index 87e0b4e..5cd162c 100644
--- a/server/IdletimerController.h
+++ b/server/IdletimerController.h
@@ -26,8 +26,6 @@
IdletimerController();
virtual ~IdletimerController();
- int enableIdletimerControl();
- int disableIdletimerControl();
int addInterfaceIdletimer(const char *iface, uint32_t timeout,
const char *classLabel);
int removeInterfaceIdletimer(const char *iface, uint32_t timeout,
@@ -36,10 +34,10 @@
static const char* LOCAL_RAW_PREROUTING;
static const char* LOCAL_MANGLE_POSTROUTING;
+ std::mutex lock;
- private:
+ private:
enum IptOp { IptOpAdd, IptOpDelete };
- int setDefaults();
int runIpxtablesCmd(int argc, const char **cmd);
int modifyInterfaceIdletimer(IptOp op, const char *iface, uint32_t timeout,
const char *classLabel);
diff --git a/server/IdletimerControllerTest.cpp b/server/IdletimerControllerTest.cpp
index ace3fd9..30c2298 100644
--- a/server/IdletimerControllerTest.cpp
+++ b/server/IdletimerControllerTest.cpp
@@ -40,29 +40,6 @@
expectIptablesRestoreCommands(ExpectedIptablesCommands{});
}
-TEST_F(IdletimerControllerTest, TestEnableDisable) {
- std::vector<std::string> expected = {
- "*raw\n"
- ":idletimer_raw_PREROUTING -\n"
- "COMMIT\n"
- "*mangle\n"
- ":idletimer_mangle_POSTROUTING -\n"
- "COMMIT\n",
- };
-
- mIt.enableIdletimerControl();
- expectIptablesRestoreCommands(expected);
-
- mIt.enableIdletimerControl();
- expectIptablesRestoreCommands(expected);
-
- mIt.disableIdletimerControl();
- expectIptablesRestoreCommands(expected);
-
- mIt.disableIdletimerControl();
- expectIptablesRestoreCommands(expected);
-}
-
const std::vector<std::string> makeAddRemoveCommands(bool add) {
const char *op = add ? "-A" : "-D";
std::vector<std::string> cmds = {
diff --git a/server/NetdNativeService.cpp b/server/NetdNativeService.cpp
index 12c78ef..c155ac1 100644
--- a/server/NetdNativeService.cpp
+++ b/server/NetdNativeService.cpp
@@ -747,5 +747,33 @@
return binder::Status::ok();
}
+binder::Status NetdNativeService::idletimerAddInterface(const std::string& ifName, int32_t timeout,
+ const std::string& classLabel) {
+ NETD_LOCKING_RPC(NETWORK_STACK, gCtls->idletimerCtrl.lock);
+ auto entry = gLog.newEntry()
+ .prettyFunction(__PRETTY_FUNCTION__)
+ .arg(ifName)
+ .arg(timeout)
+ .arg(classLabel);
+ int res =
+ gCtls->idletimerCtrl.addInterfaceIdletimer(ifName.c_str(), timeout, classLabel.c_str());
+ gLog.log(entry.returns(res).withAutomaticDuration());
+ return statusFromErrcode(res);
+}
+
+binder::Status NetdNativeService::idletimerRemoveInterface(const std::string& ifName,
+ int32_t timeout,
+ const std::string& classLabel) {
+ NETD_LOCKING_RPC(NETWORK_STACK, gCtls->idletimerCtrl.lock);
+ auto entry = gLog.newEntry()
+ .prettyFunction(__PRETTY_FUNCTION__)
+ .arg(ifName)
+ .arg(timeout)
+ .arg(classLabel);
+ int res = gCtls->idletimerCtrl.removeInterfaceIdletimer(ifName.c_str(), timeout,
+ classLabel.c_str());
+ gLog.log(entry.returns(res).withAutomaticDuration());
+ return statusFromErrcode(res);
+}
} // namespace net
} // namespace android
diff --git a/server/NetdNativeService.h b/server/NetdNativeService.h
index 6ae5c89..3023f80 100644
--- a/server/NetdNativeService.h
+++ b/server/NetdNativeService.h
@@ -194,6 +194,12 @@
int32_t oKey);
binder::Status removeVirtualTunnelInterface(const std::string& deviceName);
+
+ // Idletimer-related commands
+ binder::Status idletimerAddInterface(const std::string& ifName, int32_t timeout,
+ const std::string& classLabel) override;
+ binder::Status idletimerRemoveInterface(const std::string& ifName, int32_t timeout,
+ const std::string& classLabel) override;
};
} // namespace net
diff --git a/server/binder/android/net/INetd.aidl b/server/binder/android/net/INetd.aidl
index 6ab6183..9401e92 100644
--- a/server/binder/android/net/INetd.aidl
+++ b/server/binder/android/net/INetd.aidl
@@ -563,4 +563,32 @@
* running on the device.
*/
boolean trafficCheckBpfStatsEnable();
+
+ /**
+ * Add idletimer for specific interface
+ *
+ * @param ifName Name of target interface
+ * @param timeout The time in seconds that will trigger idletimer
+ * @param classLabel The unique identifier for this idletimer
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the the failure.
+ */
+ void idletimerAddInterface(
+ in @utf8InCpp String ifName,
+ int timeout,
+ in @utf8InCpp String classLabel);
+
+ /**
+ * Remove idletimer for specific interface
+ *
+ * @param ifName Name of target interface
+ * @param timeout The time in seconds that will trigger idletimer
+ * @param classLabel The unique identifier for this idletimer
+ * @throws ServiceSpecificException in case of failure, with an error code indicating the
+ * cause of the the failure.
+ */
+ void idletimerRemoveInterface(
+ in @utf8InCpp String ifName,
+ int timeout,
+ in @utf8InCpp String classLabel);
}
diff --git a/tests/binder_test.cpp b/tests/binder_test.cpp
index 689e2e6..e97d191 100644
--- a/tests/binder_test.cpp
+++ b/tests/binder_test.cpp
@@ -57,6 +57,8 @@
#define IP6TABLES_PATH "/system/bin/ip6tables"
#define IPTABLES_PATH "/system/bin/iptables"
#define TUN_DEV "/dev/tun"
+#define RAW_TABLE "raw"
+#define MANGLE_TABLE "mangle"
using namespace android;
using namespace android::base;
@@ -150,7 +152,6 @@
static std::vector<std::string> runCommand(const std::string& command) {
std::vector<std::string> lines;
-
FILE *f = popen(command.c_str(), "r"); // NOLINT(cert-env33-c)
if (f == nullptr) {
perror("popen");
@@ -958,3 +959,78 @@
expectNoTestCounterRules();
}
+namespace {
+
+constexpr char chainName_LOCAL_RAW_PREROUTING[] = "idletimer_raw_PREROUTING";
+constexpr char chainName_MANGLE_POSTROUTING[] = "idletimer_mangle_POSTROUTING";
+
+static std::vector<std::string> listIptablesRuleByTable(const char* binary, const char* table,
+ const char* chainName) {
+ std::string command = StringPrintf("%s -t %s -w -n -v -L %s", binary, table, chainName);
+ return runCommand(command);
+}
+
+bool iptablesIdleTimerInterfcaeRuleExists(const char* binary, const char* chainName,
+ const std::string& expectedInterface,
+ const std::string& expectedRule, const char* table) {
+ std::vector<std::string> rules = listIptablesRuleByTable(binary, table, chainName);
+ for (const auto& rule : rules) {
+ if (rule.find(expectedInterface) != std::string::npos) {
+ if (rule.find(expectedRule) != std::string::npos) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void expectIdletimerInterfaceRuleExists(const std::string& ifname, int timeout,
+ const std::string& classLable) {
+ std::string IdletimerRule =
+ StringPrintf("timeout:%u label:%s send_nl_msg:1", timeout, classLable.c_str());
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
+ EXPECT_TRUE(iptablesIdleTimerInterfcaeRuleExists(binary, chainName_LOCAL_RAW_PREROUTING,
+ ifname, IdletimerRule, RAW_TABLE));
+ EXPECT_TRUE(iptablesIdleTimerInterfcaeRuleExists(binary, chainName_MANGLE_POSTROUTING,
+ ifname, IdletimerRule, MANGLE_TABLE));
+ }
+}
+
+void expectIdletimerInterfaceRuleNotExists(const std::string& ifname, int timeout,
+ const std::string& classLable) {
+ std::string IdletimerRule =
+ StringPrintf("timeout:%u label:%s send_nl_msg:1", timeout, classLable.c_str());
+ for (const auto& binary : {IPTABLES_PATH, IP6TABLES_PATH}) {
+ EXPECT_FALSE(iptablesIdleTimerInterfcaeRuleExists(binary, chainName_LOCAL_RAW_PREROUTING,
+ ifname, IdletimerRule, RAW_TABLE));
+ EXPECT_FALSE(iptablesIdleTimerInterfcaeRuleExists(binary, chainName_MANGLE_POSTROUTING,
+ ifname, IdletimerRule, MANGLE_TABLE));
+ }
+}
+
+TEST_F(BinderTest, TestIdletimerAddRemoveInterface) {
+ // TODO: We will get error in if expectIdletimerInterfaceRuleNotExists if there are the same
+ // rule in the table. Because we only check the result after calling remove function. We might
+ // check the actual rule which is removed by our function (maybe compare the results between
+ // calling function before and after)
+ binder::Status status;
+ const struct TestData {
+ const std::string ifname;
+ int32_t timeout;
+ const std::string classLabel;
+ } idleTestData[] = {
+ {"wlan0", 1234, "happyday"},
+ {"rmnet_data0", 4567, "friday"},
+ };
+ for (const auto& td : idleTestData) {
+ status = mNetd->idletimerAddInterface(td.ifname, td.timeout, td.classLabel);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectIdletimerInterfaceRuleExists(td.ifname, td.timeout, td.classLabel);
+
+ status = mNetd->idletimerRemoveInterface(td.ifname, td.timeout, td.classLabel);
+ EXPECT_TRUE(status.isOk()) << status.exceptionMessage();
+ expectIdletimerInterfaceRuleNotExists(td.ifname, td.timeout, td.classLabel);
+ }
+}
+
+} // namespace
\ No newline at end of file