netd: Add ingress throttling

Change-Id: Id86a0d0d0bdfa9bca36e7c7bce7e9290c8532082
Signed-off-by: San Mehat <san@google.com>
diff --git a/ThrottleController.cpp b/ThrottleController.cpp
index 3501f57..9b2202b 100644
--- a/ThrottleController.cpp
+++ b/ThrottleController.cpp
@@ -36,6 +36,9 @@
 static char TC_PATH[] = "/system/bin/tc";
 
 extern "C" int logwrap(int argc, const char **argv, int background);
+extern "C" int ifc_init(void);
+extern "C" int ifc_up(const char *name);
+extern "C" int ifc_down(const char *name);
 
 int ThrottleController::runTcCmd(const char *cmd) {
     char buffer[255];
@@ -63,53 +66,131 @@
 }
 
 int ThrottleController::setInterfaceThrottle(const char *iface, int rxKbps, int txKbps) {
-    char *cmd;
+    char cmd[512];
+    char ifn[65];
     int rc;
 
+    memset(ifn, 0, sizeof(ifn));
+    strncpy(ifn, iface, sizeof(ifn)-1);
+
     if (txKbps == -1) {
-        reset(iface);
+        reset(ifn);
         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;
-    }
+    /*
+     *
+     * Target interface configuration
+     *
+     */
 
-    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);
+    /*
+     * Add root qdisc for the interface
+     */
+    sprintf(cmd, "qdisc add dev %s root handle 1: cbq avpkt 1000 bandwidth 10mbit",ifn);
     if (runTcCmd(cmd)) {
-        LOGE("Failed to add filter (%s)", strerror(errno));
-        reset(iface);
-        return -1;
+        LOGE("Failed to add root qdisc (%s)", strerror(errno));
+        goto fail;
+    }
+
+    /*
+     * Add our egress throttling class
+     */
+    sprintf(cmd, "class add dev %s parent 1: classid 1:1 cbq rate %dkbit allot 1500 "
+            "prio 5 bounded isolated", ifn, txKbps);
+    if (runTcCmd(cmd)) {
+        LOGE("Failed to add egress throttling class (%s)", strerror(errno));
+        goto fail;
+    }
+
+    /*
+     * Add filter for egress matching
+     */
+    sprintf(cmd, "filter add dev %s parent 1: protocol ip prio 16 u32 match "
+            "ip dst 0.0.0.0/0 flowid 1:1", ifn);
+    if (runTcCmd(cmd)) {
+        LOGE("Failed to add egress throttling filter (%s)", strerror(errno));
+        goto fail;
+    }
+
+    /*
+     * Bring up the IFD device
+     */
+    ifc_init();
+    if (ifc_up("ifb0")) {
+        LOGE("Failed to up ifb0 (%s)", strerror(errno));
+        goto fail;
+    }
+
+    /*
+     * Add ingress qdisc for pkt redirection
+     */
+    sprintf(cmd, "qdisc add dev %s ingress", ifn);
+    if (runTcCmd(cmd)) {
+        LOGE("Failed to add ingress qdisc (%s)", strerror(errno));
+        goto fail;
+    }
+
+    /*
+     * Add filter to link <ifn> -> ifb0
+     */
+    sprintf(cmd, "filter add dev %s parent 1: protocol ip prio 10 u32 match "
+            "u32 0 0 flowid 1:1 action mirred egress redirect dev ifb0", ifn);
+    if (runTcCmd(cmd)) {
+        LOGE("Failed to add ifb filter (%s)", strerror(errno));
+        goto fail;
+    }
+
+    /*
+     *
+     * IFD configuration
+     *
+     */
+
+    /*
+     * Add root qdisc for the interface
+     */
+    sprintf(cmd, "qdisc add dev ifb0 root handle 1: cbq avpkt 1000 bandwidth 10mbit");
+    if (runTcCmd(cmd)) {
+        LOGE("Failed to add root ifb qdisc (%s)", strerror(errno));
+        goto fail;
+    }
+
+    /*
+     * Add our ingress throttling class
+     */
+    sprintf(cmd, "class add dev ifb0 parent 1: classid 1:1 cbq rate %dkbit allot 1500 "
+            "prio 5 bounded isolated", rxKbps);
+    if (runTcCmd(cmd)) {
+        LOGE("Failed to add ingress throttling class (%s)", strerror(errno));
+        goto fail;
+    }
+
+    /*
+     * Add filter for ingress matching
+     */
+    sprintf(cmd, "filter add dev ifb0 parent 1: protocol ip prio 16 u32 match "
+            "ip dst 0.0.0.0/0 flowid 1:1");
+    if (runTcCmd(cmd)) {
+        LOGE("Failed to add ingress throttling filter (%s)", strerror(errno));
+        goto fail;
     }
 
     return 0;
+fail:
+    reset(ifn);
+    return -1;
 }
 
 void ThrottleController::reset(const char *iface) {
-    char *cmd;
-    asprintf(&cmd, "qdisc del dev %s root", iface);
+    char cmd[128];
+
+    sprintf(cmd, "qdisc del dev %s root", iface);
     runTcCmd(cmd);
-    free(cmd);
+    sprintf(cmd, "qdisc del dev %s ingress", iface);
+    runTcCmd(cmd);
+
+    runTcCmd("qdisc del dev ifb0 root");
 }
 
 int ThrottleController::getInterfaceRxThrottle(const char *iface, int *rx) {