ThrottleController.cpp revision 7e1f476ce965d9bde6e834bbe862faef548b2abb
1a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat/*
2a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat * Copyright (C) 2008 The Android Open Source Project
3a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat *
4a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat * Licensed under the Apache License, Version 2.0 (the "License");
5a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat * you may not use this file except in compliance with the License.
6a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat * You may obtain a copy of the License at
7a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat *
8a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat *      http://www.apache.org/licenses/LICENSE-2.0
9a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat *
10a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat * Unless required by applicable law or agreed to in writing, software
11a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat * distributed under the License is distributed on an "AS IS" BASIS,
12a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat * See the License for the specific language governing permissions and
14a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat * limitations under the License.
15a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat */
16a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
17a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat#include <stdlib.h>
18a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat#include <errno.h>
19a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat#include <fcntl.h>
20a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
21a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat#include <sys/socket.h>
22a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat#include <sys/stat.h>
23a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat#include <sys/types.h>
24a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat#include <sys/wait.h>
25a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
26a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat#include <linux/netlink.h>
27a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat#include <linux/rtnetlink.h>
28a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat#include <linux/pkt_sched.h>
29a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
30a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat#define LOG_TAG "ThrottleController"
31a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat#include <cutils/log.h>
32a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
33a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
34a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat#include "ThrottleController.h"
35a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
36a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehatstatic char TC_PATH[] = "/system/bin/tc";
37a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
38a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehatextern "C" int logwrap(int argc, const char **argv, int background);
397e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehatextern "C" int ifc_init(void);
407e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehatextern "C" int ifc_up(const char *name);
417e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehatextern "C" int ifc_down(const char *name);
42a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
43a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehatint ThrottleController::runTcCmd(const char *cmd) {
44a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    char buffer[255];
45a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
46a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    strncpy(buffer, cmd, sizeof(buffer)-1);
47a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
48a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    const char *args[32];
49a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    char *next = buffer;
50a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    char *tmp;
51a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
52a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    args[0] = TC_PATH;
53a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    int i = 1;
54a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
55a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    while ((tmp = strsep(&next, " "))) {
56a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat        args[i++] = tmp;
57a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat        if (i == 32) {
58a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat            LOGE("tc argument overflow");
59a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat            errno = E2BIG;
60a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat            return -1;
61a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat        }
62a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    }
63a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    args[i] = NULL;
64a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
65a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    return logwrap(i, args, 0);
66a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat}
67a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
68a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehatint ThrottleController::setInterfaceThrottle(const char *iface, int rxKbps, int txKbps) {
697e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    char cmd[512];
707e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    char ifn[65];
71a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    int rc;
72a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
737e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    memset(ifn, 0, sizeof(ifn));
747e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    strncpy(ifn, iface, sizeof(ifn)-1);
757e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat
76a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    if (txKbps == -1) {
777e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        reset(ifn);
78a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat        return 0;
79a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    }
80a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
817e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    /*
827e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     *
837e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     * Target interface configuration
847e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     *
857e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     */
867e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat
877e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    /*
887e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     * Add root qdisc for the interface
897e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     */
907e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    sprintf(cmd, "qdisc add dev %s root handle 1: cbq avpkt 1000 bandwidth 10mbit",ifn);
917e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    if (runTcCmd(cmd)) {
927e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        LOGE("Failed to add root qdisc (%s)", strerror(errno));
937e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        goto fail;
94a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    }
95a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
967e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    /*
977e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     * Add our egress throttling class
987e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     */
997e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    sprintf(cmd, "class add dev %s parent 1: classid 1:1 cbq rate %dkbit allot 1500 "
1007e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat            "prio 5 bounded isolated", ifn, txKbps);
1017e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    if (runTcCmd(cmd)) {
1027e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        LOGE("Failed to add egress throttling class (%s)", strerror(errno));
1037e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        goto fail;
104a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    }
105a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
1067e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    /*
1077e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     * Add filter for egress matching
1087e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     */
1097e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    sprintf(cmd, "filter add dev %s parent 1: protocol ip prio 16 u32 match "
1107e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat            "ip dst 0.0.0.0/0 flowid 1:1", ifn);
111a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    if (runTcCmd(cmd)) {
1127e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        LOGE("Failed to add egress throttling filter (%s)", strerror(errno));
1137e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        goto fail;
1147e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    }
1157e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat
1167e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    /*
1177e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     * Bring up the IFD device
1187e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     */
1197e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    ifc_init();
1207e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    if (ifc_up("ifb0")) {
1217e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        LOGE("Failed to up ifb0 (%s)", strerror(errno));
1227e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        goto fail;
1237e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    }
1247e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat
1257e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    /*
1267e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     * Add ingress qdisc for pkt redirection
1277e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     */
1287e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    sprintf(cmd, "qdisc add dev %s ingress", ifn);
1297e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    if (runTcCmd(cmd)) {
1307e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        LOGE("Failed to add ingress qdisc (%s)", strerror(errno));
1317e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        goto fail;
1327e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    }
1337e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat
1347e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    /*
1357e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     * Add filter to link <ifn> -> ifb0
1367e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     */
1377e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    sprintf(cmd, "filter add dev %s parent 1: protocol ip prio 10 u32 match "
1387e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat            "u32 0 0 flowid 1:1 action mirred egress redirect dev ifb0", ifn);
1397e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    if (runTcCmd(cmd)) {
1407e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        LOGE("Failed to add ifb filter (%s)", strerror(errno));
1417e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        goto fail;
1427e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    }
1437e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat
1447e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    /*
1457e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     *
1467e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     * IFD configuration
1477e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     *
1487e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     */
1497e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat
1507e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    /*
1517e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     * Add root qdisc for the interface
1527e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     */
1537e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    sprintf(cmd, "qdisc add dev ifb0 root handle 1: cbq avpkt 1000 bandwidth 10mbit");
1547e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    if (runTcCmd(cmd)) {
1557e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        LOGE("Failed to add root ifb qdisc (%s)", strerror(errno));
1567e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        goto fail;
1577e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    }
1587e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat
1597e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    /*
1607e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     * Add our ingress throttling class
1617e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     */
1627e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    sprintf(cmd, "class add dev ifb0 parent 1: classid 1:1 cbq rate %dkbit allot 1500 "
1637e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat            "prio 5 bounded isolated", rxKbps);
1647e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    if (runTcCmd(cmd)) {
1657e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        LOGE("Failed to add ingress throttling class (%s)", strerror(errno));
1667e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        goto fail;
1677e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    }
1687e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat
1697e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    /*
1707e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     * Add filter for ingress matching
1717e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     */
1727e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    sprintf(cmd, "filter add dev ifb0 parent 1: protocol ip prio 16 u32 match "
1737e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat            "ip dst 0.0.0.0/0 flowid 1:1");
1747e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    if (runTcCmd(cmd)) {
1757e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        LOGE("Failed to add ingress throttling filter (%s)", strerror(errno));
1767e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        goto fail;
177a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    }
178a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
179a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    return 0;
1807e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehatfail:
1817e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    reset(ifn);
1827e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    return -1;
183a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat}
184a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
185a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehatvoid ThrottleController::reset(const char *iface) {
1867e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    char cmd[128];
1877e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat
1887e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    sprintf(cmd, "qdisc del dev %s root", iface);
1897e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    runTcCmd(cmd);
1907e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    sprintf(cmd, "qdisc del dev %s ingress", iface);
191a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    runTcCmd(cmd);
1927e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat
1937e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    runTcCmd("qdisc del dev ifb0 root");
194a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat}
195a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
196a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehatint ThrottleController::getInterfaceRxThrottle(const char *iface, int *rx) {
197a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    *rx = 0;
198a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    return 0;
199a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat}
200a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
201a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehatint ThrottleController::getInterfaceTxThrottle(const char *iface, int *tx) {
202a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    *tx = 0;
203a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    return 0;
204a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat}
205