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 38extern "C" int system_nosh(const char *command); 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; 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 60int 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; 144fail: 145 reset(ifn); 146 return -1; 147} 148 149void 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 160int ThrottleController::getInterfaceRxThrottle(const char *iface, int *rx) { 161 *rx = 0; 162 return 0; 163} 164 165int ThrottleController::getInterfaceTxThrottle(const char *iface, int *tx) { 166 *tx = 0; 167 return 0; 168} 169