1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (c) 2022 Meta Platforms, Inc. and affiliates. */ 3 4 #include <ctype.h> 5 #include <test_progs.h> 6 #include <bpf/btf.h> 7 8 /* 9 * Utility function uppercasing an entire string. 10 */ 11 static void uppercase(char *s) 12 { 13 for (; *s != '\0'; s++) 14 *s = toupper(*s); 15 } 16 17 /* 18 * Test case to check that all bpf_attach_type variants are covered by 19 * libbpf_bpf_attach_type_str. 20 */ 21 static void test_libbpf_bpf_attach_type_str(void) 22 { 23 struct btf *btf; 24 const struct btf_type *t; 25 const struct btf_enum *e; 26 int i, n, id; 27 28 btf = btf__parse("/sys/kernel/btf/vmlinux", NULL); 29 if (!ASSERT_OK_PTR(btf, "btf_parse")) 30 return; 31 32 /* find enum bpf_attach_type and enumerate each value */ 33 id = btf__find_by_name_kind(btf, "bpf_attach_type", BTF_KIND_ENUM); 34 if (!ASSERT_GT(id, 0, "bpf_attach_type_id")) 35 goto cleanup; 36 t = btf__type_by_id(btf, id); 37 e = btf_enum(t); 38 n = btf_vlen(t); 39 for (i = 0; i < n; e++, i++) { 40 enum bpf_attach_type attach_type = (enum bpf_attach_type)e->val; 41 const char *attach_type_name; 42 const char *attach_type_str; 43 char buf[256]; 44 45 if (attach_type == __MAX_BPF_ATTACH_TYPE) 46 continue; 47 48 attach_type_name = btf__str_by_offset(btf, e->name_off); 49 attach_type_str = libbpf_bpf_attach_type_str(attach_type); 50 ASSERT_OK_PTR(attach_type_str, attach_type_name); 51 52 snprintf(buf, sizeof(buf), "BPF_%s", attach_type_str); 53 uppercase(buf); 54 55 ASSERT_STREQ(buf, attach_type_name, "exp_str_value"); 56 } 57 58 cleanup: 59 btf__free(btf); 60 } 61 62 /* 63 * Test case to check that all bpf_link_type variants are covered by 64 * libbpf_bpf_link_type_str. 65 */ 66 static void test_libbpf_bpf_link_type_str(void) 67 { 68 struct btf *btf; 69 const struct btf_type *t; 70 const struct btf_enum *e; 71 int i, n, id; 72 73 btf = btf__parse("/sys/kernel/btf/vmlinux", NULL); 74 if (!ASSERT_OK_PTR(btf, "btf_parse")) 75 return; 76 77 /* find enum bpf_link_type and enumerate each value */ 78 id = btf__find_by_name_kind(btf, "bpf_link_type", BTF_KIND_ENUM); 79 if (!ASSERT_GT(id, 0, "bpf_link_type_id")) 80 goto cleanup; 81 t = btf__type_by_id(btf, id); 82 e = btf_enum(t); 83 n = btf_vlen(t); 84 for (i = 0; i < n; e++, i++) { 85 enum bpf_link_type link_type = (enum bpf_link_type)e->val; 86 const char *link_type_name; 87 const char *link_type_str; 88 char buf[256]; 89 90 if (link_type == MAX_BPF_LINK_TYPE) 91 continue; 92 93 link_type_name = btf__str_by_offset(btf, e->name_off); 94 link_type_str = libbpf_bpf_link_type_str(link_type); 95 ASSERT_OK_PTR(link_type_str, link_type_name); 96 97 snprintf(buf, sizeof(buf), "BPF_LINK_TYPE_%s", link_type_str); 98 uppercase(buf); 99 100 ASSERT_STREQ(buf, link_type_name, "exp_str_value"); 101 } 102 103 cleanup: 104 btf__free(btf); 105 } 106 107 /* 108 * Test case to check that all bpf_map_type variants are covered by 109 * libbpf_bpf_map_type_str. 110 */ 111 static void test_libbpf_bpf_map_type_str(void) 112 { 113 struct btf *btf; 114 const struct btf_type *t; 115 const struct btf_enum *e; 116 int i, n, id; 117 118 btf = btf__parse("/sys/kernel/btf/vmlinux", NULL); 119 if (!ASSERT_OK_PTR(btf, "btf_parse")) 120 return; 121 122 /* find enum bpf_map_type and enumerate each value */ 123 id = btf__find_by_name_kind(btf, "bpf_map_type", BTF_KIND_ENUM); 124 if (!ASSERT_GT(id, 0, "bpf_map_type_id")) 125 goto cleanup; 126 t = btf__type_by_id(btf, id); 127 e = btf_enum(t); 128 n = btf_vlen(t); 129 for (i = 0; i < n; e++, i++) { 130 enum bpf_map_type map_type = (enum bpf_map_type)e->val; 131 const char *map_type_name; 132 const char *map_type_str; 133 char buf[256]; 134 135 map_type_name = btf__str_by_offset(btf, e->name_off); 136 map_type_str = libbpf_bpf_map_type_str(map_type); 137 ASSERT_OK_PTR(map_type_str, map_type_name); 138 139 snprintf(buf, sizeof(buf), "BPF_MAP_TYPE_%s", map_type_str); 140 uppercase(buf); 141 142 /* Special case for map_type_name BPF_MAP_TYPE_CGROUP_STORAGE_DEPRECATED 143 * where it and BPF_MAP_TYPE_CGROUP_STORAGE have the same enum value 144 * (map_type). For this enum value, libbpf_bpf_map_type_str() picks 145 * BPF_MAP_TYPE_CGROUP_STORAGE. 146 */ 147 if (strcmp(map_type_name, "BPF_MAP_TYPE_CGROUP_STORAGE_DEPRECATED") == 0) 148 continue; 149 150 ASSERT_STREQ(buf, map_type_name, "exp_str_value"); 151 } 152 153 cleanup: 154 btf__free(btf); 155 } 156 157 /* 158 * Test case to check that all bpf_prog_type variants are covered by 159 * libbpf_bpf_prog_type_str. 160 */ 161 static void test_libbpf_bpf_prog_type_str(void) 162 { 163 struct btf *btf; 164 const struct btf_type *t; 165 const struct btf_enum *e; 166 int i, n, id; 167 168 btf = btf__parse("/sys/kernel/btf/vmlinux", NULL); 169 if (!ASSERT_OK_PTR(btf, "btf_parse")) 170 return; 171 172 /* find enum bpf_prog_type and enumerate each value */ 173 id = btf__find_by_name_kind(btf, "bpf_prog_type", BTF_KIND_ENUM); 174 if (!ASSERT_GT(id, 0, "bpf_prog_type_id")) 175 goto cleanup; 176 t = btf__type_by_id(btf, id); 177 e = btf_enum(t); 178 n = btf_vlen(t); 179 for (i = 0; i < n; e++, i++) { 180 enum bpf_prog_type prog_type = (enum bpf_prog_type)e->val; 181 const char *prog_type_name; 182 const char *prog_type_str; 183 char buf[256]; 184 185 prog_type_name = btf__str_by_offset(btf, e->name_off); 186 prog_type_str = libbpf_bpf_prog_type_str(prog_type); 187 ASSERT_OK_PTR(prog_type_str, prog_type_name); 188 189 snprintf(buf, sizeof(buf), "BPF_PROG_TYPE_%s", prog_type_str); 190 uppercase(buf); 191 192 ASSERT_STREQ(buf, prog_type_name, "exp_str_value"); 193 } 194 195 cleanup: 196 btf__free(btf); 197 } 198 199 /* 200 * Run all libbpf str conversion tests. 201 */ 202 void test_libbpf_str(void) 203 { 204 if (test__start_subtest("bpf_attach_type_str")) 205 test_libbpf_bpf_attach_type_str(); 206 207 if (test__start_subtest("bpf_link_type_str")) 208 test_libbpf_bpf_link_type_str(); 209 210 if (test__start_subtest("bpf_map_type_str")) 211 test_libbpf_bpf_map_type_str(); 212 213 if (test__start_subtest("bpf_prog_type_str")) 214 test_libbpf_bpf_prog_type_str(); 215 } 216