add more precise bpf levels

This is to allow fixing a broken OffloadUtils netd test, but this will
also be useful for future support to make programs per kernel version.

We make the string versions of the enum more readable, because there
is exactly one user:

adb shell dumpsys netd | egrep -i bpf
  BPF module status: enabled
  BPF support level: Extended [4.14]
  ...

Test: build, atest
Signed-off-by: Maciej Żenczykowski <maze@google.com>
Change-Id: I843bd7355703a78acc8343ca7f647ce9366927eb
diff --git a/libbpf_android/BpfUtils.cpp b/libbpf_android/BpfUtils.cpp
index 535c537..f8ed6d5 100644
--- a/libbpf_android/BpfUtils.cpp
+++ b/libbpf_android/BpfUtils.cpp
@@ -98,19 +98,22 @@
 
 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]".
+        case BpfLevel::NONE:
+            return "None [pre-4.9]";
+        case BpfLevel::BASIC_4_9:
+            return "Basic [4.9]";
+        case BpfLevel::EXTENDED_4_14:
+            return "Extended [4.14]";
+        case BpfLevel::EXTENDED_4_19:
+            return "Extended [4.19]";
+        case BpfLevel::EXTENDED_5_4:
+            return "Extended [5.4+]";
+            // No default statement. We want to see errors of the form:
+            // "enumeration value 'BPF_LEVEL_xxx' not handled in switch [-Werror,-Wswitch]".
     }
 }
 
 static BpfLevel getUncachedBpfSupportLevel() {
-    struct utsname buf;
-    int kernel_version_major;
-    int kernel_version_minor;
-
     uint64_t api_level = GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
     if (api_level == 0) {
         ALOGE("Cannot determine initial API level of the device");
@@ -120,17 +123,23 @@
     // Check if the device is shipped originally with android P.
     if (api_level < MINIMUM_API_REQUIRED) return BpfLevel::NONE;
 
+    struct utsname buf;
     int ret = uname(&buf);
-    if (ret) {
-        return BpfLevel::NONE;
-    }
+    if (ret) return BpfLevel::NONE;
+
+    int kernel_version_major;
+    int kernel_version_minor;
     char dummy;
     ret = sscanf(buf.release, "%d.%d%c", &kernel_version_major, &kernel_version_minor, &dummy);
     // 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;
+
+    if (kernel_version_major > 5) return BpfLevel::EXTENDED_5_4;
+    if (kernel_version_major == 5 && kernel_version_minor >= 4) return BpfLevel::EXTENDED_5_4;
+    if (kernel_version_major == 5) return BpfLevel::EXTENDED_4_19;
+    if (kernel_version_major == 4 && kernel_version_minor >= 19) return BpfLevel::EXTENDED_4_19;
+    if (kernel_version_major == 4 && kernel_version_minor >= 14) return BpfLevel::EXTENDED_4_14;
+    if (kernel_version_major == 4 && kernel_version_minor >= 9) return BpfLevel::BASIC_4_9;
 
     return BpfLevel::NONE;
 }
diff --git a/libbpf_android/include/bpf/BpfUtils.h b/libbpf_android/include/bpf/BpfUtils.h
index be3cc8f..06dcc47 100644
--- a/libbpf_android/include/bpf/BpfUtils.h
+++ b/libbpf_android/include/bpf/BpfUtils.h
@@ -40,10 +40,12 @@
     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,
+    BASIC_4_9,
     // For devices that have 4.14 kernel. It supports advanced features like
     // map_in_map and cgroup socket filter.
-    EXTENDED,
+    EXTENDED_4_14,
+    EXTENDED_4_19,
+    EXTENDED_5_4,
 };
 
 constexpr const int OVERFLOW_COUNTERSET = 2;
@@ -166,13 +168,13 @@
         if (android::bpf::isBpfSupported()) return; \
     } while (0)
 
-#define SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED                                           \
-    do {                                                                             \
-        if (android::bpf::getBpfSupportLevel() < android::bpf::BpfLevel::EXTENDED) { \
-            GTEST_LOG_(INFO) << "This test is skipped since extended bpf feature"    \
-                             << "not supported\n";                                   \
-            return;                                                                  \
-        }                                                                            \
+#define SKIP_IF_EXTENDED_BPF_NOT_SUPPORTED                                                \
+    do {                                                                                  \
+        if (android::bpf::getBpfSupportLevel() < android::bpf::BpfLevel::EXTENDED_4_14) { \
+            GTEST_LOG_(INFO) << "This test is skipped since extended bpf feature"         \
+                             << "not supported\n";                                        \
+            return;                                                                       \
+        }                                                                                 \
     } while (0)
 
 }  // namespace bpf