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 #include "NetdConstants.h"
37
38 extern "C" int system_nosh(const char *command);
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;
45 size_t len = strnlen(cmd, 255);
46 int res;
47
48 if (len == 255) {
49 ALOGE("tc command too long");
50 errno = E2BIG;
51 return -1;
52 }
53
54 asprintf(&buffer, "%s %s", TC_PATH, cmd);
55 res = system_nosh(buffer);
56 free(buffer);
57 return res;
58 }
59
setInterfaceThrottle(const char * iface,int rxKbps,int txKbps)60 int ThrottleController::setInterfaceThrottle(const char *iface, int rxKbps, int txKbps) {
61 char cmd[512];
62 char ifn[65];
63 int rc;
64
65 memset(ifn, 0, sizeof(ifn));
66 strncpy(ifn, iface, sizeof(ifn)-1);
67
68 if (txKbps == -1) {
69 reset(ifn);
70 return 0;
71 }
72
73 /*
74 *
75 * Target interface configuration
76 *
77 */
78
79 /*
80 * Add root qdisc for the interface
81 */
82 sprintf(cmd, "qdisc add dev %s root handle 1: htb default 1 r2q 1000", ifn);
83 if (runTcCmd(cmd)) {
84 ALOGE("Failed to add root qdisc (%s)", strerror(errno));
85 goto fail;
86 }
87
88 /*
89 * Add our egress throttling class
90 */
91 sprintf(cmd, "class add dev %s parent 1: classid 1:1 htb rate %dkbit", ifn, txKbps);
92 if (runTcCmd(cmd)) {
93 ALOGE("Failed to add egress throttling class (%s)", strerror(errno));
94 goto fail;
95 }
96
97 /*
98 * Bring up the IFD device
99 */
100 ifc_init();
101 if (ifc_up("ifb0")) {
102 ALOGE("Failed to up ifb0 (%s)", strerror(errno));
103 goto fail;
104 }
105
106 /*
107 * Add root qdisc for IFD
108 */
109 sprintf(cmd, "qdisc add dev ifb0 root handle 1: htb default 1 r2q 1000");
110 if (runTcCmd(cmd)) {
111 ALOGE("Failed to add root ifb qdisc (%s)", strerror(errno));
112 goto fail;
113 }
114
115 /*
116 * Add our ingress throttling class
117 */
118 sprintf(cmd, "class add dev ifb0 parent 1: classid 1:1 htb rate %dkbit", rxKbps);
119 if (runTcCmd(cmd)) {
120 ALOGE("Failed to add ingress throttling class (%s)", strerror(errno));
121 goto fail;
122 }
123
124 /*
125 * Add ingress qdisc for pkt redirection
126 */
127 sprintf(cmd, "qdisc add dev %s ingress", ifn);
128 if (runTcCmd(cmd)) {
129 ALOGE("Failed to add ingress qdisc (%s)", strerror(errno));
130 goto fail;
131 }
132
133 /*
134 * Add filter to link <ifn> -> ifb0
135 */
136 sprintf(cmd, "filter add dev %s parent ffff: protocol ip prio 10 u32 match "
137 "u32 0 0 flowid 1:1 action mirred egress redirect dev ifb0", ifn);
138 if (runTcCmd(cmd)) {
139 ALOGE("Failed to add ifb filter (%s)", strerror(errno));
140 goto fail;
141 }
142
143 return 0;
144 fail:
145 reset(ifn);
146 return -1;
147 }
148
reset(const char * iface)149 void ThrottleController::reset(const char *iface) {
150 char cmd[128];
151
152 sprintf(cmd, "qdisc del dev %s root", iface);
153 runTcCmd(cmd);
154 sprintf(cmd, "qdisc del dev %s ingress", iface);
155 runTcCmd(cmd);
156
157 runTcCmd("qdisc del dev ifb0 root");
158 }
159
getInterfaceRxThrottle(const char * iface,int * rx)160 int ThrottleController::getInterfaceRxThrottle(const char *iface, int *rx) {
161 *rx = 0;
162 return 0;
163 }
164
getInterfaceTxThrottle(const char * iface,int * tx)165 int ThrottleController::getInterfaceTxThrottle(const char *iface, int *tx) {
166 *tx = 0;
167 return 0;
168 }
169