Merge "Add detailed kernel version when checking bpf support"
diff --git a/libbpf_android/BpfUtils.cpp b/libbpf_android/BpfUtils.cpp
index 74585b2..109715b 100644
--- a/libbpf_android/BpfUtils.cpp
+++ b/libbpf_android/BpfUtils.cpp
@@ -237,7 +237,17 @@
     return 0;
 }
 
-bool hasBpfSupport() {
+std::string BpfLevelToString(BpfLevel bpfLevel) {
+    switch (bpfLevel) {
+        case BpfLevel::NONE:      return "NONE_SUPPORT";
+        case BpfLevel::BASIC:     return "BPF_LEVEL_BASIC";
+        case BpfLevel::EXTENDED:  return "BPF_LEVEL_EXTENDED";
+        // No default statement. We want to see errors of the form:
+        // "enumeration value 'BPF_LEVEL_xxx' not handled in switch [-Werror,-Wswitch]".
+    }
+}
+
+BpfLevel getBpfSupportLevel() {
     struct utsname buf;
     int kernel_version_major;
     int kernel_version_minor;
@@ -248,18 +258,22 @@
         api_level = GetUintProperty<uint64_t>("ro.build.version.sdk", 0);
     }
 
+    // Check if the device is shipped originally with android P.
+    if (api_level < MINIMUM_API_REQUIRED) return BpfLevel::NONE;
+
     int ret = uname(&buf);
     if (ret) {
-        return false;
+        return BpfLevel::NONE;
     }
     char dummy;
     ret = sscanf(buf.release, "%d.%d%c", &kernel_version_major, &kernel_version_minor, &dummy);
-    if (ret >= 2 &&
-        ((kernel_version_major > 4) || (kernel_version_major == 4 && kernel_version_minor >= 9))) {
-        // Check if the device is shipped originally with android P.
-        return api_level >= MINIMUM_API_REQUIRED;
-    }
-    return false;
+    // Check the device kernel version
+    if (ret < 2) return BpfLevel::NONE;
+    if (kernel_version_major > 4 || (kernel_version_major == 4 && kernel_version_minor >= 14))
+        return BpfLevel::EXTENDED;
+    if (kernel_version_major == 4 && kernel_version_minor >= 9) return BpfLevel::BASIC;
+
+    return BpfLevel::NONE;
 }
 
 int loadAndPinProgram(BpfProgInfo* prog, Slice progBlock) {
diff --git a/libbpf_android/include/bpf/BpfUtils.h b/libbpf_android/include/bpf/BpfUtils.h
index 296b0fd..77a18fa 100644
--- a/libbpf_android/include/bpf/BpfUtils.h
+++ b/libbpf_android/include/bpf/BpfUtils.h
@@ -121,6 +121,18 @@
     }
 };
 
+enum class BpfLevel {
+    // Devices shipped before P or kernel version is lower than 4.9 do not
+    // have eBPF enabled.
+    NONE,
+    // Devices shipped in P with android 4.9 kernel only have the basic eBPF
+    // functionalities such as xt_bpf and cgroup skb filter.
+    BASIC,
+    // For devices that have 4.14 kernel. It supports advanced features like
+    // map_in_map and cgroup socket filter.
+    EXTENDED,
+};
+
 #ifndef DEFAULT_OVERFLOWUID
 #define DEFAULT_OVERFLOWUID 65534
 #endif
@@ -145,14 +157,23 @@
 int attachProgram(bpf_attach_type type, uint32_t prog_fd, uint32_t cg_fd);
 int detachProgram(bpf_attach_type type, uint32_t cg_fd);
 uint64_t getSocketCookie(int sockFd);
-bool hasBpfSupport();
+std::string BpfLevelToString(BpfLevel BpfLevel);
+BpfLevel getBpfSupportLevel();
 int parseProgramsFromFile(const char* path, BpfProgInfo* programs, size_t size,
                           const std::vector<BpfMapInfo>& mapPatterns);
 int synchronizeKernelRCU();
 
-#define SKIP_IF_BPF_NOT_SUPPORTED     \
-    do {                              \
-        if (!hasBpfSupport()) return; \
+#define SKIP_IF_BPF_NOT_SUPPORTED                                                    \
+    do {                                                                             \
+        if (android::bpf::getBpfSupportLevel() == android::bpf::BpfLevel::NONE) {    \
+            GTEST_LOG_(INFO) << "This test is skipped since bpf is not available\n"; \
+            return;                                                                  \
+        }                                                                            \
+    } while (0)
+
+#define SKIP_IF_BPF_SUPPORTED                                                           \
+    do {                                                                                \
+        if (android::bpf::getBpfSupportLevel() != android::bpf::BpfLevel::NONE) return; \
     } while (0)
 
 constexpr int BPF_CONTINUE = 0;