Use xt_bpf programs to do bandwidth control

To completely move away from xt_qtaguid module, the bandwidth controller
should not using it for uid owner match any more. Instead, it can use a
eBPF map to store the uid need to be matched and use two eBPF program
running on the xt_bpf hooks to filter out the packet.

Bug: 80649292
Test: ./netd_unit_test
Change-Id: I8e9c7cb3371aae0c24ccc6f64e05e6cbd4f78aae
diff --git a/server/BandwidthController.cpp b/server/BandwidthController.cpp
index 7cd1598..c85d102 100644
--- a/server/BandwidthController.cpp
+++ b/server/BandwidthController.cpp
@@ -56,6 +56,7 @@
 #include "FirewallController.h" /* For makeCriticalCommands */
 #include "Fwmark.h"
 #include "NetdConstants.h"
+#include "TrafficController.h"
 #include "bpf/BpfUtils.h"
 
 /* Alphabetical */
@@ -71,9 +72,13 @@
 using android::base::Join;
 using android::base::StringAppendF;
 using android::base::StringPrintf;
+using android::bpf::XT_BPF_BLACKLIST_PROG_PATH;
 using android::bpf::XT_BPF_EGRESS_PROG_PATH;
 using android::bpf::XT_BPF_INGRESS_PROG_PATH;
+using android::bpf::XT_BPF_WHITELIST_PROG_PATH;
+using android::net::gCtls;
 using android::netdutils::StatusOr;
+using android::netdutils::Status;
 using android::netdutils::UniqueFile;
 
 namespace {
@@ -149,6 +154,11 @@
 const std::string COMMIT_AND_CLOSE = "COMMIT\n";
 const std::string HAPPY_BOX_WHITELIST_COMMAND = StringPrintf(
     "-I bw_happy_box -m owner --uid-owner %d-%d --jump RETURN", 0, MAX_SYSTEM_UID);
+const std::string BPF_HAPPY_BOX_WHITELIST_COMMAND =
+    StringPrintf("-I bw_happy_box -m bpf --object-pinned %s -j RETURN", XT_BPF_WHITELIST_PROG_PATH);
+const std::string BPF_PENALTY_BOX_BLACKLIST_COMMAND =
+    StringPrintf("-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 = {
     /*
@@ -206,8 +216,7 @@
  * See go/ipsec-data-accounting for more information.
  */
 
-const std::vector<std::string> getBasicAccountingCommands() {
-    bool useBpf = BandwidthController::getBpfStatsStatus();
+const std::vector<std::string> getBasicAccountingCommands(const bool useBpf) {
     const std::vector<std::string> ipt_basic_accounting_commands = {
         "*filter",
         // Prevents IPSec double counting (ESP and UDP-encap-ESP respectively)
@@ -224,10 +233,11 @@
         "-A bw_OUTPUT -m owner --socket-exists", /* This is a tracking rule. */
 
         "-A bw_costly_shared --jump bw_penalty_box",
+        useBpf ? BPF_PENALTY_BOX_BLACKLIST_COMMAND : "",
         "-A bw_penalty_box --jump bw_happy_box",
         "-A bw_happy_box --jump bw_data_saver",
         "-A bw_data_saver -j RETURN",
-        HAPPY_BOX_WHITELIST_COMMAND,
+        useBpf ? BPF_HAPPY_BOX_WHITELIST_COMMAND : HAPPY_BOX_WHITELIST_COMMAND,
         "COMMIT",
 
         "*raw",
@@ -237,7 +247,7 @@
         "-A bw_raw_PREROUTING -m policy --pol ipsec --dir in -j RETURN",
         "-A bw_raw_PREROUTING -m owner --socket-exists", /* This is a tracking rule. */
         useBpf ? StringPrintf("-A bw_raw_PREROUTING -m bpf --object-pinned %s",
-                              XT_BPF_INGRESS_PROG_PATH):"",
+                              XT_BPF_INGRESS_PROG_PATH) : "",
         "COMMIT",
 
         "*mangle",
@@ -249,7 +259,7 @@
         StringPrintf("-A bw_mangle_POSTROUTING -j MARK --set-mark 0x0/0x%x",
                      uidBillingMask), // Clear the mark before sending this packet
         useBpf ? StringPrintf("-A bw_mangle_POSTROUTING -m bpf --object-pinned %s",
-                              XT_BPF_EGRESS_PROG_PATH):"",
+                              XT_BPF_EGRESS_PROG_PATH) : "",
         COMMIT_AND_CLOSE
     };
     return ipt_basic_accounting_commands;
@@ -266,9 +276,11 @@
 
 }  // namespace
 
-bool BandwidthController::getBpfStatsStatus() {
+bool BandwidthController::getBpfStatus() {
     return (access(XT_BPF_INGRESS_PROG_PATH, F_OK) != -1) &&
-           (access(XT_BPF_EGRESS_PROG_PATH, F_OK) != -1);
+           (access(XT_BPF_EGRESS_PROG_PATH, F_OK) != -1) &&
+           (access(XT_BPF_WHITELIST_PROG_PATH, F_OK) != -1) &&
+           (access(XT_BPF_BLACKLIST_PROG_PATH, F_OK) != -1);
 }
 
 BandwidthController::BandwidthController() {
@@ -306,7 +318,8 @@
 
     flushCleanTables(false);
 
-    std::string commands = Join(getBasicAccountingCommands(), '\n');
+    mBpfSupported = getBpfStatus();
+    std::string commands = Join(getBasicAccountingCommands(mBpfSupported), '\n');
     return iptablesRestoreFunction(V4V6, commands, nullptr);
 }
 
@@ -360,6 +373,13 @@
 int BandwidthController::manipulateSpecialApps(const std::vector<std::string>& appStrUids,
                                                const std::string& chain, IptJumpOp jumpHandling,
                                                IptOp op) {
+    if (mBpfSupported) {
+      Status status = gCtls->trafficCtrl.updateBandwidthUidMap(appStrUids, jumpHandling, op);
+      if (!isOk(status)) {
+          ALOGE("unable to update the Bandwidth Uid Map: %s", toString(status).c_str());
+      }
+      return status.code();
+    }
     std::string cmd = "*filter\n";
     for (const auto& appStrUid : appStrUids) {
         StringAppendF(&cmd, "%s %s -m owner --uid-owner %s%s\n", opToString(op), chain.c_str(),