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