OSDN Git Service

netd: Plumb interface throttling
authorSan Mehat <san@google.com>
Wed, 7 Apr 2010 22:21:36 +0000 (15:21 -0700)
committerSan Mehat <san@google.com>
Wed, 7 Apr 2010 22:24:36 +0000 (15:24 -0700)
Change-Id: I9092a37b3d5f2bfa4f49ddc473d0a5490abaae8f
Signed-off-by: San Mehat <san@google.com>
Android.mk
CommandListener.cpp
ThrottleController.cpp [new file with mode: 0644]
ThrottleController.h [new file with mode: 0644]
logwrapper.c

index e20f5ee..600f36e 100644 (file)
@@ -21,7 +21,8 @@ LOCAL_SRC_FILES:=                                      \
                   PppController.cpp                    \
                   PanController.cpp                    \
                   SoftapController.cpp                 \
-                  UsbController.cpp
+                  UsbController.cpp                    \
+                  ThrottleController.cpp
 
 LOCAL_MODULE:= netd
 
index c16e0ed..2b7d4f6 100644 (file)
@@ -31,6 +31,8 @@
 
 #include "CommandListener.h"
 #include "ResponseCode.h"
+#include "ThrottleController.h"
+
 
 extern "C" int ifc_init(void);
 extern "C" int ifc_get_hwaddr(const char *name, void *ptr);
