BandwidthController.cpp revision 26e0d49fa743d7881104196a9eda733bd2aac92f
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 <fcntl.h> 194a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <string.h> 204a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 214a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <sys/socket.h> 224a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <sys/stat.h> 234a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <sys/types.h> 244a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <sys/wait.h> 254a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 264a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <linux/netlink.h> 274a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <linux/rtnetlink.h> 284a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <linux/pkt_sched.h> 294a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 304a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#define LOG_TAG "BandwidthController" 314a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <cutils/log.h> 324a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include <cutils/properties.h> 334a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 344a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallextern "C" int logwrap(int argc, const char **argv, int background); 354a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 364a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall#include "BandwidthController.h" 374a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 38fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallconst int BandwidthController::MAX_CMD_LEN = 1024; 394a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst int BandwidthController::MAX_IFACENAME_LEN = 64; 404a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst int BandwidthController::MAX_CMD_ARGS = 32; 414a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst char BandwidthController::IPTABLES_PATH[] = "/system/bin/iptables"; 42fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallconst char BandwidthController::IP6TABLES_PATH[] = "/system/bin/ip6tables"; 434a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 444a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall/** 454a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * Some comments about the rules: 464a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * * Ordering 474a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * - when an interface is marked as costly it should be INSERTED into the INPUT/OUTPUT chains. 484a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * E.g. "-I INPUT -i rmnet0 --goto costly" 494a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * - quota'd rules in the costly chain should be before penalty_box lookups. 504a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * 514a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * * global quota vs per interface quota 524a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * - global quota for all costly interfaces uses a single costly chain: 534a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * . initial rules 544a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -N costly 554a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -I INPUT -i iface0 --goto costly 564a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -I OUTPUT -o iface0 --goto costly 574a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -I costly -m quota \! --quota 500000 --jump REJECT --reject-with icmp-net-prohibited 584a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -A costly --jump penalty_box 594a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -A costly -m owner --socket-exists 604a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * . adding a new iface to this, E.g.: 614a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -I INPUT -i iface1 --goto costly 624a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -I OUTPUT -o iface1 --goto costly 634a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * 644a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * - quota per interface. This is achieve by having "costly" chains per quota. 654a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * E.g. adding a new costly interface iface0 with its own quota: 664a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -N costly_iface0 674a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -I INPUT -i iface0 --goto costly_iface0 684a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -I OUTPUT -o iface0 --goto costly_iface0 694a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -A costly_iface0 -m quota \! --quota 500000 --jump REJECT --reject-with icmp-net-prohibited 704a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -A costly_iface0 --jump penalty_box 714a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -A costly_iface0 -m owner --socket-exists 724a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * 734a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * * penalty_box handling: 744a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * - only one penalty_box for all interfaces 754a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * E.g Adding an app: 764a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * iptables -A penalty_box -m owner --uid-owner app_3 --jump REJECT --reject-with icmp-net-prohibited 774a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall */ 784a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst char *BandwidthController::cleanupCommands[] = { 790dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall /* Cleanup rules. */ 800dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall "-F", 810dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall "-t raw -F", 820dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall "-X costly", 830dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall "-X penalty_box", 840dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall}; 854a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 864a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallconst char *BandwidthController::setupCommands[] = { 870dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall /* Created needed chains. */ 880dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall "-N costly", 890dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall "-N penalty_box", 900dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall}; 910dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 920dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrallconst char *BandwidthController::basicAccountingCommands[] = { 930dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall "-F INPUT", 940dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall "-A INPUT -i lo --jump ACCEPT", 950dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall "-A INPUT -m owner --socket-exists", /* This is a tracking rule. */ 960dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 970dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall "-F OUTPUT", 980dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall "-A OUTPUT -o lo --jump ACCEPT", 990dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall "-A OUTPUT -m owner --socket-exists", /* This is a tracking rule. */ 1000dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 1010dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall "-F costly", 1020dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall "-A costly --jump penalty_box", 1030dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall "-A costly -m owner --socket-exists", /* This is a tracking rule. */ 1040dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall /* TODO(jpa): Figure out why iptables doesn't correctly return from this 1050dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall * chain. For now, hack the chain exit with an ACCEPT. 1060dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall */ 1070dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall "-A costly --jump ACCEPT", 1080dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall}; 1094a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1104a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP AbgrallBandwidthController::BandwidthController(void) { 1114a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1124a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall char value[PROPERTY_VALUE_MAX]; 1134a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1144a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall property_get("persist.bandwidth.enable", value, "0"); 1154a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall if (!strcmp(value, "1")) { 1164a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall enableBandwidthControl(); 1174a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall } 1184a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1194a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall} 1204a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 12126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrallint BandwidthController::runIpxtablesCmd(const char *cmd, IptRejectOp rejectHandling) { 1220dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall int res = 0; 12326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall LOGD("runIpxtablesCmd(cmd=%s)", cmd); 12426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall res |= runIptablesCmd(cmd, rejectHandling, IptIpV4); 12526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall res |= runIptablesCmd(cmd, rejectHandling, IptIpV6); 1260dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall return res; 1270dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall} 1280dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 12926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrallint BandwidthController::StrncpyAndCheck(char *buffer, const char *src, size_t buffSize) { 13026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall 13126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall memset(buffer, '\0', buffSize); // strncpy() is not filling leftover with '\0' 13226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall strncpy(buffer, src, buffSize); 13326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall return buffer[buffSize - 1]; 13426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall} 13526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall 13626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrallint BandwidthController::runIptablesCmd(const char *cmd, IptRejectOp rejectHandling, IptIpVer iptVer) { 13726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall char buffer[MAX_CMD_LEN]; 1384a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall const char *argv[MAX_CMD_ARGS]; 13926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall int argc = 0; 1404a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall char *next = buffer; 1414a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall char *tmp; 1424a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1430dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall std::string fullCmd = cmd; 14426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall 14526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall if (rejectHandling == IptRejectAdd) { 1460dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall fullCmd += " --jump REJECT --reject-with"; 14726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall switch (iptVer) { 14826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall case IptIpV4: 14926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall fullCmd += " icmp-net-prohibited"; 15026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall break; 15126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall case IptIpV6: 15226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall fullCmd += " icmp6-adm-prohibited"; 15326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall break; 1540dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall } 1550dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall } 1560dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 15726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall argc = 0; 15826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall argv[argc++] = iptVer == IptIpV4 ? IPTABLES_PATH : IP6TABLES_PATH; 1590dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall LOGD("About to run: %s %s", argv[0], fullCmd.c_str()); 160fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall 16126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall LOGD("runIpxtablesCmd(): fullCmd.c_str()=%s buffSize=%d", fullCmd.c_str(), sizeof(buffer)); 16226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall if (StrncpyAndCheck(buffer, fullCmd.c_str(), sizeof(buffer))) { 1630dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall LOGE("iptables command too long"); 1640dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall return -1; 1650dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall } 1664a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1674a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall while ((tmp = strsep(&next, " "))) { 16826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall argv[argc++] = tmp; 1690dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall if (argc >= MAX_CMD_ARGS) { 1704a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall LOGE("iptables argument overflow"); 1714a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall return -1; 1724a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall } 1734a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall } 174fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall 1754a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall argv[argc] = NULL; 17626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall LOGD("runIpxtablesCmd(): argc=%d, argv[argc]=%p", argc, argv[argc]); 1774a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall /* TODO(jpa): Once this stabilizes, remove logwrap() as it tends to wedge netd 1784a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * Then just talk directly to the kernel via rtnetlink. 1794a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall */ 18026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall for (int i = 0 ; i < argc; i++) { 18126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall LOGD("runIpxtablesCmd(): argv[%d]=%p:%s", i, argv[i], argv[i]?:"null"); 18226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall } 1834a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall return logwrap(argc, argv, 0); 1844a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall} 1854a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1864a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallint BandwidthController::enableBandwidthControl(void) { 187fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall int res; 188fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall /* Some of the initialCommands are allowed to fail */ 18926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall runCommands(sizeof(cleanupCommands) / sizeof(char*), cleanupCommands, RunCmdFailureOk); 19026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall runCommands(sizeof(setupCommands) / sizeof(char*), setupCommands, RunCmdFailureOk); 19126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall res = runCommands(sizeof(basicAccountingCommands) / sizeof(char*), basicAccountingCommands, RunCmdFailureBad); 192fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall return res; 1934a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1944a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall} 1954a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 1964a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrallint BandwidthController::disableBandwidthControl(void) { 197fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall /* The cleanupCommands are allowed to fail. */ 19826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall runCommands(sizeof(cleanupCommands) / sizeof(char*), cleanupCommands, RunCmdFailureOk); 199fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall return 0; 2004a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall} 2014a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 20226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrallint BandwidthController::runCommands(int numCommands, const char *commands[], RunCmdErrHandling cmdErrHandling) { 203fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall int res = 0; 204fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall LOGD("runCommands(): %d commands", numCommands); 205fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall for (int cmdNum = 0; cmdNum < numCommands; cmdNum++) { 20626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall res = runIpxtablesCmd(commands[cmdNum], IptRejectNoAdd); 20726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall if (res && cmdErrHandling != RunCmdFailureBad) 208fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall return res; 209fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall } 21026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall return cmdErrHandling == RunCmdFailureBad ? res : 0; 211fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall} 212fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall 2130dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrallstd::string BandwidthController::makeIptablesNaughtyCmd(IptOp op, int uid) { 214fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall std::string res; 21526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall char *convBuff; 216fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall 217fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall switch (op) { 218fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall case IptOpInsert: 219fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall res = "-I"; 220fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall break; 221fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall case IptOpReplace: 222fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall res = "-R"; 223fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall break; 224fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall default: 225fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall case IptOpDelete: 226fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall res = "-D"; 227fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall break; 228fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall } 229fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall res += " penalty_box"; 23026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall asprintf(&convBuff, "%d", uid); 231fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall res += " -m owner --uid-owner "; 232fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall res += convBuff; 23326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall free(convBuff); 23426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall LOGD("makeIptablesNaughtyCmd() res=%s", res.c_str()); 235fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall return res; 236fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall} 237fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall 238fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallint BandwidthController::addNaughtyApps(int numUids, char *appUids[]) { 23926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall return maninpulateNaughtyApps(numUids, appUids, NaughtyAppOpAdd); 240fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall} 241fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall 242fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallint BandwidthController::removeNaughtyApps(int numUids, char *appUids[]) { 24326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall return maninpulateNaughtyApps(numUids, appUids, NaughtyAppOpRemove); 244fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall} 245fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall 24626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrallint BandwidthController::maninpulateNaughtyApps(int numUids, char *appStrUids[], NaughtyAppOp appOp) { 247fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall char cmd[MAX_CMD_LEN]; 248fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall int uidNum; 24926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall const char *failLogTemplate; 25026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall IptOp op; 251fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall int appUids[numUids]; 25226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall std::string naughtyCmd; 25326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall LOGD("manipulateNaughtyApps()"); 25426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall switch (appOp) { 25526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall case NaughtyAppOpAdd: 25626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall op = IptOpInsert; 25726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall failLogTemplate = "Failed to add app uid %d to penalty box."; 25826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall break; 25926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall case NaughtyAppOpRemove: 26026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall op = IptOpDelete; 26126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall failLogTemplate = "Failed to delete app uid %d from penalty box."; 26226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall break; 26326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall } 26426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall 265fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall for (uidNum = 0; uidNum < numUids; uidNum++) { 266fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall appUids[uidNum] = atol(appStrUids[uidNum]); 267fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall if (appUids[uidNum] == 0) { 26826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall LOGE(failLogTemplate, appUids[uidNum]); 269fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall goto fail_parse; 270fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall } 271fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall } 27226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall LOGD("manipulateNaughtyApps() got the appUids"); 273fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall 274fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall for (uidNum = 0; uidNum < numUids; uidNum++) { 27526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall naughtyCmd = makeIptablesNaughtyCmd(op, appUids[uidNum]); 27626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall if (runIpxtablesCmd(naughtyCmd.c_str(), IptRejectAdd)) { 27726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall LOGE(failLogTemplate, appUids[uidNum]); 278fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall goto fail_with_uidNum; 279fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall } 280fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall } 281fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall return 0; 282fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall 28326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrallfail_with_uidNum: 284fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall /* Try to remove the uid that failed in any case*/ 28526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall naughtyCmd = makeIptablesNaughtyCmd(IptOpDelete, appUids[uidNum]); 28626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall runIpxtablesCmd(naughtyCmd.c_str(), IptRejectAdd); 28726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrallfail_parse: 28826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall return -1; 2894a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall} 2904a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 29126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrallstd::string BandwidthController::makeIptablesQuotaCmd(IptOp op, const char *costName, int64_t quota) { 292fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall std::string res; 293fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall char convBuff[21]; // log10(2^64) ~ 20 2940dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 2950dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall LOGD("makeIptablesQuotaCmd(%d, %llu)", op, quota); 2960dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 297fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall switch (op) { 298fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall case IptOpInsert: 299fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall res = "-I"; 300fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall break; 301fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall case IptOpReplace: 302fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall res = "-R"; 303fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall break; 304fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall default: 305fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall case IptOpDelete: 306fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall res = "-D"; 307fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall break; 308fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall } 309fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall res += " costly"; 310fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall if (costName) { 3110dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall res += "_"; 3120dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall res += costName; 313fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall } 314fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall sprintf(convBuff, "%lld", quota); 3150dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall /* TODO(jpa): Use -m quota2 --name " + costName + " ! --quota " 3160dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall * once available. 3170dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall */ 318fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall res += " -m quota ! --quota "; 319fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall res += convBuff; 320fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall ; 3210dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall // The requried --jump REJECT ... will be added later. 3220dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall return res; 3230dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall} 3240dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 32526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrallint BandwidthController::prepCostlyIface(const char *ifn, QuotaType quotaType) { 3260dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall char cmd[MAX_CMD_LEN]; 3270dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall int res = 0; 3280dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall std::string costString; 3290dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall const char *costCString; 3300dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 3310dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall costString = "costly"; 3320dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall /* The "-N costly" is created upfront, no need to handle it here. */ 33326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall switch (quotaType) { 33426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall case QuotaUnique: 3350dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall costString += "_"; 3360dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall costString += ifn; 3370dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall costCString = costString.c_str(); 3380dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall snprintf(cmd, sizeof(cmd), "-N %s", costCString); 33926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall res |= runIpxtablesCmd(cmd, IptRejectNoAdd); 3400dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall snprintf(cmd, sizeof(cmd), "-A %s -j penalty_box", costCString); 34126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall res |= runIpxtablesCmd(cmd, IptRejectNoAdd); 3420dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall snprintf(cmd, sizeof(cmd), "-A %s -m owner --socket-exists", costCString); 34326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall res |= runIpxtablesCmd(cmd, IptRejectNoAdd); 3440dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall /* TODO(jpa): Figure out why iptables doesn't correctly return from this 3450dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall * chain. For now, hack the chain exit with an ACCEPT. 3460dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall */ 3470dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall snprintf(cmd, sizeof(cmd), "-A %s --jump ACCEPT", costCString); 34826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall res |= runIpxtablesCmd(cmd, IptRejectNoAdd); 34926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall break; 35026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall case QuotaShared: 3510dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall costCString = costString.c_str(); 35226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall break; 3530dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall } 3540dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 3550dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall snprintf(cmd, sizeof(cmd), "-I INPUT -i %s --goto %s", ifn, costCString); 35626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall res |= runIpxtablesCmd(cmd, IptRejectNoAdd); 3570dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall snprintf(cmd, sizeof(cmd), "-I OUTPUT -o %s --goto %s", ifn, costCString); 35826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall res |= runIpxtablesCmd(cmd, IptRejectNoAdd); 3590dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall return res; 3600dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall} 3610dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 36226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrallint BandwidthController::cleanupCostlyIface(const char *ifn, QuotaType quotaType) { 3630dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall char cmd[MAX_CMD_LEN]; 3640dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall int res = 0; 3650dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall std::string costString; 3660dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall const char *costCString; 3670dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 3680dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall costString = "costly"; 36926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall switch (quotaType) { 37026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall case QuotaUnique: 3710dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall costString += "_"; 3720dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall costString += ifn; 3730dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall costCString = costString.c_str(); 37426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall break; 37526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall case QuotaShared: 3760dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall costCString = costString.c_str(); 37726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall break; 3780dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall } 3790dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 3800dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall snprintf(cmd, sizeof(cmd), "-D INPUT -i %s --goto %s", ifn, costCString); 38126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall res |= runIpxtablesCmd(cmd, IptRejectNoAdd); 3820dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall snprintf(cmd, sizeof(cmd), "-D OUTPUT -o %s --goto %s", ifn, costCString); 38326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall res |= runIpxtablesCmd(cmd, IptRejectNoAdd); 3840dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 3850dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall /* The "-N costly" is created upfront, no need to handle it here. */ 38626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall if (quotaType == QuotaUnique) { 3870dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall snprintf(cmd, sizeof(cmd), "-F %s", costCString); 38826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall res |= runIpxtablesCmd(cmd, IptRejectNoAdd); 389fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall } 390fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall return res; 391fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall} 3924a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 3930dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrallint BandwidthController::setInterfaceSharedQuota(const char *iface, int64_t maxBytes) { 3944a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall char cmd[MAX_CMD_LEN]; 3954a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall char ifn[MAX_IFACENAME_LEN]; 396fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall int res = 0; 39726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall std::string quotaCmd; 39826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall std::string ifaceName;; 39926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall const char *costName = NULL; /* Shared quota */ 40026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall std::list<std::string>::iterator it; 4014a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 40226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall if (StrncpyAndCheck(ifn, iface, sizeof(ifn))) { 40326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall LOGE("Interface name longer than %d", MAX_IFACENAME_LEN); 40426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall return -1; 40526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall } 40626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall ifaceName = ifn; 4074a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 4084a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall if (maxBytes == -1) { 409fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall return removeInterfaceSharedQuota(ifn); 4104a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall } 4114a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 4124a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall /* Insert ingress quota. */ 4130dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) { 4140dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall if (*it == ifaceName) 415fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall break; 4164a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall } 417fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall 4180dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall if (it == sharedQuotaIfaces.end()) { 41926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall res |= prepCostlyIface(ifn, QuotaShared); 4200dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall if (sharedQuotaIfaces.empty()) { 4210dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes); 42226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd); 4234a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall if (res) { 424fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall LOGE("Failed set quota rule."); 425fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall goto fail; 4264a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall } 427fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall sharedQuotaBytes = maxBytes; 428fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall } 4290dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall sharedQuotaIfaces.push_front(ifaceName); 430fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall 431fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall } 432fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall 433fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall if (maxBytes != sharedQuotaBytes) { 434fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall /* Instead of replacing, which requires being aware of the rules in 435fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall * the kernel, we just add a new one, then delete the older one. 436fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall */ 437fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall 4380dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes); 43926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd); 440fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall 4410dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall quotaCmd = makeIptablesQuotaCmd(IptOpDelete, costName, sharedQuotaBytes); 44226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd); 443fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall 444fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall if (res) { 445fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall LOGE("Failed replace quota rule."); 446fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall goto fail; 447fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall } 448fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall sharedQuotaBytes = maxBytes; 4494a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall } 4504a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall return 0; 451fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall 452fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall fail: 4534a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall /* 4544a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse 4554a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall * rules in the kernel to see which ones need cleaning up. 456fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall * For now callers needs to choose if they want to "ndc bandwidth enable" 457fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall * which resets everything. 4584a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall */ 459fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall removeInterfaceSharedQuota(ifn); 4604a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall return -1; 4614a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall} 4624a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 463fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrallint BandwidthController::removeInterfaceSharedQuota(const char *iface) { 4644a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall char ifn[MAX_IFACENAME_LEN]; 465fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall int res = 0; 46626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall std::string ifaceName; 4670dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall std::list<std::string>::iterator it; 4684a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall 46926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall if(StrncpyAndCheck(ifn, iface, sizeof(ifn))) { 47026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall LOGE("Interface name longer than %d", MAX_IFACENAME_LEN); 47126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall return -1; 47226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall } 47326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall ifaceName =ifn; 47426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall 4750dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall for (it = sharedQuotaIfaces.begin(); it != sharedQuotaIfaces.end(); it++) { 4760dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall if (*it == ifaceName) 477fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall break; 4784a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall } 4790dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall if (it == sharedQuotaIfaces.end()) { 480fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall LOGE("No such iface %s to delete.", ifn); 481fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall return -1; 4824a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall } 483fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall 48426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall res |= cleanupCostlyIface(ifn, QuotaShared); 4850dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall sharedQuotaIfaces.erase(it); 486fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall 4870dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall if (sharedQuotaIfaces.empty()) { 488fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall std::string quotaCmd; 4890dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall quotaCmd = makeIptablesQuotaCmd(IptOpDelete, NULL, sharedQuotaBytes); 49026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd); 491fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall sharedQuotaBytes = -1; 492fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall } 493fa6f46d3370ae5475fc3bc8273bbe04ee7348d60JP Abgrall 4944a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall return res; 4954a5f5ca3c9e07fc3e6feca2afde07f41a8a64f11JP Abgrall} 4960dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 4970dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrallint BandwidthController::setInterfaceQuota(const char *iface, int64_t maxBytes) { 4980dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall char ifn[MAX_IFACENAME_LEN]; 4990dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall int res = 0; 50026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall std::string ifaceName; 50126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall const char *costName; 50226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall std::list<QuotaInfo>::iterator it; 50326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall std::string quotaCmd; 5040dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 5050dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall if (maxBytes == -1) { 50626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall return removeInterfaceQuota(iface); 5070dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall } 5080dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 50926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall if(StrncpyAndCheck(ifn, iface, sizeof(ifn))) { 51026e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall LOGE("Interface name longer than %d", MAX_IFACENAME_LEN); 51126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall return -1; 51226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall } 51326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall ifaceName = ifn; 51426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall costName = iface; 51526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall 5160dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 5170dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall /* Insert ingress quota. */ 5180dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) { 5190dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall if (it->first == ifaceName) 5200dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall break; 5210dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall } 5220dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 5230dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall if (it == quotaIfaces.end()) { 52426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall res |= prepCostlyIface(ifn, QuotaUnique); 5250dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes); 52626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd); 5270dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall if (res) { 5280dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall LOGE("Failed set quota rule."); 5290dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall goto fail; 5300dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall } 5310dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 5320dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall quotaIfaces.push_front(QuotaInfo(ifaceName, maxBytes)); 5330dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 5340dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall } else { 5350dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall /* Instead of replacing, which requires being aware of the rules in 5360dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall * the kernel, we just add a new one, then delete the older one. 5370dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall */ 5380dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall quotaCmd = makeIptablesQuotaCmd(IptOpInsert, costName, maxBytes); 53926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd); 5400dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 5410dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall quotaCmd = makeIptablesQuotaCmd(IptOpDelete, costName, it->second); 54226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall res |= runIpxtablesCmd(quotaCmd.c_str(), IptRejectAdd); 5430dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 5440dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall if (res) { 5450dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall LOGE("Failed replace quota rule."); 5460dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall goto fail; 5470dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall } 5480dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall it->second = maxBytes; 5490dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall } 5500dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall return 0; 5510dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 5520dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall fail: 5530dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall /* 5540dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall * TODO(jpa): once we get rid of iptables in favor of rtnetlink, reparse 5550dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall * rules in the kernel to see which ones need cleaning up. 5560dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall * For now callers needs to choose if they want to "ndc bandwidth enable" 5570dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall * which resets everything. 5580dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall */ 5590dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall removeInterfaceSharedQuota(ifn); 5600dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall return -1; 5610dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall} 5620dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 5630dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrallint BandwidthController::removeInterfaceQuota(const char *iface) { 5640dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 5650dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall char ifn[MAX_IFACENAME_LEN]; 5660dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall int res = 0; 56726e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall std::string ifaceName; 56826e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall const char *costName; 56926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall std::list<QuotaInfo>::iterator it; 5700dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 57126e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall if(StrncpyAndCheck(ifn, iface, sizeof(ifn))) { 57226e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall LOGE("Interface name longer than %d", MAX_IFACENAME_LEN); 57326e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall return -1; 57426e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall } 57526e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall ifaceName = ifn; 57626e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall costName = iface; 5770dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 5780dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall for (it = quotaIfaces.begin(); it != quotaIfaces.end(); it++) { 5790dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall if (it->first == ifaceName) 5800dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall break; 5810dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall } 5820dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 5830dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall if (it == quotaIfaces.end()) { 5840dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall LOGE("No such iface %s to delete.", ifn); 5850dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall return -1; 5860dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall } 5870dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 5880dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall /* This also removes the quota command of CostlyIface chain. */ 58926e0d49fa743d7881104196a9eda733bd2aac92fJP Abgrall res |= cleanupCostlyIface(ifn, QuotaUnique); 5900dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 5910dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall quotaIfaces.erase(it); 5920dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall 5930dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall return res; 5940dad7c2f1f6994fbe5e85b9e1fc72d29d6453211JP Abgrall} 595