ThrottleController.cpp revision ff2c0d8c13457e43f0d4bf06d3177271aac104c1
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdlib.h>
18#include <errno.h>
19#include <fcntl.h>
20#include <string.h>
21
22#include <sys/socket.h>
23#include <sys/stat.h>
24#include <sys/types.h>
25#include <sys/wait.h>
26
27#include <linux/netlink.h>
28#include <linux/rtnetlink.h>
29#include <linux/pkt_sched.h>
30
31#define LOG_TAG "ThrottleController"
32#include <cutils/log.h>
33
34
35#include "ThrottleController.h"
36
37static char TC_PATH[] = "/system/bin/tc";
38
39extern "C" int logwrap(int argc, const char **argv, int background);
40extern "C" int ifc_init(void);
41extern "C" int ifc_up(const char *name);
42extern "C" int ifc_down(const char *name);
43
44int ThrottleController::runTcCmd(const char *cmd) {
45    char buffer[255];
46
47    strncpy(buffer, cmd, sizeof(buffer)-1);
48
49    const char *args[32];
50    char *next = buffer;
51    char *tmp;
52
53    args[0] = TC_PATH;
54    int i = 1;
55
56    while ((tmp = strsep(&next, " "))) {
57        args[i++] = tmp;
58        if (i == 32) {
59            LOGE("tc argument overflow");
60            errno = E2BIG;
61            return -1;
62        }
63    }
64    args[i] = NULL;
65
66    return logwrap(i, args, 0);
67}
68
69int ThrottleController::setInterfaceThrottle(const char *iface, int rxKbps, int txKbps) {
70    char cmd[512];
71    char ifn[65];
72    int rc;
73
74    memset(ifn, 0, sizeof(ifn));
75    strncpy(ifn, iface, sizeof(ifn)-1);
76
77    if (txKbps == -1) {
78        reset(ifn);
79        return 0;
80    }
81
82    /*
83     *
84     * Target interface configuration
85     *
86     */
87
88    /*
89     * Add root qdisc for the interface
90     */
91    sprintf(cmd, "qdisc add dev %s root handle 1: htb default 1 r2q 1000", ifn);
92    if (runTcCmd(cmd)) {
93        LOGE("Failed to add root qdisc (%s)", strerror(errno));
94        goto fail;
95    }
96
97    /*
98     * Add our egress throttling class
99     */
100    sprintf(cmd, "class add dev %s parent 1: classid 1:1 htb rate %dkbit", ifn, txKbps);
101    if (runTcCmd(cmd)) {
102        LOGE("Failed to add egress throttling class (%s)", strerror(errno));
103        goto fail;
104    }
105
106    /*
107     * Bring up the IFD device
108     */
109    ifc_init();
110    if (ifc_up("ifb0")) {
111        LOGE("Failed to up ifb0 (%s)", strerror(errno));
112        goto fail;
113    }
114
115    /*
116     * Add root qdisc for IFD
117     */
118    sprintf(cmd, "qdisc add dev ifb0 root handle 1: htb default 1 r2q 1000");
119    if (runTcCmd(cmd)) {
120        LOGE("Failed to add root ifb qdisc (%s)", strerror(errno));
121        goto fail;
122    }
123
124    /*
125     * Add our ingress throttling class
126     */
127    sprintf(cmd, "class add dev ifb0 parent 1: classid 1:1 htb rate %dkbit", rxKbps);
128    if (runTcCmd(cmd)) {
129        LOGE("Failed to add ingress throttling class (%s)", strerror(errno));
130        goto fail;
131    }
132
133    /*
134     * Add ingress qdisc for pkt redirection
135     */
136    sprintf(cmd, "qdisc add dev %s ingress", ifn);
137    if (runTcCmd(cmd)) {
138        LOGE("Failed to add ingress qdisc (%s)", strerror(errno));
139        goto fail;
140    }
141
142    /*
143     * Add filter to link <ifn> -> ifb0
144     */
145    sprintf(cmd, "filter add dev %s parent ffff: protocol ip prio 10 u32 match "
146            "u32 0 0 flowid 1:1 action mirred egress redirect dev ifb0", ifn);
147    if (runTcCmd(cmd)) {
148        LOGE("Failed to add ifb filter (%s)", strerror(errno));
149        goto fail;
150    }
151
152    return 0;
153fail:
154    reset(ifn);
155    return -1;
156}
157
158void ThrottleController::reset(const char *iface) {
159    char cmd[128];
160
161    sprintf(cmd, "qdisc del dev %s root", iface);
162    runTcCmd(cmd);
163    sprintf(cmd, "qdisc del dev %s ingress", iface);
164    runTcCmd(cmd);
165
166    runTcCmd("qdisc del dev ifb0 root");
167}
168
169int ThrottleController::getInterfaceRxThrottle(const char *iface, int *rx) {
170    *rx = 0;
171    return 0;
172}
173
174int ThrottleController::getInterfaceTxThrottle(const char *iface, int *tx) {
175    *tx = 0;
176    return 0;
177}
178