refactor bpf maps into class

Use a class object to wrap up the bpf map file descriptor and provide
some base function to look up, write and delete the map content. The map
class also have a nested iterator class to iterate over the map and two
helper function to simplify the iterating process. Removed the
mDeleteStatsMutex since it cannot prevent framework side to read the
stats while we are deleting the stats and all the other netd operation
on the stats related map doesn't need to iterate through the map anyway.

Bug: 78250686
Test: netd_unit_test libbpf_test
Change-Id: I358ba65f7022fd03f8ca573550055734052b6fd2
diff --git a/libbpf/BpfNetworkStatsTest.cpp b/libbpf/BpfNetworkStatsTest.cpp
index 1e9ec8c..e804c40 100644
--- a/libbpf/BpfNetworkStatsTest.cpp
+++ b/libbpf/BpfNetworkStatsTest.cpp
@@ -34,6 +34,7 @@
 #include <android-base/strings.h>
 
 #include <netdutils/MockSyscalls.h>
+#include "bpf/BpfMap.h"
 #include "bpf/BpfNetworkStats.h"
 #include "bpf/BpfUtils.h"
 
@@ -50,7 +51,6 @@
 namespace bpf {
 
 using base::unique_fd;
-using netdutils::status::ok;
 
 constexpr int TEST_MAP_SIZE = 10;
 constexpr uid_t TEST_UID1 = 10086;
@@ -58,14 +58,13 @@
 constexpr uint32_t TEST_TAG = 42;
 constexpr int TEST_COUNTERSET0 = 0;
 constexpr int TEST_COUNTERSET1 = 1;
-constexpr const int COUNTERSETS_LIMIT = 2;
 constexpr uint64_t TEST_BYTES0 = 1000;
 constexpr uint64_t TEST_BYTES1 = 2000;
 constexpr uint64_t TEST_PACKET0 = 100;
 constexpr uint64_t TEST_PACKET1 = 200;
-constexpr const char* IFACE_NAME1 = "lo";
-constexpr const char* IFACE_NAME2 = "wlan0";
-constexpr const char* IFACE_NAME3 = "rmnet_data0";
+constexpr const char IFACE_NAME1[] = "lo";
+constexpr const char IFACE_NAME2[] = "wlan0";
+constexpr const char IFACE_NAME3[] = "rmnet_data0";
 constexpr uint32_t IFACE_INDEX1 = 1;
 constexpr uint32_t IFACE_INDEX2 = 2;
 constexpr uint32_t IFACE_INDEX3 = 3;
@@ -74,60 +73,54 @@
 class BpfNetworkStatsHelperTest : public testing::Test {
   protected:
     BpfNetworkStatsHelperTest() {}
-    unique_fd mFakeCookieTagMap;
-    unique_fd mFakeUidStatsMap;
-    unique_fd mFakeTagStatsMap;
-    unique_fd mFakeIfaceIndexNameMap;
-    unique_fd mFakeIfaceStatsMap;
+    BpfMap<uint64_t, UidTag> mFakeCookieTagMap;
+    BpfMap<StatsKey, StatsValue> mFakeUidStatsMap;
+    BpfMap<StatsKey, StatsValue> mFakeTagStatsMap;
+    BpfMap<uint32_t, IfaceValue> mFakeIfaceIndexNameMap;
+    BpfMap<uint32_t, StatsValue> mFakeIfaceStatsMap;
 
     void SetUp() {
-        mFakeCookieTagMap = unique_fd(createMap(BPF_MAP_TYPE_HASH, sizeof(uint64_t),
-                                                sizeof(struct UidTag), TEST_MAP_SIZE, 0));
-        ASSERT_LE(0, mFakeCookieTagMap);
+        mFakeCookieTagMap = BpfMap<uint64_t, UidTag>(createMap(
+            BPF_MAP_TYPE_HASH, sizeof(uint64_t), sizeof(struct UidTag), TEST_MAP_SIZE, 0));
+        ASSERT_LE(0, mFakeCookieTagMap.getMap());
 
-        mFakeUidStatsMap = unique_fd(createMap(BPF_MAP_TYPE_HASH, sizeof(struct StatsKey),
-                                               sizeof(struct StatsValue), TEST_MAP_SIZE, 0));
-        ASSERT_LE(0, mFakeUidStatsMap);
+        mFakeUidStatsMap =
+            BpfMap<StatsKey, StatsValue>(createMap(BPF_MAP_TYPE_HASH, sizeof(struct StatsKey),
+                                                   sizeof(struct StatsValue), TEST_MAP_SIZE, 0));
+        ASSERT_LE(0, mFakeUidStatsMap.getMap());
 
-        mFakeTagStatsMap = unique_fd(createMap(BPF_MAP_TYPE_HASH, sizeof(struct StatsKey),
-                                               sizeof(struct StatsValue), TEST_MAP_SIZE, 0));
-        ASSERT_LE(0, mFakeTagStatsMap);
+        mFakeTagStatsMap =
+            BpfMap<StatsKey, StatsValue>(createMap(BPF_MAP_TYPE_HASH, sizeof(struct StatsKey),
+                                                   sizeof(struct StatsValue), TEST_MAP_SIZE, 0));
+        ASSERT_LE(0, mFakeTagStatsMap.getMap());
 
-        mFakeIfaceIndexNameMap =
-            unique_fd(createMap(BPF_MAP_TYPE_HASH, sizeof(uint32_t), IFNAMSIZ, TEST_MAP_SIZE, 0));
-        ASSERT_LE(0, mFakeIfaceIndexNameMap);
+        mFakeIfaceIndexNameMap = BpfMap<uint32_t, IfaceValue>(
+            createMap(BPF_MAP_TYPE_HASH, sizeof(uint32_t), sizeof(IfaceValue), TEST_MAP_SIZE, 0));
+        ASSERT_LE(0, mFakeIfaceIndexNameMap.getMap());
 
-        mFakeIfaceStatsMap = unique_fd(createMap(BPF_MAP_TYPE_HASH, sizeof(uint32_t),
-                                                 sizeof(struct StatsValue), TEST_MAP_SIZE, 0));
-        ASSERT_LE(0, mFakeIfaceStatsMap);
-    }
-
-    void TearDown() {
-        mFakeCookieTagMap.reset();
-        mFakeUidStatsMap.reset();
-        mFakeTagStatsMap.reset();
-        mFakeIfaceIndexNameMap.reset();
-        mFakeIfaceStatsMap.reset();
+        mFakeIfaceStatsMap = BpfMap<uint32_t, StatsValue>(createMap(
+            BPF_MAP_TYPE_HASH, sizeof(uint32_t), sizeof(struct StatsValue), TEST_MAP_SIZE, 0));
+        ASSERT_LE(0, mFakeIfaceStatsMap.getMap());
     }
 
     void expectUidTag(uint64_t cookie, uid_t uid, uint32_t tag) {
-        struct UidTag tagResult;
-        EXPECT_EQ(0, findMapEntry(mFakeCookieTagMap, &cookie, &tagResult));
-        EXPECT_EQ(uid, tagResult.uid);
-        EXPECT_EQ(tag, tagResult.tag);
+        auto tagResult = mFakeCookieTagMap.readValue(cookie);
+        EXPECT_TRUE(isOk(tagResult));
+        EXPECT_EQ(uid, tagResult.value().uid);
+        EXPECT_EQ(tag, tagResult.value().tag);
     }
 
     void populateFakeStats(uid_t uid, uint32_t tag, uint32_t ifaceIndex, uint32_t counterSet,
-                           StatsValue* value, const base::unique_fd& map_fd) {
+                           StatsValue value, BpfMap<StatsKey, StatsValue>& map) {
         StatsKey key = {
             .uid = (uint32_t)uid, .tag = tag, .counterSet = counterSet, .ifaceIndex = ifaceIndex};
-        EXPECT_EQ(0, writeToMapEntry(map_fd, &key, value, BPF_ANY));
+        EXPECT_TRUE(isOk(map.writeValue(key, value, BPF_ANY)));
     }
 
     void updateIfaceMap(const char* ifaceName, uint32_t ifaceIndex) {
-        char iface[IFNAMSIZ];
-        strlcpy(iface, ifaceName, IFNAMSIZ);
-        EXPECT_EQ(0, writeToMapEntry(mFakeIfaceIndexNameMap, &ifaceIndex, iface, BPF_ANY));
+        IfaceValue iface;
+        strlcpy(iface.name, ifaceName, IFNAMSIZ);
+        EXPECT_TRUE(isOk(mFakeIfaceIndexNameMap.writeValue(ifaceIndex, iface, BPF_ANY)));
     }
 
     void expectStatsEqual(const StatsValue& target, const Stats& result) {
@@ -158,27 +151,29 @@
     for (int i = 0; i < 5; i++) {
         uint64_t cookie = i + 1;
         struct UidTag tag = {.uid = TEST_UID1, .tag = TEST_TAG};
-        EXPECT_EQ(0, writeToMapEntry(mFakeCookieTagMap, &cookie, &tag, BPF_ANY));
+        EXPECT_TRUE(isOk(mFakeCookieTagMap.writeValue(cookie, tag, BPF_ANY)));
     }
     uint64_t curCookie = 0;
-    uint64_t nextCookie = 0;
-    struct UidTag tagResult;
-    EXPECT_EQ(0, getNextMapKey(mFakeCookieTagMap, &curCookie, &nextCookie));
-    uint64_t headOfMap = nextCookie;
-    curCookie = nextCookie;
+    auto nextCookie = mFakeCookieTagMap.getNextKey(curCookie);
+    EXPECT_TRUE(isOk(nextCookie));
+    uint64_t headOfMap = nextCookie.value();
+    curCookie = nextCookie.value();
     // Find the second entry in the map, then immediately delete it.
-    EXPECT_EQ(0, getNextMapKey(mFakeCookieTagMap, &curCookie, &nextCookie));
-    EXPECT_EQ(0, deleteMapEntry(mFakeCookieTagMap, &nextCookie));
+    nextCookie = mFakeCookieTagMap.getNextKey(curCookie);
+    EXPECT_TRUE(isOk(nextCookie));
+    EXPECT_TRUE(isOk(mFakeCookieTagMap.deleteValue((nextCookie.value()))));
     // Find the entry that is now immediately after headOfMap, then delete that.
-    EXPECT_EQ(0, getNextMapKey(mFakeCookieTagMap, &curCookie, &nextCookie));
-    EXPECT_EQ(0, deleteMapEntry(mFakeCookieTagMap, &nextCookie));
+    nextCookie = mFakeCookieTagMap.getNextKey(curCookie);
+    EXPECT_TRUE(isOk(nextCookie));
+    EXPECT_TRUE(isOk(mFakeCookieTagMap.deleteValue((nextCookie.value()))));
     // Attempting to read an entry that has been deleted fails with ENOENT.
-    curCookie = nextCookie;
-    EXPECT_EQ(-1, findMapEntry(mFakeCookieTagMap, &curCookie, &tagResult));
-    EXPECT_EQ(ENOENT, errno);
+    curCookie = nextCookie.value();
+    auto tagResult = mFakeCookieTagMap.readValue(curCookie);
+    EXPECT_EQ(ENOENT, tagResult.status().code());
     // Finding the entry after our deleted entry restarts iteration from the beginning of the map.
-    EXPECT_EQ(0, getNextMapKey(mFakeCookieTagMap, &curCookie, &nextCookie));
-    EXPECT_EQ(headOfMap, nextCookie);
+    nextCookie = mFakeCookieTagMap.getNextKey(curCookie);
+    EXPECT_TRUE(isOk(nextCookie));
+    EXPECT_EQ(headOfMap, nextCookie.value());
 }
 
 TEST_F(BpfNetworkStatsHelperTest, TestBpfIterateMap) {
@@ -187,19 +182,18 @@
     for (int i = 0; i < 5; i++) {
         uint64_t cookie = i + 1;
         struct UidTag tag = {.uid = TEST_UID1, .tag = TEST_TAG};
-        EXPECT_EQ(0, writeToMapEntry(mFakeCookieTagMap, &cookie, &tag, BPF_ANY));
+        EXPECT_TRUE(isOk(mFakeCookieTagMap.writeValue(cookie, tag, BPF_ANY)));
     }
     int totalCount = 0;
     int totalSum = 0;
-    uint64_t dummyCookie;
-    auto iterateMapWithoutDeletion = [&totalCount, &totalSum](void* key, const base::unique_fd&) {
-        uint64_t cookie = *(uint64_t*)key;
-        EXPECT_GE((uint64_t)5, cookie);
+    const auto iterateWithoutDeletion = [&totalCount, &totalSum](const uint64_t& key,
+                                                                 const BpfMap<uint64_t, UidTag>&) {
+        EXPECT_GE((uint64_t)5, key);
         totalCount++;
-        totalSum += cookie;
-        return BPF_CONTINUE;
+        totalSum += key;
+        return netdutils::status::ok;
     };
-    EXPECT_EQ(0, bpfIterateMap(dummyCookie, mFakeCookieTagMap, iterateMapWithoutDeletion));
+    EXPECT_TRUE(isOk(mFakeCookieTagMap.iterate(iterateWithoutDeletion)));
     EXPECT_EQ(5, totalCount);
     EXPECT_EQ(1 + 2 + 3 + 4 + 5, totalSum);
 }
@@ -208,13 +202,15 @@
     SKIP_IF_BPF_NOT_SUPPORTED;
 
     updateIfaceMap(IFACE_NAME1, IFACE_INDEX1);
+    updateIfaceMap(IFACE_NAME2, IFACE_INDEX2);
+    updateIfaceMap(IFACE_NAME3, IFACE_INDEX3);
     StatsValue value1 = {.rxBytes = TEST_BYTES0,
                          .rxPackets = TEST_PACKET0,
                          .txBytes = TEST_BYTES1,
                          .txPackets = TEST_PACKET1,};
-    populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, &value1, mFakeUidStatsMap);
-    populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET1, &value1, mFakeUidStatsMap);
-    populateFakeStats(TEST_UID2, 0, IFACE_INDEX1, TEST_COUNTERSET1, &value1, mFakeUidStatsMap);
+    populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeUidStatsMap);
+    populateFakeStats(TEST_UID1, 0, IFACE_INDEX2, TEST_COUNTERSET1, value1, mFakeUidStatsMap);
+    populateFakeStats(TEST_UID2, 0, IFACE_INDEX3, TEST_COUNTERSET1, value1, mFakeUidStatsMap);
     Stats result1 = {};
     ASSERT_EQ(0, bpfGetUidStatsInternal(TEST_UID1, &result1, mFakeUidStatsMap));
     StatsValue uid1Value = {
@@ -237,7 +233,7 @@
     ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, TEST_UID2,
                                                     mFakeUidStatsMap, mFakeIfaceIndexNameMap));
     ASSERT_EQ((unsigned long)1, lines.size());
