blob: 9b2202beb999250d21958bbd1e30b271eb5849d8 [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>
20
21#include <sys/socket.h>
22#include <sys/stat.h>
23#include <sys/types.h>
24#include <sys/wait.h>
25
26#include <linux/netlink.h>
27#include <linux/rtnetlink.h>
28#include <linux/pkt_sched.h>
29
30#define LOG_TAG "ThrottleController"
31#include <cutils/log.h>
32
33
34#include "ThrottleController.h"
35
36static char TC_PATH[] = "/system/bin/tc";
37
38extern "C" int logwrap(int argc, const char **argv, int background);
San Mehat7e1f4762010-04-09 16:26:24 -070039extern "C" int ifc_init(void);
40extern "C" int ifc_up(const char *name);
41extern "C" int ifc_down(const char *name);
San Mehata1992c92010-04-07 15:21:36 -070042
43int ThrottleController::runTcCmd(const char *cmd) {
44 char buffer[255];
45
46 strncpy(buffer, cmd, sizeof(buffer)-1);
47
48 const char *args[32];
49 char *next = buffer;
50 char *tmp;
51
52 args[0] = TC_PATH;
53 int i = 1;
54
55 while ((tmp = strsep(&next, " "))) {
56 args[i++] = tmp;
57 if (i == 32) {
58 LOGE("tc argument overflow");
59 errno = E2BIG;
60 return -1;
61 }
62 }
63 args[i] = NULL;
64
65 return logwrap(i, args, 0);
66}
67
68int ThrottleController::setInterfaceThrottle(const char *iface, int rxKbps, int txKbps) {
San Mehat7e1f4762010-04-09 16:26:24 -070069 char cmd[512];
70 char ifn[65];
San Mehata1992c92010-04-07 15:21:36 -070071 int rc;
72
San Mehat7e1f4762010-04-09 16:26:24 -070073 memset(ifn, 0, sizeof(ifn));
74 strncpy(ifn, iface, sizeof(ifn)-1);
75
San Mehata1992c92010-04-07 15:21:36 -070076 if (txKbps == -1) {
San Mehat7e1f4762010-04-09 16:26:24 -070077 reset(ifn);
San Mehata1992c92010-04-07 15:21:36 -070078 return 0;
79 }
80
San Mehat7e1f4762010-04-09 16:26:24 -070081 /*
82 *
83 * Target interface configuration
84 *
85 */
San Mehata1992c92010-04-07 15:21:36 -070086
San Mehat7e1f4762010-04-09 16:26:24 -070087 /*
88 * Add root qdisc for the interface
89 */
90 sprintf(cmd, "qdisc add dev %s root handle 1: cbq avpkt 1000 bandwidth 10mbit",ifn);
San Mehata1992c92010-04-07 15:21:36 -070091 if (runTcCmd(cmd)) {
San Mehat7e1f4762010-04-09 16:26:24 -070092 LOGE("Failed to add root qdisc (%s)", strerror(errno));
93 goto fail;
94 }
95
96 /*
97 * Add our egress throttling class
98 */
99 sprintf(cmd, "class add dev %s parent 1: classid 1:1 cbq rate %dkbit allot 1500 "
100 "prio 5 bounded isolated", ifn, txKbps);
101 if (runTcCmd(cmd)) {
102 LOGE("Failed to add egress throttling class (%s)", strerror(errno));
103 goto fail;
104 }
105
106 /*
107 * Add filter for egress matching
108 */
109 sprintf(cmd, "filter add dev %s parent 1: protocol ip prio 16 u32 match "
110 "ip dst 0.0.0.0/0 flowid 1:1", ifn);
111 if (runTcCmd(cmd)) {
112 LOGE("Failed to add egress throttling filter (%s)", strerror(errno));
113 goto fail;
114 }
115
116 /*
117 * Bring up the IFD device
118 */
119 ifc_init();
120 if (ifc_up("ifb0")) {
121 LOGE("Failed to up ifb0 (%s)", strerror(errno));
122 goto fail;
123 }
124
125 /*
126 * Add ingress qdisc for pkt redirection
127 */
128 sprintf(cmd, "qdisc add dev %s ingress", ifn);
129 if (runTcCmd(cmd)) {
130 LOGE("Failed to add ingress qdisc (%s)", strerror(errno));
131 goto fail;
132 }
133
134 /*
135 * Add filter to link <ifn> -> ifb0
136 */
137 sprintf(cmd, "filter add dev %s parent 1: protocol ip prio 10 u32 match "
138 "u32 0 0 flowid 1:1 action mirred egress redirect dev ifb0", ifn);
139 if (runTcCmd(cmd)) {
140 LOGE("Failed to add ifb filter (%s)", strerror(errno));
141 goto fail;
142 }
143
144 /*
145 *
146 * IFD configuration
147 *
148 */
149
150 /*
151 * Add root qdisc for the interface
152 */
153 sprintf(cmd, "qdisc add dev ifb0 root handle 1: cbq avpkt 1000 bandwidth 10mbit");
154 if (runTcCmd(cmd)) {
155 LOGE("Failed to add root ifb qdisc (%s)", strerror(errno));
156 goto fail;
157 }
158
159 /*
160 * Add our ingress throttling class
161 */
162 sprintf(cmd, "class add dev ifb0 parent 1: classid 1:1 cbq rate %dkbit allot 1500 "
163 "prio 5 bounded isolated", rxKbps);
164 if (runTcCmd(cmd)) {
165 LOGE("Failed to add ingress throttling class (%s)", strerror(errno));
166 goto fail;
167 }
168
169 /*
170 * Add filter for ingress matching
171 */
172 sprintf(cmd, "filter add dev ifb0 parent 1: protocol ip prio 16 u32 match "
173 "ip dst 0.0.0.0/0 flowid 1:1");
174 if (runTcCmd(cmd)) {
175 LOGE("Failed to add ingress throttling filter (%s)", strerror(errno));
176 goto fail;
San Mehata1992c92010-04-07 15:21:36 -0700177 }
178
179 return 0;
San Mehat7e1f4762010-04-09 16:26:24 -0700180fail:
181 reset(ifn);
182 return -1;
San Mehata1992c92010-04-07 15:21:36 -0700183}
184
185void ThrottleController::reset(const char *iface) {
San Mehat7e1f4762010-04-09 16:26:24 -0700186 char cmd[128];
187
188 sprintf(cmd, "qdisc del dev %s root", iface);
San Mehata1992c92010-04-07 15:21:36 -0700189 runTcCmd(cmd);
San Mehat7e1f4762010-04-09 16:26:24 -0700190 sprintf(cmd, "qdisc del dev %s ingress", iface);
191 runTcCmd(cmd);
192
193 runTcCmd("qdisc del dev ifb0 root");
San Mehata1992c92010-04-07 15:21:36 -0700194}
195
196int ThrottleController::getInterfaceRxThrottle(const char *iface, int *rx) {
197 *rx = 0;
198 return 0;
199}
200
201int ThrottleController::getInterfaceTxThrottle(const char *iface, int *tx) {
202 *tx = 0;
203 return 0;
204}