BandwidthController.cpp revision 4a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11
14a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall/*
24a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * Copyright (C) 2011 The Android Open Source Project
34a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *
44a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * Licensed under the Apache License, Version 2.0 (the "License");
54a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * you may not use this file except in compliance with the License.
64a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * You may obtain a copy of the License at
74a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *
84a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      http://www.apache.org/licenses/LICENSE-2.0
94a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *
104a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * Unless required by applicable law or agreed to in writing, software
114a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * distributed under the License is distributed on an "AS IS" BASIS,
124a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * See the License for the specific language governing permissions and
144a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * limitations under the License.
154a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall */
164a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
174a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <stdlib.h>
184a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <errno.h>
194a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <fcntl.h>
204a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <string.h>
214a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
224a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <sys/socket.h>
234a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <sys/stat.h>
244a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <sys/types.h>
254a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <sys/wait.h>
264a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
274a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <linux/netlink.h>
284a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <linux/rtnetlink.h>
294a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <linux/pkt_sched.h>
304a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
314a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#define LOG_TAG "BandwidthController"
324a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <cutils/log.h>
334a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <cutils/properties.h>
344a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
354a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallextern "C" int logwrap(int argc, const char **argv, int background);
364a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
374a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include "BandwidthController.h"
384a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
394a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
404a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst int BandwidthController::MAX_CMD_LEN = 255;
414a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst int BandwidthController::MAX_IFACENAME_LEN = 64;
424a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst int BandwidthController::MAX_CMD_ARGS = 32;
434a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst char BandwidthController::IPTABLES_PATH[] = "/system/bin/iptables";
444a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
454a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
464a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall/**
474a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * Some comments about the rules:
484a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *  * Ordering
494a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *    - when an interface is marked as costly it should be INSERTED into the INPUT/OUTPUT chains.
504a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      E.g. "-I INPUT -i rmnet0 --goto costly"
514a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *    - quota'd rules in the costly chain should be before penalty_box lookups.
524a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *
534a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * * global quota vs per interface quota
544a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *   - global quota for all costly interfaces uses a single costly chain:
554a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *    . initial rules
564a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -N costly
574a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -I INPUT -i iface0 --goto costly
584a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -I OUTPUT -o iface0 --goto costly
594a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -I costly -m quota \! --quota 500000 --jump REJECT --reject-with icmp-net-prohibited
604a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -A costly                            --jump penalty_box
614a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -A costly -m owner --socket-exists
624a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *    . adding a new iface to this, E.g.:
634a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -I INPUT -i iface1 --goto costly
644a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -I OUTPUT -o iface1 --goto costly
654a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *
664a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *   - quota per interface. This is achieve by having "costly" chains per quota.
674a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *     E.g. adding a new costly interface iface0 with its own quota:
684a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -N costly_iface0
694a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -I INPUT -i iface0 --goto costly_iface0
704a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -I OUTPUT -o iface0 --goto costly_iface0
714a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -A costly_iface0 -m quota \! --quota 500000 --jump REJECT --reject-with icmp-net-prohibited
724a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -A costly_iface0                            --jump penalty_box
734a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -A costly_iface0 -m owner --socket-exists
744a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *
754a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * * penalty_box handling:
764a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *  - only one penalty_box for all interfaces
774a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *   E.g  Adding an app:
784a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *    iptables -A penalty_box -m owner --uid-owner app_3 --jump REJECT --reject-with icmp-net-prohibited
794a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall */
804a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst char *BandwidthController::cleanupCommands[] = {
814a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    /* Cleanup rules. */
824a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    "-F",
834a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    "-t raw -F",
844a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    "-X costly",
854a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    "-X penalty_box",
864a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall};
874a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
884a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst char *BandwidthController::setupCommands[] = {
894a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    /* Created needed chains. */
904a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    "-N costly",
914a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    "-N penalty_box",
924a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall};
934a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
944a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst char *BandwidthController::basicAccountingCommands[] = {
954a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    "-F INPUT",
964a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    "-A INPUT -i lo --jump ACCEPT",
974a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    "-A INPUT -m owner --socket-exists",  /* This is a tracking rule. */
984a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
994a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    "-F OUTPUT",
1004a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    "-A OUTPUT -o lo --jump ACCEPT",
1014a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    "-A OUTPUT -m owner --socket-exists",  /* This is a tracking rule. */
1024a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1034a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    "-F costly",
1044a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    "-A costly --jump penalty_box",
1054a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    "-A costly -m owner --socket-exists",    /* This is a tracking rule. */
1064a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    /* TODO(jpa): Figure out why iptables doesn't correctly return from this
1074a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall     * chain. For now, hack the chain exit with an ACCEPT.
1084a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall     */
1094a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    "-A costly --jump ACCEPT",
1104a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall};
1114a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1124a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1134a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP AbgrallBandwidthController::BandwidthController(void) {
1144a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1154a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char value[PROPERTY_VALUE_MAX];
1164a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1174a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    property_get("persist.bandwidth.enable", value, "0");
1184a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    if (!strcmp(value, "1")) {
1194a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        enableBandwidthControl();
1204a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
1214a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1224a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
1234a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1244a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallint BandwidthController::runIptablesCmd(const char *cmd) {
1254a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char buffer[MAX_CMD_LEN];
1264a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1274a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    LOGD("About to run: iptables %s", cmd);
1284a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1294a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    strncpy(buffer, cmd, sizeof(buffer)-1);
1304a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1314a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    const char *argv[MAX_CMD_ARGS];
1324a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char *next = buffer;
1334a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char *tmp;
1344a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1354a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    argv[0] = IPTABLES_PATH;
1364a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    int argc = 1;
1374a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1384a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    while ((tmp = strsep(&next, " "))) {
1394a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        argv[argc++] = tmp;
1404a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        if (argc == MAX_CMD_ARGS) {
1414a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            LOGE("iptables argument overflow");
1424a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            errno = E2BIG;
1434a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            return -1;
1444a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        }
1454a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
1464a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    argv[argc] = NULL;
1474a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    /* TODO(jpa): Once this stabilizes, remove logwrap() as it tends to wedge netd
1484a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall     * Then just talk directly to the kernel via rtnetlink.
1494a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall     */
1504a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    return logwrap(argc, argv, 0);
1514a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
1524a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1534a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1544a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallint BandwidthController::enableBandwidthControl(void) {
1554a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        /* Some of the initialCommands are allowed to fail */
1564a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        runCommands(cleanupCommands, sizeof(cleanupCommands)/sizeof(char*), true);
1574a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        runCommands(setupCommands, sizeof(setupCommands)/sizeof(char*), true);
1584a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        return runCommands(basicAccountingCommands,
1594a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall                           sizeof(basicAccountingCommands)/sizeof(char*));
1604a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1614a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
1624a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1634a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallint BandwidthController::disableBandwidthControl(void) {
1644a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        /* The cleanupCommands are allowed to fail */
1654a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        runCommands(cleanupCommands, sizeof(cleanupCommands)/sizeof(char*), true);
1664a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        return 0;
1674a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
1684a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1694a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallint BandwidthController::runCommands(const char *commands[], int numCommands, bool allowFailure) {
1704a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        int res = 0;
1714a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        LOGD("runCommands(): %d commands", numCommands);
1724a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        for (int cmdNum = 0; cmdNum < numCommands; cmdNum++) {
1734a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall                res = runIptablesCmd(commands[cmdNum]);
1744a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall                if(res && !allowFailure) return res;
1754a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        }
1764a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        return allowFailure?res:0;
1774a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
1784a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1794a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1804a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallint BandwidthController::setInterfaceQuota(const char *iface,
1814a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall                                           int64_t maxBytes) {
1824a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char cmd[MAX_CMD_LEN];
1834a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char ifn[MAX_IFACENAME_LEN];
1844a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    int res;
1854a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1864a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    memset(ifn, 0, sizeof(ifn));
1874a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    strncpy(ifn, iface, sizeof(ifn)-1);
1884a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1894a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    if (maxBytes == -1) {
1904a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        return removeQuota(ifn);
1914a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
1924a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1934a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    /* Insert ingress quota. */
1944a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    std::string ifaceName(ifn);
1954a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    std::list<std::string>::iterator it;
1964a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    int pos;
1974a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    for (pos=1, it = ifaceRules.begin(); it != ifaceRules.end(); it++, pos++) {
1984a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            if (*it == ifaceName)
1994a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall                    break;
2004a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
2014a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    if (it != ifaceRules.end()) {
2024a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            snprintf(cmd, sizeof(cmd), "-R INPUT %d -i %s --goto costly", pos, ifn);
2034a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            res = runIptablesCmd(cmd);
2044a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            snprintf(cmd, sizeof(cmd), "-R OUTPUT %d -o %s --goto costly", pos, ifn);
2054a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            res |= runIptablesCmd(cmd);
2064a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            snprintf(cmd, sizeof(cmd), "-R costly %d -m quota ! --quota %lld"
2074a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall                    " --jump REJECT --reject-with icmp-net-prohibited",
2084a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall                    pos, maxBytes);
2094a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            res |= runIptablesCmd(cmd);
2104a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            if (res) {
2114a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall                    LOGE("Failed set quota rule.");
2124a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall                    goto fail;
2134a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            }
2144a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    } else {
2154a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            pos = 1;
2164a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            snprintf(cmd, sizeof(cmd), "-I INPUT -i %s --goto costly", ifn);
2174a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            res = runIptablesCmd(cmd);
2184a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            snprintf(cmd, sizeof(cmd), "-I OUTPUT -o %s --goto costly", ifn);
2194a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            res |= runIptablesCmd(cmd);
2204a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            snprintf(cmd, sizeof(cmd), "-I costly -m quota ! --quota %lld"
2214a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall                    " --jump REJECT --reject-with icmp-net-prohibited",
2224a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall                    maxBytes);
2234a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            res |= runIptablesCmd(cmd);
2244a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            if (res) {
2254a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall                    LOGE("Failed set quota rule.");
2264a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall                    goto fail;
2274a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            }
2284a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            ifaceRules.push_front(ifaceName);
2294a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
2304a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    return 0;
2314a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallfail:
2324a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    /*
2334a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall     * Failure tends to be that the rules have been messed up.
2344a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall     * For now cleanup all the rules.
2354a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall     * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
2364a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall     * rules in the kernel to see which ones need cleaning up.
2374a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall     */
2384a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    runCommands(basicAccountingCommands,
2394a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall                sizeof(basicAccountingCommands)/sizeof(char*), true);
2404a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    removeQuota(ifn);
2414a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    return -1;
2424a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
2434a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
2444a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallint BandwidthController::removeQuota(const char *iface) {
2454a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char cmd[MAX_CMD_LEN];
2464a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char ifn[MAX_IFACENAME_LEN];
2474a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    int res;
2484a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
2494a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    memset(ifn, 0, sizeof(ifn));
2504a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    strncpy(ifn, iface, sizeof(ifn)-1);
2514a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
2524a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    std::string ifaceName(ifn);
2534a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    std::list<std::string>::iterator it;
2544a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
2554a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    int pos;
2564a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    for (pos=1, it = ifaceRules.begin(); it != ifaceRules.end(); it++, pos++) {
2574a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            if (*it == ifaceName)
2584a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall                    break;
2594a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
2604a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    if(it == ifaceRules.end()) {
2614a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            LOGE("No such iface %s to delete.", ifn);
2624a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            return -1;
2634a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
2644a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    ifaceRules.erase(it);
2654a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    snprintf(cmd, sizeof(cmd), "--delete INPUT -i %s --goto costly", ifn);
2664a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    res = runIptablesCmd(cmd);
2674a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    snprintf(cmd, sizeof(cmd), "--delete OUTPUT -o %s --goto costly", ifn);
2684a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    res |= runIptablesCmd(cmd);
2694a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    // Don't use rule-matching for this one. Quota is the remaining one.
2704a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    snprintf(cmd, sizeof(cmd), "--delete costly %d", pos);
2714a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    res |= runIptablesCmd(cmd);
2724a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    return res;
2734a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
274