C++程序  |  169行  |  4.06 KB

/*
 * Copyright (C) 2008 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>

#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>

#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/pkt_sched.h>

#define LOG_TAG "ThrottleController"
#include <cutils/log.h>


#include "ThrottleController.h"
#include "NetdConstants.h"

extern "C" int system_nosh(const char *command);
extern "C" int ifc_init(void);
extern "C" int ifc_up(const char *name);
extern "C" int ifc_down(const char *name);

int ThrottleController::runTcCmd(const char *cmd) {
    char *buffer;
    size_t len = strnlen(cmd, 255);
    int res;

    if (len == 255) {
        ALOGE("tc command too long");
        errno = E2BIG;
        return -1;
    }

    asprintf(&buffer, "%s %s", TC_PATH, cmd);
    res = system_nosh(buffer);
    free(buffer);
    return res;
}

int ThrottleController::setInterfaceThrottle(const char *iface, int rxKbps, int txKbps) {
    char cmd[512];
    char ifn[65];
    int rc;

    memset(ifn, 0, sizeof(ifn));
    strncpy(ifn, iface, sizeof(ifn)-1);

    if (txKbps == -1) {
        reset(ifn);
        return 0;
    }

    /*
     *
     * Target interface configuration
     *
     */

    /*
     * Add root qdisc for the interface
     */
    sprintf(cmd, "qdisc add dev %s root handle 1: htb default 1 r2q 1000", ifn);
    if (runTcCmd(cmd)) {
        ALOGE("Failed to add root qdisc (%s)", strerror(errno));
        goto fail;
    }

    /*
     * Add our egress throttling class
     */
    sprintf(cmd, "class add dev %s parent 1: classid 1:1 htb rate %dkbit", ifn, txKbps);
    if (runTcCmd(cmd)) {
        ALOGE("Failed to add egress throttling class (%s)", strerror(errno));
        goto fail;
    }

    /*
     * Bring up the IFD device
     */
    ifc_init();
    if (ifc_up("ifb0")) {
        ALOGE("Failed to up ifb0 (%s)", strerror(errno));
        goto fail;
    }

    /*
     * Add root qdisc for IFD
     */
    sprintf(cmd, "qdisc add dev ifb0 root handle 1: htb default 1 r2q 1000");
    if (runTcCmd(cmd)) {
        ALOGE("Failed to add root ifb qdisc (%s)", strerror(errno));
        goto fail;
    }

    /*
     * Add our ingress throttling class
     */
    sprintf(cmd, "class add dev ifb0 parent 1: classid 1:1 htb rate %dkbit", rxKbps);
    if (runTcCmd(cmd)) {
        ALOGE("Failed to add ingress throttling class (%s)", strerror(errno));
        goto fail;
    }

    /*
     * Add ingress qdisc for pkt redirection
     */
    sprintf(cmd, "qdisc add dev %s ingress", ifn);
    if (runTcCmd(cmd)) {
        ALOGE("Failed to add ingress qdisc (%s)", strerror(errno));
        goto fail;
    }

    /*
     * Add filter to link <ifn> -> ifb0
     */
    sprintf(cmd, "filter add dev %s parent ffff: protocol ip prio 10 u32 match "
            "u32 0 0 flowid 1:1 action mirred egress redirect dev ifb0", ifn);
    if (runTcCmd(cmd)) {
        ALOGE("Failed to add ifb filter (%s)", strerror(errno));
        goto fail;
    }

    return 0;
fail:
    reset(ifn);
    return -1;
}

void ThrottleController::reset(const char *iface) {
    char cmd[128];

    sprintf(cmd, "qdisc del dev %s root", iface);
    runTcCmd(cmd);
    sprintf(cmd, "qdisc del dev %s ingress", iface);
    runTcCmd(cmd);

    runTcCmd("qdisc del dev ifb0 root");
}

int ThrottleController::getInterfaceRxThrottle(const char *iface, int *rx) {
    *rx = 0;
    return 0;
}

int ThrottleController::getInterfaceTxThrottle(const char *iface, int *tx) {
    *tx = 0;
    return 0;
}