-    expectStatsLineEqual(value1, IFACE_NAME1, TEST_UID2, TEST_COUNTERSET1, 0, lines.front());
+    expectStatsLineEqual(value1, IFACE_NAME3, TEST_UID2, TEST_COUNTERSET1, 0, lines.front());
 }
 
 TEST_F(BpfNetworkStatsHelperTest, TestGetIfaceStatsInternal) {
@@ -259,11 +255,11 @@
         .txPackets = TEST_PACKET0,
     };
     uint32_t ifaceStatsKey = IFACE_INDEX1;
-    EXPECT_EQ(0, writeToMapEntry(mFakeIfaceStatsMap, &ifaceStatsKey, &value1, BPF_ANY));
+    EXPECT_TRUE(isOk(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value1, BPF_ANY)));
     ifaceStatsKey = IFACE_INDEX2;
-    EXPECT_EQ(0, writeToMapEntry(mFakeIfaceStatsMap, &ifaceStatsKey, &value2, BPF_ANY));
+    EXPECT_TRUE(isOk(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value2, BPF_ANY)));
     ifaceStatsKey = IFACE_INDEX3;
-    EXPECT_EQ(0, writeToMapEntry(mFakeIfaceStatsMap, &ifaceStatsKey, &value1, BPF_ANY));
+    EXPECT_TRUE(isOk(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value1, BPF_ANY)));
 
     Stats result1 = {};
     ASSERT_EQ(0, bpfGetIfaceStatsInternal(IFACE_NAME1, &result1, mFakeIfaceStatsMap,
@@ -294,14 +290,11 @@
                          .rxPackets = TEST_PACKET0,
                          .txBytes = TEST_BYTES1,
                          .txPackets = TEST_PACKET1,};
-    populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, &value1,
+    populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeTagStatsMap);
+    populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX2, TEST_COUNTERSET0, value1, mFakeTagStatsMap);
+    populateFakeStats(TEST_UID1, TEST_TAG + 1, IFACE_INDEX1, TEST_COUNTERSET0, value1,
                       mFakeTagStatsMap);
