Get bpf level when check bpf support

Instead of return boolean, bpf support check now returns a integer
represent the current bpf level on device. This level is used to decide
if the device support some advanced bpf feature such as map_in_map and
bpf cgroup socket filter. Delete the binder call for bpf status check
since no one is using it.

Bug: 111441138
Test: libnetdbpf_test, netd_integration_test
Change-Id: Ib70c07647ffe491d493b4582b4b4b0eba7caf3a9
diff --git a/server/Controllers.cpp b/server/Controllers.cpp
index 8f0dad2..a5c9eba 100644
--- a/server/Controllers.cpp
+++ b/server/Controllers.cpp
@@ -282,7 +282,7 @@
     }
     gLog.info("Initializing traffic control: %.1fms", s.getTimeAndReset());
 
-    bandwidthCtrl.setBpfEnabled(trafficCtrl.checkBpfStatsEnable());
+    bandwidthCtrl.setBpfEnabled(trafficCtrl.getBpfLevel() != android::bpf::BpfLevel::NONE);
     bandwidthCtrl.enableBandwidthControl();
     gLog.info("Enabling bandwidth control: %.1fms", s.getTimeAndReset());
 
diff --git a/server/FirewallController.cpp b/server/FirewallController.cpp
index 890ab5b..7512c09 100644
--- a/server/FirewallController.cpp
+++ b/server/FirewallController.cpp
@@ -41,6 +41,7 @@
 using android::base::Split;
 using android::base::StringAppendF;
 using android::base::StringPrintf;
