netd: Idletimer vs Nat vs Bandwidth controllers
* modified iptables users to work in controller specific custom chains.
- each controller only works withing his own custom chains and not the
top level ones (INPUT, OUTPUT, FORWARD, POSTROUTING,...)
- CommandListener now invokes setupIptablesHooks() for each controller
once. That is the only time they are allowed to access the top-level
chains.
* Added idletimer controller.
From https://android-git.corp.google.com/g/#/c/180769/2
- supported commands
. ndc idletimer enable
. ndc idletimer add <iface> <timeout>
. ndc idletimer remove <iface> <timeout_used_during_add>
There is a framework change elsewhere that receives netlink messages.
Signed-off-by: Ashish Sharma <ashishsharma@google.com>
Signed-off-by: JP Abgrall <jpa@google.com>
Change-Id: Ia57450c09166ce20f21d1e3b49047ef1e98f2a3d
diff --git a/IdletimerController.cpp b/IdletimerController.cpp
new file mode 100644
index 0000000..efe4f09
--- /dev/null
+++ b/IdletimerController.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define LOG_NDEBUG 0
+
+/*
+ * MODUS OPERANDI
+ * --------------
+ *
+ * IPTABLES command sequence:
+ *
+ * iptables -F
+ *
+ * iptables -t nat -F idletimer_PREROUTING
+ * iptables -t nat -F idletimer_POSTROUTING
+ *
+ *
+ * iptables -t nat -N idletimer_PREROUTING
+ * iptables -t nat -N idletimer_POSTROUTING
+ *
+ * iptables -t nat -D PREROUTING -j idletimer_PREROUTING
+ * iptables -t nat -D POSTROUTING -j idletimer_POSTROUTING
+ *
+ *
+ * iptables -t nat -I PREROUTING -j idletimer_PREROUTING
+ * iptables -t nat -I POSTROUTING -j idletimer_POSTROUTING
+ *
+ * # For notifications to work the lable name must match the name of a valid interface.
+ * # If the label name does match an interface, the rules will be a no-op.
+ *
+ * iptables -t nat -A idletimer_PREROUTING -i rmnet0 -j IDLETIMER --timeout 5 --label test-chain --send_nl_msg 1
+ * iptables -t nat -A idletimer_POSTROUTING -o rmnet0 -j IDLETIMER --timeout 5 --label test-chain --send_nl_msg 1
+ *
+ * iptables -nxvL -t nat
+ *
+ * =================
+ *
+ * ndc command sequence
+ * ------------------
+ * ndc idletimer enable
+ * ndc idletimer add <iface> <timeout>
+ * ndc idletimer remove <iface> <timeout>
+ *
+ * Monitor effect on the iptables chains after each step using:
+ * iptables -nxvL -t nat
+ *
+ * Remember that the timeout value has to be same at the time of the
+ * removal.
+ *
+ * Note that currently if the name of the iface is incorrect, iptables
+ * will setup rules without checking if it is the name of a valid
+ * interface (although no notifications will ever be received). It is
+ * the responsibility of code in Java land to ensure that the interface name
+ * is correct. The benefit of this, is that idletimers can be setup on
+ * interfaces than come and go.
+ *
+ * A remove should be called for each add command issued during cleanup, as duplicate
+ * entries of the rule may exist and will all have to removed.
+ *
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <cutils/properties.h>
+
+#define LOG_TAG "IdletimerController"
+#include <cutils/log.h>
+
+#include "IdletimerController.h"
+#include "NetdConstants.h"
+
+extern "C" int system_nosh(const char *command);
+
+IdletimerController::IdletimerController() {
+}
+
+IdletimerController::~IdletimerController() {
+}
+/* return 0 or non-zero */
+int IdletimerController::runIpxtablesCmd(const char *cmd) {
+ char *buffer;
+ size_t len = strnlen(cmd, 255);
+ int res;
+
+ if (len == 255) {
+ ALOGE("command too long");
+ return -1;
+ }
+
+ asprintf(&buffer, "%s %s", IPTABLES_PATH, cmd);
+ res = system_nosh(buffer);
+ ALOGV("%s #%d", buffer, res);
+ free(buffer);
+
+ return res;
+}
+
+bool IdletimerController::setupIptablesHooks() {
+ runIpxtablesCmd("-t nat -D PREROUTING -j idletimer_nat_PREROUTING");
+ runIpxtablesCmd("-t nat -F idletimer_nat_PREROUTING");
+ runIpxtablesCmd("-t nat -N idletimer_nat_PREROUTING");
+
+ runIpxtablesCmd("-t nat -D POSTROUTING -j idletimer_nat_POSTROUTING");
+ runIpxtablesCmd("-t nat -F idletimer_nat_POSTROUTING");
+ runIpxtablesCmd("-t nat -N idletimer_nat_POSTROUTING");
+
+ if (runIpxtablesCmd("-t nat -I PREROUTING -j idletimer_nat_PREROUTING")
+ || runIpxtablesCmd("-t nat -I POSTROUTING -j idletimer_nat_POSTROUTING")) {
+ return false;
+ }
+ return true;
+}
+
+int IdletimerController::setDefaults() {
+ if (runIpxtablesCmd("-t nat -F idletimer_nat_PREROUTING")
+ || runIpxtablesCmd("-t nat -F idletimer_nat_POSTROUTING") )
+ return -1;
+ return 0;
+}
+
+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) {
+ int res;
+ char *buffer;
+ asprintf(&buffer, "-t nat -%c idletimer_nat_PREROUTING -i %s -j IDLETIMER"
+ " --timeout %u --label %s --send_nl_msg 1",
+ (op == IptOpAdd) ? 'A' : 'D', iface, timeout, iface);
+ res = runIpxtablesCmd(buffer);
+ free(buffer);
+
+ asprintf(&buffer, "-t nat -%c idletimer_nat_POSTROUTING -o %s -j IDLETIMER"
+ " --timeout %u --label %s --send_nl_msg 1",
+ (op == IptOpAdd) ? 'A' : 'D', iface, timeout, iface);
+ res |= runIpxtablesCmd(buffer);
+ free(buffer);
+
+ return res;
+}
+
+int IdletimerController::addInterfaceIdletimer(const char *iface, uint32_t timeout) {
+ return modifyInterfaceIdletimer(IptOpAdd, iface, timeout);
+}
+
+int IdletimerController::removeInterfaceIdletimer(const char *iface, uint32_t timeout) {
+ return modifyInterfaceIdletimer(IptOpDelete, iface, timeout);
+}