1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <sys/types.h> 4 #include <sys/stat.h> 5 #include <unistd.h> 6 #include <test_progs.h> 7 8 __u32 get_map_id(struct bpf_object *obj, const char *name) 9 { 10 struct bpf_map_info map_info = {}; 11 __u32 map_info_len, duration = 0; 12 struct bpf_map *map; 13 int err; 14 15 map_info_len = sizeof(map_info); 16 17 map = bpf_object__find_map_by_name(obj, name); 18 if (CHECK(!map, "find map", "NULL map")) 19 return 0; 20 21 err = bpf_obj_get_info_by_fd(bpf_map__fd(map), 22 &map_info, &map_info_len); 23 CHECK(err, "get map info", "err %d errno %d", err, errno); 24 return map_info.id; 25 } 26 27 void test_pinning(void) 28 { 29 const char *file_invalid = "./test_pinning_invalid.o"; 30 const char *custpinpath = "/sys/fs/bpf/custom/pinmap"; 31 const char *nopinpath = "/sys/fs/bpf/nopinmap"; 32 const char *nopinpath2 = "/sys/fs/bpf/nopinmap2"; 33 const char *custpath = "/sys/fs/bpf/custom"; 34 const char *pinpath = "/sys/fs/bpf/pinmap"; 35 const char *file = "./test_pinning.o"; 36 __u32 map_id, map_id2, duration = 0; 37 struct stat statbuf = {}; 38 struct bpf_object *obj; 39 struct bpf_map *map; 40 int err, map_fd; 41 DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts, 42 .pin_root_path = custpath, 43 ); 44 45 /* check that opening fails with invalid pinning value in map def */ 46 obj = bpf_object__open_file(file_invalid, NULL); 47 err = libbpf_get_error(obj); 48 if (CHECK(err != -EINVAL, "invalid open", "err %d errno %d\n", err, errno)) { 49 obj = NULL; 50 goto out; 51 } 52 53 /* open the valid object file */ 54 obj = bpf_object__open_file(file, NULL); 55 err = libbpf_get_error(obj); 56 if (CHECK(err, "default open", "err %d errno %d\n", err, errno)) { 57 obj = NULL; 58 goto out; 59 } 60 61 err = bpf_object__load(obj); 62 if (CHECK(err, "default load", "err %d errno %d\n", err, errno)) 63 goto out; 64 65 /* check that pinmap was pinned */ 66 err = stat(pinpath, &statbuf); 67 if (CHECK(err, "stat pinpath", "err %d errno %d\n", err, errno)) 68 goto out; 69 70 /* check that nopinmap was *not* pinned */ 71 err = stat(nopinpath, &statbuf); 72 if (CHECK(!err || errno != ENOENT, "stat nopinpath", 73 "err %d errno %d\n", err, errno)) 74 goto out; 75 76 /* check that nopinmap2 was *not* pinned */ 77 err = stat(nopinpath2, &statbuf); 78 if (CHECK(!err || errno != ENOENT, "stat nopinpath2", 79 "err %d errno %d\n", err, errno)) 80 goto out; 81 82 map_id = get_map_id(obj, "pinmap"); 83 if (!map_id) 84 goto out; 85 86 bpf_object__close(obj); 87 88 obj = bpf_object__open_file(file, NULL); 89 if (CHECK_FAIL(libbpf_get_error(obj))) { 90 obj = NULL; 91 goto out; 92 } 93 94 err = bpf_object__load(obj); 95 if (CHECK(err, "default load", "err %d errno %d\n", err, errno)) 96 goto out; 97 98 /* check that same map ID was reused for second load */ 99 map_id2 = get_map_id(obj, "pinmap"); 100 if (CHECK(map_id != map_id2, "check reuse", 101 "err %d errno %d id %d id2 %d\n", err, errno, map_id, map_id2)) 102 goto out; 103 104 /* should be no-op to re-pin same map */ 105 map = bpf_object__find_map_by_name(obj, "pinmap"); 106 if (CHECK(!map, "find map", "NULL map")) 107 goto out; 108 109 err = bpf_map__pin(map, NULL); 110 if (CHECK(err, "re-pin map", "err %d errno %d\n", err, errno)) 111 goto out; 112 113 /* but error to pin at different location */ 114 err = bpf_map__pin(map, "/sys/fs/bpf/other"); 115 if (CHECK(!err, "pin map different", "err %d errno %d\n", err, errno)) 116 goto out; 117 118 /* unpin maps with a pin_path set */ 119 err = bpf_object__unpin_maps(obj, NULL); 120 if (CHECK(err, "unpin maps", "err %d errno %d\n", err, errno)) 121 goto out; 122 123 /* and re-pin them... */ 124 err = bpf_object__pin_maps(obj, NULL); 125 if (CHECK(err, "pin maps", "err %d errno %d\n", err, errno)) 126 goto out; 127 128 /* get pinning path */ 129 if (!ASSERT_STREQ(bpf_map__pin_path(map), pinpath, "get pin path")) 130 goto out; 131 132 /* set pinning path of other map and re-pin all */ 133 map = bpf_object__find_map_by_name(obj, "nopinmap"); 134 if (CHECK(!map, "find map", "NULL map")) 135 goto out; 136 137 err = bpf_map__set_pin_path(map, custpinpath); 138 if (CHECK(err, "set pin path", "err %d errno %d\n", err, errno)) 139 goto out; 140 141 /* get pinning path after set */ 142 if (!ASSERT_STREQ(bpf_map__pin_path(map), custpinpath, 143 "get pin path after set")) 144 goto out; 145 146 /* should only pin the one unpinned map */ 147 err = bpf_object__pin_maps(obj, NULL); 148 if (CHECK(err, "pin maps", "err %d errno %d\n", err, errno)) 149 goto out; 150 151 /* check that nopinmap was pinned at the custom path */ 152 err = stat(custpinpath, &statbuf); 153 if (CHECK(err, "stat custpinpath", "err %d errno %d\n", err, errno)) 154 goto out; 155 156 /* remove the custom pin path to re-test it with auto-pinning below */ 157 err = unlink(custpinpath); 158 if (CHECK(err, "unlink custpinpath", "err %d errno %d\n", err, errno)) 159 goto out; 160 161 err = rmdir(custpath); 162 if (CHECK(err, "rmdir custpindir", "err %d errno %d\n", err, errno)) 163 goto out; 164 165 bpf_object__close(obj); 166 167 /* open the valid object file again */ 168 obj = bpf_object__open_file(file, NULL); 169 err = libbpf_get_error(obj); 170 if (CHECK(err, "default open", "err %d errno %d\n", err, errno)) { 171 obj = NULL; 172 goto out; 173 } 174 175 /* set pin paths so that nopinmap2 will attempt to reuse the map at 176 * pinpath (which will fail), but not before pinmap has already been 177 * reused 178 */ 179 bpf_object__for_each_map(map, obj) { 180 if (!strcmp(bpf_map__name(map), "nopinmap")) 181 err = bpf_map__set_pin_path(map, nopinpath2); 182 else if (!strcmp(bpf_map__name(map), "nopinmap2")) 183 err = bpf_map__set_pin_path(map, pinpath); 184 else 185 continue; 186 187 if (CHECK(err, "set pin path", "err %d errno %d\n", err, errno)) 188 goto out; 189 } 190 191 /* should fail because of map parameter mismatch */ 192 err = bpf_object__load(obj); 193 if (CHECK(err != -EINVAL, "param mismatch load", "err %d errno %d\n", err, errno)) 194 goto out; 195 196 /* nopinmap2 should have been pinned and cleaned up again */ 197 err = stat(nopinpath2, &statbuf); 198 if (CHECK(!err || errno != ENOENT, "stat nopinpath2", 199 "err %d errno %d\n", err, errno)) 200 goto out; 201 202 /* pinmap should still be there */ 203 err = stat(pinpath, &statbuf); 204 if (CHECK(err, "stat pinpath", "err %d errno %d\n", err, errno)) 205 goto out; 206 207 bpf_object__close(obj); 208 209 /* test auto-pinning at custom path with open opt */ 210 obj = bpf_object__open_file(file, &opts); 211 if (CHECK_FAIL(libbpf_get_error(obj))) { 212 obj = NULL; 213 goto out; 214 } 215 216 err = bpf_object__load(obj); 217 if (CHECK(err, "custom load", "err %d errno %d\n", err, errno)) 218 goto out; 219 220 /* check that pinmap was pinned at the custom path */ 221 err = stat(custpinpath, &statbuf); 222 if (CHECK(err, "stat custpinpath", "err %d errno %d\n", err, errno)) 223 goto out; 224 225 /* remove the custom pin path to re-test it with reuse fd below */ 226 err = unlink(custpinpath); 227 if (CHECK(err, "unlink custpinpath", "err %d errno %d\n", err, errno)) 228 goto out; 229 230 err = rmdir(custpath); 231 if (CHECK(err, "rmdir custpindir", "err %d errno %d\n", err, errno)) 232 goto out; 233 234 bpf_object__close(obj); 235 236 /* test pinning at custom path with reuse fd */ 237 obj = bpf_object__open_file(file, NULL); 238 err = libbpf_get_error(obj); 239 if (CHECK(err, "default open", "err %d errno %d\n", err, errno)) { 240 obj = NULL; 241 goto out; 242 } 243 244 map_fd = bpf_map_create(BPF_MAP_TYPE_ARRAY, NULL, sizeof(__u32), 245 sizeof(__u64), 1, NULL); 246 if (CHECK(map_fd < 0, "create pinmap manually", "fd %d\n", map_fd)) 247 goto out; 248 249 map = bpf_object__find_map_by_name(obj, "pinmap"); 250 if (CHECK(!map, "find map", "NULL map")) 251 goto close_map_fd; 252 253 err = bpf_map__reuse_fd(map, map_fd); 254 if (CHECK(err, "reuse pinmap fd", "err %d errno %d\n", err, errno)) 255 goto close_map_fd; 256 257 err = bpf_map__set_pin_path(map, custpinpath); 258 if (CHECK(err, "set pin path", "err %d errno %d\n", err, errno)) 259 goto close_map_fd; 260 261 err = bpf_object__load(obj); 262 if (CHECK(err, "custom load", "err %d errno %d\n", err, errno)) 263 goto close_map_fd; 264 265 /* check that pinmap was pinned at the custom path */ 266 err = stat(custpinpath, &statbuf); 267 if (CHECK(err, "stat custpinpath", "err %d errno %d\n", err, errno)) 268 goto close_map_fd; 269 270 close_map_fd: 271 close(map_fd); 272 out: 273 unlink(pinpath); 274 unlink(nopinpath); 275 unlink(nopinpath2); 276 unlink(custpinpath); 277 rmdir(custpath); 278 if (obj) 279 bpf_object__close(obj); 280 } 281