OSDN Git Service

9b2202beb999250d21958bbd1e30b271eb5849d8
[android-x86/system-netd.git] / ThrottleController.cpp
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
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
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: cbq avpkt 1000 bandwidth 10mbit",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 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;
177     }
178
179     return 0;
180 fail:
181     reset(ifn);
182     return -1;
183 }
184
185 void ThrottleController::reset(const char *iface) {
186     char cmd[128];
187
188     sprintf(cmd, "qdisc del dev %s root", iface);
189     runTcCmd(cmd);
190     sprintf(cmd, "qdisc del dev %s ingress", iface);
191     runTcCmd(cmd);
192
193     runTcCmd("qdisc del dev ifb0 root");
194 }
195
196 int ThrottleController::getInterfaceRxThrottle(const char *iface, int *rx) {
197     *rx = 0;
198     return 0;
199 }
200
201 int ThrottleController::getInterfaceTxThrottle(const char *iface, int *tx) {
202     *tx = 0;
203     return 0;
204 }