Nat-related commands refine

We need this to ensure that the tethering IPCs don't need to grab the
lock in two different controllers

The idea is that always having a global_alert rule in bw_global_alert
chain.
TetherController will enable/disable the reference of bw_global_alert
chain.

[childchain order of filter FORWARD chain]
Chain FORWARD
   nm_mdmprxy_iface_pkt_fwder
   oem_fwd
   fw_FORWARD
   bw_FORWARD
   tetherctrl_FORWARD

--Simple rule comparison--
[Before]
Chain bw_FORWARD
    Alert rule
    ... other rules
Chain tetherctrl_FORWARD
    ... other rules
[After]
Chain bw_FORWARD
    No Alert rule
    ... other rules
Chain tetherctrl_FORWARD
    Jump to bw_global_alert
    ... other rules
Chain bw_global_alert
   Alert rule

The exact rule comparison is shown in the bug.

Bug:119735985
Test: built, flashed, booted
      system/netd/tests/runtests.sh passes

Change-Id: Ibf752d0c8de9170689fc74c89c0424d2642853ec
diff --git a/server/BandwidthController.cpp b/server/BandwidthController.cpp
index e0dc25e..7e9bff7 100644
--- a/server/BandwidthController.cpp
+++ b/server/BandwidthController.cpp
@@ -66,6 +66,7 @@
 const char BandwidthController::LOCAL_OUTPUT[] = "bw_OUTPUT";
 const char BandwidthController::LOCAL_RAW_PREROUTING[] = "bw_raw_PREROUTING";
 const char BandwidthController::LOCAL_MANGLE_POSTROUTING[] = "bw_mangle_POSTROUTING";
+const char BandwidthController::LOCAL_GLOBAL_ALERT[] = "bw_global_alert";
 
 auto BandwidthController::iptablesRestoreFunction = execIptablesRestoreWithOutput;
 
@@ -157,27 +158,27 @@
         "-I bw_penalty_box -m bpf --object-pinned %s -j REJECT", XT_BPF_BLACKLIST_PROG_PATH);
 
 static const std::vector<std::string> IPT_FLUSH_COMMANDS = {
-    /*
-     * Cleanup rules.
-     * Should normally include bw_costly_<iface>, but we rely on the way they are setup
-     * to allow coexistance.
-     */
-    "*filter",
-    ":bw_INPUT -",
-    ":bw_OUTPUT -",
-    ":bw_FORWARD -",
-    ":bw_happy_box -",
-    ":bw_penalty_box -",
-    ":bw_data_saver -",
-    ":bw_costly_shared -",
-    "COMMIT",
-    "*raw",
-    ":bw_raw_PREROUTING -",
-    "COMMIT",
-    "*mangle",
-    ":bw_mangle_POSTROUTING -",
-    COMMIT_AND_CLOSE
-};
+        /*
+         * Cleanup rules.
+         * Should normally include bw_costly_<iface>, but we rely on the way they are setup
+         * to allow coexistance.
+         */
+        "*filter",
+        ":bw_INPUT -",
+        ":bw_OUTPUT -",
+        ":bw_FORWARD -",
+        ":bw_happy_box -",
+        ":bw_penalty_box -",
+        ":bw_data_saver -",
+        ":bw_costly_shared -",
+        ":bw_global_alert -",
+        "COMMIT",
+        "*raw",
+        ":bw_raw_PREROUTING -",
+        "COMMIT",
+        "*mangle",
+        ":bw_mangle_POSTROUTING -",
+        COMMIT_AND_CLOSE};
 
 static const uint32_t uidBillingMask = Fwmark::getUidBillingMask();
 