-    populateFakeStats(TEST_UID1, TEST_TAG, IFACE_INDEX2, TEST_COUNTERSET0, &value1,
-                      mFakeTagStatsMap);
-    populateFakeStats(TEST_UID1, TEST_TAG + 1, IFACE_INDEX1, TEST_COUNTERSET0, &value1,
-                      mFakeTagStatsMap);
-    populateFakeStats(TEST_UID2, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, &value1,
-                      mFakeTagStatsMap);
+    populateFakeStats(TEST_UID2, TEST_TAG, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeTagStatsMap);
     std::vector<stats_line> lines;
     std::vector<std::string> ifaces;
     ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL,
@@ -332,11 +325,11 @@
                          .rxPackets = TEST_PACKET0,
                          .txBytes = TEST_BYTES1,
                          .txPackets = TEST_PACKET1,};
-    populateFakeStats(0, 0, 0, COUNTERSETS_LIMIT, &value1, mFakeUidStatsMap);
-    populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, &value1, mFakeUidStatsMap);
-    populateFakeStats(TEST_UID1, 0, IFACE_INDEX2, TEST_COUNTERSET0, &value1, mFakeUidStatsMap);
-    populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET1, &value1, mFakeUidStatsMap);
-    populateFakeStats(TEST_UID2, 0, IFACE_INDEX1, TEST_COUNTERSET0, &value1, mFakeUidStatsMap);
+    populateFakeStats(0, 0, 0, OVERFLOW_COUNTERSET, value1, mFakeUidStatsMap);
+    populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeUidStatsMap);
+    populateFakeStats(TEST_UID1, 0, IFACE_INDEX2, TEST_COUNTERSET0, value1, mFakeUidStatsMap);
+    populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET1, value1, mFakeUidStatsMap);
+    populateFakeStats(TEST_UID2, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeUidStatsMap);
     std::vector<stats_line> lines;
     std::vector<std::string> ifaces;
     ASSERT_EQ(0, parseBpfNetworkStatsDetailInternal(&lines, ifaces, TAG_ALL, UID_ALL,
@@ -367,13 +360,13 @@
                          .txBytes = TEST_BYTES1 * 20,
                          .txPackets = TEST_PACKET1,};
     uint32_t ifaceIndex = UNKNOWN_IFACE;
-    populateFakeStats(TEST_UID1, 0, ifaceIndex, TEST_COUNTERSET0, &value1, mFakeUidStatsMap);
-    populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, &value1, mFakeUidStatsMap);
+    populateFakeStats(TEST_UID1, 0, ifaceIndex, TEST_COUNTERSET0, value1, mFakeUidStatsMap);
+    populateFakeStats(TEST_UID1, 0, IFACE_INDEX1, TEST_COUNTERSET0, value1, mFakeUidStatsMap);
     StatsValue value2 = {.rxBytes = TEST_BYTES0 * 40,
                          .rxPackets = TEST_PACKET0,
                          .txBytes = TEST_BYTES1 * 40,
                          .txPackets = TEST_PACKET1,};
