ebpf tethering - add a map to store data limit, part 3

This actually starts enforcing the limit.

Note: this requires netd to populate both stats & limit maps
for offload to work.

Bug: 150736748
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I13c21f455155480712fba9b1464b4392d5169a52
Merged-In: I13c21f455155480712fba9b1464b4392d5169a52
diff --git a/server/TetherController.cpp b/server/TetherController.cpp
index 6f2ee09..560a01c 100644
--- a/server/TetherController.cpp
+++ b/server/TetherController.cpp
@@ -1058,6 +1058,49 @@
     return statsList;
 }
 
+// Use UINT64_MAX (~0uLL) for unlimited.
+Result<void> TetherController::setBpfLimit(uint32_t ifIndex, uint64_t limit) {
+    // The common case is an update, where the stats already exist,
+    // hence we read first, even though writing with BPF_NOEXIST
+    // first would make the code simpler.
+    uint64_t rxBytes, txBytes;
+    auto statsEntry = mBpfStatsMap.readValue(ifIndex);
+
+    if (statsEntry.ok()) {
+        // Ok, there was a stats entry.
+        rxBytes = statsEntry.value().rxBytes;
+        txBytes = statsEntry.value().txBytes;
+    } else if (statsEntry.error().code() == ENOENT) {
+        // No stats entry - create one with zeroes.
+        TetherStatsValue stats = {};
+        // This function is the *only* thing that can create entries.
+        auto ret = mBpfStatsMap.writeValue(ifIndex, stats, BPF_NOEXIST);
+        if (!ret.ok()) {
+            ALOGE("mBpfStatsMap.writeValue failure: %s", strerror(ret.error().code()));
+            return ret;
+        }
+        rxBytes = 0;
+        txBytes = 0;
+    } else {
+        // Other error while trying to get stats entry.
+        return statsEntry.error();
+    }
+
+    // rxBytes + txBytes won't overflow even at 5gbps for ~936 years.
+    uint64_t newLimit = rxBytes + txBytes + limit;
+
+    // if adding limit (e.g., if limit is UINT64_MAX) caused overflow: clamp to 'infinity'
+    if (newLimit < rxBytes + txBytes) newLimit = ~0uLL;
+
+    auto ret = mBpfLimitMap.writeValue(ifIndex, newLimit, BPF_ANY);
+    if (!ret.ok()) {
+        ALOGE("mBpfLimitMap.writeValue failure: %s", strerror(ret.error().code()));
+        return ret;
+    }
+
+    return {};
+}
+
 void TetherController::maybeStartBpf(const char* extIface) {
     if (!bpf::isBpfSupported()) return;
 
@@ -1088,6 +1131,9 @@
               isEthernet.value(), strerror(-rv));
         return;
     }
+
+    // For now we just set data limit to 'infinity' ie. unlimited.
+    setBpfLimit(ifIndex, ~0uLL);
 }
 
 void TetherController::maybeStopBpf(const char* extIface) {