@@ -137,22 +139,42 @@ int CommandListener::InterfaceCmd::runCommand(SocketClient *cli,
         free(msg);
         return 0;
     } else if (!strcmp(argv[1], "getthrottle")) {
-        if (argc != 4) {
+        if (argc != 4 || (argc == 4 && (strcmp(argv[3], "rx") && (strcmp(argv[3], "tx"))))) {
             cli->sendMsg(ResponseCode::CommandSyntaxError,
                     "Usage: interface getthrottle <interface> <rx|tx>", false);
             return 0;
         }
-        errno = ENOSYS;
-        cli->sendMsg(ResponseCode::OperationFailed, "Not Implemented", true);
+        int val = 0;
+        int rc = 0;
+        int voldRc = ResponseCode::InterfaceRxThrottleResult;
+
+        if (!strcmp(argv[3], "rx")) {
+            rc = ThrottleController::getInterfaceRxThrottle(argv[2], &val);
+        } else {
+            rc = ThrottleController::getInterfaceTxThrottle(argv[2], &val);
+            voldRc = ResponseCode::InterfaceTxThrottleResult;
+        }
+        if (rc) {
+            cli->sendMsg(ResponseCode::OperationFailed, "Failed to get throttle", true);
+        } else {
+            char *msg = NULL;
+            asprintf(&msg, "%u", val);
+            cli->sendMsg(voldRc, msg, false);
+            free(msg);
+            return 0;
+        }
         return 0;
     } else if (!strcmp(argv[1], "setthrottle")) {
         if (argc != 5) {
             cli->sendMsg(ResponseCode::CommandSyntaxError,
-                    "Usage: interface getthrottle <interface> <rx|tx> <kbps>", false);
+                    "Usage: interface setthrottle <interface> <rx_kbps> <tx_kbps>", false);
             return 0;
         }
-        errno = ENOSYS;
-        cli->sendMsg(ResponseCode::OperationFailed, "Not Implemented", true);
+        if (ThrottleController::setInterfaceThrottle(argv[2], atoi(argv[3]), atoi(argv[4]))) {
+            cli->sendMsg(ResponseCode::OperationFailed, "Failed to set throttle", true);
+        } else {
+            cli->sendMsg(ResponseCode::CommandOkay, "Interface throttling set", false);
+        }
         return 0;
     } else {
         /*
diff --git a/ThrottleController.cpp b/ThrottleController.cpp
new file mode 100644 (file)
index 0000000..3501f57
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/pkt_sched.h>
+
+#define LOG_TAG "ThrottleController"
+#include <cutils/log.h>
+
+
+#include "ThrottleController.h"
+
+static char TC_PATH[] = "/system/bin/tc";
+
+extern "C" int logwrap(int argc, const char **argv, int background);
+
+int ThrottleController::runTcCmd(const char *cmd) {
+    char buffer[255];
+
+    strncpy(buffer, cmd, sizeof(buffer)-1);
+
+    const char *args[32];
+    char *next = buffer;
+    char *tmp;
+
+    args[0] = TC_PATH;
+    int i = 1;
+
+    while ((tmp = strsep(&next, " "))) {
+        args[i++] = tmp;
+        if (i == 32) {
+            LOGE("tc argument overflow");
+            errno = E2BIG;
+            return -1;
+        }
+    }
+    args[i] = NULL;
+
+    return logwrap(i, args, 0);
+}
+
+int ThrottleController::setInterfaceThrottle(const char *iface, int rxKbps, int txKbps) {
+    char *cmd;
+    int rc;
+
+    if (txKbps == -1) {
+        reset(iface);
+        return 0;
+    }
+
+    asprintf(&cmd, "qdisc add dev %s root handle 1: cbq avpkt 1000 bandwidth 10mbit", iface);
+    rc = runTcCmd(cmd);
+    free(cmd);
+    if (rc) {
+        LOGE("Failed to add cbq qdisc (%s)", strerror(errno));
+        reset(iface);
+        return -1;
+    }
+
+    asprintf(&cmd,
+            "class add dev %s parent 1: classid 1:1 cbq rate %dkbit allot 1500 prio 5 bounded isolated",
+                    iface, txKbps);
+    rc = runTcCmd(cmd);
+    free(cmd);
+    if (rc) {
+        LOGE("Failed to add class (%s)", strerror(errno));
+        reset(iface);
+        return -1;
+    }
+
+    asprintf(&cmd,
+            "filter add dev %s parent 1: protocol ip prio 16 u32 match ip dst 0.0.0.0/0 flowid 1:1",
+                    iface);
+    rc = runTcCmd(cmd);
+    free(cmd);
+    if (runTcCmd(cmd)) {
+        LOGE("Failed to add filter (%s)", strerror(errno));
+        reset(iface);
+        return -1;
+    }
+
+    return 0;
+}
+
+void ThrottleController::reset(const char *iface) {
+    char *cmd;
+    asprintf(&cmd, "qdisc del dev %s root", iface);
+    runTcCmd(cmd);
+    free(cmd);
+}
+
+int ThrottleController::getInterfaceRxThrottle(const char *iface, int *rx) {
+    *rx = 0;
+    return 0;
+}
+
+int ThrottleController::getInterfaceTxThrottle(const char *iface, int *tx) {
+    *tx = 0;
+    return 0;
+}
diff --git a/ThrottleController.h b/ThrottleController.h
new file mode 100644 (file)
index 0000000..3538e03
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#ifndef _THROTTLE_CONTROLLER_H
+#define _THROTTLE_CONTROLLER_H
+
+class ThrottleController {
+public:
+    static int setInterfaceThrottle(const char *iface, int rxKbps, int txKbps);
+    static int getInterfaceRxThrottle(const char *iface, int *rx);
+    static int getInterfaceTxThrottle(const char *iface, int *tx);
+
+private:
+    static int runTcCmd(const char *cmd);
+    static void reset(const char *iface);
+};
+
+#endif
index c96426f..e42d00a 100644 (file)
@@ -72,8 +72,10 @@ int parent(const char *tag, int parent_read) {
     status = 0xAAAA;
     if (wait(&status) != -1) {  // Wait for child
         if (WIFEXITED(status)) {
-            LOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag,
-                    WEXITSTATUS(status));
+            if (WEXITSTATUS(status) != 0) {
+                LOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag,
+                        WEXITSTATUS(status));
+            }
             return WEXITSTATUS(status);
         } else if (WIFSIGNALED(status))
             LOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag,