[NETD-BPF#14] Move BPF map definition and utils to frameworks/libs/net/

Move BPF map definition and utilities to a common place that easy to be
referenced from both mainline module and platform code.

Bug: 202086915
Test: m; flash; boot
Test: cd system/netd/ && atest
Test: cd packages/modules/Connectivity && atest
Test: m gpuservice_unittest libtimeinstate_test bpf_module_test
      CtsAppOpsTestCases libbpf_load_test VtsBootconfigTest
      vts_test_binary_bpf_module bpf_benchmark libbpf_load_test
      libbpf_android_test
Change-Id: Ib15cf78c2da97bff835fb406c866676eec77c013
diff --git a/bpfloader/Android.bp b/bpfloader/Android.bp
index 7e7139f..c754e8d 100644
--- a/bpfloader/Android.bp
+++ b/bpfloader/Android.bp
@@ -39,6 +39,7 @@
         memtag_heap: true,
     },
     clang: true,
+    header_libs: ["bpf_map_utils"],
     shared_libs: [
         "libcutils",
         "libbpf_android",
diff --git a/libbpf_android/Android.bp b/libbpf_android/Android.bp
index b3ab84c..7ab4c47 100644
--- a/libbpf_android/Android.bp
+++ b/libbpf_android/Android.bp
@@ -61,9 +61,13 @@
         "libbpf",
     ],
     header_libs: [
-        "libbpf_android_headers"
+        "bpf_map_utils",
+        "libbpf_android_headers",
     ],
-    export_header_lib_headers: ["libbpf_android_headers"],
+    export_header_lib_headers: [
+        "libbpf_android_headers",
+        "bpf_map_utils",
+    ],
     export_shared_lib_headers: ["libbpf"],
     local_include_dirs: ["include"],
 
