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 36static char TC_PATH[] = "/system/bin/tc"; 37 38extern "C" int logwrap(int argc, const char **argv, int background); 39extern "C" int ifc_init(void); 40extern "C" int ifc_up(const char *name); 41extern "C" int ifc_down(const char *name); 42 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) { 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; 152fail: 153 reset(ifn); 154 return -1; 155} 156 157void 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 168int ThrottleController::getInterfaceRxThrottle(const char *iface, int *rx) { 169 *rx = 0; 170 return 0; 171} 172 173int ThrottleController::getInterfaceTxThrottle(const char *iface, int *tx) { 174 *tx = 0; 175 return 0; 176} 177