ThrottleController.cpp revision 5ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13
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>
20ff2c0d8c13457e43f0d4bf06d3177271aac104c1Olivier Bailly#include <string.h>
21a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
22a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat#include <sys/socket.h>
23a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat#include <sys/stat.h>
24a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat#include <sys/types.h>
25a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat#include <sys/wait.h>
26a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
27a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat#include <linux/netlink.h>
28a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat#include <linux/rtnetlink.h>
29a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat#include <linux/pkt_sched.h>
30a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
31a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat#define LOG_TAG "ThrottleController"
32a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat#include <cutils/log.h>
33a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
34a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
35a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat#include "ThrottleController.h"
36a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
37a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehatstatic char TC_PATH[] = "/system/bin/tc";
38a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
399e5e0ce62e88ddf9a09798eda51b0c270d354c8eJP Abgrallextern "C" int system_nosh(const char *command);
407e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehatextern "C" int ifc_init(void);
417e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehatextern "C" int ifc_up(const char *name);
427e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehatextern "C" int ifc_down(const char *name);
43a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
44a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehatint ThrottleController::runTcCmd(const char *cmd) {
4511b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    char *buffer;
4611b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    size_t len = strnlen(cmd, 255);
4711b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    int res;
4811b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall
4911b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    if (len == 255) {
505ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("tc command too long");
5111b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall        errno = E2BIG;
5211b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall        return -1;
53a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    }
54a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
5511b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    asprintf(&buffer, "%s %s", TC_PATH, cmd);
569e5e0ce62e88ddf9a09798eda51b0c270d354c8eJP Abgrall    res = system_nosh(buffer);
5711b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    free(buffer);
5811b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    return res;
59a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat}
60a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
61a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehatint ThrottleController::setInterfaceThrottle(const char *iface, int rxKbps, int txKbps) {
627e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    char cmd[512];
637e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    char ifn[65];
64a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    int rc;
65a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
667e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    memset(ifn, 0, sizeof(ifn));
677e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    strncpy(ifn, iface, sizeof(ifn)-1);
687e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat
69a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    if (txKbps == -1) {
707e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        reset(ifn);
71a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat        return 0;
72a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    }
73a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
747e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    /*
757e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     *
767e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     * Target interface configuration
777e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     *
787e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     */
797e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat
807e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    /*
817e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     * Add root qdisc for the interface
827e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     */
839d8d728596234e1e49cb1f8267b190bcc2d4b685San Mehat    sprintf(cmd, "qdisc add dev %s root handle 1: htb default 1 r2q 1000", ifn);
847e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    if (runTcCmd(cmd)) {
855ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("Failed to add root qdisc (%s)", strerror(errno));
867e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        goto fail;
87a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    }
88a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
897e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    /*
907e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     * Add our egress throttling class
917e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     */
929d8d728596234e1e49cb1f8267b190bcc2d4b685San Mehat    sprintf(cmd, "class add dev %s parent 1: classid 1:1 htb rate %dkbit", ifn, txKbps);
937e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    if (runTcCmd(cmd)) {
945ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("Failed to add egress throttling class (%s)", strerror(errno));
957e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        goto fail;
96a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    }
97a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
987e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    /*
997e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     * Bring up the IFD device
1007e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     */
1017e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    ifc_init();
1027e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    if (ifc_up("ifb0")) {
1035ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("Failed to up ifb0 (%s)", strerror(errno));
1047e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        goto fail;
1057e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    }
1067e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat
1077e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    /*
1089d8d728596234e1e49cb1f8267b190bcc2d4b685San Mehat     * Add root qdisc for IFD
1097e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     */
1109d8d728596234e1e49cb1f8267b190bcc2d4b685San Mehat    sprintf(cmd, "qdisc add dev ifb0 root handle 1: htb default 1 r2q 1000");
1117e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    if (runTcCmd(cmd)) {
1125ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("Failed to add root ifb qdisc (%s)", strerror(errno));
1137e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        goto fail;
1147e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    }
1157e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat
1167e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    /*
1179d8d728596234e1e49cb1f8267b190bcc2d4b685San Mehat     * Add our ingress throttling class
1187e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     */
1199d8d728596234e1e49cb1f8267b190bcc2d4b685San Mehat    sprintf(cmd, "class add dev ifb0 parent 1: classid 1:1 htb rate %dkbit", rxKbps);
1207e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    if (runTcCmd(cmd)) {
1215ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("Failed to add ingress throttling class (%s)", strerror(errno));
1227e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        goto fail;
1237e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    }
1247e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat
1257e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    /*
1269d8d728596234e1e49cb1f8267b190bcc2d4b685San Mehat     * Add ingress qdisc for pkt redirection
1277e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     */
1289d8d728596234e1e49cb1f8267b190bcc2d4b685San Mehat    sprintf(cmd, "qdisc add dev %s ingress", ifn);
1297e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    if (runTcCmd(cmd)) {
1305ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("Failed to add ingress qdisc (%s)", strerror(errno));
1317e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        goto fail;
1327e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    }
1337e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat
1347e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    /*
1359d8d728596234e1e49cb1f8267b190bcc2d4b685San Mehat     * Add filter to link <ifn> -> ifb0
1367e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat     */
1379d8d728596234e1e49cb1f8267b190bcc2d4b685San Mehat    sprintf(cmd, "filter add dev %s parent ffff: protocol ip prio 10 u32 match "
1389d8d728596234e1e49cb1f8267b190bcc2d4b685San Mehat            "u32 0 0 flowid 1:1 action mirred egress redirect dev ifb0", ifn);
1397e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    if (runTcCmd(cmd)) {
1405ea0c05a1e7d8e664b808aa1bb1efd08fdb2fb13Steve Block        ALOGE("Failed to add ifb filter (%s)", strerror(errno));
1417e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat        goto fail;
142a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    }
143a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
144a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    return 0;
1457e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehatfail:
1467e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    reset(ifn);
1477e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    return -1;
148a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat}
149a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
150a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehatvoid ThrottleController::reset(const char *iface) {
1517e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    char cmd[128];
1527e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat
1537e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    sprintf(cmd, "qdisc del dev %s root", iface);
1547e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    runTcCmd(cmd);
1557e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    sprintf(cmd, "qdisc del dev %s ingress", iface);
156a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    runTcCmd(cmd);
1577e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat
1587e1f476ce965d9bde6e834bbe862faef548b2abbSan Mehat    runTcCmd("qdisc del dev ifb0 root");
159a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat}
160a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
161a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehatint ThrottleController::getInterfaceRxThrottle(const char *iface, int *rx) {
162a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    *rx = 0;
163a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    return 0;
164a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat}
165a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat
166a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehatint ThrottleController::getInterfaceTxThrottle(const char *iface, int *tx) {
167a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    *tx = 0;
168a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat    return 0;
169a1992c9ff3e0d180c1f3042658ab9671d61a2fb8San Mehat}
170