BandwidthController.cpp revision fa6f46d3370ae5475fc3bc8273bbe04ee7348d60
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[] = {
80fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall/* Cleanup rules. */
81fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall"-F", "-t raw -F", "-X costly", "-X penalty_box", };
824a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
834a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst char *BandwidthController::setupCommands[] = {
84fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall/* Created needed chains. */
85fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall"-N costly", "-N penalty_box", };
86fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
87fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallconst char *BandwidthController::basicAccountingCommands[] = { "-F INPUT",
88fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        "-A INPUT -i lo --jump ACCEPT", "-A INPUT -m owner --socket-exists", /* This is a tracking rule. */
89fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
90fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        "-F OUTPUT", "-A OUTPUT -o lo --jump ACCEPT", "-A OUTPUT -m owner --socket-exists", /* This is a tracking rule. */
914a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
92fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        "-F costly", "-A costly --jump penalty_box", "-A costly -m owner --socket-exists", /* This is a tracking rule. */
93fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        /* TODO(jpa): Figure out why iptables doesn't correctly return from this
94fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall         * chain. For now, hack the chain exit with an ACCEPT.
95fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall         */
96fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        "-A costly --jump ACCEPT", };
974a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
984a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP AbgrallBandwidthController::BandwidthController(void) {
994a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1004a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char value[PROPERTY_VALUE_MAX];
1014a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1024a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    property_get("persist.bandwidth.enable", value, "0");
1034a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    if (!strcmp(value, "1")) {
1044a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        enableBandwidthControl();
1054a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
1064a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1074a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
1084a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
109fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallint BandwidthController::runIptablesCmd(const char *cmd, bool isIp6) {
1104a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char buffer[MAX_CMD_LEN];
1114a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    const char *argv[MAX_CMD_ARGS];
112fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    int argc = 1;
1134a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char *next = buffer;
1144a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char *tmp;
1154a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
116fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    argv[0] = isIp6 ? IP6TABLES_PATH : IPTABLES_PATH;
117fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    LOGD("About to run: %s %s", argv[0], cmd);
118fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
119fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    strncpy(buffer, cmd, sizeof(buffer) - 1);
1204a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1214a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    while ((tmp = strsep(&next, " "))) {
1224a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        argv[argc++] = tmp;
1234a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        if (argc == MAX_CMD_ARGS) {
1244a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            LOGE("iptables argument overflow");
1254a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            errno = E2BIG;
1264a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            return -1;
1274a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        }
1284a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
129fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
1304a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    argv[argc] = NULL;
1314a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    /* TODO(jpa): Once this stabilizes, remove logwrap() as it tends to wedge netd
1324a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall     * Then just talk directly to the kernel via rtnetlink.
1334a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall     */
1344a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    return logwrap(argc, argv, 0);
1354a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
1364a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1374a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallint BandwidthController::enableBandwidthControl(void) {
138fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    int res;
139fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    /* Some of the initialCommands are allowed to fail */
140fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    runCommands(sizeof(cleanupCommands) / sizeof(char*), cleanupCommands, true, false);
141fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    runCommands(sizeof(cleanupCommands) / sizeof(char*), cleanupCommands, true, true);
142fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    runCommands(sizeof(setupCommands) / sizeof(char*), setupCommands, true, false);
143fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    runCommands(sizeof(setupCommands) / sizeof(char*), setupCommands, true, true);
144fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    res = runCommands(sizeof(basicAccountingCommands) / sizeof(char*), basicAccountingCommands,
145fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall                      false, false);
146fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    res |= runCommands(sizeof(basicAccountingCommands) / sizeof(char*), basicAccountingCommands,
147fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall                       false, true);
148fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    return res;
1494a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1504a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
1514a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1524a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallint BandwidthController::disableBandwidthControl(void) {
153fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    /* The cleanupCommands are allowed to fail. */
154fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    runCommands(sizeof(cleanupCommands) / sizeof(char*), cleanupCommands, true);
155fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    runCommands(sizeof(cleanupCommands) / sizeof(char*), cleanupCommands, true, true);
156fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    return 0;
1574a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
1584a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
159fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallint BandwidthController::runCommands(int numCommands, const char *commands[], bool allowFailure,
160fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall                                     bool isIp6) {
161fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    int res = 0;
162fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    LOGD("runCommands(): %d commands", numCommands);
163fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    for (int cmdNum = 0; cmdNum < numCommands; cmdNum++) {
164fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        res = runIptablesCmd(commands[cmdNum], isIp6);
165fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        if (res && !allowFailure)
166fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            return res;
167fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
168fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    return allowFailure ? res : 0;
169fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall}
170fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
171fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallstd::string BandwidthController::makeIptablesNaughtyCmd(IptOp op, int uid, bool isIp6) {
172fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    std::string res;
173fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    char convBuff[21]; // log10(2^64) ~ 20
174fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
175fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    switch (op) {
176fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        case IptOpInsert:
177fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            res = "-I";
178fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            break;
179fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        case IptOpReplace:
180fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            res = "-R";
181fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            break;
182fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        default:
183fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        case IptOpDelete:
184fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            res = "-D";
185fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            break;
186fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
187fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    res += " penalty_box";
188fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    sprintf(convBuff, "%d", uid);
189fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    res += " -m owner --uid-owner ";
190fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    res += convBuff;
191fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    res += " --jump REJECT --reject-with";
192fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    if (isIp6) {
193fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        res += " icmp6-adm-prohibited";
194fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    } else {
195fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        res += " icmp-net-prohibited";
196fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
197fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    return res;
198fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall}
199fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
200fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallint BandwidthController::addNaughtyApps(int numUids, char *appUids[]) {
201fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    return maninpulateNaughtyApps(numUids, appUids, true);
202fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall}
203fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
204fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallint BandwidthController::removeNaughtyApps(int numUids, char *appUids[]) {
205fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    return maninpulateNaughtyApps(numUids, appUids, false);
206fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall}
207fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
208fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallint BandwidthController::maninpulateNaughtyApps(int numUids, char *appStrUids[], bool doAdd) {
209fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    char cmd[MAX_CMD_LEN];
210fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    int uidNum;
211fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    const char *addFailedTemplate = "Failed to add app uid %d to penalty box.";
212fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    const char *deleteFailedTemplate = "Failed to delete app uid %d from penalty box.";
213fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    IptOp op = doAdd ? IptOpInsert : IptOpDelete;
214fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
215fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    int appUids[numUids];
216fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    for (uidNum = 0; uidNum < numUids; uidNum++) {
217fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        appUids[uidNum] = atol(appStrUids[uidNum]);
218fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        if (appUids[uidNum] == 0) {
219fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            LOGE((doAdd ? addFailedTemplate : deleteFailedTemplate), appUids[uidNum]);
220fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            goto fail_parse;
221fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        }
222fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
223fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
224fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    for (uidNum = 0; uidNum < numUids; uidNum++) {
225fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        std::string naughtyCmd = makeIptablesNaughtyCmd(op, appUids[uidNum], false);
226fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        if (runIptablesCmd(naughtyCmd.c_str())) {
227fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            LOGE((doAdd ? addFailedTemplate : deleteFailedTemplate), appUids[uidNum]);
228fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            goto fail_with_uidNum;
2294a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        }
230fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        naughtyCmd = makeIptablesNaughtyCmd(op, appUids[uidNum], true);
231fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        if (runIptablesCmd(naughtyCmd.c_str(), true)) {
232fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            LOGE((doAdd ? addFailedTemplate : deleteFailedTemplate), appUids[uidNum]);
233fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            goto fail_with_uidNum;
234fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        }
235fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
236fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    return 0;
237fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
238fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    fail_with_uidNum:
239fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    /* Try to remove the uid that failed in any case*/
240fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    runIptablesCmd(makeIptablesNaughtyCmd(IptOpDelete, appUids[uidNum], false).c_str());
241fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    runIptablesCmd(makeIptablesNaughtyCmd(IptOpDelete, appUids[uidNum], true).c_str(), true);
242fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    fail_parse: return -1;
2434a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
2444a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
245fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallstd::string BandwidthController::makeIptablesQuotaCmd(IptOp op, char *costName, int64_t quota, bool isIp6) {
246fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    std::string res;
247fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    char convBuff[21]; // log10(2^64) ~ 20
248fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    LOGD("makeIptablesQuotaCmd(%d, %llu, %d)", op, quota, isIp6);
249fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    switch (op) {
250fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        case IptOpInsert:
251fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            res = "-I";
252fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            break;
253fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        case IptOpReplace:
254fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            res = "-R";
255fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            break;
256fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        default:
257fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        case IptOpDelete:
258fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            res = "-D";
259fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            break;
260fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
261fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    res += " costly";
262fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    if (costName) {
263fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            res += costName;
264fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
265fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    sprintf(convBuff, "%lld", quota);
266fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    res += " -m quota ! --quota ";
267fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    res += convBuff;
268fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    ;
269fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    res += " --jump REJECT --reject-with";
270fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    if (isIp6) {
271fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        res += " icmp6-adm-prohibited";
272fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    } else {
273fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        res += " icmp-net-prohibited";
274fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
275fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    return res;
276fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall}
2774a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
278fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallint BandwidthController::setInterfaceSharedQuota(int64_t maxBytes, const char *iface) {
2794a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char cmd[MAX_CMD_LEN];
2804a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char ifn[MAX_IFACENAME_LEN];
281fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    int res = 0;
2824a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
2834a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    memset(ifn, 0, sizeof(ifn));
284fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    strncpy(ifn, iface, sizeof(ifn) - 1);
2854a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
2864a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    if (maxBytes == -1) {
287fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        return removeInterfaceSharedQuota(ifn);
2884a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
2894a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
290fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    char *costName = NULL;  /* Shared quota */
291fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
2924a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    /* Insert ingress quota. */
2934a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    std::string ifaceName(ifn);
294fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    std::list<QuotaInfo>::iterator it;
295fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    for (it = ifaceRules.begin(); it != ifaceRules.end(); it++) {
296fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        if (it->first == ifaceName)
297fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            break;
2984a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
299fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
300fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    if (it == ifaceRules.end()) {
301fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        snprintf(cmd, sizeof(cmd), "-I INPUT -i %s --goto costly", ifn);
302fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        res |= runIptablesCmd(cmd);
303fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        res |= runIptablesCmd(cmd, true);
304fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        snprintf(cmd, sizeof(cmd), "-I OUTPUT -o %s --goto costly", ifn);
305fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        res |= runIptablesCmd(cmd);
306fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        res |= runIptablesCmd(cmd, true);
307fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
308fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        if (ifaceRules.empty()) {
309fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            std::string quotaCmd;
310fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes, false);
311fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            res |= runIptablesCmd(quotaCmd.c_str());
312fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes, true);
313fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            res |= runIptablesCmd(quotaCmd.c_str(), true);
3144a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            if (res) {
315fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall                LOGE("Failed set quota rule.");
316fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall                goto fail;
3174a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            }
318fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            sharedQuotaBytes = maxBytes;
319fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        }
320fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
321fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        ifaceRules.push_front(QuotaInfo(ifaceName, maxBytes));
322fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
323fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
324fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
325fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    if (maxBytes != sharedQuotaBytes) {
326fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        /* Instead of replacing, which requires being aware of the rules in
327fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall         * the kernel, we just add a new one, then delete the older one.
328fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall         */
329fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        std::string quotaCmd;
330fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
331fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes, false);
332fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        res |= runIptablesCmd(quotaCmd.c_str());
333fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes, true);
334fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        res |= runIptablesCmd(quotaCmd.c_str(), true);
335fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
336fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        quotaCmd = makeIptablesQuotaCmd(IptOpDelete, costName, sharedQuotaBytes, false);
337fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        res |= runIptablesCmd(quotaCmd.c_str());
338fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        quotaCmd = makeIptablesQuotaCmd(IptOpDelete, costName, sharedQuotaBytes, true);
339fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        res |= runIptablesCmd(quotaCmd.c_str(), true);
340fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
341fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        if (res) {
342fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            LOGE("Failed replace quota rule.");
343fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            goto fail;
344fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        }
345fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        sharedQuotaBytes = maxBytes;
3464a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
3474a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    return 0;
348fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
349fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    fail:
3504a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    /*
3514a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall     * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
3524a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall     * rules in the kernel to see which ones need cleaning up.
353fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall     * For now callers needs to choose if they want to "ndc bandwidth enable"
354fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall     * which resets everything.
3554a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall     */
356fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    removeInterfaceSharedQuota(ifn);
3574a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    return -1;
3584a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
3594a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
360fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallint BandwidthController::removeInterfaceSharedQuota(const char *iface) {
3614a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char cmd[MAX_CMD_LEN];
3624a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char ifn[MAX_IFACENAME_LEN];
363fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    int res = 0;
3644a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
3654a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    memset(ifn, 0, sizeof(ifn));
366fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    strncpy(ifn, iface, sizeof(ifn) - 1);
3674a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
3684a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    std::string ifaceName(ifn);
369fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    std::list<QuotaInfo>::iterator it;
3704a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
371fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    for (it = ifaceRules.begin(); it != ifaceRules.end(); it++) {
372fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        if (it->first == ifaceName)
373fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            break;
3744a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
375fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    if (it == ifaceRules.end()) {
376fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        LOGE("No such iface %s to delete.", ifn);
377fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        return -1;
3784a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
379fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
3804a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    snprintf(cmd, sizeof(cmd), "--delete INPUT -i %s --goto costly", ifn);
3814a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    res |= runIptablesCmd(cmd);
382fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    res |= runIptablesCmd(cmd, true);
383fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    snprintf(cmd, sizeof(cmd), "--delete OUTPUT -o %s --goto costly", ifn);
3844a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    res |= runIptablesCmd(cmd);
385fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    res |= runIptablesCmd(cmd, true);
386fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
387fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    ifaceRules.erase(it);
388fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    if (ifaceRules.empty()) {
389fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        std::string quotaCmd;
390fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        quotaCmd = makeIptablesQuotaCmd(IptOpDelete, NULL, sharedQuotaBytes, false);
391fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        res |= runIptablesCmd(quotaCmd.c_str());
392fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
393fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        quotaCmd = makeIptablesQuotaCmd(IptOpDelete, NULL, sharedQuotaBytes, true);
394fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        res |= runIptablesCmd(quotaCmd.c_str(), true);
395fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        sharedQuotaBytes = -1;
396fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
397fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
3984a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    return res;
3994a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
400