Home | History | Annotate | Download | only in netd
      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: 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 
    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 
    168 int ThrottleController::getInterfaceRxThrottle(const char *iface, int *rx) {
    169     *rx = 0;
    170     return 0;
    171 }
    172 
    173 int ThrottleController::getInterfaceTxThrottle(const char *iface, int *tx) {
    174     *tx = 0;
    175     return 0;
    176 }
    177