@@ -77,6 +81,7 @@
 
 cc_test {
     name: "libbpf_load_test",
+    header_libs: ["bpf_map_utils"],
     srcs: [
         "BpfLoadTest.cpp",
     ],
diff --git a/libbpf_android/BpfLoadTest.cpp b/libbpf_android/BpfLoadTest.cpp
index 09cd36c..a058263 100644
--- a/libbpf_android/BpfLoadTest.cpp
+++ b/libbpf_android/BpfLoadTest.cpp
@@ -19,8 +19,8 @@
 #include <stdlib.h>
 #include <unistd.h>
 #include <iostream>
-#include "include/bpf/BpfMap.h"
-#include "include/bpf/BpfUtils.h"
+#include "bpf/BpfMap.h"
+#include "bpf/BpfUtils.h"
 #include "include/libbpf_android.h"
 
 using ::testing::Test;
diff --git a/libbpf_android/include/WaitForProgsLoaded.h b/libbpf_android/include/WaitForProgsLoaded.h
deleted file mode 100644
index bc4168e..0000000
--- a/libbpf_android/include/WaitForProgsLoaded.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- * Android BPF library - public API
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <log/log.h>
-
-#include <android-base/properties.h>
-
-namespace android {
-namespace bpf {
-
-// Wait for bpfloader to load BPF programs.
-static inline void waitForProgsLoaded() {
-    // infinite loop until success with 5/10/20/40/60/60/60... delay
-    for (int delay = 5;; delay *= 2) {
-        if (delay > 60) delay = 60;
-        if (android::base::WaitForProperty("bpf.progs_loaded", "1", std::chrono::seconds(delay)))
-            return;
-        ALOGW("Waited %ds for bpf.progs_loaded, still waiting...", delay);
-    }
-}
-
-}  // namespace bpf
-}  // namespace android
diff --git a/libbpf_android/include/bpf/BpfMap.h b/libbpf_android/include/bpf/BpfMap.h
deleted file mode 100644
index bdffc0f..0000000
--- a/libbpf_android/include/bpf/BpfMap.h
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <linux/bpf.h>
-
-#include <android-base/result.h>
-#include <android-base/stringprintf.h>
-#include <android-base/unique_fd.h>
-#include <utils/Log.h>
-#include "bpf/BpfUtils.h"
-
-namespace android {
-namespace bpf {
-
-// This is a class wrapper for eBPF maps. The eBPF map is a special in-kernel
-// data structure that stores data in <Key, Value> pairs. It can be read/write
-// from userspace by passing syscalls with the map file descriptor. This class
-// is used to generalize the procedure of interacting with eBPF maps and hide
-// the implementation detail from other process. Besides the basic syscalls
-// wrapper, it also provides some useful helper functions as well as an iterator
-// nested class to iterate the map more easily.
-//
-// NOTE: A kernel eBPF map may be accessed by both kernel and userspace
-// processes at the same time. Or if the map is pinned as a virtual file, it can
-// be obtained by multiple eBPF map class object and accessed concurrently.
-// Though the map class object and the underlying kernel map are thread safe, it
-// is not safe to iterate over a map while another thread or process is deleting
-// from it. In this case the iteration can return duplicate entries.
-template <class Key, class Value>
-class BpfMap {
-  public:
-    BpfMap<Key, Value>() {};
-
-  protected:
-    // flag must be within BPF_OBJ_FLAG_MASK, ie. 0, BPF_F_RDONLY, BPF_F_WRONLY
-    BpfMap<Key, Value>(const char* pathname, uint32_t flags) {
-        int map_fd = mapRetrieve(pathname, flags);
-        if (map_fd >= 0) mMapFd.reset(map_fd);
-    }
-
-  public:
-    explicit BpfMap<Key, Value>(const char* pathname) : BpfMap<Key, Value>(pathname, 0) {}
-
-    BpfMap<Key, Value>(bpf_map_type map_type, uint32_t max_entries, uint32_t map_flags = 0) {
-        int map_fd = createMap(map_type, sizeof(Key), sizeof(Value), max_entries, map_flags);
-        if (map_fd >= 0) mMapFd.reset(map_fd);
-    }
-
-    base::Result<Key> getFirstKey() const {
-        Key firstKey;
-        if (getFirstMapKey(mMapFd, &firstKey)) {
-            return ErrnoErrorf("Get firstKey map {} failed", mMapFd.get());
-        }
-        return firstKey;
-    }
-
-    base::Result<Key> getNextKey(const Key& key) const {
-        Key nextKey;
-        if (getNextMapKey(mMapFd, &key, &nextKey)) {
-            return ErrnoErrorf("Get next key of map {} failed", mMapFd.get());
-        }
-        return nextKey;
-    }
-
-    base::Result<void> writeValue(const Key& key, const Value& value, uint64_t flags) {
-        if (writeToMapEntry(mMapFd, &key, &value, flags)) {
-            return ErrnoErrorf("Write to map {} failed", mMapFd.get());
-        }
-        return {};
-    }
-
-    base::Result<Value> readValue(const Key key) const {
-        Value value;
-        if (findMapEntry(mMapFd, &key, &value)) {
-            return ErrnoErrorf("Read value of map {} failed", mMapFd.get());
-        }
-        return value;
-    }
-
-    base::Result<void> deleteValue(const Key& key) {
-        if (deleteMapEntry(mMapFd, &key)) {
-            return ErrnoErrorf("Delete entry from map {} failed", mMapFd.get());
-        }
-        return {};
-    }
-
-    // Function that tries to get map from a pinned path.
-    base::Result<void> init(const char* path);
-
-    // Iterate through the map and handle each key retrieved based on the filter
-    // without modification of map content.
-    base::Result<void> iterate(
-            const std::function<base::Result<void>(const Key& key, const BpfMap<Key, Value>& map)>&
-                    filter) const;
-
-    // Iterate through the map and get each <key, value> pair, handle each <key,
-    // value> pair based on the filter without modification of map content.
-    base::Result<void> iterateWithValue(
-            const std::function<base::Result<void>(const Key& key, const Value& value,
-                                                   const BpfMap<Key, Value>& map)>& filter) const;
-
-    // Iterate through the map and handle each key retrieved based on the filter
-    base::Result<void> iterate(
-            const std::function<base::Result<void>(const Key& key, BpfMap<Key, Value>& map)>&
-                    filter);
-
-    // Iterate through the map and get each <key, value> pair, handle each <key,
-    // value> pair based on the filter.
-    base::Result<void> iterateWithValue(
-            const std::function<base::Result<void>(const Key& key, const Value& value,
-                                                   BpfMap<Key, Value>& map)>& filter);
-
-    const base::unique_fd& getMap() const { return mMapFd; };
-
-    // Copy assignment operator
-    BpfMap<Key, Value>& operator=(const BpfMap<Key, Value>& other) {
-        if (this != &other) mMapFd.reset(fcntl(other.mMapFd.get(), F_DUPFD_CLOEXEC, 0));
-        return *this;
-    }
-
-    // Move assignment operator
-    BpfMap<Key, Value>& operator=(BpfMap<Key, Value>&& other) noexcept {
-        mMapFd = std::move(other.mMapFd);
-        other.reset(-1);
-        return *this;
-    }
-
-    void reset(base::unique_fd fd) = delete;
-
-    void reset(int fd) { mMapFd.reset(fd); }
-
-    bool isValid() const { return mMapFd != -1; }
-
-    base::Result<void> clear() {
-        while (true) {
-            auto key = getFirstKey();
-            if (!key.ok()) {
-                if (key.error().code() == ENOENT) return {};  // empty: success
-                return key.error();                           // Anything else is an error
-            }
-            auto res = deleteValue(key.value());
-            if (!res.ok()) {
-                // Someone else could have deleted the key, so ignore ENOENT
-                if (res.error().code() == ENOENT) continue;
-                ALOGE("Failed to delete data %s", strerror(res.error().code()));
-                return res.error();
-            }
-        }
-    }
-
-    base::Result<bool> isEmpty() const {
-        auto key = getFirstKey();
-        if (!key.ok()) {
-            // Return error code ENOENT means the map is empty
-            if (key.error().code() == ENOENT) return true;
-            return key.error();
-        }
-        return false;
-    }
-
-  private:
-    base::unique_fd mMapFd;
-};
-
-template <class Key, class Value>
-base::Result<void> BpfMap<Key, Value>::init(const char* path) {
-    mMapFd = base::unique_fd(mapRetrieveRW(path));
-    if (mMapFd == -1) {
-        return ErrnoErrorf("Pinned map not accessible or does not exist: ({})", path);
-    }
-    return {};
-}
-
-template <class Key, class Value>
-base::Result<void> BpfMap<Key, Value>::iterate(
-        const std::function<base::Result<void>(const Key& key, const BpfMap<Key, Value>& map)>&
-                filter) const {
-    base::Result<Key> curKey = getFirstKey();
-    while (curKey.ok()) {
-        const base::Result<Key>& nextKey = getNextKey(curKey.value());
-        base::Result<void> status = filter(curKey.value(), *this);
-        if (!status.ok()) return status;
-        curKey = nextKey;
-    }
-    if (curKey.error().code() == ENOENT) return {};
-    return curKey.error();
-}
-
-template <class Key, class Value>
-base::Result<void> BpfMap<Key, Value>::iterateWithValue(
-        const std::function<base::Result<void>(const Key& key, const Value& value,
-                                               const BpfMap<Key, Value>& map)>& filter) const {
-    base::Result<Key> curKey = getFirstKey();
-    while (curKey.ok()) {
-        const base::Result<Key>& nextKey = getNextKey(curKey.value());
-        base::Result<Value> curValue = readValue(curKey.value());
-        if (!curValue.ok()) return curValue.error();
-        base::Result<void> status = filter(curKey.value(), curValue.value(), *this);
-        if (!status.ok()) return status;
-        curKey = nextKey;
-    }
-    if (curKey.error().code() == ENOENT) return {};
-    return curKey.error();
-}
-
-template <class Key, class Value>
-base::Result<void> BpfMap<Key, Value>::iterate(
-        const std::function<base::Result<void>(const Key& key, BpfMap<Key, Value>& map)>& filter) {
-    base::Result<Key> curKey = getFirstKey();
-    while (curKey.ok()) {
-        const base::Result<Key>& nextKey = getNextKey(curKey.value());
-        base::Result<void> status = filter(curKey.value(), *this);
-        if (!status.ok()) return status;
-        curKey = nextKey;
-    }
-    if (curKey.error().code() == ENOENT) return {};
-    return curKey.error();
-}
-
-template <class Key, class Value>
-base::Result<void> BpfMap<Key, Value>::iterateWithValue(
-        const std::function<base::Result<void>(const Key& key, const Value& value,
-                                               BpfMap<Key, Value>& map)>& filter) {
-    base::Result<Key> curKey = getFirstKey();
-    while (curKey.ok()) {
-        const base::Result<Key>& nextKey = getNextKey(curKey.value());
-        base::Result<Value> curValue = readValue(curKey.value());
-        if (!curValue.ok()) return curValue.error();
-        base::Result<void> status = filter(curKey.value(), curValue.value(), *this);
-        if (!status.ok()) return status;
-        curKey = nextKey;
-    }
-    if (curKey.error().code() == ENOENT) return {};
-    return curKey.error();
-}
-
-template <class Key, class Value>
-class BpfMapRO : public BpfMap<Key, Value> {
-  public:
-    explicit BpfMapRO<Key, Value>(const char* pathname)
-        : BpfMap<Key, Value>(pathname, BPF_F_RDONLY) {}
-};
-
-}  // namespace bpf
-}  // namespace android
diff --git a/libbpf_android/include/bpf/BpfUtils.h b/libbpf_android/include/bpf/BpfUtils.h
deleted file mode 100644
index 8f1b9a2..0000000
--- a/libbpf_android/include/bpf/BpfUtils.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <linux/if_ether.h>
-#include <linux/pfkeyv2.h>
-#include <net/if.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/resource.h>
-#include <sys/socket.h>
-#include <sys/utsname.h>
-
-#include <string>
-
-#include <android-base/unique_fd.h>
-#include <log/log.h>
-
-#include "BpfSyscallWrappers.h"
-
-// The buffer size for the buffer that records program loading logs, needs to be large enough for
-// the largest kernel program.
-
-namespace android {
-namespace bpf {
-
-constexpr const int OVERFLOW_COUNTERSET = 2;
-
-constexpr const uint64_t NONEXISTENT_COOKIE = 0;
-
-static inline uint64_t getSocketCookie(int sockFd) {
-    uint64_t sock_cookie;
-    socklen_t cookie_len = sizeof(sock_cookie);
-    int res = getsockopt(sockFd, SOL_SOCKET, SO_COOKIE, &sock_cookie, &cookie_len);
-    if (res < 0) {
-        res = -errno;
-        ALOGE("Failed to get socket cookie: %s\n", strerror(errno));
-        errno = -res;
-        // 0 is an invalid cookie. See sock_gen_cookie.
-        return NONEXISTENT_COOKIE;
-    }
-    return sock_cookie;
-}
-
-static inline int synchronizeKernelRCU() {
-    // This is a temporary hack for network stats map swap on devices running
-    // 4.9 kernels. The kernel code of socket release on pf_key socket will
-    // explicitly call synchronize_rcu() which is exactly what we need.
-    int pfSocket = socket(AF_KEY, SOCK_RAW | SOCK_CLOEXEC, PF_KEY_V2);
-
-    if (pfSocket < 0) {
-        int ret = -errno;
-        ALOGE("create PF_KEY socket failed: %s", strerror(errno));
-        return ret;
-    }
-
-    // When closing socket, synchronize_rcu() gets called in sock_release().
-    if (close(pfSocket)) {
-        int ret = -errno;
-        ALOGE("failed to close the PF_KEY socket: %s", strerror(errno));
-        return ret;
-    }
-    return 0;
-}
-
-static inline int setrlimitForTest() {
-    // Set the memory rlimit for the test process if the default MEMLOCK rlimit is not enough.
-    struct rlimit limit = {
-            .rlim_cur = 1073741824,  // 1 GiB
-            .rlim_max = 1073741824,  // 1 GiB
-    };
-    int res = setrlimit(RLIMIT_MEMLOCK, &limit);
-    if (res) {
-        ALOGE("Failed to set the default MEMLOCK rlimit: %s", strerror(errno));
-    }
-    return res;
-}
-
-#define KVER(a, b, c) (((a) << 24) + ((b) << 16) + (c))
-
-static inline unsigned kernelVersion() {
-    struct utsname buf;
-    int ret = uname(&buf);
-    if (ret) return 0;
-
-    unsigned kver_major;
-    unsigned kver_minor;
-    unsigned kver_sub;
-    char unused;
-    ret = sscanf(buf.release, "%u.%u.%u%c", &kver_major, &kver_minor, &kver_sub, &unused);
-    // Check the device kernel version
-    if (ret < 3) return 0;
-
-    return KVER(kver_major, kver_minor, kver_sub);
-}
-
-static inline bool isAtLeastKernelVersion(unsigned major, unsigned minor, unsigned sub) {
-    return kernelVersion() >= KVER(major, minor, sub);
-}
-
-#define SKIP_IF_BPF_SUPPORTED                              \
-    do {                                                   \
-        if (android::bpf::isAtLeastKernelVersion(4, 9, 0)) \
-            GTEST_SKIP() << "Skip: bpf is supported.";     \
-    } while (0)
-
-#define SKIP_IF_BPF_NOT_SUPPORTED                           \
-    do {                                                    \
-        if (!android::bpf::isAtLeastKernelVersion(4, 9, 0)) \
-            GTEST_SKIP() << "Skip: bpf is not supported.";  \
-    } while (0)
-
-#define SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED                               \
-    do {                                                                 \
-        if (!android::bpf::isAtLeastKernelVersion(4, 14, 0))             \
-            GTEST_SKIP() << "Skip: extended bpf feature not supported."; \
-    } while (0)
-
-#define SKIP_IF_XDP_NOT_SUPPORTED                           \
-    do {                                                    \
-        if (!android::bpf::isAtLeastKernelVersion(5, 9, 0)) \
-            GTEST_SKIP() << "Skip: xdp not supported.";     \
-    } while (0)
-
-}  // namespace bpf
-}  // namespace android