BandwidthController.cpp revision 11b4e9b26fe7b878992162afb39f5a8acfd143ed
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
178a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall#include <errno.h>
184a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <fcntl.h>
198a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall#include <stdlib.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";
448a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallconst char BandwidthController::ALERT_IPT_TEMPLATE[] = "%s %s -m quota2 ! --quota %lld --name %s";
458a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallconst int BandwidthController::ALERT_RULE_POS_IN_COSTLY_CHAIN = 4;
4611b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrallbool BandwidthController::useLogwrapCall = false;
474a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
484a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall/**
494a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * Some comments about the rules:
504a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *  * Ordering
514a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *    - when an interface is marked as costly it should be INSERTED into the INPUT/OUTPUT chains.
524a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      E.g. "-I INPUT -i rmnet0 --goto costly"
534a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *    - quota'd rules in the costly chain should be before penalty_box lookups.
544a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *
554a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * * global quota vs per interface quota
564a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *   - global quota for all costly interfaces uses a single costly chain:
574a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *    . initial rules
58bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *      iptables -N costly_shared
59bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *      iptables -I INPUT -i iface0 --goto costly_shared
60bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *      iptables -I OUTPUT -o iface0 --goto costly_shared
61bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *      iptables -I costly_shared -m quota \! --quota 500000 \
62bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *          --jump REJECT --reject-with icmp-net-prohibited
63bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *      iptables -A costly_shared --jump penalty_box
64bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *      iptables -A costly_shared -m owner --socket-exists
658a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall *
664a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *    . adding a new iface to this, E.g.:
67bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *      iptables -I INPUT -i iface1 --goto costly_shared
68bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *      iptables -I OUTPUT -o iface1 --goto costly_shared
694a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *
704a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *   - quota per interface. This is achieve by having "costly" chains per quota.
714a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *     E.g. adding a new costly interface iface0 with its own quota:
724a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -N costly_iface0
734a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -I INPUT -i iface0 --goto costly_iface0
744a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -I OUTPUT -o iface0 --goto costly_iface0
75bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *      iptables -A costly_iface0 -m quota \! --quota 500000 \
76bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *          --jump REJECT --reject-with icmp-net-prohibited
77bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *      iptables -A costly_iface0 --jump penalty_box
784a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *      iptables -A costly_iface0 -m owner --socket-exists
794a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *
804a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * * penalty_box handling:
814a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *  - only one penalty_box for all interfaces
824a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall *   E.g  Adding an app:
83bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *    iptables -A penalty_box -m owner --uid-owner app_3 \
84bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall *        --jump REJECT --reject-with icmp-net-prohibited
854a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall */
864a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst char *BandwidthController::cleanupCommands[] = {
870dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    /* Cleanup rules. */
880dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-F",
890dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-t raw -F",
9039f8f24246a5dac21be5cc5e32c0f395ee803766JP Abgrall    /* TODO: If at some point we need more user chains than here, then we will need
9139f8f24246a5dac21be5cc5e32c0f395ee803766JP Abgrall     * a different cleanup approach.
9239f8f24246a5dac21be5cc5e32c0f395ee803766JP Abgrall     */
93bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall    "-X",  /* Should normally only be costly_shared, penalty_box, and costly_<iface>  */
940dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall};
954a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
964a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst char *BandwidthController::setupCommands[] = {
970dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    /* Created needed chains. */
98bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall    "-N costly_shared",
990dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-N penalty_box",
1000dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall};
1010dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
1020dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrallconst char *BandwidthController::basicAccountingCommands[] = {
1030dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-F INPUT",
1040dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-A INPUT -i lo --jump ACCEPT",
1050dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-A INPUT -m owner --socket-exists", /* This is a tracking rule. */
1060dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
1070dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-F OUTPUT",
1080dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-A OUTPUT -o lo --jump ACCEPT",
1090dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    "-A OUTPUT -m owner --socket-exists", /* This is a tracking rule. */
1100dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
111bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall    "-F costly_shared",
112bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall    "-A costly_shared --jump penalty_box",
113bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall    "-A costly_shared -m owner --socket-exists", /* This is a tracking rule. */
1140dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    /* TODO(jpa): Figure out why iptables doesn't correctly return from this
1150dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall     * chain. For now, hack the chain exit with an ACCEPT.
1160dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall     */
117bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall    "-A costly_shared --jump ACCEPT",
1180dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall};
1194a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1204a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP AbgrallBandwidthController::BandwidthController(void) {
1214a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char value[PROPERTY_VALUE_MAX];
1224a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1234a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    property_get("persist.bandwidth.enable", value, "0");
1244a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    if (!strcmp(value, "1")) {
1254a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        enableBandwidthControl();
1264a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
1274a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
12811b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    property_get("persist.bandwidth.uselogwrap", value, "0");
12911b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    useLogwrapCall = !strcmp(value, "1");
1304a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
1314a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
13226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrallint BandwidthController::runIpxtablesCmd(const char *cmd, IptRejectOp rejectHandling) {
1330dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    int res = 0;
1348a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
13526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    LOGD("runIpxtablesCmd(cmd=%s)", cmd);
13626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    res |= runIptablesCmd(cmd, rejectHandling, IptIpV4);
13726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    res |= runIptablesCmd(cmd, rejectHandling, IptIpV6);
1380dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    return res;
1390dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall}
1400dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
14126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrallint BandwidthController::StrncpyAndCheck(char *buffer, const char *src, size_t buffSize) {
14226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall
14326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    memset(buffer, '\0', buffSize);  // strncpy() is not filling leftover with '\0'
14426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    strncpy(buffer, src, buffSize);
14526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    return buffer[buffSize - 1];
14626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall}
14726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall
1488a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::runIptablesCmd(const char *cmd, IptRejectOp rejectHandling,
1498a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall                                        IptIpVer iptVer) {
15026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    char buffer[MAX_CMD_LEN];
1514a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    const char *argv[MAX_CMD_ARGS];
15226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    int argc = 0;
1534a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char *next = buffer;
1544a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char *tmp;
15511b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    int res;
1564a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
1570dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    std::string fullCmd = cmd;
15826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall
15926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    if (rejectHandling == IptRejectAdd) {
1600dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        fullCmd += " --jump REJECT --reject-with";
16126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        switch (iptVer) {
16226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        case IptIpV4:
1638a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall            fullCmd += " icmp-net-prohibited";
1648a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall            break;
16526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        case IptIpV6:
1668a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall            fullCmd += " icmp6-adm-prohibited";
1678a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall            break;
1680dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        }
1690dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    }
1700dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
17111b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    fullCmd.insert(0, " ");
17211b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    fullCmd.insert(0, iptVer == IptIpV4 ? IPTABLES_PATH : IP6TABLES_PATH);
1734a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
17411b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    if (!useLogwrapCall) {
17511b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall        res = system(fullCmd.c_str());
17611b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    } else {
17711b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall        if (StrncpyAndCheck(buffer, fullCmd.c_str(), sizeof(buffer))) {
17811b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall            LOGE("iptables command too long");
1794a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            return -1;
1804a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall        }
181fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
18211b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall        argc = 0;
18311b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall        while ((tmp = strsep(&next, " "))) {
18411b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall            argv[argc++] = tmp;
18511b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall            if (argc >= MAX_CMD_ARGS) {
18611b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall                LOGE("iptables argument overflow");
18711b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall                return -1;
18811b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall            }
18911b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall        }
19011b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall
19111b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall        argv[argc] = NULL;
19211b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall        res = logwrap(argc, argv, 0);
19311b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    }
19411b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    if (res) {
19511b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall        LOGE("runIptablesCmd(): failed %s res=%d", fullCmd.c_str(), res);
19611b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    }
19711b4e9b26fe7b878992162afb39f5a8acfd143edJP Abgrall    return res;
1984a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
1994a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
2004a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallint BandwidthController::enableBandwidthControl(void) {
201fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    int res;
202fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    /* Some of the initialCommands are allowed to fail */
20326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    runCommands(sizeof(cleanupCommands) / sizeof(char*), cleanupCommands, RunCmdFailureOk);
20426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    runCommands(sizeof(setupCommands) / sizeof(char*), setupCommands, RunCmdFailureOk);
2058a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    res = runCommands(sizeof(basicAccountingCommands) / sizeof(char*), basicAccountingCommands,
2068a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall                      RunCmdFailureBad);
2078a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
2088a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    sharedQuotaBytes = sharedAlertBytes = 0;
2098a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    sharedQuotaIfaces.clear();
2108a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    quotaIfaces.clear();
2118a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    naughtyAppUids.clear();
2128a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
213fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    return res;
2144a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
2154a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
2164a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
2174a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallint BandwidthController::disableBandwidthControl(void) {
218fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    /* The cleanupCommands are allowed to fail. */
21926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    runCommands(sizeof(cleanupCommands) / sizeof(char*), cleanupCommands, RunCmdFailureOk);
220fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    return 0;
2214a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
2224a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
2238a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::runCommands(int numCommands, const char *commands[],
2248a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall                                     RunCmdErrHandling cmdErrHandling) {
225fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    int res = 0;
226fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    LOGD("runCommands(): %d commands", numCommands);
227fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    for (int cmdNum = 0; cmdNum < numCommands; cmdNum++) {
22826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        res = runIpxtablesCmd(commands[cmdNum], IptRejectNoAdd);
22926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        if (res && cmdErrHandling != RunCmdFailureBad)
230fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            return res;
231fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
23226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    return cmdErrHandling == RunCmdFailureBad ? res : 0;
233fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall}
234fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
2350dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrallstd::string BandwidthController::makeIptablesNaughtyCmd(IptOp op, int uid) {
236fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    std::string res;
2378a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    char *buff;
2388a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    const char *opFlag;
239fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
240fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    switch (op) {
2418a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    case IptOpInsert:
2428a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        opFlag = "-I";
2438a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        break;
2448a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    case IptOpReplace:
2458a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        opFlag = "-R";
2468a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        break;
2478a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    default:
2488a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    case IptOpDelete:
2498a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        opFlag = "-D";
2508a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        break;
251fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
2528a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    asprintf(&buff, "%s penalty_box -m owner --uid-owner %d", opFlag, uid);
2538a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    res = buff;
2548a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    free(buff);
255fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    return res;
256fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall}
257fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
258fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallint BandwidthController::addNaughtyApps(int numUids, char *appUids[]) {
25926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    return maninpulateNaughtyApps(numUids, appUids, NaughtyAppOpAdd);
260fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall}
261fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
262fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallint BandwidthController::removeNaughtyApps(int numUids, char *appUids[]) {
26326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    return maninpulateNaughtyApps(numUids, appUids, NaughtyAppOpRemove);
264fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall}
265fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
26626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrallint BandwidthController::maninpulateNaughtyApps(int numUids, char *appStrUids[], NaughtyAppOp appOp) {
267fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    char cmd[MAX_CMD_LEN];
268fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    int uidNum;
26926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    const char *failLogTemplate;
27026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    IptOp op;
271fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    int appUids[numUids];
27226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    std::string naughtyCmd;
2738a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
27426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    switch (appOp) {
27526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    case NaughtyAppOpAdd:
2768a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        op = IptOpInsert;
2778a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        failLogTemplate = "Failed to add app uid %d to penalty box.";
2788a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        break;
27926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    case NaughtyAppOpRemove:
2808a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        op = IptOpDelete;
2818a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        failLogTemplate = "Failed to delete app uid %d from penalty box.";
2828a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        break;
28326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    }
28426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall
285fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    for (uidNum = 0; uidNum < numUids; uidNum++) {
286fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        appUids[uidNum] = atol(appStrUids[uidNum]);
287fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        if (appUids[uidNum] == 0) {
28826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall            LOGE(failLogTemplate, appUids[uidNum]);
289fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            goto fail_parse;
290fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        }
291fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
292fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
293fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    for (uidNum = 0; uidNum < numUids; uidNum++) {
29426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        naughtyCmd = makeIptablesNaughtyCmd(op, appUids[uidNum]);
29526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        if (runIpxtablesCmd(naughtyCmd.c_str(), IptRejectAdd)) {
29626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall            LOGE(failLogTemplate, appUids[uidNum]);
297fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            goto fail_with_uidNum;
298fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        }
299fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
300fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    return 0;
301fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
30226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrallfail_with_uidNum:
303fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    /* Try to remove the uid that failed in any case*/
30426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    naughtyCmd = makeIptablesNaughtyCmd(IptOpDelete, appUids[uidNum]);
30526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    runIpxtablesCmd(naughtyCmd.c_str(), IptRejectAdd);
30626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrallfail_parse:
30726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    return -1;
3084a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
3094a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
31026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrallstd::string BandwidthController::makeIptablesQuotaCmd(IptOp op, const char *costName, int64_t quota) {
311fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    std::string res;
3128a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    char *buff;
3138a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    const char *opFlag;
3140dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
3158a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    LOGD("makeIptablesQuotaCmd(%d, %lld)", op, quota);
3160dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
317fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    switch (op) {
3188a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    case IptOpInsert:
3198a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        opFlag = "-I";
3208a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        break;
3218a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    case IptOpReplace:
3228a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        opFlag = "-R";
3238a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        break;
3248a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    default:
3258a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    case IptOpDelete:
3268a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        opFlag = "-D";
3278a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        break;
328fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
3298a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
330bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall    // The requried IP version specific --jump REJECT ... will be added later.
3318a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    asprintf(&buff, "%s costly_%s -m quota2 ! --quota %lld --name %s", opFlag, costName, quota,
3328a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall             costName);
3338a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    res = buff;
3348a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    free(buff);
3350dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    return res;
3360dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall}
3370dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
33826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrallint BandwidthController::prepCostlyIface(const char *ifn, QuotaType quotaType) {
3390dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    char cmd[MAX_CMD_LEN];
3400dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    int res = 0;
3418a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    int ruleInsertPos = 1;
3420dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    std::string costString;
3430dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    const char *costCString;
3440dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
3450dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    /* The "-N costly" is created upfront, no need to handle it here. */
34626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    switch (quotaType) {
34726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    case QuotaUnique:
348bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall        costString = "costly_";
3490dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        costString += ifn;
3500dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        costCString = costString.c_str();
3510dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        snprintf(cmd, sizeof(cmd), "-N %s", costCString);
35226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
3530dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        snprintf(cmd, sizeof(cmd), "-A %s -j penalty_box", costCString);
35426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
3550dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        snprintf(cmd, sizeof(cmd), "-A %s -m owner --socket-exists", costCString);
35626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
3570dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        /* TODO(jpa): Figure out why iptables doesn't correctly return from this
3580dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall         * chain. For now, hack the chain exit with an ACCEPT.
3590dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall         */
3600dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        snprintf(cmd, sizeof(cmd), "-A %s --jump ACCEPT", costCString);
36126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
36226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        break;
36326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    case QuotaShared:
364bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall        costCString = "costly_shared";
36526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        break;
3660dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    }
3670dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
3688a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (globalAlertBytes) {
3698a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        /* The alert rule comes 1st */
3708a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        ruleInsertPos = 2;
3718a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
3728a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    snprintf(cmd, sizeof(cmd), "-I INPUT %d -i %s --goto %s", ruleInsertPos, ifn, costCString);
37326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
3748a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    snprintf(cmd, sizeof(cmd), "-I OUTPUT %d -o %s --goto %s", ruleInsertPos, ifn, costCString);
37526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
3760dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    return res;
3770dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall}
3780dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
37926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrallint BandwidthController::cleanupCostlyIface(const char *ifn, QuotaType quotaType) {
3800dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    char cmd[MAX_CMD_LEN];
3810dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    int res = 0;
3820dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    std::string costString;
3830dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    const char *costCString;
3840dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
38526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    switch (quotaType) {
38626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    case QuotaUnique:
387bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall        costString = "costly_";
3880dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        costString += ifn;
3890dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        costCString = costString.c_str();
39026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        break;
39126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    case QuotaShared:
392bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall        costCString = "costly_shared";
39326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        break;
3940dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    }
3950dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
3960dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    snprintf(cmd, sizeof(cmd), "-D INPUT -i %s --goto %s", ifn, costCString);
39726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
3980dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    snprintf(cmd, sizeof(cmd), "-D OUTPUT -o %s --goto %s", ifn, costCString);
39926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
4000dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
401bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall    /* The "-N costly_shared" is created upfront, no need to handle it here. */
40226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    if (quotaType == QuotaUnique) {
4030dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        snprintf(cmd, sizeof(cmd), "-F %s", costCString);
40426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
405a9f802c23f4c2c53fa1065b75f712ce46f384c3aJP Abgrall        snprintf(cmd, sizeof(cmd), "-X %s", costCString);
406a9f802c23f4c2c53fa1065b75f712ce46f384c3aJP Abgrall        res |= runIpxtablesCmd(cmd, IptRejectNoAdd);
407fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
408fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    return res;
409fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall}
4104a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
4110dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrallint BandwidthController::setInterfaceSharedQuota(const char *iface, int64_t maxBytes) {
4124a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char cmd[MAX_CMD_LEN];
4134a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char ifn[MAX_IFACENAME_LEN];
414fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    int res = 0;
41526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    std::string quotaCmd;
4168a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    std::string ifaceName;
4178a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    ;
418bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall    const char *costName = "shared";
41926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    std::list<std::string>::iterator it;
4204a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
4218a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (!maxBytes) {
4228a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        /* Don't talk about -1, deprecate it. */
4238a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        LOGE("Invalid bytes value. 1..max_int64.");
4248a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        return -1;
4258a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
42626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
42726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        LOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
42826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        return -1;
42926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    }
43026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    ifaceName = ifn;
4314a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
4324a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    if (maxBytes == -1) {
433fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        return removeInterfaceSharedQuota(ifn);
4344a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
4354a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
4364a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    /* Insert ingress quota. */
4370dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
4380dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        if (*it == ifaceName)
439fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            break;
4404a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
441fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
4420dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    if (it == sharedQuotaIfaces.end()) {
44326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        res |= prepCostlyIface(ifn, QuotaShared);
4440dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        if (sharedQuotaIfaces.empty()) {
4450dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall            quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
44626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall            res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
4474a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            if (res) {
4488a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall                LOGE("Failed set quota rule");
449fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall                goto fail;
4504a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall            }
451fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            sharedQuotaBytes = maxBytes;
452fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        }
4530dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        sharedQuotaIfaces.push_front(ifaceName);
454fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
455fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
456fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
457fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    if (maxBytes != sharedQuotaBytes) {
4588a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        res |= updateQuota(costName, maxBytes);
459fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        if (res) {
4608a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall            LOGE("Failed update quota for %s", costName);
461fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            goto fail;
462fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        }
463fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        sharedQuotaBytes = maxBytes;
4644a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
4654a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    return 0;
466fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
467fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    fail:
4684a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    /*
4694a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall     * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
4704a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall     * rules in the kernel to see which ones need cleaning up.
471fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall     * For now callers needs to choose if they want to "ndc bandwidth enable"
472fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall     * which resets everything.
4734a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall     */
474fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    removeInterfaceSharedQuota(ifn);
4754a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    return -1;
4764a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
4774a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
4788a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall/* It will also cleanup any shared alerts */
479fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallint BandwidthController::removeInterfaceSharedQuota(const char *iface) {
4804a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    char ifn[MAX_IFACENAME_LEN];
481fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    int res = 0;
48226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    std::string ifaceName;
4830dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    std::list<std::string>::iterator it;
484bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall    const char *costName = "shared";
4854a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall
4868a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
48726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        LOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
48826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        return -1;
48926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    }
4908a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    ifaceName = ifn;
49126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall
4920dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) {
4930dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        if (*it == ifaceName)
494fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall            break;
4954a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
4960dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    if (it == sharedQuotaIfaces.end()) {
4978a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        LOGE("No such iface %s to delete", ifn);
498fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        return -1;
4994a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    }
500fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
50126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    res |= cleanupCostlyIface(ifn, QuotaShared);
5020dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    sharedQuotaIfaces.erase(it);
503fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall
5040dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    if (sharedQuotaIfaces.empty()) {
505fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall        std::string quotaCmd;
506bfa7466b328101a8b04807f26e85c84526c9a774JP Abgrall        quotaCmd = makeIptablesQuotaCmd(IptOpDelete, costName, sharedQuotaBytes);
50726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
5088a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        sharedQuotaBytes = 0;
5098a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        if (sharedAlertBytes) {
5108a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall            removeSharedAlert();
5118a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall            sharedAlertBytes = 0;
5128a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        }
513fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall    }
5144a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall    return res;
5154a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall}
5160dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5170dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrallint BandwidthController::setInterfaceQuota(const char *iface, int64_t maxBytes) {
5180dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    char ifn[MAX_IFACENAME_LEN];
5190dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    int res = 0;
52026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    std::string ifaceName;
52126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    const char *costName;
52226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    std::list<QuotaInfo>::iterator it;
52326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    std::string quotaCmd;
5240dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5258a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (!maxBytes) {
5268a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        /* Don't talk about -1, deprecate it. */
5278a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        LOGE("Invalid bytes value. 1..max_int64.");
5288a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        return -1;
5298a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
5300dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    if (maxBytes == -1) {
53126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        return removeInterfaceQuota(iface);
5320dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    }
5330dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5348a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
53526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        LOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
53626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        return -1;
53726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    }
53826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    ifaceName = ifn;
53926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    costName = iface;
54026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall
5410dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    /* Insert ingress quota. */
5420dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
5438a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        if (it->ifaceName == ifaceName)
5440dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall            break;
5450dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    }
5460dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5470dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    if (it == quotaIfaces.end()) {
54826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        res |= prepCostlyIface(ifn, QuotaUnique);
5490dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes);
55026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd);
5510dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        if (res) {
5528a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall            LOGE("Failed set quota rule");
5530dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall            goto fail;
5540dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        }
5550dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5568a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        quotaIfaces.push_front(QuotaInfo(ifaceName, maxBytes, 0));
5570dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5580dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    } else {
5598a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        res |= updateQuota(costName, maxBytes);
5600dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        if (res) {
5618a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall            LOGE("Failed update quota for %s", iface);
5620dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall            goto fail;
5630dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        }
5648a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        it->quota = maxBytes;
5650dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    }
5660dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    return 0;
5670dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5680dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    fail:
5690dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    /*
5700dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall     * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse
5710dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall     * rules in the kernel to see which ones need cleaning up.
5720dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall     * For now callers needs to choose if they want to "ndc bandwidth enable"
5730dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall     * which resets everything.
5740dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall     */
5750dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    removeInterfaceSharedQuota(ifn);
5760dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    return -1;
5770dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall}
5780dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
5798a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::getInterfaceSharedQuota(int64_t *bytes) {
5808a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    return getInterfaceQuota("shared", bytes);
5818a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall}
5828a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
5838a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::getInterfaceQuota(const char *costName, int64_t *bytes) {
5848a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    FILE *fp;
5858a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    char *fname;
5868a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    int scanRes;
5878a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
5888a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    asprintf(&fname, "/proc/net/xt_quota/%s", costName);
5898a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    fp = fopen(fname, "r");
5908a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    free(fname);
5918a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (!fp) {
5928a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        LOGE("Reading quota %s failed (%s)", costName, strerror(errno));
5938a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        return -1;
5948a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
5958a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    scanRes = fscanf(fp, "%lld", bytes);
5968a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    LOGD("Read quota res=%d bytes=%lld", scanRes, *bytes);
5978a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    fclose(fp);
5988a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    return scanRes == 1 ? 0 : -1;
5998a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall}
6008a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
6010dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrallint BandwidthController::removeInterfaceQuota(const char *iface) {
6020dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
6030dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    char ifn[MAX_IFACENAME_LEN];
6040dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    int res = 0;
60526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    std::string ifaceName;
60626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    const char *costName;
60726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    std::list<QuotaInfo>::iterator it;
6080dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
6098a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) {
61026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        LOGE("Interface name longer than %d", MAX_IFACENAME_LEN);
61126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall        return -1;
61226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    }
61326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    ifaceName = ifn;
61426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    costName = iface;
6150dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
6160dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
6178a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        if (it->ifaceName == ifaceName)
6180dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall            break;
6190dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    }
6200dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
6210dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    if (it == quotaIfaces.end()) {
6228a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        LOGE("No such iface %s to delete", ifn);
6230dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall        return -1;
6240dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    }
6250dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
6260dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    /* This also removes the quota command of CostlyIface chain. */
62726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall    res |= cleanupCostlyIface(ifn, QuotaUnique);
6280dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
6290dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    quotaIfaces.erase(it);
6300dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall
6310dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall    return res;
6320dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall}
6338a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
6348a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::updateQuota(const char *quotaName, int64_t bytes) {
6358a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    FILE *fp;
6368a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    char *fname;
6378a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
6388a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    asprintf(&fname, "/proc/net/xt_quota/%s", quotaName);
6398a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    fp = fopen(fname, "w");
6408a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    free(fname);
6418a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (!fp) {
6428a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        LOGE("Updating quota %s failed (%s)", quotaName, strerror(errno));
6438a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        return -1;
6448a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
6458a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    fprintf(fp, "%lld\n", bytes);
6468a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    fclose(fp);
6478a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    return 0;
6488a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall}
6498a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
6508a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::runIptablesAlertCmd(IptOp op, const char *alertName, int64_t bytes) {
6518a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    int res = 0;
6528a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    const char *opFlag;
6538a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    char *alertQuotaCmd;
6548a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
6558a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    switch (op) {
6568a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    case IptOpInsert:
6578a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        opFlag = "-I";
6588a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        break;
6598a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    case IptOpReplace:
6608a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        opFlag = "-R";
6618a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        break;
6628a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    default:
6638a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    case IptOpDelete:
6648a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        opFlag = "-D";
6658a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        break;
6668a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
6678a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
6688a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "INPUT", bytes, alertName, alertName);
6698a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
6708a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    free(alertQuotaCmd);
6718a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "OUTPUT", bytes, alertName, alertName);
6728a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
6738a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    free(alertQuotaCmd);
6748a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    return res;
6758a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall}
6768a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
6778a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::setGlobalAlert(int64_t bytes) {
6788a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    char *alertQuotaCmd;
6798a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    const char *alertName = "globalAlert";
6808a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    int res = 0;
6818a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
6828a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (!bytes) {
6838a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        LOGE("Invalid bytes value. 1..max_int64.");
6848a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        return -1;
6858a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
6868a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (globalAlertBytes) {
6878a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        res = updateQuota(alertName, bytes);
6888a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    } else {
6898a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        res = runIptablesAlertCmd(IptOpInsert, alertName, bytes);
6908a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
6918a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    globalAlertBytes = bytes;
6928a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    return res;
6938a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall}
6948a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
6958a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::removeGlobalAlert(void) {
6968a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    char *alertQuotaCmd;
6978a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
6988a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    const char *alertName = "globalAlert";
6998a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    int res = 0;
7008a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
7018a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (!globalAlertBytes) {
7028a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        LOGE("No prior alert set");
7038a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        return -1;
7048a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
7058a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    res = runIptablesAlertCmd(IptOpDelete, alertName, globalAlertBytes);
7068a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    globalAlertBytes = 0;
7078a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    return res;
7088a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall}
7098a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
7108a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::setSharedAlert(int64_t bytes) {
7118a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (!sharedQuotaBytes) {
7128a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        LOGE("Need to have a prior shared quota set to set an alert");
7138a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        return -1;
7148a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
7158a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (!bytes) {
7168a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        LOGE("Invalid bytes value. 1..max_int64.");
7178a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        return -1;
7188a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
7198a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    return setCostlyAlert("shared", bytes, &sharedAlertBytes);
7208a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall}
7218a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
7228a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::removeSharedAlert(void) {
7238a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    return removeCostlyAlert("shared", &sharedAlertBytes);
7248a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall}
7258a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
7268a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::setInterfaceAlert(const char *iface, int64_t bytes) {
7278a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    std::list<QuotaInfo>::iterator it;
7288a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
7298a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (!bytes) {
7308a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        LOGE("Invalid bytes value. 1..max_int64.");
7318a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        return -1;
7328a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
7338a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
7348a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        if (it->ifaceName == iface)
7358a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall            break;
7368a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
7378a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
7388a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (it == quotaIfaces.end()) {
7398a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        LOGE("Need to have a prior interface quota set to set an alert");
7408a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        return -1;
7418a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
7428a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
7438a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    return setCostlyAlert(iface, bytes, &it->alert);
7448a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall}
7458a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
7468a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::removeInterfaceAlert(const char *iface) {
7478a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    std::list<QuotaInfo>::iterator it;
7488a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
7498a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) {
7508a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        if (it->ifaceName == iface)
7518a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall            break;
7528a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
7538a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
7548a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (it == quotaIfaces.end()) {
7558a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        LOGE("No prior alert set for interface %s", iface);
7568a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        return -1;
7578a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
7588a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
7598a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    return removeCostlyAlert(iface, &it->alert);
7608a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall}
7618a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
7628a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::setCostlyAlert(const char *costName, int64_t bytes, int64_t *alertBytes) {
7638a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    char *alertQuotaCmd;
7648a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    char *chainNameAndPos;
7658a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    int res = 0;
7668a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    char *alertName;
7678a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
7688a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (!bytes) {
7698a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        LOGE("Invalid bytes value. 1..max_int64.");
7708a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        return -1;
7718a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
7728a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    asprintf(&alertName, "%sAlert", costName);
7738a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (*alertBytes) {
7748a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        res = updateQuota(alertName, *alertBytes);
7758a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    } else {
7768a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        asprintf(&chainNameAndPos, "costly_%s %d", costName, ALERT_RULE_POS_IN_COSTLY_CHAIN);
7778a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "-I", chainNameAndPos, bytes, alertName,
7788a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall                 alertName);
7798a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
7808a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        free(alertQuotaCmd);
7818a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        free(chainNameAndPos);
7828a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
7838a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    *alertBytes = bytes;
7848a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    free(alertName);
7858a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    return res;
7868a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall}
7878a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
7888a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrallint BandwidthController::removeCostlyAlert(const char *costName, int64_t *alertBytes) {
7898a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    char *alertQuotaCmd;
7908a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    char *chainName;
7918a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    char *alertName;
7928a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    int res = 0;
7938a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
7948a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    asprintf(&alertName, "%sAlert", costName);
7958a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    if (!*alertBytes) {
7968a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        LOGE("No prior alert set for %s alert", costName);
7978a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall        return -1;
7988a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    }
7998a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
8008a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    asprintf(&chainName, "costly_%s", costName);
8018a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    asprintf(&alertQuotaCmd, ALERT_IPT_TEMPLATE, "-D", chainName, *alertBytes, alertName, alertName);
8028a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    res |= runIpxtablesCmd(alertQuotaCmd, IptRejectNoAdd);
8038a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    free(alertQuotaCmd);
8048a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    free(chainName);
8058a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall
8068a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    *alertBytes = 0;
8078a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    free(alertName);
8088a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall    return res;
8098a93272255f1b7e3083a97e1e28ddf675c0c7fb0JP Abgrall}
810