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;
 }