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
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
36 static char TC_PATH[] = "/system/bin/tc";
37
38 extern "C" int logwrap(int argc, const char **argv, int background);
39 extern "C" int ifc_init(void);
40 extern "C" int ifc_up(const char *name);
41 extern "C" int ifc_down(const char *name);
42
runTcCmd(const char * cmd)43 int 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
setInterfaceThrottle(const char * iface,int rxKbps,int txKbps)68 int ThrottleController::setInterfaceThrottle(const char *iface, int rxKbps, int txKbps) {
69 char cmd[512];
70 char ifn[65];
71 int rc;
72
73 memset(ifn, 0, sizeof(ifn));
74 strncpy(ifn, iface, sizeof(ifn)-1);
75
76 if (txKbps == -1) {
77 reset(ifn);
78 return 0;
79 }
80
81 /*
82 *
83 * Target interface configuration
84 *
85 */
86
87 /*
88 * Add root qdisc for the interface
89 */
90 sprintf(cmd, "qdisc add dev %s root handle 1: htb default 1 r2q 1000", ifn);
91 if (runTcCmd(cmd)) {
92 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 htb rate %dkbit", ifn, txKbps);
100 if (runTcCmd(cmd)) {
101 LOGE("Failed to add egress throttling class (%s)", strerror(errno));
102 goto fail;
103 }
104
105 /*
106 * Bring up the IFD device
107 */
108 ifc_init();
109 if (ifc_up("ifb0")) {
110 LOGE("Failed to up ifb0 (%s)", strerror(errno));
111 goto fail;
112 }
113
114 /*
115 * Add root qdisc for IFD
116 */
117 sprintf(cmd, "qdisc add dev ifb0 root handle 1: htb default 1 r2q 1000");
118 if (runTcCmd(cmd)) {
119 LOGE("Failed to add root ifb qdisc (%s)", strerror(errno));
120 goto fail;
121 }
122
123 /*
124 * Add our ingress throttling class
125 */
126 sprintf(cmd, "class add dev ifb0 parent 1: classid 1:1 htb rate %dkbit", rxKbps);
127 if (runTcCmd(cmd)) {
128 LOGE("Failed to add ingress throttling class (%s)", strerror(errno));
129 goto fail;
130 }
131
132 /*
133 * Add ingress qdisc for pkt redirection
134 */
135 sprintf(cmd, "qdisc add dev %s ingress", ifn);
136 if (runTcCmd(cmd)) {
137 LOGE("Failed to add ingress qdisc (%s)", strerror(errno));
138 goto fail;
139 }
140
141 /*
142 * Add filter to link <ifn> -> ifb0
143 */
144 sprintf(cmd, "filter add dev %s parent ffff: protocol ip prio 10 u32 match "
145 "u32 0 0 flowid 1:1 action mirred egress redirect dev ifb0", ifn);
146 if (runTcCmd(cmd)) {
147 LOGE("Failed to add ifb filter (%s)", strerror(errno));
148 goto fail;
149 }
150
151 return 0;
152 fail:
153 reset(ifn);
154 return -1;
155 }
156
reset(const char * iface)157 void ThrottleController::reset(const char *iface) {
158 char cmd[128];
159
160 sprintf(cmd, "qdisc del dev %s root", iface);
161 runTcCmd(cmd);
162 sprintf(cmd, "qdisc del dev %s ingress", iface);
163 runTcCmd(cmd);
164
165 runTcCmd("qdisc del dev ifb0 root");
166 }
167
getInterfaceRxThrottle(const char * iface,int * rx)168 int ThrottleController::getInterfaceRxThrottle(const char *iface, int *rx) {
169 *rx = 0;
170 return 0;
171 }
172
getInterfaceTxThrottle(const char * iface,int * tx)173 int ThrottleController::getInterfaceTxThrottle(const char *iface, int *tx) {
174 *tx = 0;
175 return 0;
176 }
177