OSDN Git Service

BandwidthController: add support for "nice apps" and the "happy box"
authorJP Abgrall <jpa@google.com>
Wed, 3 Jul 2013 03:28:45 +0000 (20:28 -0700)
committerJP Abgrall <jpa@google.com>
Wed, 3 Jul 2013 18:12:48 +0000 (11:12 -0700)
* ndc bandwidth happybox (enable | disable)
 - enable
  . creates a an empty happy_box chain which rejects all traffic from all UIDs by default.
  . Uses the penalty_box as a hook. Any costly_interface automatically  gets the happy_box as it has a penalty_box.
  . any app UID not in the happy_box will be treated as if it was in the penalty_box (i.e. addnaughtyapps)
  . penalty_box (addnaughtyapps) still applies.
 - disable
  . removes the happy box.
* ndc bandwidth addniceapps <appUid> ...
 - similar to addnaughtyapps, but for the happy_box
* ndc bandwidth removeniceapps <appUid> ...
 - similar to removenaughtyapps, but for the happy_box

Bug: 6212480
Change-Id: I1f10e8c6fa1b230c7b3bb070d88508e437589705

BandwidthController.cpp
BandwidthController.h
CommandListener.cpp

index 4f72126..debb005 100644 (file)
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#define LOG_NDEBUG 0
+// #define LOG_NDEBUG 0
 
 /*
  * The CommandListener, FrameworkListener don't allow for
@@ -66,6 +66,7 @@ const int  BandwidthController::MAX_IPT_OUTPUT_LINE_LEN = 256;
  *    - when an interface is marked as costly it should be INSERTED into the INPUT/OUTPUT chains.
  *      E.g. "-I bw_INPUT -i rmnet0 --jump costly"
  *    - quota'd rules in the costly chain should be before penalty_box lookups.
+ *    - happy_box rejects everything by default.
  *    - the qtaguid counting is done at the end of the bw_INPUT/bw_OUTPUT user chains.
  *
  * * global quota vs per interface quota
@@ -77,6 +78,8 @@ const int  BandwidthController::MAX_IPT_OUTPUT_LINE_LEN = 256;
  *      iptables -I costly_shared -m quota \! --quota 500000 \
  *          --jump REJECT --reject-with icmp-net-prohibited
  *      iptables -A costly_shared --jump penalty_box
+ *      If the happy box is enabled,
+ *        iptables -A penalty_box --jump happy_box
  *
  *    . adding a new iface to this, E.g.:
  *      iptables -I bw_INPUT -i iface1 --jump costly_shared
@@ -88,14 +91,20 @@ const int  BandwidthController::MAX_IPT_OUTPUT_LINE_LEN = 256;
  *      iptables -I bw_INPUT -i iface0 --jump costly_iface0
  *      iptables -I bw_OUTPUT -o iface0 --jump costly_iface0
  *      iptables -A costly_iface0 -m quota \! --quota 500000 \
- *          --jump REJECT --reject-with icmp-net-prohibited
+ *          --jump REJECT --reject-with icmp-port-unreachable
  *      iptables -A costly_iface0 --jump penalty_box
  *
  * * penalty_box handling:
  *  - only one penalty_box for all interfaces
- *   E.g  Adding an app:
- *    iptables -A penalty_box -m owner --uid-owner app_3 \
- *        --jump REJECT --reject-with icmp-net-prohibited
+ *   E.g  Adding an app, it has to preserve the appened happy_box, so "-I":
+ *    iptables -I penalty_box -m owner --uid-owner app_3 \
+ *        --jump REJECT --reject-with icmp-port-unreachable
+ *
+ * * happy_box handling:
+ *  - The happy_box goes at the end of the penalty box.
+ *   E.g  Adding a happy app,
+ *    iptables -I happy_box -m owner --uid-owner app_3 \
+ *        --jump RETURN
  */
 const char *BandwidthController::IPT_FLUSH_COMMANDS[] = {
     /*
@@ -106,22 +115,33 @@ const char *BandwidthController::IPT_FLUSH_COMMANDS[] = {
     "-F bw_INPUT",
     "-F bw_OUTPUT",
     "-F bw_FORWARD",
+    "-F happy_box",
     "-F penalty_box",
     "-F costly_shared",
 
+    /* Just a couple that are the most common. */
+    "-F costly_rmnet0",
+    "-F costly_wlan0",
+
     "-t raw -F bw_raw_PREROUTING",
     "-t mangle -F bw_mangle_POSTROUTING",
 };
 
 /* The cleanup commands assume flushing has been done. */
 const char *BandwidthController::IPT_CLEANUP_COMMANDS[] = {
+    "-X happy_box",
     "-X penalty_box",
     "-X costly_shared",
+
+    /* Just a couple that are the most common. */
+    "-X costly_rmnet0",
+    "-X costly_wlan0",
 };
 
 const char *BandwidthController::IPT_SETUP_COMMANDS[] = {
-    "-N costly_shared",
+    "-N happy_box",
     "-N penalty_box",
+    "-N costly_shared",
 };
 
 const char *BandwidthController::IPT_BASIC_ACCOUNTING_COMMANDS[] = {
@@ -240,6 +260,7 @@ int BandwidthController::enableBandwidthControl(bool force) {
     sharedQuotaIfaces.clear();
     quotaIfaces.clear();
     naughtyAppUids.clear();
+    niceAppUids.clear();
     globalAlertBytes = 0;
     globalAlertTetherCount = 0;
     sharedQuotaBytes = sharedAlertBytes = 0;
@@ -304,6 +325,53 @@ std::string BandwidthController::makeIptablesSpecialAppCmd(IptOp op, int uid, co
     return res;
 }
 
+int BandwidthController::enableHappyBox(void) {
+    char cmd[MAX_CMD_LEN];
+    int res = 0;
+
+    /*
+     * We tentatively delete before adding, which helps recovering
+     * from bad states (e.g. netd died).
+     */
+
+    /* Should not exist, but ignore result if already there. */
+    snprintf(cmd, sizeof(cmd), "-N happy_box");
+    runIpxtablesCmd(cmd, IptJumpNoAdd);
+
+    /* Should be empty, but clear in case something was wrong. */
+    niceAppUids.clear();
+    snprintf(cmd, sizeof(cmd), "-F happy_box");
+    res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
+
+    snprintf(cmd, sizeof(cmd), "-D penalty_box -j happy_box");
+    runIpxtablesCmd(cmd, IptJumpNoAdd);
+    snprintf(cmd, sizeof(cmd), "-A penalty_box -j happy_box");
+    res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
+
+    /* Reject. Defaulting to prot-unreachable */
+    snprintf(cmd, sizeof(cmd), "-D happy_box -j REJECT");
+    runIpxtablesCmd(cmd, IptJumpNoAdd);
+    snprintf(cmd, sizeof(cmd), "-A happy_box -j REJECT");
+    res |= runIpxtablesCmd(cmd, IptJumpNoAdd);
+
+    return res;
+}
+
+int BandwidthController::disableHappyBox(void) {
+    char cmd[MAX_CMD_LEN];
+
+    /* Best effort */
+    snprintf(cmd, sizeof(cmd), "-D penalty_box -j happy_box");
+    runIpxtablesCmd(cmd, IptJumpNoAdd);
+    niceAppUids.clear();
+    snprintf(cmd, sizeof(cmd), "-F happy_box");
+    runIpxtablesCmd(cmd, IptJumpNoAdd);
+    snprintf(cmd, sizeof(cmd), "-X happy_box");
+    runIpxtablesCmd(cmd, IptJumpNoAdd);
+
+    return 0;
+}
+
 int BandwidthController::addNaughtyApps(int numUids, char *appUids[]) {
     return manipulateNaughtyApps(numUids, appUids, SpecialAppOpAdd);
 }
@@ -312,10 +380,22 @@ int BandwidthController::removeNaughtyApps(int numUids, char *appUids[]) {
     return manipulateNaughtyApps(numUids, appUids, SpecialAppOpRemove);
 }
 
+int BandwidthController::addNiceApps(int numUids, char *appUids[]) {
+    return manipulateNiceApps(numUids, appUids, SpecialAppOpAdd);
+}
+
+int BandwidthController::removeNiceApps(int numUids, char *appUids[]) {
+    return manipulateNiceApps(numUids, appUids, SpecialAppOpRemove);
+}
+
 int BandwidthController::manipulateNaughtyApps(int numUids, char *appStrUids[], SpecialAppOp appOp) {
     return manipulateSpecialApps(numUids, appStrUids, "penalty_box", naughtyAppUids, IptJumpReject, appOp);
 }
 
+int BandwidthController::manipulateNiceApps(int numUids, char *appStrUids[], SpecialAppOp appOp) {
+    return manipulateSpecialApps(numUids, appStrUids, "happy_box", niceAppUids, IptJumpReturn, appOp);
+}
+
 
 int BandwidthController::manipulateSpecialApps(int numUids, char *appStrUids[],
                                                const char *chain,
@@ -647,10 +727,10 @@ int BandwidthController::setInterfaceQuota(const char *iface, int64_t maxBytes)
     }
 
     if (it == quotaIfaces.end()) {
-        /* Preparing the iface adds a penalty_box check */
+        /* Preparing the iface adds a penalty/happy box check */
         res |= prepCostlyIface(ifn, QuotaUnique);
         /*
-         * The rejecting quota limit should go after the penalty box checks
+         * The rejecting quota limit should go after the penalty/happy box checks
          * or else a naughty app could just eat up the quota.
          * So we append here.
          */
index b76ee0a..3953e26 100644 (file)
@@ -64,8 +64,12 @@ public:
     int getInterfaceQuota(const char *iface, int64_t *bytes);
     int removeInterfaceQuota(const char *iface);
 
+    int enableHappyBox(void);
+    int disableHappyBox(void);
     int addNaughtyApps(int numUids, char *appUids[]);
     int removeNaughtyApps(int numUids, char *appUids[]);
+    int addNiceApps(int numUids, char *appUids[]);
+    int removeNiceApps(int numUids, char *appUids[]);
 
     int setGlobalAlert(int64_t bytes);
     int removeGlobalAlert(void);
@@ -120,6 +124,7 @@ protected:
                                std::list<int /*appUid*/> &specialAppUids,
                                IptJumpOp jumpHandling, SpecialAppOp appOp);
     int manipulateNaughtyApps(int numUids, char *appStrUids[], SpecialAppOp appOp);
+    int manipulateNiceApps(int numUids, char *appStrUids[], SpecialAppOp appOp);
 
     int prepCostlyIface(const char *ifn, QuotaType quotaType);
     int cleanupCostlyIface(const char *ifn, QuotaType quotaType);
@@ -177,6 +182,7 @@ protected:
 
     std::list<QuotaInfo> quotaIfaces;
     std::list<int /*appUid*/> naughtyAppUids;
+    std::list<int /*appUid*/> niceAppUids;
 
 private:
     static const char *IPT_FLUSH_COMMANDS[];
index 3950f72..1d8c60f 100644 (file)
@@ -1142,7 +1142,43 @@ int CommandListener::BandwidthControlCmd::runCommand(SocketClient *cli, int argc
         int rc = sBandwidthCtrl->removeNaughtyApps(argc - 2, argv + 2);
         sendGenericOkFail(cli, rc);
         return 0;
+    }
+    if (!strcmp(argv[1], "happybox")) {
+        if (argc < 3) {
+            sendGenericSyntaxError(cli, "happybox (enable | disable)");
+            return 0;
+        }
+        if (!strcmp(argv[2], "enable")) {
+            int rc = sBandwidthCtrl->enableHappyBox();
+            sendGenericOkFail(cli, rc);
+            return 0;
 
+        }
+        if (!strcmp(argv[2], "disable")) {
+            int rc = sBandwidthCtrl->disableHappyBox();
+            sendGenericOkFail(cli, rc);
+            return 0;
+        }
+        sendGenericSyntaxError(cli, "happybox (enable | disable)");
+        return 0;
+    }
+    if (!strcmp(argv[1], "addniceapps") || !strcmp(argv[1], "aha")) {
+        if (argc < 3) {
+            sendGenericSyntaxError(cli, "addniceapps <appUid> ...");
+            return 0;
+        }
+        int rc = sBandwidthCtrl->addNiceApps(argc - 2, argv + 2);
+        sendGenericOkFail(cli, rc);
+        return 0;
+    }
+    if (!strcmp(argv[1], "removeniceapps") || !strcmp(argv[1], "rha")) {
+        if (argc < 3) {
+            sendGenericSyntaxError(cli, "removeniceapps <appUid> ...");
+            return 0;
+        }
+        int rc = sBandwidthCtrl->removeNiceApps(argc - 2, argv + 2);
+        sendGenericOkFail(cli, rc);
+        return 0;
     }
     if (!strcmp(argv[1], "setglobalalert") || !strcmp(argv[1], "sga")) {
         if (argc != 3) {
@@ -1152,7 +1188,6 @@ int CommandListener::BandwidthControlCmd::runCommand(SocketClient *cli, int argc
         int rc = sBandwidthCtrl->setGlobalAlert(atoll(argv[2]));
         sendGenericOkFail(cli, rc);
         return 0;
-
     }
     if (!strcmp(argv[1], "debugsettetherglobalalert") || !strcmp(argv[1], "dstga")) {
         if (argc != 4) {