-    populateFakeStats(TEST_UID1, 0, IFACE_INDEX2, TEST_COUNTERSET0, &value2, mFakeUidStatsMap);
+    populateFakeStats(TEST_UID1, 0, IFACE_INDEX2, TEST_COUNTERSET0, value2, mFakeUidStatsMap);
     StatsKey curKey = {.uid = TEST_UID1,
                        .tag = 0,
                        .ifaceIndex = ifaceIndex,
@@ -381,11 +374,11 @@
     char ifname[IFNAMSIZ];
     int64_t unknownIfaceBytesTotal = 0;
     ASSERT_EQ(-ENODEV, getIfaceNameFromMap(mFakeIfaceIndexNameMap, mFakeUidStatsMap, ifaceIndex,
-                                           ifname, &curKey, &unknownIfaceBytesTotal));
+                                           ifname, curKey, &unknownIfaceBytesTotal));
     ASSERT_EQ(((int64_t)(TEST_BYTES0 * 20 + TEST_BYTES1 * 20)), unknownIfaceBytesTotal);
     curKey.ifaceIndex = IFACE_INDEX2;
     ASSERT_EQ(-ENODEV, getIfaceNameFromMap(mFakeIfaceIndexNameMap, mFakeUidStatsMap, ifaceIndex,
-                                           ifname, &curKey, &unknownIfaceBytesTotal));
+                                           ifname, curKey, &unknownIfaceBytesTotal));
     ASSERT_EQ(-1, unknownIfaceBytesTotal);
     std::vector<stats_line> lines;
     std::vector<std::string> ifaces;
@@ -415,11 +408,11 @@
         .txPackets = TEST_PACKET0,
     };
     uint32_t ifaceStatsKey = IFACE_INDEX1;
-    EXPECT_EQ(0, writeToMapEntry(mFakeIfaceStatsMap, &ifaceStatsKey, &value1, BPF_ANY));
+    EXPECT_TRUE(isOk(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value1, BPF_ANY)));
     ifaceStatsKey = IFACE_INDEX2;
-    EXPECT_EQ(0, writeToMapEntry(mFakeIfaceStatsMap, &ifaceStatsKey, &value2, BPF_ANY));
+    EXPECT_TRUE(isOk(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value2, BPF_ANY)));
     ifaceStatsKey = IFACE_INDEX3;
-    EXPECT_EQ(0, writeToMapEntry(mFakeIfaceStatsMap, &ifaceStatsKey, &value1, BPF_ANY));
+    EXPECT_TRUE(isOk(mFakeIfaceStatsMap.writeValue(ifaceStatsKey, value1, BPF_ANY)));
     std::vector<stats_line> lines;
     ASSERT_EQ(0,
               parseBpfNetworkStatsDevInternal(&lines, mFakeIfaceStatsMap, mFakeIfaceIndexNameMap));