blob: 41f9939d51f0afc5eedc27a60f986cc1a8740d2d [file] [log] [blame]
San Mehata1992c92010-04-07 15:21:36 -07001/*
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>
Olivier Baillyff2c0d82010-11-17 11:45:07 -080020#include <string.h>
San Mehata1992c92010-04-07 15:21:36 -070021
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);
San Mehat7e1f4762010-04-09 16:26:24 -070040extern "C" int ifc_init(void);
41extern "C" int ifc_up(const char *name);
42extern "C" int ifc_down(const char *name);
San Mehata1992c92010-04-07 15:21:36 -070043
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) {
San Mehat7e1f4762010-04-09 16:26:24 -070070 char cmd[512];
71 char ifn[65];
San Mehata1992c92010-04-07 15:21:36 -070072 int rc;
73
San Mehat7e1f4762010-04-09 16:26:24 -070074 memset(ifn, 0, sizeof(ifn));
75 strncpy(ifn, iface, sizeof(ifn)-1);
76
San Mehata1992c92010-04-07 15:21:36 -070077 if (txKbps == -1) {
San Mehat7e1f4762010-04-09 16:26:24 -070078 reset(ifn);
San Mehata1992c92010-04-07 15:21:36 -070079 return 0;
80 }
81
San Mehat7e1f4762010-04-09 16:26:24 -070082 /*
83 *
84 * Target interface configuration
85 *
86 */
San Mehata1992c92010-04-07 15:21:36 -070087
San Mehat7e1f4762010-04-09 16:26:24 -070088 /*
89 * Add root qdisc for the interface
90 */
San Mehat9d8d7282010-04-30 06:19:07 -070091 sprintf(cmd, "qdisc add dev %s root handle 1: htb default 1 r2q 1000", ifn);
San Mehata1992c92010-04-07 15:21:36 -070092 if (runTcCmd(cmd)) {
San Mehat7e1f4762010-04-09 16:26:24 -070093 LOGE("Failed to add root qdisc (%s)", strerror(errno));
94 goto fail;
95 }
96
97 /*
98 * Add our egress throttling class
99 */
San Mehat9d8d7282010-04-30 06:19:07 -0700100 sprintf(cmd, "class add dev %s parent 1: classid 1:1 htb rate %dkbit", ifn, txKbps);
San Mehat7e1f4762010-04-09 16:26:24 -0700101 if (runTcCmd(cmd)) {
102 LOGE("Failed to add egress throttling class (%s)", strerror(errno));
103 goto fail;
104 }
105
106 /*
San Mehat7e1f4762010-04-09 16:26:24 -0700107 * 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 /*
San Mehat9d8d7282010-04-30 06:19:07 -0700116 * 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 /*
San Mehat7e1f4762010-04-09 16:26:24 -0700134 * 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 */
San Mehat9d8d7282010-04-30 06:19:07 -0700145 sprintf(cmd, "filter add dev %s parent ffff: protocol ip prio 10 u32 match "
San Mehat7e1f4762010-04-09 16:26:24 -0700146 "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
San Mehata1992c92010-04-07 15:21:36 -0700152 return 0;
San Mehat7e1f4762010-04-09 16:26:24 -0700153fail:
154 reset(ifn);
155 return -1;
San Mehata1992c92010-04-07 15:21:36 -0700156}
157
158void ThrottleController::reset(const char *iface) {
San Mehat7e1f4762010-04-09 16:26:24 -0700159 char cmd[128];
160
161 sprintf(cmd, "qdisc del dev %s root", iface);
San Mehata1992c92010-04-07 15:21:36 -0700162 runTcCmd(cmd);
San Mehat7e1f4762010-04-09 16:26:24 -0700163 sprintf(cmd, "qdisc del dev %s ingress", iface);
164 runTcCmd(cmd);
165
166 runTcCmd("qdisc del dev ifb0 root");
San Mehata1992c92010-04-07 15:21:36 -0700167}
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}