@@ -215,6 +216,8 @@
 const std::vector<std::string> getBasicAccountingCommands(const bool useBpf) {
     const std::vector<std::string> ipt_basic_accounting_commands = {
             "*filter",
+
+            "-A bw_INPUT -j bw_global_alert",
             // Prevents IPSec double counting (ESP and UDP-encap-ESP respectively)
             "-A bw_INPUT -p esp -j RETURN",
             StringPrintf("-A bw_INPUT -m mark --mark 0x%x/0x%x -j RETURN", uidBillingMask,
@@ -222,6 +225,7 @@
             useBpf ? "" : "-A bw_INPUT -m owner --socket-exists",
             StringPrintf("-A bw_INPUT -j MARK --or-mark 0x%x", uidBillingMask),
 
+            "-A bw_OUTPUT -j bw_global_alert",
             // Prevents IPSec double counting (Tunnel mode and Transport mode,
             // respectively)
             "-A bw_OUTPUT -o " IPSEC_IFACE_PREFIX "+ -j RETURN",
@@ -293,7 +297,6 @@
     mSharedQuotaIfaces.clear();
     mQuotaIfaces.clear();
     mGlobalAlertBytes = 0;
-    mGlobalAlertTetherCount = 0;
     mSharedQuotaBytes = mSharedAlertBytes = 0;
 
     flushCleanTables(false);
@@ -630,20 +633,13 @@
 
     // TODO: consider using an alternate template for the delete that does not include the --quota
     // value. This code works because the --quota value is ignored by deletes
-    StringAppendF(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_INPUT", bytes,
-                  alertName.c_str());
-    StringAppendF(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_OUTPUT", bytes,
-                  alertName.c_str());
-    StringAppendF(&alertQuotaCmd, "COMMIT\n");
 
-    return iptablesRestoreFunction(V4V6, alertQuotaCmd, nullptr);
-}
-
-int BandwidthController::runIptablesAlertFwdCmd(IptOp op, const std::string& alertName,
-                                                int64_t bytes) {
-    const char *opFlag = opToString(op);
-    std::string alertQuotaCmd = "*filter\n";
-    StringAppendF(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, "bw_FORWARD", bytes,
+    /*
+     * Add alert rule in bw_global_alert chain, 3 chains might reference bw_global_alert.
+     * bw_INPUT, bw_OUTPUT (added by BandwidthController in enableBandwidthControl)
+     * bw_FORWARD (added by TetherController in setTetherGlobalAlertRule if nat enable/disable)
+     */
+    StringAppendF(&alertQuotaCmd, ALERT_IPT_TEMPLATE, opFlag, LOCAL_GLOBAL_ALERT, bytes,
                   alertName.c_str());
     StringAppendF(&alertQuotaCmd, "COMMIT\n");
 
@@ -663,10 +659,6 @@
         res = updateQuota(alertName, bytes);
     } else {
         res = runIptablesAlertCmd(IptOpInsert, alertName, bytes);
-        if (mGlobalAlertTetherCount) {
-            ALOGV("setGlobalAlert for %d tether", mGlobalAlertTetherCount);
-            res |= runIptablesAlertFwdCmd(IptOpInsert, alertName, bytes);
-        }
         if (res) {
             res = -EREMOTEIO;
         }
@@ -675,26 +667,6 @@
     return res;
 }
 
-int BandwidthController::setGlobalAlertInForwardChain() {
-    const char *alertName = ALERT_GLOBAL_NAME;
-
-    mGlobalAlertTetherCount++;
-    ALOGV("setGlobalAlertInForwardChain(): %d tether", mGlobalAlertTetherCount);
-
-    /*
-     * If there is no globalAlert active we are done.
-     * If there is an active globalAlert but this is not the 1st
-     * tether, we are also done.
-     */
-    if (!mGlobalAlertBytes || mGlobalAlertTetherCount != 1) {
-        return 0;
-    }
-
-    /* We only add the rule if this was the 1st tether added. */
-    return (runIptablesAlertFwdCmd(IptOpInsert, alertName, mGlobalAlertBytes) == 0) ? 0
-                                                                                    : -EREMOTEIO;
-}
-
 int BandwidthController::removeGlobalAlert() {
 
     const char *alertName = ALERT_GLOBAL_NAME;
@@ -706,36 +678,10 @@
 
     int res = 0;
     res = runIptablesAlertCmd(IptOpDelete, alertName, mGlobalAlertBytes);
-    if (mGlobalAlertTetherCount) {
-        res |= runIptablesAlertFwdCmd(IptOpDelete, alertName, mGlobalAlertBytes);
-    }
     mGlobalAlertBytes = 0;
     return res;
 }
 
-int BandwidthController::removeGlobalAlertInForwardChain() {
-    const char *alertName = ALERT_GLOBAL_NAME;
-
-    if (!mGlobalAlertTetherCount) {
-        ALOGE("No prior alert set");
-        return -ENOENT;
-    }
-
-    mGlobalAlertTetherCount--;
-    /*
-     * If there is no globalAlert active we are done.
-     * If there is an active globalAlert but there are more
-     * tethers, we are also done.
-     */
-    if (!mGlobalAlertBytes || mGlobalAlertTetherCount >= 1) {
-        return 0;
-    }
-
-    /* We only detete the rule if this was the last tether removed. */
-    return (runIptablesAlertFwdCmd(IptOpDelete, alertName, mGlobalAlertBytes) == 0) ? 0
-                                                                                    : -EREMOTEIO;
-}
-
 int BandwidthController::setSharedAlert(int64_t bytes) {
     if (!mSharedQuotaBytes) {
         ALOGE("Need to have a prior shared quota set to set an alert");
diff --git a/server/BandwidthController.h b/server/BandwidthController.h
index 31575b8..b8691dc 100644
--- a/server/BandwidthController.h
+++ b/server/BandwidthController.h
@@ -73,6 +73,7 @@
     static const char LOCAL_OUTPUT[];
     static const char LOCAL_RAW_PREROUTING[];
     static const char LOCAL_MANGLE_POSTROUTING[];
+    static const char LOCAL_GLOBAL_ALERT[];
 
     enum IptJumpOp { IptJumpReject, IptJumpReturn, IptJumpNoAdd };
     enum IptOp { IptOpInsert, IptOpDelete };
@@ -136,15 +137,6 @@
     int64_t mSharedQuotaBytes = 0;
     int64_t mSharedAlertBytes = 0;
     int64_t mGlobalAlertBytes = 0;
-    /*
-     * This tracks the number of tethers setup.
-     * The FORWARD chain is updated in the following cases:
-     *  - The 1st time a globalAlert is setup and there are tethers setup.
-     *  - Anytime a globalAlert is removed and there are tethers setup.
-     *  - The 1st tether is setup and there is a globalAlert active.
-     *  - The last tether is removed and there is a globalAlert active.
-     */
-    int mGlobalAlertTetherCount = 0;
 
     std::map<std::string, QuotaInfo> mQuotaIfaces;
     std::set<std::string> mSharedQuotaIfaces;
diff --git a/server/BandwidthControllerTest.cpp b/server/BandwidthControllerTest.cpp
index dc67f6c..febbe62 100644
--- a/server/BandwidthControllerTest.cpp
+++ b/server/BandwidthControllerTest.cpp
@@ -53,10 +53,12 @@
 
 const std::string ACCOUNT_RULES_WITHOUT_BPF =
         "*filter\n"
+        "-A bw_INPUT -j bw_global_alert\n"
         "-A bw_INPUT -p esp -j RETURN\n"
         "-A bw_INPUT -m mark --mark 0x100000/0x100000 -j RETURN\n"
         "-A bw_INPUT -m owner --socket-exists\n"
         "-A bw_INPUT -j MARK --or-mark 0x100000\n"
+        "-A bw_OUTPUT -j bw_global_alert\n"
         "-A bw_OUTPUT -o ipsec+ -j RETURN\n"
         "-A bw_OUTPUT -m policy --pol ipsec --dir out -j RETURN\n"
         "-A bw_OUTPUT -m owner --socket-exists\n"
@@ -82,10 +84,12 @@
 
 const std::string ACCOUNT_RULES_WITH_BPF =
         "*filter\n"
+        "-A bw_INPUT -j bw_global_alert\n"
         "-A bw_INPUT -p esp -j RETURN\n"
         "-A bw_INPUT -m mark --mark 0x100000/0x100000 -j RETURN\n"
         "\n"
         "-A bw_INPUT -j MARK --or-mark 0x100000\n"
+        "-A bw_OUTPUT -j bw_global_alert\n"
         "-A bw_OUTPUT -o ipsec+ -j RETURN\n"
         "-A bw_OUTPUT -m policy --pol ipsec --dir out -j RETURN\n"
         "\n"
@@ -128,28 +132,30 @@
         mTun.destroy();
     }
 
-    void expectSetupCommands(const std::string& expectedClean, std::string expectedAccounting) {
+    void expectSetupCommands(const std::string& expectedClean,
+                             const std::string& expectedAccounting) {
         std::string expectedList =
             "*filter\n"
             "-S\n"
             "COMMIT\n";
 
         std::string expectedFlush =
-            "*filter\n"
-            ":bw_INPUT -\n"
-            ":bw_OUTPUT -\n"
-            ":bw_FORWARD -\n"
-            ":bw_happy_box -\n"
-            ":bw_penalty_box -\n"
-            ":bw_data_saver -\n"
-            ":bw_costly_shared -\n"
-            "COMMIT\n"
-            "*raw\n"
-            ":bw_raw_PREROUTING -\n"
-            "COMMIT\n"
-            "*mangle\n"
-            ":bw_mangle_POSTROUTING -\n"
-            "COMMIT\n";
+                "*filter\n"
+                ":bw_INPUT -\n"
+                ":bw_OUTPUT -\n"
+                ":bw_FORWARD -\n"
+                ":bw_happy_box -\n"
+                ":bw_penalty_box -\n"
+                ":bw_data_saver -\n"
+                ":bw_costly_shared -\n"
+                ":bw_global_alert -\n"
+                "COMMIT\n"
+                "*raw\n"
+                ":bw_raw_PREROUTING -\n"
+                "COMMIT\n"
+                "*mangle\n"
+                ":bw_mangle_POSTROUTING -\n"
+                "COMMIT\n";
 
         ExpectedIptablesCommands expected = {{ V4, expectedList }};
         if (expectedClean.size()) {
@@ -165,14 +171,10 @@
 
     using IptOp = BandwidthController::IptOp;
 
-    int runIptablesAlertCmd(IptOp a, const char *b, int64_t c) {
+    int runIptablesAlertCmd(IptOp a, const char* b, int64_t c) {
         return mBw.runIptablesAlertCmd(a, b, c);
     }
 
-    int runIptablesAlertFwdCmd(IptOp a, const char *b, int64_t c) {
-        return mBw.runIptablesAlertFwdCmd(a, b, c);
-    }
-
     int setCostlyAlert(const std::string& a, int64_t b, int64_t* c) {
         return mBw.setCostlyAlert(a, b, c);
     }
@@ -467,42 +469,20 @@
 
 TEST_F(BandwidthControllerTest, IptablesAlertCmd) {
     std::vector<std::string> expected = {
-        "*filter\n"
-        "-I bw_INPUT -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
-        "-I bw_OUTPUT -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
-        "COMMIT\n"
-    };
+            "*filter\n"
+            "-I bw_global_alert -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
+            "COMMIT\n"};
     EXPECT_EQ(0, runIptablesAlertCmd(IptOp::IptOpInsert, "MyWonderfulAlert", 123456));
     expectIptablesRestoreCommands(expected);
 
     expected = {
-        "*filter\n"
-        "-D bw_INPUT -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
-        "-D bw_OUTPUT -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
-        "COMMIT\n"
-    };
+            "*filter\n"
+            "-D bw_global_alert -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
+            "COMMIT\n"};
     EXPECT_EQ(0, runIptablesAlertCmd(IptOp::IptOpDelete, "MyWonderfulAlert", 123456));
     expectIptablesRestoreCommands(expected);
 }
 
-TEST_F(BandwidthControllerTest, IptablesAlertFwdCmd) {
-    std::vector<std::string> expected = {
-        "*filter\n"
-        "-I bw_FORWARD -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
-        "COMMIT\n"
-    };
-    EXPECT_EQ(0, runIptablesAlertFwdCmd(IptOp::IptOpInsert, "MyWonderfulAlert", 123456));
-    expectIptablesRestoreCommands(expected);
-
-    expected = {
-        "*filter\n"
-        "-D bw_FORWARD -m quota2 ! --quota 123456 --name MyWonderfulAlert\n"
-        "COMMIT\n"
-    };
-    EXPECT_EQ(0, runIptablesAlertFwdCmd(IptOp::IptOpDelete, "MyWonderfulAlert", 123456));
-    expectIptablesRestoreCommands(expected);
-}
-
 TEST_F(BandwidthControllerTest, CostlyAlert) {
     const int64_t kQuota = 123456;
     int64_t alertBytes = 0;
diff --git a/server/CommandListener.cpp b/server/CommandListener.cpp
index 7629c9a..6156221 100644
--- a/server/CommandListener.cpp
+++ b/server/CommandListener.cpp
@@ -531,14 +531,8 @@
     // nat disable intiface extiface
     if (!strcmp(argv[1], "enable") && argc >= 4) {
         rc = gCtls->tetherCtrl.enableNat(argv[2], argv[3]);
-        if(!rc) {
-            /* Ignore ifaces for now. */
-            rc = gCtls->bandwidthCtrl.setGlobalAlertInForwardChain();
-        }
     } else if (!strcmp(argv[1], "disable") && argc >= 4) {
-        /* Ignore ifaces for now. */
-        rc = gCtls->bandwidthCtrl.removeGlobalAlertInForwardChain();
-        rc |= gCtls->tetherCtrl.disableNat(argv[2], argv[3]);
+        rc = gCtls->tetherCtrl.disableNat(argv[2], argv[3]);
     } else {
         cli->sendMsg(ResponseCode::CommandSyntaxError, "Unknown nat cmd", false);
         return 0;
@@ -871,17 +865,6 @@
         sendGenericOkFail(cli, rc);
         return 0;
     }
-    if (!strcmp(argv[1], "debugsettetherglobalalert") || !strcmp(argv[1], "dstga")) {
-        if (argc != 4) {
-            sendGenericSyntaxError(cli, "debugsettetherglobalalert <interface0> <interface1>");
-            return 0;
-        }
-        /* We ignore the interfaces for now. */
-        int rc = gCtls->bandwidthCtrl.setGlobalAlertInForwardChain();
-        sendGenericOkFail(cli, rc);
-        return 0;
-
-    }
     if (!strcmp(argv[1], "removeglobalalert") || !strcmp(argv[1], "rga")) {
         if (argc != 2) {
             sendGenericSyntaxError(cli, "removeglobalalert");
@@ -892,17 +875,6 @@
         return 0;
 
     }
-    if (!strcmp(argv[1], "debugremovetetherglobalalert") || !strcmp(argv[1], "drtga")) {
-        if (argc != 4) {
-            sendGenericSyntaxError(cli, "debugremovetetherglobalalert <interface0> <interface1>");
-            return 0;
-        }
-        /* We ignore the interfaces for now. */
-        int rc = gCtls->bandwidthCtrl.removeGlobalAlertInForwardChain();
-        sendGenericOkFail(cli, rc);
-        return 0;
-
-    }
     if (!strcmp(argv[1], "setsharedalert") || !strcmp(argv[1], "ssa")) {
         if (argc != 3) {
             sendGenericSyntaxError(cli, "setsharedalert <bytes>");
diff --git a/server/ControllersTest.cpp b/server/ControllersTest.cpp
index 0c56594..cc8b1aa 100644
--- a/server/ControllersTest.cpp
+++ b/server/ControllersTest.cpp
@@ -70,121 +70,125 @@
 TEST_F(ControllersTest, TestInitIptablesRules) {
     // Test what happens when we boot and there are no rules.
     ExpectedIptablesCommands expected = {
-        { V4V6, "*filter\n"
-                ":INPUT -\n"
-                "-F INPUT\n"
-                ":bw_INPUT -\n"
-                "-A INPUT -j bw_INPUT\n"
-                ":fw_INPUT -\n"
-                "-A INPUT -j fw_INPUT\n"
-                "COMMIT\n"
-        },
-        { V4V6, "*filter\n"
-                ":FORWARD -\n"
-                "-F FORWARD\n"
-                ":oem_fwd -\n"
-                "-A FORWARD -j oem_fwd\n"
-                ":fw_FORWARD -\n"
-                "-A FORWARD -j fw_FORWARD\n"
-                ":bw_FORWARD -\n"
-                "-A FORWARD -j bw_FORWARD\n"
-                ":tetherctrl_FORWARD -\n"
-                "-A FORWARD -j tetherctrl_FORWARD\n"
-                "COMMIT\n"
-        },
-        { V4V6, "*raw\n"
-                ":PREROUTING -\n"
-                "-F PREROUTING\n"
-                ":bw_raw_PREROUTING -\n"
-                "-A PREROUTING -j bw_raw_PREROUTING\n"
-                ":idletimer_raw_PREROUTING -\n"
-                "-A PREROUTING -j idletimer_raw_PREROUTING\n"
-                ":tetherctrl_raw_PREROUTING -\n"
-                "-A PREROUTING -j tetherctrl_raw_PREROUTING\n"
-                "COMMIT\n"
-        },
-        { V4V6, "*mangle\n"
-                ":FORWARD -\n"
-                "-F FORWARD\n"
-                ":tetherctrl_mangle_FORWARD -\n"
-                "-A FORWARD -j tetherctrl_mangle_FORWARD\n"
-                "COMMIT\n"
-        },
-        { V4V6, "*mangle\n"
-                ":INPUT -\n"
-                "-F INPUT\n"
-                ":wakeupctrl_mangle_INPUT -\n"
-                "-A INPUT -j wakeupctrl_mangle_INPUT\n"
-                ":routectrl_mangle_INPUT -\n"
-                "-A INPUT -j routectrl_mangle_INPUT\n"
-                "COMMIT\n"
-        },
-        { V4,   "*nat\n"
-                ":PREROUTING -\n"
-                "-F PREROUTING\n"
-                ":oem_nat_pre -\n"
-                "-A PREROUTING -j oem_nat_pre\n"
-                "COMMIT\n"
-        },
-        { V4,   "*nat\n"
-                ":POSTROUTING -\n"
-                "-F POSTROUTING\n"
-                ":tetherctrl_nat_POSTROUTING -\n"
-                "-A POSTROUTING -j tetherctrl_nat_POSTROUTING\n"
-                "COMMIT\n"
-        },
-        { V4, "*filter\n"
-              "-S OUTPUT\n"
-              "COMMIT\n" },
-        { V4, "*filter\n"
-              ":oem_out -\n"
-              "-A OUTPUT -j oem_out\n"
-              ":fw_OUTPUT -\n"
-              "-A OUTPUT -j fw_OUTPUT\n"
-              ":st_OUTPUT -\n"
-              "-A OUTPUT -j st_OUTPUT\n"
-              ":bw_OUTPUT -\n"
-              "-A OUTPUT -j bw_OUTPUT\n"
-              "COMMIT\n"
-        },
-        { V6, "*filter\n"
-              "-S OUTPUT\n"
-              "COMMIT\n" },
-        { V6, "*filter\n"
-              ":oem_out -\n"
-              "-A OUTPUT -j oem_out\n"
-              ":fw_OUTPUT -\n"
-              "-A OUTPUT -j fw_OUTPUT\n"
-              ":st_OUTPUT -\n"
-              "-A OUTPUT -j st_OUTPUT\n"
-              ":bw_OUTPUT -\n"
-              "-A OUTPUT -j bw_OUTPUT\n"
-              "COMMIT\n"
-        },
-        { V4, "*mangle\n"
-              "-S POSTROUTING\n"
-              "COMMIT\n" },
-        { V4, "*mangle\n"
-              ":oem_mangle_post -\n"
-              "-A POSTROUTING -j oem_mangle_post\n"
-              ":bw_mangle_POSTROUTING -\n"
-              "-A POSTROUTING -j bw_mangle_POSTROUTING\n"
-              ":idletimer_mangle_POSTROUTING -\n"
-              "-A POSTROUTING -j idletimer_mangle_POSTROUTING\n"
-              "COMMIT\n"
-        },
-        { V6, "*mangle\n"
-              "-S POSTROUTING\n"
-              "COMMIT\n" },
-        { V6, "*mangle\n"
-              ":oem_mangle_post -\n"
-              "-A POSTROUTING -j oem_mangle_post\n"
-              ":bw_mangle_POSTROUTING -\n"
-              "-A POSTROUTING -j bw_mangle_POSTROUTING\n"
-              ":idletimer_mangle_POSTROUTING -\n"
-              "-A POSTROUTING -j idletimer_mangle_POSTROUTING\n"
-              "COMMIT\n"
-        },
+            {V4V6,
+             "*filter\n"
+             ":INPUT -\n"
+             "-F INPUT\n"
+             ":bw_INPUT -\n"
+             "-A INPUT -j bw_INPUT\n"
+             ":fw_INPUT -\n"
+             "-A INPUT -j fw_INPUT\n"
+             "COMMIT\n"},
+            {V4V6,
+             "*filter\n"
+             ":FORWARD -\n"
+             "-F FORWARD\n"
+             ":oem_fwd -\n"
+             "-A FORWARD -j oem_fwd\n"
+             ":fw_FORWARD -\n"
+             "-A FORWARD -j fw_FORWARD\n"
+             ":bw_FORWARD -\n"
+             "-A FORWARD -j bw_FORWARD\n"
+             ":tetherctrl_FORWARD -\n"
+             "-A FORWARD -j tetherctrl_FORWARD\n"
+             "COMMIT\n"},
+            {V4V6,
+             "*raw\n"
+             ":PREROUTING -\n"
+             "-F PREROUTING\n"
+             ":bw_raw_PREROUTING -\n"
+             "-A PREROUTING -j bw_raw_PREROUTING\n"
+             ":idletimer_raw_PREROUTING -\n"
+             "-A PREROUTING -j idletimer_raw_PREROUTING\n"
+             ":tetherctrl_raw_PREROUTING -\n"
+             "-A PREROUTING -j tetherctrl_raw_PREROUTING\n"
+             "COMMIT\n"},
+            {V4V6,
+             "*mangle\n"
+             ":FORWARD -\n"
+             "-F FORWARD\n"
+             ":tetherctrl_mangle_FORWARD -\n"
+             "-A FORWARD -j tetherctrl_mangle_FORWARD\n"
+             "COMMIT\n"},
+            {V4V6,
+             "*mangle\n"
+             ":INPUT -\n"
+             "-F INPUT\n"
+             ":wakeupctrl_mangle_INPUT -\n"
+             "-A INPUT -j wakeupctrl_mangle_INPUT\n"
+             ":routectrl_mangle_INPUT -\n"
+             "-A INPUT -j routectrl_mangle_INPUT\n"
+             "COMMIT\n"},
+            {V4,
+             "*nat\n"
+             ":PREROUTING -\n"
+             "-F PREROUTING\n"
+             ":oem_nat_pre -\n"
+             "-A PREROUTING -j oem_nat_pre\n"
+             "COMMIT\n"},
+            {V4,
+             "*nat\n"
+             ":POSTROUTING -\n"
+             "-F POSTROUTING\n"
+             ":tetherctrl_nat_POSTROUTING -\n"
+             "-A POSTROUTING -j tetherctrl_nat_POSTROUTING\n"
+             "COMMIT\n"},
+            {V4,
+             "*filter\n"
+             "-S OUTPUT\n"
+             "COMMIT\n"},
+            {V4,
+             "*filter\n"
+             ":oem_out -\n"
+             "-A OUTPUT -j oem_out\n"
+             ":fw_OUTPUT -\n"
+             "-A OUTPUT -j fw_OUTPUT\n"
+             ":st_OUTPUT -\n"
+             "-A OUTPUT -j st_OUTPUT\n"
+             ":bw_OUTPUT -\n"
+             "-A OUTPUT -j bw_OUTPUT\n"
+             "COMMIT\n"},
+            {V6,
+             "*filter\n"
+             "-S OUTPUT\n"
+             "COMMIT\n"},
+            {V6,
+             "*filter\n"
+             ":oem_out -\n"
+             "-A OUTPUT -j oem_out\n"
+             ":fw_OUTPUT -\n"
+             "-A OUTPUT -j fw_OUTPUT\n"
+             ":st_OUTPUT -\n"
+             "-A OUTPUT -j st_OUTPUT\n"
+             ":bw_OUTPUT -\n"
+             "-A OUTPUT -j bw_OUTPUT\n"
+             "COMMIT\n"},
+            {V4,
+             "*mangle\n"
+             "-S POSTROUTING\n"
+             "COMMIT\n"},
+            {V4,
+             "*mangle\n"
+             ":oem_mangle_post -\n"
+             "-A POSTROUTING -j oem_mangle_post\n"
+             ":bw_mangle_POSTROUTING -\n"
+             "-A POSTROUTING -j bw_mangle_POSTROUTING\n"
+             ":idletimer_mangle_POSTROUTING -\n"
+             "-A POSTROUTING -j idletimer_mangle_POSTROUTING\n"
+             "COMMIT\n"},
+            {V6,
+             "*mangle\n"
+             "-S POSTROUTING\n"
+             "COMMIT\n"},
+            {V6,
+             "*mangle\n"
+             ":oem_mangle_post -\n"
+             "-A POSTROUTING -j oem_mangle_post\n"
+             ":bw_mangle_POSTROUTING -\n"
+             "-A POSTROUTING -j bw_mangle_POSTROUTING\n"
+             ":idletimer_mangle_POSTROUTING -\n"
+             "-A POSTROUTING -j idletimer_mangle_POSTROUTING\n"
+             "COMMIT\n"},
     };
 
     // Check that we run these commands and these only.
diff --git a/server/NetdNativeService.cpp b/server/NetdNativeService.cpp
index 7647e20..ebf1788 100644
--- a/server/NetdNativeService.cpp
+++ b/server/NetdNativeService.cpp
@@ -1493,10 +1493,6 @@
     auto entry = gLog.newEntry().prettyFunction(__PRETTY_FUNCTION__).args(intIface, extIface);
 
     int res = gCtls->tetherCtrl.enableNat(intIface.c_str(), extIface.c_str());
-    if (!res) {
-        std::lock_guard lock(gCtls->bandwidthCtrl.lock);
-        res = gCtls->bandwidthCtrl.setGlobalAlertInForwardChain();
-    }
     gLog.log(entry.returns(res).withAutomaticDuration());
     return statusFromErrcode(res);
 }
@@ -1504,11 +1500,9 @@
 binder::Status NetdNativeService::tetherRemoveForward(const std::string& intIface,
                                                       const std::string& extIface) {
     NETD_LOCKING_RPC(NETWORK_STACK, gCtls->tetherCtrl.lock);
-    std::lock_guard lock(gCtls->bandwidthCtrl.lock);
     auto entry = gLog.newEntry().prettyFunction(__PRETTY_FUNCTION__).args(intIface, extIface);
 
-    int res = gCtls->bandwidthCtrl.removeGlobalAlertInForwardChain();
-    res |= gCtls->tetherCtrl.disableNat(intIface.c_str(), extIface.c_str());
+    int res = gCtls->tetherCtrl.disableNat(intIface.c_str(), extIface.c_str());
     gLog.log(entry.returns(res).withAutomaticDuration());
     return statusFromErrcode(res);
 }
diff --git a/server/TetherController.cpp b/server/TetherController.cpp
index 49c1b7e..62dcbbf 100644
--- a/server/TetherController.cpp
+++ b/server/TetherController.cpp
@@ -507,12 +507,13 @@
         "COMMIT\n", LOCAL_FORWARD, LOCAL_FORWARD, LOCAL_NAT_POSTROUTING);
 
     std::string v6Cmd = StringPrintf(
-        "*filter\n"
-        ":%s -\n"
-        "COMMIT\n"
-        "*raw\n"
-        ":%s -\n"
-        "COMMIT\n", LOCAL_FORWARD, LOCAL_RAW_PREROUTING);
+            "*filter\n"
+            ":%s -\n"
+            "COMMIT\n"
+            "*raw\n"
+            ":%s -\n"
+            "COMMIT\n",
+            LOCAL_FORWARD, LOCAL_RAW_PREROUTING);
 
     int res = iptablesRestoreFunction(V4, v4Cmd, nullptr);
     if (res < 0) {
@@ -552,8 +553,8 @@
             "COMMIT\n"
         };
 
-        if (iptablesRestoreFunction(V4, Join(v4Cmds, '\n'), nullptr) ||
-            setupIPv6CountersChain()) {
+        if (iptablesRestoreFunction(V4, Join(v4Cmds, '\n'), nullptr) || setupIPv6CountersChain() ||
+            setTetherGlobalAlertRule()) {
             ALOGE("Error setting postroute rule: iface=%s", extIface);
             if (!isAnyForwardingPairEnabled()) {
                 // unwind what's been done, but don't care about success - what more could we do?
@@ -574,6 +575,19 @@
     return 0;
 }
 
+int TetherController::setTetherGlobalAlertRule() {
+    // Only add this if we are the first enabled nat
+    if (isAnyForwardingPairEnabled()) {
+        return 0;
+    }
+    const std::string cmds =
+            "*filter\n" +
+            StringPrintf("-I %s -j %s\n", LOCAL_FORWARD, BandwidthController::LOCAL_GLOBAL_ALERT) +
+            "COMMIT\n";
+
+    return iptablesRestoreFunction(V4V6, cmds, nullptr);
+}
+
 int TetherController::setupIPv6CountersChain() {
     // Only add this if we are the first enabled nat
     if (isAnyForwardingPairEnabled()) {
@@ -584,13 +598,11 @@
      * IPv6 tethering doesn't need the state-based conntrack rules, so
      * it unconditionally jumps to the tether counters chain all the time.
      */
-    std::vector<std::string> v6Cmds = {
-        "*filter",
-        StringPrintf("-A %s -g %s", LOCAL_FORWARD, LOCAL_TETHER_COUNTERS_CHAIN),
-        "COMMIT\n"
-    };
+    const std::string v6Cmds =
+            "*filter\n" +
+            StringPrintf("-A %s -g %s\n", LOCAL_FORWARD, LOCAL_TETHER_COUNTERS_CHAIN) + "COMMIT\n";
 
-    return iptablesRestoreFunction(V6, Join(v6Cmds, '\n'), nullptr);
+    return iptablesRestoreFunction(V6, v6Cmds, nullptr);
 }
 
 // Gets a pointer to the ForwardingDownstream for an interface pair in the map, or nullptr
@@ -738,7 +750,8 @@
 
 int TetherController::disableNat(const char* intIface, const char* extIface) {
     if (!isIfaceName(intIface) || !isIfaceName(extIface)) {
-        return -ENODEV;
+        errno = ENODEV;
+        return -errno;
     }
 
     setForwardRules(false, intIface, extIface);
diff --git a/server/TetherController.h b/server/TetherController.h
index 54fa6da..18d0dc3 100644
--- a/server/TetherController.h
+++ b/server/TetherController.h
@@ -158,6 +158,7 @@
     bool tetherCountingRuleExists(const std::string& iface1, const std::string& iface2);
 
     int setDefaults();
+    int setTetherGlobalAlertRule();
     int setForwardRules(bool set, const char *intIface, const char *extIface);
     int setTetherCountingRules(bool add, const char *intIface, const char *extIface);
 
diff --git a/server/TetherControllerTest.cpp b/server/TetherControllerTest.cpp
index 7ccdc0c..969cbcd 100644
--- a/server/TetherControllerTest.cpp
+++ b/server/TetherControllerTest.cpp
@@ -56,42 +56,55 @@
     }
 
     const ExpectedIptablesCommands FLUSH_COMMANDS = {
-        { V4,   "*filter\n"
-                ":tetherctrl_FORWARD -\n"
-                "-A tetherctrl_FORWARD -j DROP\n"
-                "COMMIT\n"
-                "*nat\n"
-                ":tetherctrl_nat_POSTROUTING -\n"
-                "COMMIT\n" },
-        { V6,   "*filter\n"
-                ":tetherctrl_FORWARD -\n"
-                "COMMIT\n"
-                "*raw\n"
-                ":tetherctrl_raw_PREROUTING -\n"
-                "COMMIT\n" },
+            {V4,
+             "*filter\n"
+             ":tetherctrl_FORWARD -\n"
+             "-A tetherctrl_FORWARD -j DROP\n"
+             "COMMIT\n"
+             "*nat\n"
+             ":tetherctrl_nat_POSTROUTING -\n"
+             "COMMIT\n"},
+            {V6,
+             "*filter\n"
+             ":tetherctrl_FORWARD -\n"
+             "COMMIT\n"
+             "*raw\n"
+             ":tetherctrl_raw_PREROUTING -\n"
+             "COMMIT\n"},
     };
 
     const ExpectedIptablesCommands SETUP_COMMANDS = {
-        { V4,   "*filter\n"
-                ":tetherctrl_FORWARD -\n"
-                "-A tetherctrl_FORWARD -j DROP\n"
-                "COMMIT\n"
-                "*nat\n"
-                ":tetherctrl_nat_POSTROUTING -\n"
-                "COMMIT\n" },
-        { V6,   "*filter\n"
-                ":tetherctrl_FORWARD -\n"
-                "COMMIT\n"
-                "*raw\n"
-                ":tetherctrl_raw_PREROUTING -\n"
-                "COMMIT\n" },
-        { V4,   "*mangle\n"
-                "-A tetherctrl_mangle_FORWARD -p tcp --tcp-flags SYN SYN "
-                    "-j TCPMSS --clamp-mss-to-pmtu\n"
-                "COMMIT\n" },
-        { V4V6, "*filter\n"
-                ":tetherctrl_counters -\n"
-                "COMMIT\n" },
+            {V4,
+             "*filter\n"
+             ":tetherctrl_FORWARD -\n"
+             "-A tetherctrl_FORWARD -j DROP\n"
+             "COMMIT\n"
+             "*nat\n"
+             ":tetherctrl_nat_POSTROUTING -\n"
+             "COMMIT\n"},
+            {V6,
+             "*filter\n"
+             ":tetherctrl_FORWARD -\n"
+             "COMMIT\n"
+             "*raw\n"
+             ":tetherctrl_raw_PREROUTING -\n"
+             "COMMIT\n"},
+            {V4,
+             "*mangle\n"
+             "-A tetherctrl_mangle_FORWARD -p tcp --tcp-flags SYN SYN "
+             "-j TCPMSS --clamp-mss-to-pmtu\n"
+             "COMMIT\n"},
+            {V4V6,
+             "*filter\n"
+             ":tetherctrl_counters -\n"
+             "COMMIT\n"},
+    };
+
+    const ExpectedIptablesCommands ALERT_ADD_COMMAND = {
+            {V4V6,
+             "*filter\n"
+             "-I tetherctrl_FORWARD -j bw_global_alert\n"
+             "COMMIT\n"},
     };
 
     ExpectedIptablesCommands firstIPv4UpstreamCommands(const char *extIf) {
@@ -106,9 +119,9 @@
 
     ExpectedIptablesCommands firstIPv6UpstreamCommands() {
         std::string v6Cmd =
-            "*filter\n"
-            "-A tetherctrl_FORWARD -g tetherctrl_counters\n"
-            "COMMIT\n";
+                "*filter\n"
+                "-A tetherctrl_FORWARD -g tetherctrl_counters\n"
+                "COMMIT\n";
         return {
             { V6, v6Cmd },
         };
@@ -178,10 +191,9 @@
     constexpr static const bool NO_COUNTERS = false;
     constexpr static const bool WITH_IPV6 = true;
     constexpr static const bool NO_IPV6 = false;
-    ExpectedIptablesCommands allNewNatCommands(
-            const char *intIf, const char *extIf, bool withCounterChainRules,
-            bool withIPv6Upstream) {
-
+    ExpectedIptablesCommands allNewNatCommands(const char* intIf, const char* extIf,
+                                               bool withCounterChainRules, bool withIPv6Upstream,
+                                               bool firstEnableNat) {
         ExpectedIptablesCommands commands;
         ExpectedIptablesCommands setupFirstIPv4Commands = firstIPv4UpstreamCommands(extIf);
         ExpectedIptablesCommands startFirstNatCommands = startNatCommands(intIf, extIf,
@@ -192,6 +204,9 @@
             ExpectedIptablesCommands setupFirstIPv6Commands = firstIPv6UpstreamCommands();
             appendAll(commands, setupFirstIPv6Commands);
         }
+        if (firstEnableNat) {
+            appendAll(commands, ALERT_ADD_COMMAND);
+        }
         appendAll(commands, startFirstNatCommands);
 
         return commands;
@@ -243,8 +258,8 @@
 
 TEST_F(TetherControllerTest, TestAddAndRemoveNat) {
     // Start first NAT on first upstream interface. Expect the upstream and NAT rules to be created.
-    ExpectedIptablesCommands firstNat = allNewNatCommands(
-            "wlan0", "rmnet0", WITH_COUNTERS, WITH_IPV6);
+    ExpectedIptablesCommands firstNat =
+            allNewNatCommands("wlan0", "rmnet0", WITH_COUNTERS, WITH_IPV6, true);
     mTetherCtrl.enableNat("wlan0", "rmnet0");
     expectIptablesRestoreCommands(firstNat);
 
@@ -267,7 +282,7 @@
     expectIptablesRestoreCommands(stopLastNat);
 
     // Re-add a NAT removed previously: tetherctrl_counters chain rules are not re-added
-    firstNat = allNewNatCommands("wlan0", "rmnet0", NO_COUNTERS, WITH_IPV6);
+    firstNat = allNewNatCommands("wlan0", "rmnet0", NO_COUNTERS, WITH_IPV6, true);
     mTetherCtrl.enableNat("wlan0", "rmnet0");
     expectIptablesRestoreCommands(firstNat);
 
@@ -280,15 +295,15 @@
 
 TEST_F(TetherControllerTest, TestMultipleUpstreams) {
     // Start first NAT on first upstream interface. Expect the upstream and NAT rules to be created.
-    ExpectedIptablesCommands firstNat = allNewNatCommands(
-            "wlan0", "rmnet0", WITH_COUNTERS, WITH_IPV6);
+    ExpectedIptablesCommands firstNat =
+            allNewNatCommands("wlan0", "rmnet0", WITH_COUNTERS, WITH_IPV6, true);
     mTetherCtrl.enableNat("wlan0", "rmnet0");
     expectIptablesRestoreCommands(firstNat);
 
     // Start second NAT, on new upstream. Expect the upstream and NAT rules to be created for IPv4,
     // but no counter rules for IPv6.
-    ExpectedIptablesCommands secondNat = allNewNatCommands(
-            "wlan0", "v4-rmnet0", WITH_COUNTERS, NO_IPV6);
+    ExpectedIptablesCommands secondNat =
+            allNewNatCommands("wlan0", "v4-rmnet0", WITH_COUNTERS, NO_IPV6, false);
     mTetherCtrl.enableNat("wlan0", "v4-rmnet0");
     expectIptablesRestoreCommands(secondNat);
 
diff --git a/server/binder/android/net/INetd.aidl b/server/binder/android/net/INetd.aidl
index a6905b1..495b672 100644
--- a/server/binder/android/net/INetd.aidl
+++ b/server/binder/android/net/INetd.aidl
@@ -1133,6 +1133,7 @@
     *         cause of the the failure.
     */
     void interfaceSetMtu(in @utf8InCpp String ifName, int mtu);
+
    /**
     * Add forwarding rule/stats on given interface.
     *