BandwidthController.cpp revision 0dad7c2f1f6994fbe5e85b9e1fc72d29d6453211
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
39fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallconst int BandwidthController::MAX_CMD_LEN = 1024;
404a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst int BandwidthController::MAX_IFACENAME_LEN = 64;
414a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst int BandwidthController::MAX_CMD_ARGS = 32;
424a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst char BandwidthController::IPTABLES_PATH[] = "/system/bin/iptables";
43fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallconst char BandwidthController::IP6TABLES_PATH[] = "/system/bin/ip6tables";
444a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
454a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall/**
464a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * Some comments about the rules:
474a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *  * Ordering
484a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *    - when an interface is marked as costly it should be INSERTED into the INPUT/OUTPUT chains.
494a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      E.g. "-I INPUT -i rmnet0 --goto costly"
504a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *    - quota'd rules in the costly chain should be before penalty_box lookups.
514a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *
524a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * * global quota vs per interface quota
534a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *   - global quota for all costly interfaces uses a single costly chain:
544a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *    . initial rules
554a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -N costly
564a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -I INPUT -i iface0 --goto costly
574a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -I OUTPUT -o iface0 --goto costly
584a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -I costly -m quota \! --quota 500000 --jump REJECT --reject-with icmp-net-prohibited
594a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -A costly                            --jump penalty_box
604a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -A costly -m owner --socket-exists
614a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *    . adding a new iface to this, E.g.:
624a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -I INPUT -i iface1 --goto costly
634a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -I OUTPUT -o iface1 --goto costly
644a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *
654a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *   - quota per interface. This is achieve by having "costly" chains per quota.
664a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *     E.g. adding a new costly interface iface0 with its own quota:
674a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -N costly_iface0
684a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -I INPUT -i iface0 --goto costly_iface0
694a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -I OUTPUT -o iface0 --goto costly_iface0
704a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -A costly_iface0 -m quota \! --quota 500000 --jump REJECT --reject-with icmp-net-prohibited
714a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -A costly_iface0                            --jump penalty_box
724a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -A costly_iface0 -m owner --socket-exists
734a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *
744a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * * penalty_box handling:
754a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *  - only one penalty_box for all interfaces
764a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *   E.g  Adding an app:
774a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *    iptables -A penalty_box -m owner --uid-owner app_3 --jump REJECT --reject-with icmp-net-prohibited
784a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall */
794a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst char *BandwidthController::cleanupCommands[] = {
800dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    /* Cleanup rules. */
810dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-F",
820dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-t raw -F",
830dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-X costly",
840dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-X penalty_box",
850dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall};
864a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
874a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst char *BandwidthController::setupCommands[] = {
880dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    /* Created needed chains. */
890dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-N costly",
900dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-N penalty_box",
910dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall};
920dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
930dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrallconst char *BandwidthController::basicAccountingCommands[] = {
940dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-F INPUT",
950dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-A INPUT -i lo --jump ACCEPT",
960dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-A INPUT -m owner --socket-exists", /* This is a tracking rule. */
970dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
980dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-F OUTPUT",
990dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-A OUTPUT -o lo --jump ACCEPT",
1000dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-A OUTPUT -m owner --socket-exists", /* This is a tracking rule. */
1010dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
1020dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-F costly",
1030dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-A costly --jump penalty_box",
1040dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-A costly -m owner --socket-exists", /* This is a tracking rule. */
1050dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    /* TODO(jpa): Figure out why iptables doesn't correctly return from this
1060dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall     * chain. For now, hack the chain exit with an ACCEPT.
1070dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall     */
1080dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-A costly --jump ACCEPT",
1090dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall};
1104a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1114a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP AbgrallBandwidthController::BandwidthController(void) {
1124a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1134a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char value[PROPERTY_VALUE_MAX];
1144a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1154a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    property_get("persist.bandwidth.enable", value, "0");
1164a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    if (!strcmp(value, "1")) {
1174a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        enableBandwidthControl();
1184a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
1194a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1204a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
1214a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1220dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrallint BandwidthController::runIpxtablesCmd(const char *cmd, bool appendReject) {
1230dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    int res = 0;
1240dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    res |= runIptablesCmd(cmd, appendReject, false);
1250dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    res |= runIptablesCmd(cmd, appendReject, true);
1260dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    return res;
1270dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall}
1280dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
1290dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrallint BandwidthController::runIptablesCmd(const char *cmd, bool appendReject, bool isIp6) {
1300dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    char buffer[MAX_CMD_LEN] = { 0 }; // strncpy() is not filling leftover with '\0'
1314a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    const char *argv[MAX_CMD_ARGS];
1320dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    int argc, nextArg;
1334a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char *next = buffer;
1344a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char *tmp;
1354a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1360dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    std::string fullCmd = cmd;
1370dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    if (appendReject) {
1380dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        fullCmd += " --jump REJECT --reject-with";
1390dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        if (isIp6) {
1400dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall            fullCmd += " icmp6-adm-prohibited";
1410dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        } else {
1420dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall            fullCmd += " icmp-net-prohibited";
1430dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        }
1440dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        argc = 4; //  --jump ...
1450dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    }
1460dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
1470dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    nextArg = 0;
1480dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    argv[nextArg++] = isIp6 ? IP6TABLES_PATH : IPTABLES_PATH;
1490dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    argc++;
1500dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    LOGD("About to run: %s %s", argv[0], fullCmd.c_str());
151fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
1520dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    strncpy(buffer, fullCmd.c_str(), sizeof(buffer) - 1);
1530dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    if (buffer[sizeof(buffer) - 1]) {
1540dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        LOGE("iptables command too long");
1550dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        errno = E2BIG;
1560dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        return -1;
1570dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    }
1584a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1594a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    while ((tmp = strsep(&next, " "))) {
1600dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        argv[nextArg++] = tmp;
1610dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        argc++;
1620dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        if (argc >= MAX_CMD_ARGS) {
1634a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            LOGE("iptables argument overflow");
1644a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            errno = E2BIG;
1654a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            return -1;
1664a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        }
1674a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
168fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
1694a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    argv[argc] = NULL;
1704a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    /* TODO(jpa): Once this stabilizes, remove logwrap() as it tends to wedge netd
1714a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall     * Then just talk directly to the kernel via rtnetlink.
1724a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall     */
1734a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    return logwrap(argc, argv, 0);
1744a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
1754a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1764a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallint BandwidthController::enableBandwidthControl(void) {
177fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    int res;
178fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    /* Some of the initialCommands are allowed to fail */
1790dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    runCommands(sizeof(cleanupCommands) / sizeof(char*), cleanupCommands, true);
1800dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    runCommands(sizeof(setupCommands) / sizeof(char*), setupCommands, true);
181fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    res = runCommands(sizeof(basicAccountingCommands) / sizeof(char*), basicAccountingCommands,
1820dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall                      false);
183fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    return res;
1844a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1854a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
1864a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1874a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallint BandwidthController::disableBandwidthControl(void) {
188fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    /* The cleanupCommands are allowed to fail. */
189fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    runCommands(sizeof(cleanupCommands) / sizeof(char*), cleanupCommands, true);
190fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    return 0;
1914a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
1924a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1930dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrallint BandwidthController::runCommands(int numCommands, const char *commands[], bool allowFailure) {
194fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    int res = 0;
195fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    LOGD("runCommands(): %d commands", numCommands);
196fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    for (int cmdNum = 0; cmdNum < numCommands; cmdNum++) {
1970dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        res = runIpxtablesCmd(commands[cmdNum], false);
198fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        if (res && !allowFailure)
199fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            return res;
200fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
201fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    return allowFailure ? res : 0;
202fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall}
203fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
2040dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrallstd::string BandwidthController::makeIptablesNaughtyCmd(IptOp op, int uid) {
205fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    std::string res;
206fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    char convBuff[21]; // log10(2^64) ~ 20
207fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
208fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    switch (op) {
209fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        case IptOpInsert:
210fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            res = "-I";
211fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            break;
212fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        case IptOpReplace:
213fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            res = "-R";
214fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            break;
215fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        default:
216fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        case IptOpDelete:
217fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            res = "-D";
218fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            break;
219fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
220fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    res += " penalty_box";
221fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    sprintf(convBuff, "%d", uid);
222fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    res += " -m owner --uid-owner ";
223fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    res += convBuff;
224fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    return res;
225fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall}
226fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
227fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallint BandwidthController::addNaughtyApps(int numUids, char *appUids[]) {
228fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    return maninpulateNaughtyApps(numUids, appUids, true);
229fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall}
230fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
231fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallint BandwidthController::removeNaughtyApps(int numUids, char *appUids[]) {
232fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    return maninpulateNaughtyApps(numUids, appUids, false);
233fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall}
234fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
235fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallint BandwidthController::maninpulateNaughtyApps(int numUids, char *appStrUids[], bool doAdd) {
236fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    char cmd[MAX_CMD_LEN];
237fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    int uidNum;
238fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    const char *addFailedTemplate = "Failed to add app uid %d to penalty box.";
239fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    const char *deleteFailedTemplate = "Failed to delete app uid %d from penalty box.";
240fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    IptOp op = doAdd ? IptOpInsert : IptOpDelete;
241fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
242fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    int appUids[numUids];
243fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    for (uidNum = 0; uidNum < numUids; uidNum++) {
244fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        appUids[uidNum] = atol(appStrUids[uidNum]);
245fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        if (appUids[uidNum] == 0) {
246fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            LOGE((doAdd ? addFailedTemplate : deleteFailedTemplate), appUids[uidNum]);
247fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            goto fail_parse;
248fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        }
249fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
250fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
251fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    for (uidNum = 0; uidNum < numUids; uidNum++) {
2520dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        std::string naughtyCmd = makeIptablesNaughtyCmd(op, appUids[uidNum]);
2530dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        if (runIpxtablesCmd(naughtyCmd.c_str(), true)) {
254fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            LOGE((doAdd ? addFailedTemplate : deleteFailedTemplate), appUids[uidNum]);
255fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            goto fail_with_uidNum;
256fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        }
257fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
258fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    return 0;
259fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
260fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    fail_with_uidNum:
261fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    /* Try to remove the uid that failed in any case*/
2620dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    runIpxtablesCmd(makeIptablesNaughtyCmd(IptOpDelete, appUids[uidNum]).c_str(), true);
263fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    fail_parse: return -1;
2644a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
2654a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
2660dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrallstd::string BandwidthController::makeIptablesQuotaCmd(IptOp op, char *costName, int64_t quota) {
267fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    std::string res;
268fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    char convBuff[21]; // log10(2^64) ~ 20
2690dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
2700dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    LOGD("makeIptablesQuotaCmd(%d, %llu)", op, quota);
2710dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
272fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    switch (op) {
273fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        case IptOpInsert:
274fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            res = "-I";
275fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            break;
276fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        case IptOpReplace:
277fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            res = "-R";
278fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            break;
279fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        default:
280fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        case IptOpDelete:
281fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            res = "-D";
282fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            break;
283fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
284fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    res += " costly";
285fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    if (costName) {
2860dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        res += "_";
2870dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        res += costName;
288fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
289fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    sprintf(convBuff, "%lld", quota);
2900dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    /* TODO(jpa): Use -m quota2 --name " + costName + " ! --quota "
2910dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall     * once available.
2920dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall     */
293fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    res += " -m quota ! --quota ";
294fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    res += convBuff;
295fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    ;
2960dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    // The requried --jump REJECT ... will be added later.
2970dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    return res;
2980dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall}
2990dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
3000dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrallint BandwidthController::prepCostlyIface(const char *ifn, bool isShared) {
3010dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    char cmd[MAX_CMD_LEN];
3020dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    int res = 0;
3030dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    std::string costString;
3040dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    const char *costCString;
3050dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
3060dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    costString = "costly";
3070dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    /* The "-N costly" is created upfront, no need to handle it here. */
3080dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    if (!isShared) {
3090dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        costString += "_";
3100dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        costString += ifn;
3110dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        costCString = costString.c_str();
3120dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        snprintf(cmd, sizeof(cmd), "-N %s", costCString);
3130dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        res |= runIpxtablesCmd(cmd, false);
3140dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        snprintf(cmd, sizeof(cmd), "-A %s -j penalty_box", costCString);
3150dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        res |= runIpxtablesCmd(cmd, false);
3160dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        snprintf(cmd, sizeof(cmd), "-A %s -m owner --socket-exists", costCString);
3170dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        res |= runIpxtablesCmd(cmd, false);
3180dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        /* TODO(jpa): Figure out why iptables doesn't correctly return from this
3190dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall         * chain. For now, hack the chain exit with an ACCEPT.
3200dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall         */
3210dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        snprintf(cmd, sizeof(cmd), "-A %s --jump ACCEPT", costCString);
3220dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        res |= runIpxtablesCmd(cmd, false);
3230dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    } else {
3240dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        costCString = costString.c_str();
3250dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    }
3260dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
3270dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    snprintf(cmd, sizeof(cmd), "-I INPUT -i %s --goto %s", ifn, costCString);
3280dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    res |= runIpxtablesCmd(cmd, false);
3290dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    snprintf(cmd, sizeof(cmd), "-I OUTPUT -o %s --goto %s", ifn, costCString);
3300dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    res |= runIpxtablesCmd(cmd, false);
3310dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    return res;
3320dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall}
3330dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
3340dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrallint BandwidthController::cleanupCostlyIface(const char *ifn, bool isShared) {
3350dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    char cmd[MAX_CMD_LEN];
3360dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    int res = 0;
3370dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    std::string costString;
3380dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    const char *costCString;
3390dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
3400dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    costString = "costly";
3410dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    if (!isShared) {
3420dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        costString += "_";
3430dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        costString += ifn;
3440dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        costCString = costString.c_str();
345fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    } else {
3460dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        costCString = costString.c_str();
3470dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    }
3480dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
3490dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    snprintf(cmd, sizeof(cmd), "-D INPUT -i %s --goto %s", ifn, costCString);
3500dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    res |= runIpxtablesCmd(cmd, false);
3510dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    snprintf(cmd, sizeof(cmd), "-D OUTPUT -o %s --goto %s", ifn, costCString);
3520dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    res |= runIpxtablesCmd(cmd, false);
3530dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
3540dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    /* The "-N costly" is created upfront, no need to handle it here. */
3550dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    if (!isShared) {
3560dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        snprintf(cmd, sizeof(cmd), "-F %s", costCString);
3570dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        res |= runIpxtablesCmd(cmd, false);
358fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
359fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    return res;
360fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall}
3614a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
3620dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrallint BandwidthController::setInterfaceSharedQuota(const char *iface, int64_t maxBytes) {
3634a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char cmd[MAX_CMD_LEN];
3644a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char ifn[MAX_IFACENAME_LEN];
365fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    int res = 0;
3664a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
3674a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    memset(ifn, 0, sizeof(ifn));
368fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    strncpy(ifn, iface, sizeof(ifn) - 1);
3694a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
3704a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    if (maxBytes == -1) {
371fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        return removeInterfaceSharedQuota(ifn);
3724a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
3734a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
3740dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    char *costName = NULL; /* Shared quota */
375fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
3764a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    /* Insert ingress quota. */
3774a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    std::string ifaceName(ifn);
3780dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    std::list<std::string>::iterator it;
3790dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
3800dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        if (*it == ifaceName)
381fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            break;
3824a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
383fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
3840dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    if (it == sharedQuotaIfaces.end()) {
3850dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        res |= prepCostlyIface(ifn, true);
3860dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        if (sharedQuotaIfaces.empty()) {
387fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            std::string quotaCmd;
3880dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall            quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
3890dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall            res |= runIpxtablesCmd(quotaCmd.c_str(), true);
3904a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            if (res) {
391fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall                LOGE("Failed set quota rule.");
392fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall                goto fail;
3934a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            }
394fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            sharedQuotaBytes = maxBytes;
395fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        }
3960dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        sharedQuotaIfaces.push_front(ifaceName);
397fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
398fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
399fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
400fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    if (maxBytes != sharedQuotaBytes) {
401fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        /* Instead of replacing, which requires being aware of the rules in
402fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall         * the kernel, we just add a new one, then delete the older one.
403fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall         */
404fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        std::string quotaCmd;
405fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
4060dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
4070dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        res |= runIpxtablesCmd(quotaCmd.c_str(), true);
408fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
4090dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        quotaCmd = makeIptablesQuotaCmd(IptOpDelete, costName, sharedQuotaBytes);
4100dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        res |= runIpxtablesCmd(quotaCmd.c_str(), true);
411fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
412fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        if (res) {
413fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            LOGE("Failed replace quota rule.");
414fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            goto fail;
415fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        }
416fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        sharedQuotaBytes = maxBytes;
4174a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
4184a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    return 0;
419fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
420fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    fail:
4214a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    /*
4224a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall     * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
4234a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall     * rules in the kernel to see which ones need cleaning up.
424fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall     * For now callers needs to choose if they want to "ndc bandwidth enable"
425fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall     * which resets everything.
4264a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall     */
427fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    removeInterfaceSharedQuota(ifn);
4284a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    return -1;
4294a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
4304a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
431fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallint BandwidthController::removeInterfaceSharedQuota(const char *iface) {
4324a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char ifn[MAX_IFACENAME_LEN];
433fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    int res = 0;
4344a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
4354a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    memset(ifn, 0, sizeof(ifn));
436fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    strncpy(ifn, iface, sizeof(ifn) - 1);
4374a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
4384a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    std::string ifaceName(ifn);
4390dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    std::list<std::string>::iterator it;
4404a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
4410dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
4420dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        if (*it == ifaceName)
443fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            break;
4444a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
4450dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    if (it == sharedQuotaIfaces.end()) {
446fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        LOGE("No such iface %s to delete.", ifn);
447fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        return -1;
4484a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
449fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
4500dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    res |= cleanupCostlyIface(ifn, true);
4510dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    sharedQuotaIfaces.erase(it);
452fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
4530dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    if (sharedQuotaIfaces.empty()) {
454fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        std::string quotaCmd;
4550dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        quotaCmd = makeIptablesQuotaCmd(IptOpDelete, NULL, sharedQuotaBytes);
4560dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        res |= runIpxtablesCmd(quotaCmd.c_str(), true);
457fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        sharedQuotaBytes = -1;
458fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
459fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
4604a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    return res;
4614a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
4620dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
4630dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrallint BandwidthController::setInterfaceQuota(const char *iface, int64_t maxBytes) {
4640dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    char ifn[MAX_IFACENAME_LEN];
4650dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    int res = 0;
4660dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
4670dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    memset(ifn, 0, sizeof(ifn));
4680dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    strncpy(ifn, iface, sizeof(ifn) - 1);
4690dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
4700dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    if (maxBytes == -1) {
4710dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        return removeInterfaceQuota(ifn);
4720dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    }
4730dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
4740dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    char *costName = ifn;
4750dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
4760dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    /* Insert ingress quota. */
4770dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    std::string ifaceName(ifn);
4780dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    std::list<QuotaInfo>::iterator it;
4790dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
4800dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        if (it->first == ifaceName)
4810dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall            break;
4820dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    }
4830dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
4840dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    if (it == quotaIfaces.end()) {
4850dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
4860dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        res |= prepCostlyIface(ifn, false);
4870dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
4880dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        std::string quotaCmd;
4890dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
4900dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        res |= runIpxtablesCmd(quotaCmd.c_str(), true);
4910dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        if (res) {
4920dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall            LOGE("Failed set quota rule.");
4930dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall            goto fail;
4940dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        }
4950dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
4960dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        quotaIfaces.push_front(QuotaInfo(ifaceName, maxBytes));
4970dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
4980dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    } else {
4990dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        /* Instead of replacing, which requires being aware of the rules in
5000dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall         * the kernel, we just add a new one, then delete the older one.
5010dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall         */
5020dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        std::string quotaCmd;
5030dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5040dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
5050dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        res |= runIpxtablesCmd(quotaCmd.c_str(), true);
5060dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5070dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        quotaCmd = makeIptablesQuotaCmd(IptOpDelete, costName, it->second);
5080dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        res |= runIpxtablesCmd(quotaCmd.c_str(), true);
5090dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5100dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        if (res) {
5110dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall            LOGE("Failed replace quota rule.");
5120dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall            goto fail;
5130dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        }
5140dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        it->second = maxBytes;
5150dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    }
5160dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    return 0;
5170dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5180dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    fail:
5190dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    /*
5200dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall     * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
5210dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall     * rules in the kernel to see which ones need cleaning up.
5220dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall     * For now callers needs to choose if they want to "ndc bandwidth enable"
5230dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall     * which resets everything.
5240dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall     */
5250dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    removeInterfaceSharedQuota(ifn);
5260dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    return -1;
5270dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall}
5280dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5290dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrallint BandwidthController::removeInterfaceQuota(const char *iface) {
5300dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5310dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    char ifn[MAX_IFACENAME_LEN];
5320dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    int res = 0;
5330dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5340dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    memset(ifn, 0, sizeof(ifn));
5350dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    strncpy(ifn, iface, sizeof(ifn) - 1);
5360dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5370dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    char *costName = ifn;
5380dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5390dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    std::string ifaceName(ifn);
5400dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    std::list<QuotaInfo>::iterator it;
5410dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
5420dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        if (it->first == ifaceName)
5430dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall            break;
5440dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    }
5450dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5460dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    if (it == quotaIfaces.end()) {
5470dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        LOGE("No such iface %s to delete.", ifn);
5480dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        return -1;
5490dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    }
5500dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5510dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    /* This also removes the quota command of CostlyIface chain. */
5520dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    res |= cleanupCostlyIface(ifn, false);
5530dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5540dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    quotaIfaces.erase(it);
5550dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5560dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    return res;
5570dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall}
558