+using android::bpf::BpfLevel;
 using android::net::gCtls;
 
 namespace {
@@ -53,8 +54,8 @@
 // Proc file containing the uid mapping for the user namespace of the current process.
 const char kUidMapProcFile[] = "/proc/self/uid_map";
 
-bool getBpfOwnerStatus() {
-    return gCtls->trafficCtrl.checkBpfStatsEnable();
+android::bpf::BpfLevel getBpfOwnerStatus() {
+    return gCtls->trafficCtrl.getBpfLevel();
 }
 
 }  // namespace
@@ -95,7 +96,7 @@
 int FirewallController::setupIptablesHooks(void) {
     int res = 0;
     mUseBpfOwnerMatch = getBpfOwnerStatus();
-    if (mUseBpfOwnerMatch) {
+    if (mUseBpfOwnerMatch != BpfLevel::NONE) {
         return res;
     }
     res |= createChain(LOCAL_DOZABLE, getFirewallType(DOZABLE));
@@ -159,7 +160,7 @@
             return res;
     }
 
-    if (mUseBpfOwnerMatch) {
+    if (mUseBpfOwnerMatch != BpfLevel::NONE) {
         return gCtls->trafficCtrl.toggleUidOwnerMap(chain, enable);
     }
 
@@ -258,7 +259,7 @@
             ALOGW("Unknown child chain: %d", chain);
             return -EINVAL;
     }
-    if (mUseBpfOwnerMatch) {
+    if (mUseBpfOwnerMatch != BpfLevel::NONE) {
         return gCtls->trafficCtrl.changeUidOwnerRule(chain, uid, rule, firewallType);
     }
 
@@ -346,8 +347,8 @@
 
 int FirewallController::replaceUidChain(
         const std::string &name, bool isWhitelist, const std::vector<int32_t>& uids) {
-   if (mUseBpfOwnerMatch) {
-       return gCtls->trafficCtrl.replaceUidOwnerMap(name, isWhitelist, uids);
+    if (mUseBpfOwnerMatch != BpfLevel::NONE) {
+        return gCtls->trafficCtrl.replaceUidOwnerMap(name, isWhitelist, uids);
    }
    std::string commands4 = makeUidRules(V4, name.c_str(), isWhitelist, uids);
    std::string commands6 = makeUidRules(V6, name.c_str(), isWhitelist, uids);
diff --git a/server/FirewallController.h b/server/FirewallController.h
index a7082da..43da322 100644
--- a/server/FirewallController.h
+++ b/server/FirewallController.h
@@ -26,6 +26,7 @@
 #include "android/net/INetd.h"
 
 #include "NetdConstants.h"
+#include "bpf/BpfUtils.h"
 
 namespace android {
 namespace net {
@@ -103,7 +104,7 @@
   //    fails with EPERM. Netd can therefore assumes the max valid uid to be const.
   const uid_t mMaxUid;
   FirewallType mFirewallType;
-  bool mUseBpfOwnerMatch;
+  android::bpf::BpfLevel mUseBpfOwnerMatch;
   std::set<std::string> mIfaceRules;
   int attachChain(const char*, const char*);
   int detachChain(const char*, const char*);
diff --git a/server/FirewallControllerTest.cpp b/server/FirewallControllerTest.cpp
index 71cc532..bd933b4 100644
--- a/server/FirewallControllerTest.cpp
+++ b/server/FirewallControllerTest.cpp
@@ -39,7 +39,10 @@
 protected:
     FirewallControllerTest() {
         FirewallController::execIptablesRestore = fakeExecIptablesRestore;
-        mFw.mUseBpfOwnerMatch = false;
+        // This unit test currently doesn't cover the eBPF owner match case so
+        // we have to manually turn eBPF support off.
+        // TODO: find a way to unit test the eBPF code path.
+        mFw.mUseBpfOwnerMatch = android::bpf::BpfLevel::NONE;
     }
     FirewallController mFw;
 
diff --git a/server/NetdNativeService.cpp b/server/NetdNativeService.cpp
index 5b213b4..f607069 100644
--- a/server/NetdNativeService.cpp
+++ b/server/NetdNativeService.cpp
@@ -911,12 +911,6 @@
     return asBinderStatus(gCtls->wakeupCtrl.delInterface(ifName, prefix, mark, mask));
 }
 
-binder::Status NetdNativeService::trafficCheckBpfStatsEnable(bool* ret) {
-    ENFORCE_PERMISSION(NETWORK_STACK);
-    *ret = gCtls->trafficCtrl.checkBpfStatsEnable();
-    return binder::Status::ok();
-}
-
 binder::Status NetdNativeService::idletimerAddInterface(const std::string& ifName, int32_t timeout,
                                                         const std::string& classLabel) {
     NETD_LOCKING_RPC(NETWORK_STACK, gCtls->idletimerCtrl.lock);
diff --git a/server/NetdNativeService.h b/server/NetdNativeService.h
index e399fac..607bec8 100644
--- a/server/NetdNativeService.h
+++ b/server/NetdNativeService.h
@@ -205,8 +205,6 @@
                                              int32_t direction, int32_t markValue, int32_t markMask,
                                              int32_t interfaceId);
 
-    binder::Status trafficCheckBpfStatsEnable(bool* ret) override;
-
     binder::Status ipSecAddTunnelInterface(const std::string& deviceName,
                                            const std::string& localAddress,
                                            const std::string& remoteAddress, int32_t iKey,
diff --git a/server/TrafficController.cpp b/server/TrafficController.cpp
index e3b950c..677f32c 100644
--- a/server/TrafficController.cpp
+++ b/server/TrafficController.cpp
@@ -157,9 +157,7 @@
     return netdutils::status::ok;
 }
 
-TrafficController::TrafficController() {
-    ebpfSupported = hasBpfSupport();
-}
+TrafficController::TrafficController() : mBpfLevel(getBpfSupportLevel()) {}
 
 Status TrafficController::initMaps() {
     std::lock_guard ownerMapGuard(mOwnerMatchMutex);
@@ -260,8 +258,7 @@
 }
 
 Status TrafficController::start() {
-
-    if (!ebpfSupported) {
+    if (mBpfLevel == BpfLevel::NONE) {
         return netdutils::status::ok;
     }
 
@@ -326,7 +323,7 @@
         return -EPERM;
     }
 
-    if (!ebpfSupported) {
+    if (mBpfLevel == BpfLevel::NONE) {
         if (legacy_tagSocket(sockFd, tag, uid)) return -errno;
         return 0;
     }
@@ -349,7 +346,7 @@
 }
 
 int TrafficController::untagSocket(int sockFd) {
-    if (!ebpfSupported) {
+    if (mBpfLevel == BpfLevel::NONE) {
         if (legacy_untagSocket(sockFd)) return -errno;
         return 0;
     }
@@ -368,7 +365,7 @@
 
     if (!hasUpdateDeviceStatsPermission(callingUid)) return -EPERM;
 
-    if (!ebpfSupported) {
+    if (mBpfLevel == BpfLevel::NONE) {
         if (legacy_setCounterSet(counterSetNum, uid)) return -errno;
         return 0;
     }
@@ -400,7 +397,7 @@
 int TrafficController::deleteTagData(uint32_t tag, uid_t uid, uid_t callingUid) {
     if (!hasUpdateDeviceStatsPermission(callingUid)) return -EPERM;
 
-    if (!ebpfSupported) {
+    if (mBpfLevel == BpfLevel::NONE) {
         if (legacy_deleteTagData(tag, uid)) return -errno;
         return 0;
     }
@@ -462,7 +459,7 @@
 }
 
 int TrafficController::addInterface(const char* name, uint32_t ifaceIndex) {
-    if (!ebpfSupported) return 0;
+    if (mBpfLevel == BpfLevel::NONE) return 0;
 
     IfaceValue iface;
     if (ifaceIndex == 0) {
@@ -563,7 +560,7 @@
 
 int TrafficController::changeUidOwnerRule(ChildChain chain, uid_t uid, FirewallRule rule,
                                           FirewallType type) {
-    if (!ebpfSupported) {
+    if (mBpfLevel == BpfLevel::NONE) {
         ALOGE("bpf is not set up, should use iptables rule");
         return -ENOSYS;
     }
@@ -677,8 +674,8 @@
     return -res.code();
 }
 
-bool TrafficController::checkBpfStatsEnable() {
-    return ebpfSupported;
+BpfLevel TrafficController::getBpfLevel() {
+    return mBpfLevel;
 }
 
 void TrafficController::setPermissionForUids(int permission, const std::vector<uid_t>& uids) {
@@ -746,9 +743,9 @@
     dw.println("TrafficController");
 
     ScopedIndent indentPreBpfModule(dw);
-    dw.println("BPF module status: %s", ebpfSupported? "ON" : "OFF");
+    dw.println("BPF module status: %s", BpfLevelToString(mBpfLevel).c_str());
 
-    if (!ebpfSupported) {
+    if (mBpfLevel == BpfLevel::NONE) {
         return;
     }
 
diff --git a/server/TrafficController.h b/server/TrafficController.h
index 35bea4a..1576882 100644
--- a/server/TrafficController.h
+++ b/server/TrafficController.h
@@ -86,7 +86,7 @@
      * Check if the current device have the bpf traffic stats accounting service
      * running.
      */
-    bool checkBpfStatsEnable();
+    bpf::BpfLevel getBpfLevel();
 
     /*
      * Add the interface name and index pair into the eBPF map.
@@ -204,7 +204,7 @@
     netdutils::Status addMatch(BpfMap<uint32_t, uint8_t>& map, uint32_t uid,
                                UidOwnerMatchType match) REQUIRES(mOwnerMatchMutex);
 
-    bool ebpfSupported;
+    bpf::BpfLevel mBpfLevel;
 
     std::mutex mOwnerMatchMutex;
 
diff --git a/server/TrafficControllerTest.cpp b/server/TrafficControllerTest.cpp
index 31d3b6b..05702e2 100644
--- a/server/TrafficControllerTest.cpp
+++ b/server/TrafficControllerTest.cpp
@@ -102,8 +102,6 @@
         mFakeUidPermissionMap.reset(
                 createMap(BPF_MAP_TYPE_HASH, sizeof(uint32_t), sizeof(uint8_t), TEST_MAP_SIZE, 0));
         ASSERT_TRUE(mFakeUidPermissionMap.isValid());
-        // Make sure trafficController use the eBPF code path.
-        mTc.ebpfSupported = true;
 
         mTc.mCookieTagMap.reset(mFakeCookieTagMap.getMap());
         mTc.mUidCounterSetMap.reset(mFakeUidCounterSetMap.getMap());
diff --git a/server/binder/android/net/INetd.aidl b/server/binder/android/net/INetd.aidl
index c198aa6..1b6c988 100644
--- a/server/binder/android/net/INetd.aidl
+++ b/server/binder/android/net/INetd.aidl
@@ -569,12 +569,6 @@
     void setIPv6AddrGenMode(in @utf8InCpp String ifName, int mode);
 
    /**
-    * Query the netd service to know if the eBPF traffic stats accounting service is currently
-    * running on the device.
-    */
-    boolean trafficCheckBpfStatsEnable();
-
-   /**
     * Add idletimer for specific interface
     *
     * @param ifName Name of target interface